mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2025-12-27 06:10:13 +01:00
kk: Add KosmicKrisp
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/37522>
This commit is contained in:
parent
f6c7f16322
commit
7c268a1e91
130 changed files with 24271 additions and 2 deletions
|
|
@ -271,7 +271,7 @@ elif _vulkan_drivers.contains('all')
|
|||
_vulkan_drivers = ['amd', 'intel', 'intel_hasvk', 'swrast',
|
||||
'freedreno', 'panfrost', 'virtio', 'broadcom',
|
||||
'imagination', 'microsoft-experimental',
|
||||
'nouveau', 'asahi', 'gfxstream']
|
||||
'nouveau', 'asahi', 'gfxstream', 'kosmickrisp']
|
||||
endif
|
||||
|
||||
with_intel_vk = _vulkan_drivers.contains('intel')
|
||||
|
|
@ -288,6 +288,7 @@ with_microsoft_vk = _vulkan_drivers.contains('microsoft-experimental')
|
|||
with_nouveau_vk = _vulkan_drivers.contains('nouveau')
|
||||
with_asahi_vk = _vulkan_drivers.contains('asahi')
|
||||
with_gfxstream_vk = _vulkan_drivers.contains('gfxstream')
|
||||
with_kosmickrisp_vk = _vulkan_drivers.contains('kosmickrisp')
|
||||
with_any_vk = _vulkan_drivers.length() != 0
|
||||
|
||||
with_llvm = with_llvm \
|
||||
|
|
@ -829,6 +830,7 @@ with_driver_using_cl = [
|
|||
with_gallium_asahi, with_asahi_vk, with_tools.contains('asahi'),
|
||||
with_gallium_panfrost, with_panfrost_vk,
|
||||
with_nouveau_vk, with_imagination_vk,
|
||||
with_kosmickrisp_vk,
|
||||
].contains(true)
|
||||
|
||||
if get_option('mesa-clc') == 'system'
|
||||
|
|
|
|||
|
|
@ -209,7 +209,7 @@ option(
|
|||
choices : ['auto', 'amd', 'broadcom', 'freedreno', 'intel', 'intel_hasvk',
|
||||
'panfrost', 'swrast', 'virtio', 'imagination',
|
||||
'microsoft-experimental', 'nouveau', 'asahi', 'gfxstream',
|
||||
'all'],
|
||||
'kosmickrisp', 'all'],
|
||||
description : 'List of vulkan drivers to build. If this is set to auto ' +
|
||||
'all drivers applicable to the target OS/architecture ' +
|
||||
'will be built'
|
||||
|
|
|
|||
7
src/kosmickrisp/.clang-format
Normal file
7
src/kosmickrisp/.clang-format
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
BasedOnStyle: InheritParentConfig
|
||||
DisableFormat: false
|
||||
|
||||
AlignConsecutiveBitFields: true
|
||||
ColumnLimit: 80
|
||||
BreakStringLiterals: false
|
||||
SpaceBeforeParens: ControlStatementsExceptControlMacros
|
||||
61
src/kosmickrisp/bridge/meson.build
Normal file
61
src/kosmickrisp/bridge/meson.build
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
# Copyright 2025 LunarG, Inc.
|
||||
# Copyright 2025 Google LLC
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
mtl_bridge_files = files(
|
||||
'vk_to_mtl_map.h',
|
||||
'vk_to_mtl_map.c',
|
||||
'mtl_format.h',
|
||||
)
|
||||
|
||||
if host_machine.system() == 'darwin'
|
||||
mtl_bridge_files += files(
|
||||
'mtl_bridge.m',
|
||||
'mtl_buffer.m',
|
||||
'mtl_command_buffer.m',
|
||||
'mtl_command_queue.m',
|
||||
'mtl_compute_state.m',
|
||||
'mtl_device.m',
|
||||
'mtl_encoder.m',
|
||||
'mtl_heap.m',
|
||||
'mtl_library.m',
|
||||
'mtl_render_state.m',
|
||||
'mtl_sampler.m',
|
||||
'mtl_sync.m',
|
||||
'mtl_texture.m',
|
||||
)
|
||||
else
|
||||
mtl_bridge_files += files(
|
||||
'stubs/mtl_bridge.c',
|
||||
'stubs/mtl_buffer.c',
|
||||
'stubs/mtl_command_buffer.c',
|
||||
'stubs/mtl_command_queue.c',
|
||||
'stubs/mtl_compute_state.c',
|
||||
'stubs/mtl_device.c',
|
||||
'stubs/mtl_encoder.c',
|
||||
'stubs/mtl_heap.c',
|
||||
'stubs/mtl_library.c',
|
||||
'stubs/mtl_render_state.c',
|
||||
'stubs/mtl_sampler.c',
|
||||
'stubs/mtl_sync.c',
|
||||
'stubs/mtl_texture.c',
|
||||
)
|
||||
endif
|
||||
|
||||
mtl_bridge_dependencies = [
|
||||
idep_vulkan_lite_runtime_headers,
|
||||
idep_vulkan_util_headers
|
||||
]
|
||||
|
||||
libmtl_bridge = static_library(
|
||||
'mtl_bridge',
|
||||
[mtl_bridge_files],
|
||||
include_directories : [include_directories('../vulkan/'), inc_include, inc_src],
|
||||
dependencies : mtl_bridge_dependencies,
|
||||
gnu_symbol_visibility: 'hidden',
|
||||
build_by_default: false,
|
||||
)
|
||||
|
||||
idep_mtl_bridge = declare_dependency(
|
||||
link_with : libmtl_bridge,
|
||||
)
|
||||
43
src/kosmickrisp/bridge/mtl_bridge.h
Normal file
43
src/kosmickrisp/bridge/mtl_bridge.h
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef KK_BRIDGE_H
|
||||
#define KK_BRIDGE_H 1
|
||||
|
||||
/* C wrappers for Metal. May not be complete. If you find something you need
|
||||
* feel free to add them where they belong. As a rule of thumb, member functions
|
||||
* go in the objects' .h/.m/.c Naming convention for wrappers is:
|
||||
* object_type* mtl_new_object_type(params...);
|
||||
* void mtl_member_function(object_type* ptr, params...);
|
||||
* void mtl_object_set_member(object_type* ptr, member_type value);
|
||||
* member_type mtl_object_get_member(object_type* ptr);
|
||||
*
|
||||
* Functions that have new in the name require to release the returned object
|
||||
* via mtl_release(object);
|
||||
* */
|
||||
|
||||
#include "mtl_types.h"
|
||||
|
||||
#include "mtl_buffer.h"
|
||||
#include "mtl_command_buffer.h"
|
||||
#include "mtl_command_queue.h"
|
||||
#include "mtl_compute_state.h"
|
||||
#include "mtl_device.h"
|
||||
#include "mtl_encoder.h"
|
||||
#include "mtl_format.h"
|
||||
#include "mtl_heap.h"
|
||||
#include "mtl_library.h"
|
||||
#include "mtl_render_state.h"
|
||||
#include "mtl_sampler.h"
|
||||
#include "mtl_sync.h"
|
||||
#include "mtl_texture.h"
|
||||
|
||||
mtl_texture *mtl_drawable_get_texture(void *drawable_ptr);
|
||||
|
||||
void *mtl_retain(void *handle);
|
||||
void mtl_release(void *handle);
|
||||
|
||||
#endif /* KK_BRIDGE_H */
|
||||
50
src/kosmickrisp/bridge/mtl_bridge.m
Normal file
50
src/kosmickrisp/bridge/mtl_bridge.m
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "mtl_bridge.h"
|
||||
|
||||
// kk_image_layout.h should also includes "vulkan/vulkan.h", but just to be safe
|
||||
#include "vulkan/vulkan.h"
|
||||
#include "kk_image_layout.h"
|
||||
|
||||
#include "util/macros.h"
|
||||
|
||||
#include <Metal/MTLCommandBuffer.h>
|
||||
#include <Metal/MTLCommandQueue.h>
|
||||
#include <Metal/MTLDevice.h>
|
||||
#include <Metal/MTLHeap.h>
|
||||
#include <Metal/MTLEvent.h>
|
||||
|
||||
#include <QuartzCore/CAMetalLayer.h>
|
||||
|
||||
static_assert(sizeof(MTLResourceID) == sizeof(uint64_t), "Must match, otherwise descriptors are broken");
|
||||
|
||||
mtl_texture *
|
||||
mtl_drawable_get_texture(void *drawable_ptr)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<CAMetalDrawable> drawable = (id<CAMetalDrawable>)drawable_ptr;
|
||||
return drawable.texture;
|
||||
}
|
||||
}
|
||||
|
||||
void *
|
||||
mtl_retain(void *handle)
|
||||
{
|
||||
@autoreleasepool {
|
||||
NSObject *obj = (NSObject *)handle;
|
||||
return [obj retain];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_release(void *handle)
|
||||
{
|
||||
@autoreleasepool {
|
||||
NSObject *obj = (NSObject *)handle;
|
||||
[obj release];
|
||||
}
|
||||
}
|
||||
26
src/kosmickrisp/bridge/mtl_buffer.h
Normal file
26
src/kosmickrisp/bridge/mtl_buffer.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef MTL_BUFFER_H
|
||||
#define MTL_BUFFER_H 1
|
||||
|
||||
#include "mtl_types.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
struct kk_image_layout;
|
||||
|
||||
/* Utils */
|
||||
uint64_t mtl_buffer_get_length(mtl_buffer *buffer);
|
||||
uint64_t mtl_buffer_get_gpu_address(mtl_buffer *buffer);
|
||||
/* Gets CPU address */
|
||||
void *mtl_get_contents(mtl_buffer *buffer);
|
||||
|
||||
/* Allocation from buffer */
|
||||
mtl_texture *mtl_new_texture_with_descriptor_linear(
|
||||
mtl_buffer *buffer, const struct kk_image_layout *layout, uint64_t offset);
|
||||
|
||||
#endif /* MTL_BUFFER_H */
|
||||
78
src/kosmickrisp/bridge/mtl_buffer.m
Normal file
78
src/kosmickrisp/bridge/mtl_buffer.m
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "mtl_buffer.h"
|
||||
|
||||
/* TODO_KOSMICKRISP Remove */
|
||||
#include "kk_image_layout.h"
|
||||
|
||||
#include <Metal/MTLBuffer.h>
|
||||
#include <Metal/MTLTexture.h>
|
||||
|
||||
uint64_t
|
||||
mtl_buffer_get_length(mtl_buffer *buffer)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLBuffer> buf = (id<MTLBuffer>)buffer;
|
||||
return buf.length;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t
|
||||
mtl_buffer_get_gpu_address(mtl_buffer *buffer)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLBuffer> buf = (id<MTLBuffer>)buffer;
|
||||
return [buf gpuAddress];
|
||||
}
|
||||
}
|
||||
|
||||
void *
|
||||
mtl_get_contents(mtl_buffer *buffer)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLBuffer> buf = (id<MTLBuffer>)buffer;
|
||||
return [buf contents];
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO_KOSMICKRISP This is a duplicate, but both should be removed once we move kk_image_layout to the bridge. */
|
||||
static MTLTextureDescriptor *
|
||||
mtl_new_texture_descriptor(const struct kk_image_layout *layout)
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLTextureDescriptor *descriptor = [MTLTextureDescriptor new];
|
||||
descriptor.textureType = (MTLTextureType)layout->type;
|
||||
descriptor.pixelFormat = layout->format.mtl;
|
||||
descriptor.width = layout->width_px;
|
||||
descriptor.height = layout->height_px;
|
||||
descriptor.depth = layout->depth_px;
|
||||
descriptor.mipmapLevelCount = layout->levels;
|
||||
descriptor.sampleCount = layout->sample_count_sa;
|
||||
descriptor.arrayLength = layout->layers;
|
||||
descriptor.allowGPUOptimizedContents = layout->optimized_layout;
|
||||
descriptor.usage = (MTLTextureUsage)layout->usage;
|
||||
/* We don't set the swizzle because Metal complains when the usage has store or render target with swizzle... */
|
||||
|
||||
return descriptor;
|
||||
}
|
||||
}
|
||||
|
||||
mtl_texture *
|
||||
mtl_new_texture_with_descriptor_linear(mtl_buffer *buffer,
|
||||
const struct kk_image_layout *layout,
|
||||
uint64_t offset)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLBuffer> buf = (id<MTLBuffer>)buffer;
|
||||
MTLTextureDescriptor *descriptor = [mtl_new_texture_descriptor(layout) autorelease];
|
||||
descriptor.resourceOptions = buf.resourceOptions;
|
||||
id<MTLTexture> texture = [buf newTextureWithDescriptor:descriptor offset:offset bytesPerRow:layout->linear_stride_B];
|
||||
|
||||
return texture;
|
||||
}
|
||||
}
|
||||
|
||||
27
src/kosmickrisp/bridge/mtl_command_buffer.h
Normal file
27
src/kosmickrisp/bridge/mtl_command_buffer.h
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef MTL_COMMAND_BUFFER_H
|
||||
#define MTL_COMMAND_BUFFER_H 1
|
||||
|
||||
#include "mtl_types.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void mtl_encode_signal_event(mtl_command_buffer *cmd_buf_handle,
|
||||
mtl_event *event_handle, uint64_t value);
|
||||
|
||||
void mtl_encode_wait_for_event(mtl_command_buffer *cmd_buf_handle,
|
||||
mtl_event *event_handle, uint64_t value);
|
||||
|
||||
void mtl_add_completed_handler(mtl_command_buffer *cmd,
|
||||
void (*callback)(void *data), void *data);
|
||||
|
||||
void mtl_command_buffer_commit(mtl_command_buffer *cmd_buf);
|
||||
|
||||
void mtl_present_drawable(mtl_command_buffer *cmd_buf, void *drawable);
|
||||
|
||||
#endif /* MTL_COMMAND_BUFFER_H */
|
||||
64
src/kosmickrisp/bridge/mtl_command_buffer.m
Normal file
64
src/kosmickrisp/bridge/mtl_command_buffer.m
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "mtl_command_buffer.h"
|
||||
|
||||
#include <Metal/MTLCommandBuffer.h>
|
||||
#include <QuartzCore/CAMetalLayer.h>
|
||||
|
||||
void
|
||||
mtl_encode_signal_event(mtl_command_buffer *cmd_buf_handle,
|
||||
mtl_event *event_handle, uint64_t value)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLCommandBuffer> cmd_buf = (id<MTLCommandBuffer>)cmd_buf_handle;
|
||||
id<MTLEvent> event = (id<MTLEvent>)event_handle;
|
||||
[cmd_buf encodeSignalEvent:event value:value];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_encode_wait_for_event(mtl_command_buffer *cmd_buf_handle,
|
||||
mtl_event *event_handle, uint64_t value)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLCommandBuffer> cmd_buf = (id<MTLCommandBuffer>)cmd_buf_handle;
|
||||
id<MTLEvent> event = (id<MTLEvent>)event_handle;
|
||||
[cmd_buf encodeWaitForEvent:event value:value];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_add_completed_handler(mtl_command_buffer *cmd, void (*callback)(void *data),
|
||||
void *data)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLCommandBuffer> mtl_cmd = (id<MTLCommandBuffer>)cmd;
|
||||
[mtl_cmd addCompletedHandler:^(id<MTLCommandBuffer> _Nonnull cmd_buf) {
|
||||
if (callback)
|
||||
callback(data);
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_command_buffer_commit(mtl_command_buffer *cmd_buffer)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLCommandBuffer> cmd_buf = (id<MTLCommandBuffer>)cmd_buffer;
|
||||
[cmd_buf commit];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_present_drawable(mtl_command_buffer *cmd_buf, void *drawable_ptr)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLCommandBuffer> cmd = (id<MTLCommandBuffer>)cmd_buf;
|
||||
id<CAMetalDrawable> drawable = [(id<CAMetalDrawable>)drawable_ptr autorelease];
|
||||
[cmd presentDrawable:drawable];
|
||||
}
|
||||
}
|
||||
19
src/kosmickrisp/bridge/mtl_command_queue.h
Normal file
19
src/kosmickrisp/bridge/mtl_command_queue.h
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef MTL_COMMAND_QUEUE_H
|
||||
#define MTL_COMMAND_QUEUE_H 1
|
||||
|
||||
#include "mtl_types.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
mtl_command_queue *mtl_new_command_queue(mtl_device *device,
|
||||
uint32_t cmd_buffer_count);
|
||||
|
||||
mtl_command_buffer *mtl_new_command_buffer(mtl_command_queue *cmd_queue);
|
||||
|
||||
#endif /* MTL_COMMAND_QUEUE_H */
|
||||
28
src/kosmickrisp/bridge/mtl_command_queue.m
Normal file
28
src/kosmickrisp/bridge/mtl_command_queue.m
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "mtl_command_queue.h"
|
||||
|
||||
#include <Metal/MTLDevice.h>
|
||||
#include <Metal/MTLCommandQueue.h>
|
||||
|
||||
mtl_command_queue *
|
||||
mtl_new_command_queue(mtl_device *device, uint32_t cmd_buffer_count)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLDevice> dev = (id<MTLDevice>)device;
|
||||
return [dev newCommandQueueWithMaxCommandBufferCount:cmd_buffer_count];
|
||||
}
|
||||
}
|
||||
|
||||
mtl_command_buffer *
|
||||
mtl_new_command_buffer(mtl_command_queue *cmd_queue)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLCommandQueue> queue = (id<MTLCommandQueue>)cmd_queue;
|
||||
return [[queue commandBuffer] retain];
|
||||
}
|
||||
}
|
||||
13
src/kosmickrisp/bridge/mtl_compute_state.h
Normal file
13
src/kosmickrisp/bridge/mtl_compute_state.h
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "mtl_types.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
mtl_compute_pipeline_state *
|
||||
mtl_new_compute_pipeline_state(mtl_device *device, mtl_function *function,
|
||||
uint64_t max_total_threads_per_threadgroup);
|
||||
29
src/kosmickrisp/bridge/mtl_compute_state.m
Normal file
29
src/kosmickrisp/bridge/mtl_compute_state.m
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "mtl_compute_state.h"
|
||||
|
||||
#include <Metal/MTLComputePipeline.h>
|
||||
|
||||
mtl_compute_pipeline_state *
|
||||
mtl_new_compute_pipeline_state(mtl_device *device, mtl_function *function,
|
||||
uint64_t max_total_threads_per_threadgroup)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLDevice> dev = (id<MTLDevice>)device;
|
||||
id<MTLComputePipelineState> pipeline = NULL;
|
||||
|
||||
MTLComputePipelineDescriptor *comp_desc = [[[MTLComputePipelineDescriptor alloc] init] autorelease];
|
||||
NSError *error;
|
||||
comp_desc.computeFunction = (id<MTLFunction>)function;
|
||||
comp_desc.maxTotalThreadsPerThreadgroup = max_total_threads_per_threadgroup;
|
||||
pipeline = [dev newComputePipelineStateWithDescriptor:comp_desc options:0 reflection:nil error:&error];
|
||||
|
||||
/* TODO_KOSMICKRISP Error checking */
|
||||
|
||||
return pipeline;
|
||||
}
|
||||
}
|
||||
40
src/kosmickrisp/bridge/mtl_device.h
Normal file
40
src/kosmickrisp/bridge/mtl_device.h
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef MTL_DEVICE_H
|
||||
#define MTL_DEVICE_H 1
|
||||
|
||||
#include "mtl_types.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* TODO_KOSMICKRISP Remove */
|
||||
struct kk_image_layout;
|
||||
|
||||
/* Device creation */
|
||||
mtl_device *mtl_device_create(void);
|
||||
|
||||
/* Device operations */
|
||||
void mtl_start_gpu_capture(mtl_device *mtl_dev_handle);
|
||||
void mtl_stop_gpu_capture(void);
|
||||
|
||||
/* Device feature query */
|
||||
void mtl_device_get_name(mtl_device *dev, char buffer[256]);
|
||||
void mtl_device_get_architecture_name(mtl_device *dev, char buffer[256]);
|
||||
uint64_t mtl_device_get_peer_group_id(mtl_device *dev);
|
||||
uint32_t mtl_device_get_peer_index(mtl_device *dev);
|
||||
uint64_t mtl_device_get_registry_id(mtl_device *dev);
|
||||
struct mtl_size mtl_device_max_threads_per_threadgroup(mtl_device *dev);
|
||||
|
||||
/* Resource queries */
|
||||
void mtl_heap_buffer_size_and_align_with_length(mtl_device *device,
|
||||
uint64_t *size_B,
|
||||
uint64_t *align_B);
|
||||
void
|
||||
mtl_heap_texture_size_and_align_with_descriptor(mtl_device *device,
|
||||
struct kk_image_layout *layout);
|
||||
|
||||
#endif /* MTL_DEVICE_H */
|
||||
197
src/kosmickrisp/bridge/mtl_device.m
Normal file
197
src/kosmickrisp/bridge/mtl_device.m
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "mtl_device.h"
|
||||
|
||||
/* TODO_KOSMICKRISP Remove */
|
||||
#include "kk_image_layout.h"
|
||||
#include "kk_private.h"
|
||||
|
||||
#include <Metal/MTLDevice.h>
|
||||
#include <Metal/MTLCaptureManager.h>
|
||||
|
||||
/* Device creation */
|
||||
mtl_device *
|
||||
mtl_device_create()
|
||||
{
|
||||
mtl_device *device = 0u;
|
||||
|
||||
@autoreleasepool {
|
||||
NSArray<id<MTLDevice>> *devs = MTLCopyAllDevices();
|
||||
uint32_t device_count = [devs count];
|
||||
|
||||
for (uint32_t i = 0u; i < device_count; ++i) {
|
||||
if (@available(macOS 10.15, *)) {
|
||||
if (!device && [devs[i] supportsFamily:MTLGPUFamilyMetal3]) {
|
||||
device = (mtl_device *)[devs[i] retain];
|
||||
}
|
||||
[devs[i] autorelease];
|
||||
}
|
||||
}
|
||||
|
||||
return device;
|
||||
}
|
||||
}
|
||||
|
||||
/* Device operations */
|
||||
void
|
||||
mtl_start_gpu_capture(mtl_device *mtl_dev_handle)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLDevice> mtl_dev = (id<MTLDevice>)mtl_dev_handle;
|
||||
MTLCaptureManager *captureMgr = [MTLCaptureManager sharedCaptureManager];
|
||||
|
||||
// Before macOS 10.15 and iOS 13.0, captureDesc will just be nil
|
||||
MTLCaptureDescriptor *captureDesc = [[MTLCaptureDescriptor new] autorelease];
|
||||
captureDesc.captureObject = mtl_dev;
|
||||
captureDesc.destination = MTLCaptureDestinationDeveloperTools;
|
||||
|
||||
// TODO_KOSMICKRISP Support dumping a trace to a file?
|
||||
// NSString *tmp_dir = NSTemporaryDirectory();
|
||||
// NSString *pname = [[NSProcessInfo processInfo] processName];
|
||||
// NSString *capture_path = [NSString stringWithFormat:@"%@/%@.gputrace", tmp_dir, pname];
|
||||
// if ([captureMgr supportsDestination: MTLCaptureDestinationGPUTraceDocument] ) {
|
||||
// captureDesc.destination = MTLCaptureDestinationGPUTraceDocument;
|
||||
// captureDesc.outputURL = [NSURL fileURLWithPath: capture_path];
|
||||
//}
|
||||
|
||||
NSError *err = nil;
|
||||
if (![captureMgr startCaptureWithDescriptor:captureDesc error:&err]) {
|
||||
// fprintf(stderr, "Failed to automatically start GPU capture session (Error code %li) using startCaptureWithDescriptor: %s\n",
|
||||
// (long)err.code, err.localizedDescription.UTF8String);
|
||||
// fprintf(stderr, "Using startCaptureWithDevice\n");
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
[captureMgr startCaptureWithDevice:mtl_dev];
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
|
||||
//[tmp_dir release];
|
||||
//[pname release];
|
||||
//[capture_path release];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_stop_gpu_capture()
|
||||
{
|
||||
@autoreleasepool {
|
||||
[[MTLCaptureManager sharedCaptureManager] stopCapture];
|
||||
}
|
||||
}
|
||||
|
||||
/* Device feature query */
|
||||
void
|
||||
mtl_device_get_name(mtl_device *dev, char buffer[256])
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLDevice> device = (id<MTLDevice>)dev;
|
||||
[device.name getCString:buffer maxLength:(sizeof(char) * 256) encoding:NSUTF8StringEncoding];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_device_get_architecture_name(mtl_device *dev, char buffer[256])
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLDevice> device = (id<MTLDevice>)dev;
|
||||
[device.architecture.name getCString:buffer maxLength:(sizeof(char) * 256) encoding:NSUTF8StringEncoding];
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t
|
||||
mtl_device_get_peer_group_id(mtl_device *dev)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLDevice> device = (id<MTLDevice>)dev;
|
||||
return device.peerGroupID;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
mtl_device_get_peer_index(mtl_device *dev)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLDevice> device = (id<MTLDevice>)dev;
|
||||
return device.peerIndex;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t
|
||||
mtl_device_get_registry_id(mtl_device *dev)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLDevice> device = (id<MTLDevice>)dev;
|
||||
return device.registryID;
|
||||
}
|
||||
}
|
||||
|
||||
struct mtl_size
|
||||
mtl_device_max_threads_per_threadgroup(mtl_device *dev)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLDevice> device = (id<MTLDevice>)dev;
|
||||
return (struct mtl_size){.x = device.maxThreadsPerThreadgroup.width,
|
||||
.y = device.maxThreadsPerThreadgroup.height,
|
||||
.z = device.maxThreadsPerThreadgroup.depth};
|
||||
}
|
||||
}
|
||||
|
||||
/* Resource queries */
|
||||
/* TODO_KOSMICKRISP Return a struct */
|
||||
void
|
||||
mtl_heap_buffer_size_and_align_with_length(mtl_device *device, uint64_t *size_B,
|
||||
uint64_t *align_B)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLDevice> dev = (id<MTLDevice>)device;
|
||||
MTLSizeAndAlign size_align = [dev heapBufferSizeAndAlignWithLength:*size_B options:KK_MTL_RESOURCE_OPTIONS];
|
||||
*size_B = size_align.size;
|
||||
*align_B = size_align.align;
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO_KOSMICKRISP Remove */
|
||||
static MTLTextureDescriptor *
|
||||
mtl_new_texture_descriptor(const struct kk_image_layout *layout)
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLTextureDescriptor *descriptor = [MTLTextureDescriptor new];
|
||||
descriptor.textureType = (MTLTextureType)layout->type;
|
||||
descriptor.pixelFormat = layout->format.mtl;
|
||||
descriptor.width = layout->width_px;
|
||||
descriptor.height = layout->height_px;
|
||||
descriptor.depth = layout->depth_px;
|
||||
descriptor.mipmapLevelCount = layout->levels;
|
||||
descriptor.sampleCount = layout->sample_count_sa;
|
||||
descriptor.arrayLength = layout->layers;
|
||||
descriptor.allowGPUOptimizedContents = layout->optimized_layout;
|
||||
descriptor.usage = (MTLTextureUsage)layout->usage;
|
||||
/* We don't set the swizzle because Metal complains when the usage has store or render target with swizzle... */
|
||||
|
||||
return descriptor;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_heap_texture_size_and_align_with_descriptor(mtl_device *device,
|
||||
struct kk_image_layout *layout)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLDevice> dev = (id<MTLDevice>)device;
|
||||
if (layout->optimized_layout) {
|
||||
MTLTextureDescriptor *descriptor = [mtl_new_texture_descriptor(layout) autorelease];
|
||||
descriptor.resourceOptions = KK_MTL_RESOURCE_OPTIONS;
|
||||
MTLSizeAndAlign size_align = [dev heapTextureSizeAndAlignWithDescriptor:descriptor];
|
||||
layout->size_B = size_align.size;
|
||||
layout->align_B = size_align.align;
|
||||
} else {
|
||||
/* Linear textures have different alignment since they are allocated on top of MTLBuffers */
|
||||
layout->align_B = [dev minimumLinearTextureAlignmentForPixelFormat:layout->format.mtl];
|
||||
}
|
||||
}
|
||||
}
|
||||
152
src/kosmickrisp/bridge/mtl_encoder.h
Normal file
152
src/kosmickrisp/bridge/mtl_encoder.h
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef MTL_ENCODER_H
|
||||
#define MTL_ENCODER_H 1
|
||||
|
||||
#include "mtl_types.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* Common encoder utils */
|
||||
void mtl_end_encoding(void *encoder);
|
||||
|
||||
/* MTLBlitEncoder */
|
||||
mtl_blit_encoder *mtl_new_blit_command_encoder(mtl_command_buffer *cmd_buffer);
|
||||
|
||||
void mtl_blit_update_fence(mtl_blit_encoder *encoder, mtl_fence *fence);
|
||||
void mtl_blit_wait_for_fence(mtl_blit_encoder *encoder, mtl_fence *fence);
|
||||
|
||||
void mtl_copy_from_buffer_to_buffer(mtl_blit_encoder *blit_enc_handle,
|
||||
mtl_buffer *src_buf, size_t src_offset,
|
||||
mtl_buffer *dst_buf, size_t dst_offset,
|
||||
size_t size);
|
||||
|
||||
void mtl_copy_from_buffer_to_texture(mtl_blit_encoder *blit_enc_handle,
|
||||
struct mtl_buffer_image_copy *data);
|
||||
|
||||
void mtl_copy_from_texture_to_buffer(mtl_blit_encoder *blit_enc_handle,
|
||||
struct mtl_buffer_image_copy *data);
|
||||
|
||||
void mtl_copy_from_texture_to_texture(
|
||||
mtl_blit_encoder *blit_enc_handle, mtl_texture *src_tex_handle,
|
||||
size_t src_slice, size_t src_level, struct mtl_origin src_origin,
|
||||
struct mtl_size src_size, mtl_texture *dst_tex_handle, size_t dst_slice,
|
||||
size_t dst_level, struct mtl_origin dst_origin);
|
||||
|
||||
/* MTLComputeEncoder */
|
||||
mtl_compute_encoder *
|
||||
mtl_new_compute_command_encoder(mtl_command_buffer *cmd_buffer);
|
||||
|
||||
void mtl_compute_update_fence(mtl_compute_encoder *encoder, mtl_fence *fence);
|
||||
void mtl_compute_wait_for_fence(mtl_compute_encoder *encoder, mtl_fence *fence);
|
||||
|
||||
void mtl_compute_set_pipeline_state(mtl_compute_encoder *encoder,
|
||||
mtl_compute_pipeline_state *state_handle);
|
||||
|
||||
void mtl_compute_set_buffer(mtl_compute_encoder *encoder, mtl_buffer *buffer,
|
||||
size_t offset, size_t index);
|
||||
|
||||
void mtl_compute_use_resource(mtl_compute_encoder *encoder,
|
||||
mtl_resource *res_handle, uint32_t usage);
|
||||
|
||||
void mtl_compute_use_resources(mtl_compute_encoder *encoder,
|
||||
mtl_resource **resource_handles, uint32_t count,
|
||||
enum mtl_resource_usage usage);
|
||||
|
||||
void mtl_compute_use_heaps(mtl_compute_encoder *encoder, mtl_heap **heaps,
|
||||
uint32_t count);
|
||||
|
||||
void mtl_dispatch_threads(mtl_compute_encoder *encoder,
|
||||
struct mtl_size grid_size,
|
||||
struct mtl_size local_size);
|
||||
|
||||
void mtl_dispatch_threadgroups_with_indirect_buffer(
|
||||
mtl_compute_encoder *encoder, mtl_buffer *buffer, uint32_t offset,
|
||||
struct mtl_size local_size);
|
||||
|
||||
/* MTLRenderEncoder */
|
||||
mtl_render_encoder *mtl_new_render_command_encoder_with_descriptor(
|
||||
mtl_command_buffer *command_buffer, mtl_render_pass_descriptor *descriptor);
|
||||
|
||||
void mtl_render_update_fence(mtl_render_encoder *encoder, mtl_fence *fence);
|
||||
void mtl_render_wait_for_fence(mtl_render_encoder *encoder, mtl_fence *fence);
|
||||
|
||||
void mtl_set_viewports(mtl_render_encoder *encoder,
|
||||
struct mtl_viewport *viewports, uint32_t count);
|
||||
|
||||
void mtl_set_scissor_rects(mtl_render_encoder *encoder,
|
||||
struct mtl_scissor_rect *scissor_rects,
|
||||
uint32_t count);
|
||||
|
||||
void mtl_render_set_pipeline_state(mtl_render_encoder *encoder,
|
||||
mtl_render_pipeline_state *pipeline);
|
||||
|
||||
void mtl_set_depth_stencil_state(mtl_render_encoder *encoder,
|
||||
mtl_depth_stencil_state *state);
|
||||
|
||||
void mtl_set_stencil_references(mtl_render_encoder *encoder, uint32_t front,
|
||||
uint32_t back);
|
||||
|
||||
void mtl_set_front_face_winding(mtl_render_encoder *encoder,
|
||||
enum mtl_winding winding);
|
||||
|
||||
void mtl_set_cull_mode(mtl_render_encoder *encoder, enum mtl_cull_mode mode);
|
||||
|
||||
void mtl_set_visibility_result_mode(mtl_render_encoder *encoder,
|
||||
enum mtl_visibility_result_mode mode,
|
||||
size_t offset);
|
||||
|
||||
void mtl_set_depth_bias(mtl_render_encoder *encoder, float depth_bias,
|
||||
float slope_scale, float clamp);
|
||||
|
||||
void mtl_set_depth_clip_mode(mtl_render_encoder *encoder,
|
||||
enum mtl_depth_clip_mode mode);
|
||||
|
||||
void mtl_set_vertex_amplification_count(mtl_render_encoder *encoder,
|
||||
uint32_t *layer_ids, uint32_t id_count);
|
||||
|
||||
void mtl_set_vertex_buffer(mtl_render_encoder *encoder, mtl_buffer *buffer,
|
||||
uint32_t offset, uint32_t index);
|
||||
|
||||
void mtl_set_fragment_buffer(mtl_render_encoder *encoder, mtl_buffer *buffer,
|
||||
uint32_t offset, uint32_t index);
|
||||
|
||||
void mtl_draw_primitives(mtl_render_encoder *encoder,
|
||||
enum mtl_primitive_type primitve_type,
|
||||
uint32_t vertexStart, uint32_t vertexCount,
|
||||
uint32_t instanceCount, uint32_t baseInstance);
|
||||
|
||||
void mtl_draw_indexed_primitives(
|
||||
mtl_render_encoder *encoder, enum mtl_primitive_type primitve_type,
|
||||
uint32_t index_count, enum mtl_index_type index_type,
|
||||
mtl_buffer *index_buffer, uint32_t index_buffer_offset,
|
||||
uint32_t instance_count, int32_t base_vertex, uint32_t base_instance);
|
||||
|
||||
void mtl_draw_primitives_indirect(mtl_render_encoder *encoder,
|
||||
enum mtl_primitive_type primitve_type,
|
||||
mtl_buffer *indirect_buffer,
|
||||
uint64_t indirect_buffer_offset);
|
||||
|
||||
void mtl_draw_indexed_primitives_indirect(mtl_render_encoder *encoder,
|
||||
enum mtl_primitive_type primitve_type,
|
||||
enum mtl_index_type index_type,
|
||||
mtl_buffer *index_buffer,
|
||||
uint32_t index_buffer_offset,
|
||||
mtl_buffer *indirect_buffer,
|
||||
uint64_t indirect_buffer_offset);
|
||||
|
||||
void mtl_render_use_resource(mtl_compute_encoder *encoder,
|
||||
mtl_resource *res_handle, uint32_t usage);
|
||||
|
||||
void mtl_render_use_resources(mtl_render_encoder *encoder,
|
||||
mtl_resource **resource_handles, uint32_t count,
|
||||
enum mtl_resource_usage usage);
|
||||
|
||||
void mtl_render_use_heaps(mtl_render_encoder *encoder, mtl_heap **heaps,
|
||||
uint32_t count);
|
||||
|
||||
#endif /* MTL_ENCODER_H */
|
||||
537
src/kosmickrisp/bridge/mtl_encoder.m
Normal file
537
src/kosmickrisp/bridge/mtl_encoder.m
Normal file
|
|
@ -0,0 +1,537 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "mtl_encoder.h"
|
||||
|
||||
#include <Metal/MTLBlitCommandEncoder.h>
|
||||
#include <Metal/MTLComputeCommandEncoder.h>
|
||||
#include <Metal/MTLRenderCommandEncoder.h>
|
||||
|
||||
/* Common encoder utils */
|
||||
void
|
||||
mtl_end_encoding(void *encoder)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLCommandEncoder> enc = (id<MTLComputeCommandEncoder>)encoder;
|
||||
[enc endEncoding];
|
||||
}
|
||||
}
|
||||
|
||||
/* MTLBlitEncoder */
|
||||
mtl_blit_encoder *
|
||||
mtl_new_blit_command_encoder(mtl_command_buffer *cmd_buffer)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLCommandBuffer> cmd_buf = (id<MTLCommandBuffer>)cmd_buffer;
|
||||
return [[cmd_buf blitCommandEncoder] retain];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_blit_update_fence(mtl_blit_encoder *encoder,
|
||||
mtl_fence *fence)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLBlitCommandEncoder> enc = (id<MTLBlitCommandEncoder>)encoder;
|
||||
id<MTLFence> f = (id<MTLFence>)fence;
|
||||
[enc updateFence:f];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_blit_wait_for_fence(mtl_blit_encoder *encoder,
|
||||
mtl_fence *fence)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLBlitCommandEncoder> enc = (id<MTLBlitCommandEncoder>)encoder;
|
||||
id<MTLFence> f = (id<MTLFence>)fence;
|
||||
[enc waitForFence:f];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_copy_from_buffer_to_buffer(mtl_blit_encoder *blit_enc_handle,
|
||||
mtl_buffer *src_buf, size_t src_offset,
|
||||
mtl_buffer *dst_buf, size_t dst_offset,
|
||||
size_t size)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLBlitCommandEncoder> blit = (id<MTLBlitCommandEncoder>)blit_enc_handle;
|
||||
id<MTLBuffer> mtl_src_buffer = (id<MTLBuffer>)src_buf;
|
||||
id<MTLBuffer> mtl_dst_buffer = (id<MTLBuffer>)dst_buf;
|
||||
[blit copyFromBuffer:mtl_src_buffer sourceOffset:src_offset toBuffer:mtl_dst_buffer destinationOffset:dst_offset size:size];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_copy_from_buffer_to_texture(mtl_blit_encoder *blit_enc_handle,
|
||||
struct mtl_buffer_image_copy *data)
|
||||
{
|
||||
@autoreleasepool {
|
||||
const MTLSize size = MTLSizeMake(data->image_size.x, data->image_size.y, data->image_size.z);
|
||||
const MTLOrigin origin = MTLOriginMake(data->image_origin.x, data->image_origin.y, data->image_origin.z);
|
||||
id<MTLBlitCommandEncoder> blit = (id<MTLBlitCommandEncoder>)blit_enc_handle;
|
||||
id<MTLBuffer> buffer = (id<MTLBuffer>)data->buffer;
|
||||
id<MTLTexture> image = (id<MTLTexture>)data->image;
|
||||
[blit copyFromBuffer:buffer
|
||||
sourceOffset:data->buffer_offset_B
|
||||
sourceBytesPerRow:data->buffer_stride_B
|
||||
sourceBytesPerImage:data->buffer_2d_image_size_B
|
||||
sourceSize:size
|
||||
toTexture:image
|
||||
destinationSlice:data->image_slice
|
||||
destinationLevel:data->image_level
|
||||
destinationOrigin:origin
|
||||
options:(MTLBlitOption)data->options];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_copy_from_texture_to_buffer(mtl_blit_encoder *blit_enc_handle,
|
||||
struct mtl_buffer_image_copy *data)
|
||||
{
|
||||
@autoreleasepool {
|
||||
const MTLSize size = MTLSizeMake(data->image_size.x, data->image_size.y, data->image_size.z);
|
||||
const MTLOrigin origin = MTLOriginMake(data->image_origin.x, data->image_origin.y, data->image_origin.z);
|
||||
id<MTLBlitCommandEncoder> blit = (id<MTLBlitCommandEncoder>)blit_enc_handle;
|
||||
id<MTLBuffer> buffer = (id<MTLBuffer>)data->buffer;
|
||||
id<MTLTexture> image = (id<MTLTexture>)data->image;
|
||||
[blit copyFromTexture:image
|
||||
sourceSlice:data->image_slice
|
||||
sourceLevel:data->image_level
|
||||
sourceOrigin:origin
|
||||
sourceSize:size
|
||||
toBuffer:buffer
|
||||
destinationOffset:data->buffer_offset_B
|
||||
destinationBytesPerRow:data->buffer_stride_B
|
||||
destinationBytesPerImage:data->buffer_2d_image_size_B
|
||||
options:(MTLBlitOption)data->options];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_copy_from_texture_to_texture(mtl_blit_encoder *blit_enc_handle,
|
||||
mtl_texture *src_tex_handle, size_t src_slice,
|
||||
size_t src_level, struct mtl_origin src_origin,
|
||||
struct mtl_size src_size,
|
||||
mtl_texture *dst_tex_handle, size_t dst_slice,
|
||||
size_t dst_level, struct mtl_origin dst_origin)
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLOrigin mtl_src_origin = MTLOriginMake(src_origin.x, src_origin.y, src_origin.z);
|
||||
MTLSize mtl_src_size = MTLSizeMake(src_size.x, src_size.y, src_size.z);
|
||||
MTLOrigin mtl_dst_origin = MTLOriginMake(dst_origin.x, dst_origin.y, dst_origin.z);
|
||||
id<MTLTexture> mtl_dst_tex = (id<MTLTexture>)dst_tex_handle;
|
||||
id<MTLBlitCommandEncoder> blit = (id<MTLBlitCommandEncoder>)blit_enc_handle;
|
||||
id<MTLTexture> mtl_src_tex = (id<MTLTexture>)src_tex_handle;
|
||||
[blit copyFromTexture:mtl_src_tex
|
||||
sourceSlice:src_slice
|
||||
sourceLevel:src_level
|
||||
sourceOrigin:mtl_src_origin
|
||||
sourceSize:mtl_src_size
|
||||
toTexture:mtl_dst_tex
|
||||
destinationSlice:dst_slice
|
||||
destinationLevel:dst_level
|
||||
destinationOrigin:mtl_dst_origin];
|
||||
}
|
||||
}
|
||||
|
||||
/* MTLComputeEncoder */
|
||||
mtl_compute_encoder *
|
||||
mtl_new_compute_command_encoder(mtl_command_buffer *cmd_buffer)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLCommandBuffer> cmd_buf = (id<MTLCommandBuffer>)cmd_buffer;
|
||||
return [[cmd_buf computeCommandEncoder] retain];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_compute_update_fence(mtl_compute_encoder *encoder, mtl_fence *fence)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLComputeCommandEncoder> enc = (id<MTLComputeCommandEncoder>)encoder;
|
||||
id<MTLFence> f = (id<MTLFence>)fence;
|
||||
[enc updateFence:f];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_compute_wait_for_fence(mtl_compute_encoder *encoder, mtl_fence *fence)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLComputeCommandEncoder> enc = (id<MTLComputeCommandEncoder>)encoder;
|
||||
id<MTLFence> f = (id<MTLFence>)fence;
|
||||
[enc waitForFence:f];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_compute_set_pipeline_state(mtl_compute_encoder *encoder,
|
||||
mtl_compute_pipeline_state *state_handle)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLComputeCommandEncoder> enc = (id<MTLComputeCommandEncoder>)encoder;
|
||||
id<MTLComputePipelineState> state = (id<MTLComputePipelineState>)state_handle;
|
||||
[enc setComputePipelineState:state];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_compute_set_buffer(mtl_compute_encoder *encoder,
|
||||
mtl_buffer *buffer, size_t offset, size_t index)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLComputeCommandEncoder> enc = (id<MTLComputeCommandEncoder>)encoder;
|
||||
id<MTLBuffer> buf = (id<MTLBuffer>)buffer;
|
||||
[enc setBuffer:buf offset:offset atIndex:index];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_compute_use_resource(mtl_compute_encoder *encoder,
|
||||
mtl_resource *res_handle, uint32_t usage)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLComputeCommandEncoder> enc = (id<MTLComputeCommandEncoder>)encoder;
|
||||
id<MTLResource> res = (id<MTLResource>)res_handle;
|
||||
[enc useResource:res usage:(MTLResourceUsage)usage];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_compute_use_resources(mtl_compute_encoder *encoder,
|
||||
mtl_resource **resource_handles, uint32_t count,
|
||||
enum mtl_resource_usage usage)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLComputeCommandEncoder> enc = (id<MTLComputeCommandEncoder>)encoder;
|
||||
id<MTLResource> *handles = (id<MTLResource>*)resource_handles;
|
||||
[enc useResources:handles count:count usage:(MTLResourceUsage)usage];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_compute_use_heaps(mtl_compute_encoder *encoder, mtl_heap **heaps,
|
||||
uint32_t count)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLComputeCommandEncoder> enc = (id<MTLComputeCommandEncoder>)encoder;
|
||||
id<MTLHeap> *handles = (id<MTLHeap>*)heaps;
|
||||
[enc useHeaps:handles count:count];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_dispatch_threads(mtl_compute_encoder *encoder,
|
||||
struct mtl_size grid_size, struct mtl_size local_size)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLComputeCommandEncoder> enc = (id<MTLComputeCommandEncoder>)encoder;
|
||||
MTLSize thread_count = MTLSizeMake(grid_size.x * local_size.x,
|
||||
grid_size.y * local_size.y,
|
||||
grid_size.z * local_size.z);
|
||||
MTLSize threads_per_threadgroup = MTLSizeMake(local_size.x,
|
||||
local_size.y,
|
||||
local_size.z);
|
||||
|
||||
// TODO_KOSMICKRISP can we rely on nonuniform threadgroup size support?
|
||||
[enc dispatchThreads:thread_count threadsPerThreadgroup:threads_per_threadgroup];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_dispatch_threadgroups_with_indirect_buffer(mtl_compute_encoder *encoder,
|
||||
mtl_buffer *buffer,
|
||||
uint32_t offset,
|
||||
struct mtl_size local_size)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLComputeCommandEncoder> enc = (id<MTLComputeCommandEncoder>)encoder;
|
||||
id<MTLBuffer> buf = (id<MTLBuffer>)buffer;
|
||||
MTLSize threads_per_threadgroup = MTLSizeMake(local_size.x,
|
||||
local_size.y,
|
||||
local_size.z);
|
||||
|
||||
[enc dispatchThreadgroupsWithIndirectBuffer:buf indirectBufferOffset:offset threadsPerThreadgroup:threads_per_threadgroup];
|
||||
}
|
||||
}
|
||||
|
||||
/* MTLRenderEncoder */
|
||||
|
||||
/* Encoder commands */
|
||||
mtl_render_encoder *
|
||||
mtl_new_render_command_encoder_with_descriptor(
|
||||
mtl_command_buffer *command_buffer, mtl_render_pass_descriptor *descriptor)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLCommandBuffer> cmd = (id<MTLCommandBuffer>)command_buffer;
|
||||
MTLRenderPassDescriptor *desc = (MTLRenderPassDescriptor *)descriptor;
|
||||
return [[cmd renderCommandEncoderWithDescriptor:desc] retain];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_update_fence(mtl_render_encoder *encoder, mtl_fence *fence)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLRenderCommandEncoder> enc = (id<MTLRenderCommandEncoder>)encoder;
|
||||
id<MTLFence> f = (id<MTLFence>)fence;
|
||||
[enc updateFence:f afterStages:MTLRenderStageFragment];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_wait_for_fence(mtl_render_encoder *encoder, mtl_fence *fence)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLRenderCommandEncoder> enc = (id<MTLRenderCommandEncoder>)encoder;
|
||||
id<MTLFence> f = (id<MTLFence>)fence;
|
||||
[enc waitForFence:f beforeStages:MTLRenderStageVertex];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_set_viewports(mtl_render_encoder *encoder, struct mtl_viewport *viewports,
|
||||
uint32_t count)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLRenderCommandEncoder> enc = (id<MTLRenderCommandEncoder>)encoder;
|
||||
MTLViewport *vps = (MTLViewport *)viewports;
|
||||
[enc setViewports:vps count:count];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_set_scissor_rects(mtl_render_encoder *encoder,
|
||||
struct mtl_scissor_rect *scissor_rects, uint32_t count)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLRenderCommandEncoder> enc = (id<MTLRenderCommandEncoder>)encoder;
|
||||
MTLScissorRect *rects = (MTLScissorRect *)scissor_rects;
|
||||
[enc setScissorRects:rects count:count];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_set_pipeline_state(mtl_render_encoder *encoder,
|
||||
mtl_render_pipeline_state *pipeline)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLRenderCommandEncoder> enc = (id<MTLRenderCommandEncoder>)encoder;
|
||||
id<MTLRenderPipelineState> pipe = (id<MTLRenderPipelineState>)pipeline;
|
||||
[enc setRenderPipelineState:pipe];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_set_depth_stencil_state(mtl_render_encoder *encoder,
|
||||
mtl_depth_stencil_state *state)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLRenderCommandEncoder> enc = (id<MTLRenderCommandEncoder>)encoder;
|
||||
id<MTLDepthStencilState> s = (id<MTLDepthStencilState>)state;
|
||||
[enc setDepthStencilState:s];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_set_stencil_references(mtl_render_encoder *encoder, uint32_t front,
|
||||
uint32_t back)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLRenderCommandEncoder> enc = (id<MTLRenderCommandEncoder>)encoder;
|
||||
[enc setStencilFrontReferenceValue:front backReferenceValue:back];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_set_front_face_winding(mtl_render_encoder *encoder,
|
||||
enum mtl_winding winding)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLRenderCommandEncoder> enc = (id<MTLRenderCommandEncoder>)encoder;
|
||||
[enc setFrontFacingWinding:(MTLWinding)winding];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_set_cull_mode(mtl_render_encoder *encoder, enum mtl_cull_mode mode)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLRenderCommandEncoder> enc = (id<MTLRenderCommandEncoder>)encoder;
|
||||
[enc setCullMode:(MTLCullMode)mode];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_set_visibility_result_mode(mtl_render_encoder *encoder,
|
||||
enum mtl_visibility_result_mode mode,
|
||||
size_t offset)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLRenderCommandEncoder> enc = (id<MTLRenderCommandEncoder>)encoder;
|
||||
[enc setVisibilityResultMode:(MTLVisibilityResultMode)mode offset:offset];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_set_depth_bias(mtl_render_encoder *encoder, float depth_bias,
|
||||
float slope_scale, float clamp)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLRenderCommandEncoder> enc = (id<MTLRenderCommandEncoder>)encoder;
|
||||
[enc setDepthBias:depth_bias slopeScale:slope_scale clamp:clamp];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_set_depth_clip_mode(mtl_render_encoder *encoder,
|
||||
enum mtl_depth_clip_mode mode)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLRenderCommandEncoder> enc = (id<MTLRenderCommandEncoder>)encoder;
|
||||
[enc setDepthClipMode:(MTLDepthClipMode)mode];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_set_vertex_amplification_count(mtl_render_encoder *encoder,
|
||||
uint32_t *layer_ids, uint32_t id_count)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLRenderCommandEncoder> enc = (id<MTLRenderCommandEncoder>)encoder;
|
||||
MTLVertexAmplificationViewMapping mappings[32];
|
||||
for (uint32_t i = 0u; i < id_count; ++i) {
|
||||
mappings[i].renderTargetArrayIndexOffset = layer_ids[i];
|
||||
mappings[i].viewportArrayIndexOffset = 0u;
|
||||
}
|
||||
[enc setVertexAmplificationCount:id_count viewMappings:mappings];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_set_vertex_buffer(mtl_render_encoder *encoder, mtl_buffer *buffer,
|
||||
uint32_t offset, uint32_t index)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLRenderCommandEncoder> enc = (id<MTLRenderCommandEncoder>)encoder;
|
||||
id<MTLBuffer> buf = (id<MTLBuffer>)buffer;
|
||||
[enc setVertexBuffer:buf offset:offset atIndex:index];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_set_fragment_buffer(mtl_render_encoder *encoder, mtl_buffer *buffer,
|
||||
uint32_t offset, uint32_t index)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLRenderCommandEncoder> enc = (id<MTLRenderCommandEncoder>)encoder;
|
||||
id<MTLBuffer> buf = (id<MTLBuffer>)buffer;
|
||||
[enc setFragmentBuffer:buf offset:offset atIndex:index];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_draw_primitives(mtl_render_encoder *encoder,
|
||||
enum mtl_primitive_type primitve_type, uint32_t vertexStart,
|
||||
uint32_t vertexCount, uint32_t instanceCount,
|
||||
uint32_t baseInstance)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLRenderCommandEncoder> enc = (id<MTLRenderCommandEncoder>)encoder;
|
||||
MTLPrimitiveType type = (MTLPrimitiveType)primitve_type;
|
||||
[enc drawPrimitives:type vertexStart:vertexStart vertexCount:vertexCount instanceCount:instanceCount baseInstance:baseInstance];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_draw_indexed_primitives(
|
||||
mtl_render_encoder *encoder, enum mtl_primitive_type primitve_type,
|
||||
uint32_t index_count, enum mtl_index_type index_type,
|
||||
mtl_buffer *index_buffer, uint32_t index_buffer_offset,
|
||||
uint32_t instance_count, int32_t base_vertex, uint32_t base_instance)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLRenderCommandEncoder> enc = (id<MTLRenderCommandEncoder>)encoder;
|
||||
id<MTLBuffer> buf = (id<MTLBuffer>)index_buffer;
|
||||
MTLIndexType ndx_type = (MTLIndexType)index_type;
|
||||
MTLPrimitiveType primitive = (MTLPrimitiveType)primitve_type;
|
||||
[enc drawIndexedPrimitives:primitive indexCount:index_count indexType:ndx_type indexBuffer:buf indexBufferOffset:index_buffer_offset instanceCount:instance_count baseVertex:base_vertex baseInstance:base_instance];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_draw_primitives_indirect(mtl_render_encoder *encoder,
|
||||
enum mtl_primitive_type primitve_type,
|
||||
mtl_buffer *indirect_buffer,
|
||||
uint64_t indirect_buffer_offset)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLRenderCommandEncoder> enc = (id<MTLRenderCommandEncoder>)encoder;
|
||||
id<MTLBuffer> buf = (id<MTLBuffer>)indirect_buffer;
|
||||
MTLPrimitiveType type = (MTLPrimitiveType)primitve_type;
|
||||
[enc drawPrimitives:type indirectBuffer:buf indirectBufferOffset:indirect_buffer_offset];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_draw_indexed_primitives_indirect(mtl_render_encoder *encoder,
|
||||
enum mtl_primitive_type primitve_type,
|
||||
enum mtl_index_type index_type,
|
||||
mtl_buffer *index_buffer,
|
||||
uint32_t index_buffer_offset,
|
||||
mtl_buffer *indirect_buffer,
|
||||
uint64_t indirect_buffer_offset)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLRenderCommandEncoder> enc = (id<MTLRenderCommandEncoder>)encoder;
|
||||
id<MTLBuffer> buf = (id<MTLBuffer>)indirect_buffer;
|
||||
id<MTLBuffer> ndx_buf = (id<MTLBuffer>)index_buffer;
|
||||
MTLPrimitiveType type = (MTLPrimitiveType)primitve_type;
|
||||
MTLIndexType ndx_type = (MTLIndexType)index_type;
|
||||
[enc drawIndexedPrimitives:type indexType:ndx_type indexBuffer:ndx_buf indexBufferOffset:index_buffer_offset indirectBuffer:buf indirectBufferOffset:indirect_buffer_offset];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_use_resource(mtl_compute_encoder *encoder, mtl_resource *res_handle,
|
||||
uint32_t usage)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLRenderCommandEncoder> enc = (id<MTLRenderCommandEncoder>)encoder;
|
||||
id<MTLResource> res = (id<MTLResource>)res_handle;
|
||||
[enc useResource:res usage:(MTLResourceUsage)usage stages:MTLRenderStageVertex|MTLRenderStageFragment];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_use_resources(mtl_render_encoder *encoder,
|
||||
mtl_resource **resource_handles, uint32_t count,
|
||||
enum mtl_resource_usage usage)
|
||||
{
|
||||
@autoreleasepool {
|
||||
// id<MTLRenderCommandEncoder> enc = (id<MTLRenderCommandEncoder>)encoder;
|
||||
id<MTLResource> *handles = (id<MTLResource>*)resource_handles;
|
||||
for (uint32_t i = 0u; i < count; ++i) {
|
||||
if (handles[i] != NULL)
|
||||
mtl_render_use_resource(encoder, handles[i], usage);
|
||||
}
|
||||
/* TODO_KOSMICKRISP No null values in the array or Metal complains */
|
||||
// [enc useResources:handles count:count usage:(MTLResourceUsage)usage];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_use_heaps(mtl_render_encoder *encoder, mtl_heap **heaps,
|
||||
uint32_t count)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLRenderCommandEncoder> enc = (id<MTLRenderCommandEncoder>)encoder;
|
||||
id<MTLHeap> *handles = (id<MTLHeap>*)heaps;
|
||||
[enc useHeaps:handles count:count stages:MTLRenderStageVertex|MTLRenderStageFragment];
|
||||
}
|
||||
}
|
||||
205
src/kosmickrisp/bridge/mtl_format.h
Normal file
205
src/kosmickrisp/bridge/mtl_format.h
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
#ifndef MTL_FORMAT_H
|
||||
#define MTL_FORMAT_H 1
|
||||
|
||||
/* TODO_KOSMICKRISP Haven't modified all
|
||||
* Slightly modified naming so they match to enum pipe_format for convenience
|
||||
*/
|
||||
enum mtl_pixel_format {
|
||||
MTL_PIXEL_FORMAT_INVALID = 0,
|
||||
|
||||
/* Normal 8 bit formats */
|
||||
MTL_PIXEL_FORMAT_A8_UNORM = 1,
|
||||
|
||||
MTL_PIXEL_FORMAT_R8_UNORM = 10,
|
||||
MTL_PIXEL_FORMAT_R8_SRGB = 11,
|
||||
MTL_PIXEL_FORMAT_R8_SNORM = 12,
|
||||
MTL_PIXEL_FORMAT_R8_UINT = 13,
|
||||
MTL_PIXEL_FORMAT_R8_SINT = 14,
|
||||
|
||||
/* Normal 16 bit formats */
|
||||
MTL_PIXEL_FORMAT_R16_UNORM = 20,
|
||||
MTL_PIXEL_FORMAT_R16_SNORM = 22,
|
||||
MTL_PIXEL_FORMAT_R16_UINT = 23,
|
||||
MTL_PIXEL_FORMAT_R16_SINT = 24,
|
||||
MTL_PIXEL_FORMAT_R16_FLOAT = 25,
|
||||
|
||||
MTL_PIXEL_FORMAT_R8G8_UNORM = 30,
|
||||
MTL_PIXEL_FORMAT_R8G8_SRGB = 31,
|
||||
MTL_PIXEL_FORMAT_R8G8_SNORM = 32,
|
||||
MTL_PIXEL_FORMAT_R8G8_UINT = 33,
|
||||
MTL_PIXEL_FORMAT_R8G8_SINT = 34,
|
||||
|
||||
/* Packed 16 bit formats */
|
||||
MTL_PIXEL_FORMAT_B5G6R5_UNORM = 40,
|
||||
MTL_PIXEL_FORMAT_A1B5G5R5_UNORM = 41,
|
||||
MTL_PIXEL_FORMAT_A4B4G4R4_UNORM = 42,
|
||||
MTL_PIXEL_FORMAT_B5G5R5A1_UNORM = 43,
|
||||
|
||||
/* Normal 32 bit formats */
|
||||
MTL_PIXEL_FORMAT_R32_UINT = 53,
|
||||
MTL_PIXEL_FORMAT_R32_SINT = 54,
|
||||
MTL_PIXEL_FORMAT_R32_FLOAT = 55,
|
||||
|
||||
MTL_PIXEL_FORMAT_R16G16_UNORM = 60,
|
||||
MTL_PIXEL_FORMAT_R16G16_SNORM = 62,
|
||||
MTL_PIXEL_FORMAT_R16G16_UINT = 63,
|
||||
MTL_PIXEL_FORMAT_R16G16_SINT = 64,
|
||||
MTL_PIXEL_FORMAT_R16G16_FLOAT = 65,
|
||||
|
||||
MTL_PIXEL_FORMAT_R8G8B8A8_UNORM = 70,
|
||||
MTL_PIXEL_FORMAT_R8G8B8A8_SRGB = 71,
|
||||
MTL_PIXEL_FORMAT_R8G8B8A8_SNORM = 72,
|
||||
MTL_PIXEL_FORMAT_R8G8B8A8_UINT = 73,
|
||||
MTL_PIXEL_FORMAT_R8G8B8A8_SINT = 74,
|
||||
|
||||
MTL_PIXEL_FORMAT_B8G8R8A8_UNORM = 80,
|
||||
MTL_PIXEL_FORMAT_B8G8R8A8_SRGB = 81,
|
||||
|
||||
/* Packed 32 bit formats */
|
||||
MTL_PIXEL_FORMAT_R10G10B10A2_UNORM = 90,
|
||||
MTL_PIXEL_FORMAT_R10G10B10A2_UINT = 91,
|
||||
|
||||
MTL_PIXEL_FORMAT_R11G11B10_FLOAT = 92,
|
||||
MTL_PIXEL_FORMAT_R9G9B9E5_FLOAT = 93,
|
||||
|
||||
MTL_PIXEL_FORMAT_B10G10R10A2_UNORM = 94,
|
||||
|
||||
MTL_PIXEL_FORMAT_BGR10_XR = 554,
|
||||
MTL_PIXEL_FORMAT_BGR10_XR_SRGB = 555,
|
||||
|
||||
/* Normal 64 bit formats */
|
||||
MTL_PIXEL_FORMAT_R32G32_UINT = 103,
|
||||
MTL_PIXEL_FORMAT_R32G32_SINT = 104,
|
||||
MTL_PIXEL_FORMAT_R32G32_FLOAT = 105,
|
||||
|
||||
MTL_PIXEL_FORMAT_R16G16B16A16_UNORM = 110,
|
||||
MTL_PIXEL_FORMAT_R16G16B16A16_SNORM = 112,
|
||||
MTL_PIXEL_FORMAT_R16G16B16A16_UINT = 113,
|
||||
MTL_PIXEL_FORMAT_R16G16B16A16_SINT = 114,
|
||||
MTL_PIXEL_FORMAT_R16G16B16A16_FLOAT = 115,
|
||||
|
||||
MTL_PIXEL_FORMAT_BGRA10_XR = 552,
|
||||
MTL_PIXEL_FORMAT_BGRA10_XR_SRGB = 553,
|
||||
|
||||
/* Normal 128 bit formats */
|
||||
MTL_PIXEL_FORMAT_R32G32B32A32_UINT = 123,
|
||||
MTL_PIXEL_FORMAT_R32G32B32A32_SINT = 124,
|
||||
MTL_PIXEL_FORMAT_R32G32B32A32_FLOAT = 125,
|
||||
|
||||
/* Compressed formats. */
|
||||
|
||||
/* S3TC/DXT */
|
||||
MTL_PIXEL_FORMAT_BC1_RGBA = 130,
|
||||
MTL_PIXEL_FORMAT_BC1_RGBA_SRGB = 131,
|
||||
MTL_PIXEL_FORMAT_BC2_RGBA = 132,
|
||||
MTL_PIXEL_FORMAT_BC2_RGBA_SRGB = 133,
|
||||
MTL_PIXEL_FORMAT_BC3_RGBA = 134,
|
||||
MTL_PIXEL_FORMAT_BC3_RGBA_SRGB = 135,
|
||||
|
||||
/* RGTC */
|
||||
MTL_PIXEL_FORMAT_BC4_R_UNORM = 140,
|
||||
MTL_PIXEL_FORMAT_BC4_R_SNORM = 141,
|
||||
MTL_PIXEL_FORMAT_BC5_RG_UNORM = 142,
|
||||
MTL_PIXEL_FORMAT_BC5_RG_SNORM = 143,
|
||||
|
||||
/* BPTC */
|
||||
MTL_PIXEL_FORMAT_BC6H_RGB_FLOAT = 150,
|
||||
MTL_PIXEL_FORMAT_BC6H_RGBU_FLOAT = 151,
|
||||
MTL_PIXEL_FORMAT_BC7_RGBA_UNORM = 152,
|
||||
MTL_PIXEL_FORMAT_BC7_RGBA_SRGB = 153,
|
||||
|
||||
/* PVRTC */
|
||||
MTL_PIXEL_FORMAT_PVRTC_RGB_2BPP = 160,
|
||||
MTL_PIXEL_FORMAT_PVRTC_RGB_2BPP_SRGB = 161,
|
||||
MTL_PIXEL_FORMAT_PVRTC_RGB_4BPP = 162,
|
||||
MTL_PIXEL_FORMAT_PVRTC_RGB_4BPP_SRGB = 163,
|
||||
MTL_PIXEL_FORMAT_PVRTC_RGBA_2BPP = 164,
|
||||
MTL_PIXEL_FORMAT_PVRTC_RGBA_2BPP_SRGB = 165,
|
||||
MTL_PIXEL_FORMAT_PVRTC_RGBA_4BPP = 166,
|
||||
MTL_PIXEL_FORMAT_PVRTC_RGBA_4BPP_SRGB = 167,
|
||||
|
||||
/* ETC2 */
|
||||
MTL_PIXEL_FORMAT_ETC2_R11_UNORM = 170,
|
||||
MTL_PIXEL_FORMAT_ETC2_R11_SNORM = 172,
|
||||
MTL_PIXEL_FORMAT_ETC2_RG11_UNORM = 174,
|
||||
MTL_PIXEL_FORMAT_ETC2_RG11_SNORM = 176,
|
||||
MTL_PIXEL_FORMAT_ETC2_RGBA8 = 178,
|
||||
MTL_PIXEL_FORMAT_ETC2_SRGBA8 = 179,
|
||||
|
||||
MTL_PIXEL_FORMAT_ETC2_RGB8 = 180,
|
||||
MTL_PIXEL_FORMAT_ETC2_SRGB8 = 181,
|
||||
MTL_PIXEL_FORMAT_ETC2_RGB8A1 = 182,
|
||||
MTL_PIXEL_FORMAT_ETC2_SRGB8A1 = 183,
|
||||
|
||||
/* ASTC */
|
||||
MTL_PIXEL_FORMAT_ASTC_4x4_SRGB = 186,
|
||||
MTL_PIXEL_FORMAT_ASTC_5x4_SRGB = 187,
|
||||
MTL_PIXEL_FORMAT_ASTC_5x5_SRGB = 188,
|
||||
MTL_PIXEL_FORMAT_ASTC_6x5_SRGB = 189,
|
||||
MTL_PIXEL_FORMAT_ASTC_6x6_SRGB = 190,
|
||||
MTL_PIXEL_FORMAT_ASTC_8x5_SRGB = 192,
|
||||
MTL_PIXEL_FORMAT_ASTC_8x6_SRGB = 193,
|
||||
MTL_PIXEL_FORMAT_ASTC_8x8_SRGB = 194,
|
||||
MTL_PIXEL_FORMAT_ASTC_10x5_SRGB = 195,
|
||||
MTL_PIXEL_FORMAT_ASTC_10x6_SRGB = 196,
|
||||
MTL_PIXEL_FORMAT_ASTC_10x8_SRGB = 197,
|
||||
MTL_PIXEL_FORMAT_ASTC_10x10_SRGB = 198,
|
||||
MTL_PIXEL_FORMAT_ASTC_12x10_SRGB = 199,
|
||||
MTL_PIXEL_FORMAT_ASTC_12x12_SRGB = 200,
|
||||
|
||||
MTL_PIXEL_FORMAT_ASTC_4x4 = 204,
|
||||
MTL_PIXEL_FORMAT_ASTC_5x4 = 205,
|
||||
MTL_PIXEL_FORMAT_ASTC_5x5 = 206,
|
||||
MTL_PIXEL_FORMAT_ASTC_6x5 = 207,
|
||||
MTL_PIXEL_FORMAT_ASTC_6x6 = 208,
|
||||
MTL_PIXEL_FORMAT_ASTC_8x5 = 210,
|
||||
MTL_PIXEL_FORMAT_ASTC_8x6 = 211,
|
||||
MTL_PIXEL_FORMAT_ASTC_8x8 = 212,
|
||||
MTL_PIXEL_FORMAT_ASTC_10x5 = 213,
|
||||
MTL_PIXEL_FORMAT_ASTC_10x6 = 214,
|
||||
MTL_PIXEL_FORMAT_ASTC_10x8 = 215,
|
||||
MTL_PIXEL_FORMAT_ASTC_10x10 = 216,
|
||||
MTL_PIXEL_FORMAT_ASTC_12x10 = 217,
|
||||
MTL_PIXEL_FORMAT_ASTC_12x12 = 218,
|
||||
|
||||
/* ASTC HDR (High Dynamic Range) */
|
||||
MTL_PIXEL_FORMAT_ASTC_4x4_HDR = 222,
|
||||
MTL_PIXEL_FORMAT_ASTC_5x4_HDR = 223,
|
||||
MTL_PIXEL_FORMAT_ASTC_5x5_HDR = 224,
|
||||
MTL_PIXEL_FORMAT_ASTC_6x5_HDR = 225,
|
||||
MTL_PIXEL_FORMAT_ASTC_6x6_HDR = 226,
|
||||
MTL_PIXEL_FORMAT_ASTC_8x5_HDR = 228,
|
||||
MTL_PIXEL_FORMAT_ASTC_8x6_HDR = 229,
|
||||
MTL_PIXEL_FORMAT_ASTC_8x8_HDR = 230,
|
||||
MTL_PIXEL_FORMAT_ASTC_10x5_HDR = 231,
|
||||
MTL_PIXEL_FORMAT_ASTC_10x6_HDR = 232,
|
||||
MTL_PIXEL_FORMAT_ASTC_10x8_HDR = 233,
|
||||
MTL_PIXEL_FORMAT_ASTC_10x10_HDR = 234,
|
||||
MTL_PIXEL_FORMAT_ASTC_12x10_HDR = 235,
|
||||
MTL_PIXEL_FORMAT_ASTC_12x12_HDR = 236,
|
||||
|
||||
/* YUV */
|
||||
MTL_PIXEL_FORMAT_GBGR422 = 240,
|
||||
MTL_PIXEL_FORMAT_BGRG422 = 241,
|
||||
|
||||
/* DEPTH */
|
||||
MTL_PIXEL_FORMAT_Z16_UNORM = 250,
|
||||
MTL_PIXEL_FORMAT_Z32_FLOAT = 252,
|
||||
|
||||
/* STENCIL */
|
||||
MTL_PIXEL_FORMAT_S8_UINT = 253,
|
||||
|
||||
/* DEPTH STENCIL */
|
||||
MTL_PIXEL_FORMAT_Z24_UNORM_S8_UINT = 255,
|
||||
MTL_PIXEL_FORMAT_Z32_FLOAT_S8X24_UINT = 260,
|
||||
|
||||
MTL_PIXEL_FORMAT_X32_S8X24_UINT = 261,
|
||||
MTL_PIXEL_FORMAT_X24_S8_UINT = 262,
|
||||
};
|
||||
|
||||
#endif /* MTL_FORMAT_H */
|
||||
30
src/kosmickrisp/bridge/mtl_heap.h
Normal file
30
src/kosmickrisp/bridge/mtl_heap.h
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef MTL_HEAP_H
|
||||
#define MTL_HEAP_H 1
|
||||
|
||||
#include "mtl_types.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
/* TODO_KOSMICKRISP We should move this struct to the bridge side. */
|
||||
struct kk_image_layout;
|
||||
|
||||
/* Creation */
|
||||
mtl_heap *mtl_new_heap(mtl_device *device, uint64_t size,
|
||||
enum mtl_resource_options resource_options);
|
||||
|
||||
/* Utils */
|
||||
uint64_t mtl_heap_get_size(mtl_heap *heap);
|
||||
|
||||
/* Allocation from heap */
|
||||
mtl_buffer *mtl_new_buffer_with_length(mtl_heap *heap, uint64_t size_B,
|
||||
uint64_t offset_B);
|
||||
mtl_texture *mtl_new_texture_with_descriptor(
|
||||
mtl_heap *heap, const struct kk_image_layout *layout, uint64_t offset);
|
||||
|
||||
#endif /* MTL_HEAP_H */
|
||||
83
src/kosmickrisp/bridge/mtl_heap.m
Normal file
83
src/kosmickrisp/bridge/mtl_heap.m
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "mtl_heap.h"
|
||||
|
||||
/* TODO_KOSMICKRISP Remove */
|
||||
#include "kk_private.h"
|
||||
#include "kk_image_layout.h"
|
||||
|
||||
#include <Metal/MTLHeap.h>
|
||||
|
||||
/* Creation */
|
||||
mtl_heap *
|
||||
mtl_new_heap(mtl_device *device, uint64_t size,
|
||||
enum mtl_resource_options resource_options)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLDevice> dev = (id<MTLDevice>)device;
|
||||
MTLHeapDescriptor *descriptor = [[MTLHeapDescriptor new] autorelease];
|
||||
descriptor.type = MTLHeapTypePlacement;
|
||||
descriptor.resourceOptions = (MTLResourceOptions)resource_options;
|
||||
descriptor.size = size;
|
||||
descriptor.sparsePageSize = MTLSparsePageSize16;
|
||||
return [dev newHeapWithDescriptor:descriptor];
|
||||
}
|
||||
}
|
||||
|
||||
/* Utils */
|
||||
uint64_t
|
||||
mtl_heap_get_size(mtl_heap *heap)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLHeap> hp = (id<MTLHeap>)heap;
|
||||
return hp.size;
|
||||
}
|
||||
}
|
||||
|
||||
static MTLTextureDescriptor *
|
||||
mtl_new_texture_descriptor(const struct kk_image_layout *layout)
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLTextureDescriptor *descriptor = [MTLTextureDescriptor new];
|
||||
descriptor.textureType = (MTLTextureType)layout->type;
|
||||
descriptor.pixelFormat = layout->format.mtl;
|
||||
descriptor.width = layout->width_px;
|
||||
descriptor.height = layout->height_px;
|
||||
descriptor.depth = layout->depth_px;
|
||||
descriptor.mipmapLevelCount = layout->levels;
|
||||
descriptor.sampleCount = layout->sample_count_sa;
|
||||
descriptor.arrayLength = layout->layers;
|
||||
descriptor.allowGPUOptimizedContents = layout->optimized_layout;
|
||||
descriptor.usage = (MTLTextureUsage)layout->usage;
|
||||
/* We don't set the swizzle because Metal complains when the usage has store or render target with swizzle... */
|
||||
|
||||
return descriptor;
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocation from heap */
|
||||
mtl_buffer *
|
||||
mtl_new_buffer_with_length(mtl_heap *heap, uint64_t size_B, uint64_t offset_B)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLHeap> hp = (id<MTLHeap>)heap;
|
||||
return (mtl_buffer *)[hp newBufferWithLength:size_B options:KK_MTL_RESOURCE_OPTIONS offset:offset_B];
|
||||
}
|
||||
}
|
||||
|
||||
mtl_texture *
|
||||
mtl_new_texture_with_descriptor(mtl_heap *heap,
|
||||
const struct kk_image_layout *layout,
|
||||
uint64_t offset)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLHeap> hp = (id<MTLHeap>)heap;
|
||||
MTLTextureDescriptor *descriptor = [mtl_new_texture_descriptor(layout) autorelease];
|
||||
descriptor.resourceOptions = hp.resourceOptions;
|
||||
return [hp newTextureWithDescriptor:descriptor offset:offset];
|
||||
}
|
||||
}
|
||||
16
src/kosmickrisp/bridge/mtl_library.h
Normal file
16
src/kosmickrisp/bridge/mtl_library.h
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef MTL_LIBRARY_H
|
||||
#define MTL_LIBRARY_H 1
|
||||
|
||||
#include "mtl_types.h"
|
||||
|
||||
mtl_library *mtl_new_library(mtl_device *device, const char *src);
|
||||
mtl_function *mtl_new_function_with_name(mtl_library *lib,
|
||||
const char *entry_point);
|
||||
|
||||
#endif /* MTL_LIBRARY_H */
|
||||
43
src/kosmickrisp/bridge/mtl_library.m
Normal file
43
src/kosmickrisp/bridge/mtl_library.m
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "mtl_library.h"
|
||||
|
||||
#include <Metal/MTLDevice.h>
|
||||
|
||||
mtl_library *
|
||||
mtl_new_library(mtl_device *device, const char *src)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLDevice> dev = (id<MTLDevice>)device;
|
||||
id<MTLLibrary> lib = NULL;
|
||||
NSString *nsstr = [NSString stringWithCString:src encoding:NSASCIIStringEncoding];
|
||||
NSError *error;
|
||||
MTLCompileOptions *comp_opts = [MTLCompileOptions new];
|
||||
comp_opts.languageVersion = MTLLanguageVersion3_2;
|
||||
comp_opts.mathMode = MTLMathModeSafe;
|
||||
comp_opts.mathFloatingPointFunctions = MTLMathFloatingPointFunctionsPrecise;
|
||||
lib = [dev newLibraryWithSource:nsstr options:comp_opts error:&error];
|
||||
|
||||
if (error != nil) {
|
||||
fprintf(stderr, "Failed to create MTLLibrary: %s\n", [error.localizedDescription UTF8String]);
|
||||
}
|
||||
|
||||
[comp_opts release];
|
||||
return lib;
|
||||
}
|
||||
}
|
||||
|
||||
mtl_function *
|
||||
mtl_new_function_with_name(mtl_library *lib, const char *entry_point)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLLibrary> mtl_lib = (id<MTLLibrary>)lib;
|
||||
NSString *ns_entry_point = [NSString stringWithCString:entry_point encoding:NSASCIIStringEncoding];
|
||||
return [mtl_lib newFunctionWithName:ns_entry_point];
|
||||
}
|
||||
}
|
||||
|
||||
165
src/kosmickrisp/bridge/mtl_render_state.h
Normal file
165
src/kosmickrisp/bridge/mtl_render_state.h
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef MTL_RENDER_STATE_H
|
||||
#define MTL_RENDER_STATE_H 1
|
||||
|
||||
#include "mtl_types.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/* Bridge enums */
|
||||
enum mtl_pixel_format;
|
||||
|
||||
/* TODO_KOSMICKRISP Remove */
|
||||
enum VkCompareOp;
|
||||
enum VkStencilOp;
|
||||
|
||||
/* Render pass descriptor */
|
||||
mtl_render_pass_descriptor *mtl_new_render_pass_descriptor(void);
|
||||
|
||||
mtl_render_pass_attachment_descriptor *
|
||||
mtl_render_pass_descriptor_get_color_attachment(
|
||||
mtl_render_pass_descriptor *descriptor, uint32_t index);
|
||||
|
||||
mtl_render_pass_attachment_descriptor *
|
||||
mtl_render_pass_descriptor_get_depth_attachment(
|
||||
mtl_render_pass_descriptor *descriptor);
|
||||
|
||||
mtl_render_pass_attachment_descriptor *
|
||||
mtl_render_pass_descriptor_get_stencil_attachment(
|
||||
mtl_render_pass_descriptor *descriptor);
|
||||
|
||||
void mtl_render_pass_attachment_descriptor_set_texture(
|
||||
mtl_render_pass_attachment_descriptor *descriptor, mtl_texture *texture);
|
||||
|
||||
void mtl_render_pass_attachment_descriptor_set_level(
|
||||
mtl_render_pass_attachment_descriptor *descriptor, uint32_t level);
|
||||
|
||||
void mtl_render_pass_attachment_descriptor_set_slice(
|
||||
mtl_render_pass_attachment_descriptor *descriptor, uint32_t slice);
|
||||
|
||||
void mtl_render_pass_attachment_descriptor_set_load_action(
|
||||
mtl_render_pass_attachment_descriptor *descriptor,
|
||||
enum mtl_load_action action);
|
||||
|
||||
void mtl_render_pass_attachment_descriptor_set_store_action(
|
||||
mtl_render_pass_attachment_descriptor *descriptor,
|
||||
enum mtl_store_action action);
|
||||
|
||||
void mtl_render_pass_attachment_descriptor_set_clear_color(
|
||||
mtl_render_pass_attachment_descriptor *descriptor,
|
||||
struct mtl_clear_color clear_color);
|
||||
|
||||
void mtl_render_pass_attachment_descriptor_set_clear_depth(
|
||||
mtl_render_pass_attachment_descriptor *descriptor, double depth);
|
||||
|
||||
void mtl_render_pass_attachment_descriptor_set_clear_stencil(
|
||||
mtl_render_pass_attachment_descriptor *descriptor, uint32_t stencil);
|
||||
|
||||
void mtl_render_pass_descriptor_set_render_target_array_length(
|
||||
mtl_render_pass_descriptor *descriptor, uint32_t length);
|
||||
|
||||
void mtl_render_pass_descriptor_set_render_target_width(
|
||||
mtl_render_pass_descriptor *descriptor, uint32_t width);
|
||||
|
||||
void mtl_render_pass_descriptor_set_render_target_height(
|
||||
mtl_render_pass_descriptor *descriptor, uint32_t height);
|
||||
|
||||
void mtl_render_pass_descriptor_set_default_raster_sample_count(
|
||||
mtl_render_pass_descriptor *descriptor, uint32_t sample_count);
|
||||
|
||||
void mtl_render_pass_descriptor_set_visibility_buffer(
|
||||
mtl_render_pass_descriptor *descriptor, mtl_buffer *visibility_buffer);
|
||||
|
||||
/* Render pipeline descriptor */
|
||||
mtl_render_pipeline_descriptor *mtl_new_render_pipeline_descriptor(void);
|
||||
|
||||
void mtl_render_pipeline_descriptor_set_vertex_shader(
|
||||
mtl_render_pass_descriptor *descriptor, mtl_function *shader);
|
||||
|
||||
void mtl_render_pipeline_descriptor_set_fragment_shader(
|
||||
mtl_render_pass_descriptor *descriptor, mtl_function *shader);
|
||||
|
||||
void mtl_render_pipeline_descriptor_set_input_primitive_topology(
|
||||
mtl_render_pass_descriptor *descriptor,
|
||||
enum mtl_primitive_topology_class topology_class);
|
||||
|
||||
void mtl_render_pipeline_descriptor_set_color_attachment_format(
|
||||
mtl_render_pass_descriptor *descriptor, uint8_t index,
|
||||
enum mtl_pixel_format format);
|
||||
|
||||
void mtl_render_pipeline_descriptor_set_depth_attachment_format(
|
||||
mtl_render_pass_descriptor *descriptor, enum mtl_pixel_format format);
|
||||
|
||||
void mtl_render_pipeline_descriptor_set_stencil_attachment_format(
|
||||
mtl_render_pass_descriptor *descriptor, enum mtl_pixel_format format);
|
||||
|
||||
void mtl_render_pipeline_descriptor_set_raster_sample_count(
|
||||
mtl_render_pass_descriptor *descriptor, uint32_t sample_count);
|
||||
|
||||
void mtl_render_pipeline_descriptor_set_alpha_to_coverage(
|
||||
mtl_render_pass_descriptor *descriptor, bool enabled);
|
||||
|
||||
void mtl_render_pipeline_descriptor_set_alpha_to_one(
|
||||
mtl_render_pass_descriptor *descriptor, bool enabled);
|
||||
|
||||
void mtl_render_pipeline_descriptor_set_rasterization_enabled(
|
||||
mtl_render_pass_descriptor *descriptor, bool enabled);
|
||||
|
||||
void mtl_render_pipeline_descriptor_set_max_vertex_amplification_count(
|
||||
mtl_render_pass_descriptor *descriptor, uint32_t count);
|
||||
|
||||
/* Render pipeline */
|
||||
mtl_render_pipeline_state *
|
||||
mtl_new_render_pipeline(mtl_device *device,
|
||||
mtl_render_pass_descriptor *descriptor);
|
||||
|
||||
/* Stencil descriptor */
|
||||
mtl_stencil_descriptor *mtl_new_stencil_descriptor(void);
|
||||
|
||||
void mtl_stencil_descriptor_set_stencil_failure_operation(
|
||||
mtl_stencil_descriptor *descriptor, enum VkStencilOp op);
|
||||
|
||||
void mtl_stencil_descriptor_set_depth_failure_operation(
|
||||
mtl_stencil_descriptor *descriptor, enum VkStencilOp op);
|
||||
|
||||
void mtl_stencil_descriptor_set_depth_stencil_pass_operation(
|
||||
mtl_stencil_descriptor *descriptor, enum VkStencilOp op);
|
||||
|
||||
void mtl_stencil_descriptor_set_stencil_compare_function(
|
||||
mtl_stencil_descriptor *descriptor, enum VkCompareOp op);
|
||||
|
||||
void mtl_stencil_descriptor_set_read_mask(mtl_stencil_descriptor *descriptor,
|
||||
uint32_t mask);
|
||||
|
||||
void mtl_stencil_descriptor_set_write_mask(mtl_stencil_descriptor *descriptor,
|
||||
uint32_t mask);
|
||||
|
||||
/* Depth stencil descriptor */
|
||||
mtl_depth_stencil_descriptor *mtl_new_depth_stencil_descriptor(void);
|
||||
|
||||
void mtl_depth_stencil_descriptor_set_depth_compare_function(
|
||||
mtl_depth_stencil_descriptor *descriptor, enum VkCompareOp op);
|
||||
|
||||
void mtl_depth_stencil_descriptor_set_depth_write_enabled(
|
||||
mtl_depth_stencil_descriptor *descriptor, bool enable_write);
|
||||
|
||||
void mtl_depth_stencil_descriptor_set_back_face_stencil(
|
||||
mtl_depth_stencil_descriptor *descriptor,
|
||||
mtl_stencil_descriptor *stencil_descriptor);
|
||||
|
||||
void mtl_depth_stencil_descriptor_set_front_face_stencil(
|
||||
mtl_depth_stencil_descriptor *descriptor,
|
||||
mtl_stencil_descriptor *stencil_descriptor);
|
||||
|
||||
/* Depth stencil state */
|
||||
mtl_depth_stencil_state *
|
||||
mtl_new_depth_stencil_state(mtl_device *device,
|
||||
mtl_depth_stencil_descriptor *descriptor);
|
||||
|
||||
#endif /* MTL_RENDER_STATE_H */
|
||||
475
src/kosmickrisp/bridge/mtl_render_state.m
Normal file
475
src/kosmickrisp/bridge/mtl_render_state.m
Normal file
|
|
@ -0,0 +1,475 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "mtl_render_state.h"
|
||||
|
||||
#include "mtl_format.h"
|
||||
|
||||
/* TODO_KOSMICKRISP Remove */
|
||||
#include "vk_to_mtl_map.h"
|
||||
|
||||
/* TODO_KOSMICKRISP Remove */
|
||||
#include "vulkan/vulkan.h"
|
||||
|
||||
#include <Metal/MTLRenderPass.h>
|
||||
#include <Metal/MTLRenderPipeline.h>
|
||||
#include <Metal/MTLDepthStencil.h>
|
||||
|
||||
/* Render pass descriptor */
|
||||
mtl_render_pass_descriptor *
|
||||
mtl_new_render_pass_descriptor(void)
|
||||
{
|
||||
@autoreleasepool {
|
||||
return [[MTLRenderPassDescriptor renderPassDescriptor] retain];
|
||||
}
|
||||
}
|
||||
|
||||
mtl_render_pass_attachment_descriptor *
|
||||
mtl_render_pass_descriptor_get_color_attachment(
|
||||
mtl_render_pass_descriptor *descriptor, uint32_t index)
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLRenderPassDescriptor *desc = (MTLRenderPassDescriptor *)descriptor;
|
||||
return desc.colorAttachments[index];
|
||||
}
|
||||
}
|
||||
|
||||
mtl_render_pass_attachment_descriptor *
|
||||
mtl_render_pass_descriptor_get_depth_attachment(
|
||||
mtl_render_pass_descriptor *descriptor)
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLRenderPassDescriptor *desc = (MTLRenderPassDescriptor *)descriptor;
|
||||
return desc.depthAttachment;
|
||||
}
|
||||
}
|
||||
|
||||
mtl_render_pass_attachment_descriptor *
|
||||
mtl_render_pass_descriptor_get_stencil_attachment(
|
||||
mtl_render_pass_descriptor *descriptor)
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLRenderPassDescriptor *desc = (MTLRenderPassDescriptor *)descriptor;
|
||||
return desc.stencilAttachment;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_pass_attachment_descriptor_set_texture(
|
||||
mtl_render_pass_attachment_descriptor *descriptor, mtl_texture *texture)
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLRenderPassAttachmentDescriptor *desc = (MTLRenderPassAttachmentDescriptor *)descriptor;
|
||||
desc.texture = (id<MTLTexture>)texture;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_pass_attachment_descriptor_set_level(
|
||||
mtl_render_pass_attachment_descriptor *descriptor, uint32_t level)
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLRenderPassAttachmentDescriptor *desc = (MTLRenderPassAttachmentDescriptor *)descriptor;
|
||||
desc.level = level;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_pass_attachment_descriptor_set_slice(
|
||||
mtl_render_pass_attachment_descriptor *descriptor, uint32_t slice)
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLRenderPassAttachmentDescriptor *desc = (MTLRenderPassAttachmentDescriptor *)descriptor;
|
||||
desc.slice = slice;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_pass_attachment_descriptor_set_load_action(
|
||||
mtl_render_pass_attachment_descriptor *descriptor,
|
||||
enum mtl_load_action action)
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLRenderPassAttachmentDescriptor *desc = (MTLRenderPassAttachmentDescriptor *)descriptor;
|
||||
desc.loadAction = (MTLLoadAction)action;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_pass_attachment_descriptor_set_store_action(
|
||||
mtl_render_pass_attachment_descriptor *descriptor,
|
||||
enum mtl_store_action action)
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLRenderPassAttachmentDescriptor *desc = (MTLRenderPassAttachmentDescriptor *)descriptor;
|
||||
desc.storeAction = (MTLStoreAction)action;
|
||||
desc.storeActionOptions = MTLStoreActionOptionNone; /* TODO_KOSMICKRISP Maybe expose this? */
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_pass_attachment_descriptor_set_clear_color(
|
||||
mtl_render_pass_attachment_descriptor *descriptor,
|
||||
struct mtl_clear_color clear_color)
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLRenderPassColorAttachmentDescriptor *desc = (MTLRenderPassColorAttachmentDescriptor *)descriptor;
|
||||
desc.clearColor = MTLClearColorMake(clear_color.red, clear_color.green, clear_color.blue, clear_color.alpha);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_pass_attachment_descriptor_set_clear_depth(
|
||||
mtl_render_pass_attachment_descriptor *descriptor, double depth)
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLRenderPassDepthAttachmentDescriptor *desc = (MTLRenderPassDepthAttachmentDescriptor *)descriptor;
|
||||
desc.clearDepth = depth;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_pass_attachment_descriptor_set_clear_stencil(mtl_render_pass_attachment_descriptor *descriptor,
|
||||
uint32_t stencil)
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLRenderPassStencilAttachmentDescriptor *desc = (MTLRenderPassStencilAttachmentDescriptor *)descriptor;
|
||||
desc.clearStencil = stencil;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_pass_descriptor_set_render_target_array_length(mtl_render_pass_descriptor *descriptor,
|
||||
uint32_t length)
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLRenderPassDescriptor *desc = (MTLRenderPassDescriptor *)descriptor;
|
||||
desc.renderTargetArrayLength = length;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_pass_descriptor_set_render_target_width(mtl_render_pass_descriptor *descriptor,
|
||||
uint32_t width)
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLRenderPassDescriptor *desc = (MTLRenderPassDescriptor *)descriptor;
|
||||
desc.renderTargetWidth = width;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_pass_descriptor_set_render_target_height(mtl_render_pass_descriptor *descriptor,
|
||||
uint32_t height)
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLRenderPassDescriptor *desc = (MTLRenderPassDescriptor *)descriptor;
|
||||
desc.renderTargetHeight = height;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_pass_descriptor_set_default_raster_sample_count(mtl_render_pass_descriptor *descriptor,
|
||||
uint32_t sample_count)
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLRenderPassDescriptor *desc = (MTLRenderPassDescriptor *)descriptor;
|
||||
desc.defaultRasterSampleCount = sample_count;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_pass_descriptor_set_visibility_buffer(mtl_render_pass_descriptor *descriptor,
|
||||
mtl_buffer *visibility_buffer)
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLRenderPassDescriptor *desc = (MTLRenderPassDescriptor *)descriptor;
|
||||
id<MTLBuffer> buffer = (id<MTLBuffer>)visibility_buffer;
|
||||
desc.visibilityResultBuffer = buffer;
|
||||
}
|
||||
}
|
||||
|
||||
/* Render pipeline descriptor */
|
||||
mtl_render_pipeline_descriptor *
|
||||
mtl_new_render_pipeline_descriptor()
|
||||
{
|
||||
@autoreleasepool {
|
||||
return [[MTLRenderPipelineDescriptor alloc] init];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_pipeline_descriptor_set_vertex_shader(mtl_render_pass_descriptor *descriptor,
|
||||
mtl_function *shader)
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLRenderPipelineDescriptor *desc = (MTLRenderPipelineDescriptor *)descriptor;
|
||||
desc.vertexFunction = (id<MTLFunction>)shader;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_pipeline_descriptor_set_fragment_shader(mtl_render_pass_descriptor *descriptor,
|
||||
mtl_function *shader)
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLRenderPipelineDescriptor *desc = (MTLRenderPipelineDescriptor *)descriptor;
|
||||
desc.fragmentFunction = (id<MTLFunction>)shader;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_pipeline_descriptor_set_input_primitive_topology(mtl_render_pass_descriptor *descriptor,
|
||||
enum mtl_primitive_topology_class class)
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLRenderPipelineDescriptor *desc = (MTLRenderPipelineDescriptor *)descriptor;
|
||||
desc.inputPrimitiveTopology = (MTLPrimitiveTopologyClass)class;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_pipeline_descriptor_set_color_attachment_format(mtl_render_pass_descriptor *descriptor,
|
||||
uint8_t index,
|
||||
enum mtl_pixel_format format)
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLRenderPipelineDescriptor *desc = (MTLRenderPipelineDescriptor *)descriptor;
|
||||
desc.colorAttachments[index].pixelFormat = (MTLPixelFormat)format;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_pipeline_descriptor_set_depth_attachment_format(mtl_render_pass_descriptor *descriptor,
|
||||
enum mtl_pixel_format format)
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLRenderPipelineDescriptor *desc = (MTLRenderPipelineDescriptor *)descriptor;
|
||||
desc.depthAttachmentPixelFormat = (MTLPixelFormat)format;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_pipeline_descriptor_set_stencil_attachment_format(mtl_render_pass_descriptor *descriptor,
|
||||
enum mtl_pixel_format format)
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLRenderPipelineDescriptor *desc = (MTLRenderPipelineDescriptor *)descriptor;
|
||||
desc.stencilAttachmentPixelFormat = (MTLPixelFormat)format;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_pipeline_descriptor_set_raster_sample_count(mtl_render_pass_descriptor *descriptor,
|
||||
uint32_t sample_count)
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLRenderPipelineDescriptor *desc = (MTLRenderPipelineDescriptor *)descriptor;
|
||||
desc.rasterSampleCount = sample_count;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_pipeline_descriptor_set_alpha_to_coverage(mtl_render_pass_descriptor *descriptor,
|
||||
bool enabled)
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLRenderPipelineDescriptor *desc = (MTLRenderPipelineDescriptor *)descriptor;
|
||||
desc.alphaToCoverageEnabled = enabled;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_pipeline_descriptor_set_alpha_to_one(mtl_render_pass_descriptor *descriptor,
|
||||
bool enabled)
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLRenderPipelineDescriptor *desc = (MTLRenderPipelineDescriptor *)descriptor;
|
||||
desc.alphaToOneEnabled = enabled;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_pipeline_descriptor_set_rasterization_enabled(mtl_render_pass_descriptor *descriptor,
|
||||
bool enabled)
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLRenderPipelineDescriptor *desc = (MTLRenderPipelineDescriptor *)descriptor;
|
||||
desc.rasterizationEnabled = enabled;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_pipeline_descriptor_set_max_vertex_amplification_count( mtl_render_pass_descriptor *descriptor,
|
||||
uint32_t count)
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLRenderPipelineDescriptor *desc = (MTLRenderPipelineDescriptor *)descriptor;
|
||||
desc.maxVertexAmplificationCount = count;
|
||||
}
|
||||
}
|
||||
|
||||
/* Render pipeline */
|
||||
mtl_render_pipeline_state *
|
||||
mtl_new_render_pipeline(mtl_device *device, mtl_render_pass_descriptor *descriptor)
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLRenderPipelineDescriptor *desc = (MTLRenderPipelineDescriptor *)descriptor;
|
||||
id<MTLDevice> dev = (id<MTLDevice>)device;
|
||||
NSError *error = nil;
|
||||
mtl_render_pipeline_state *pipeline = [dev newRenderPipelineStateWithDescriptor:desc error:&error];
|
||||
if (error != nil) {
|
||||
fprintf(stderr, "Failed to create MTLLibrary: %s\n", [error.localizedDescription UTF8String]);
|
||||
}
|
||||
|
||||
return pipeline;
|
||||
}
|
||||
}
|
||||
|
||||
/* Stencil descriptor */
|
||||
mtl_stencil_descriptor *
|
||||
mtl_new_stencil_descriptor()
|
||||
{
|
||||
@autoreleasepool {
|
||||
return [[MTLStencilDescriptor new] init];
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO_KOSMICKRISP Move this to map */
|
||||
static MTLStencilOperation
|
||||
map_vk_stencil_op_to_mtl_stencil_operation(VkStencilOp op)
|
||||
{
|
||||
switch (op) {
|
||||
case VK_STENCIL_OP_KEEP:
|
||||
return MTLStencilOperationKeep;
|
||||
case VK_STENCIL_OP_ZERO:
|
||||
return MTLStencilOperationZero;
|
||||
case VK_STENCIL_OP_REPLACE:
|
||||
return MTLStencilOperationReplace;
|
||||
case VK_STENCIL_OP_INCREMENT_AND_CLAMP:
|
||||
return MTLStencilOperationIncrementClamp;
|
||||
case VK_STENCIL_OP_DECREMENT_AND_CLAMP:
|
||||
return MTLStencilOperationDecrementClamp;
|
||||
case VK_STENCIL_OP_INVERT:
|
||||
return MTLStencilOperationInvert;
|
||||
case VK_STENCIL_OP_INCREMENT_AND_WRAP:
|
||||
return MTLStencilOperationIncrementWrap;
|
||||
case VK_STENCIL_OP_DECREMENT_AND_WRAP:
|
||||
return MTLStencilOperationDecrementWrap;
|
||||
default:
|
||||
assert(false && "Unsupported VkStencilOp");
|
||||
return MTLStencilOperationZero;
|
||||
};
|
||||
}
|
||||
|
||||
void
|
||||
mtl_stencil_descriptor_set_stencil_failure_operation(mtl_stencil_descriptor *descriptor, VkStencilOp op)
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLStencilDescriptor *desc = (MTLStencilDescriptor *)descriptor;
|
||||
desc.stencilFailureOperation = map_vk_stencil_op_to_mtl_stencil_operation(op);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_stencil_descriptor_set_depth_failure_operation(mtl_stencil_descriptor *descriptor, VkStencilOp op)
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLStencilDescriptor *desc = (MTLStencilDescriptor *)descriptor;
|
||||
desc.depthFailureOperation = map_vk_stencil_op_to_mtl_stencil_operation(op);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_stencil_descriptor_set_depth_stencil_pass_operation(mtl_stencil_descriptor *descriptor, VkStencilOp op)
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLStencilDescriptor *desc = (MTLStencilDescriptor *)descriptor;
|
||||
desc.depthStencilPassOperation = map_vk_stencil_op_to_mtl_stencil_operation(op);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_stencil_descriptor_set_stencil_compare_function(mtl_stencil_descriptor *descriptor, VkCompareOp op)
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLStencilDescriptor *desc = (MTLStencilDescriptor *)descriptor;
|
||||
desc.stencilCompareFunction = (MTLCompareFunction)vk_compare_op_to_mtl_compare_function(op);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_stencil_descriptor_set_read_mask(mtl_stencil_descriptor *descriptor, uint32_t mask)
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLStencilDescriptor *desc = (MTLStencilDescriptor *)descriptor;
|
||||
desc.readMask = mask;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_stencil_descriptor_set_write_mask(mtl_stencil_descriptor *descriptor, uint32_t mask)
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLStencilDescriptor *desc = (MTLStencilDescriptor *)descriptor;
|
||||
desc.writeMask = mask;
|
||||
}
|
||||
}
|
||||
|
||||
/* Depth stencil descriptor */
|
||||
mtl_depth_stencil_descriptor *
|
||||
mtl_new_depth_stencil_descriptor()
|
||||
{
|
||||
@autoreleasepool {
|
||||
return [[MTLDepthStencilDescriptor new] init];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_depth_stencil_descriptor_set_depth_compare_function(mtl_depth_stencil_descriptor *descriptor, VkCompareOp op)
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLDepthStencilDescriptor *desc = (MTLDepthStencilDescriptor *)descriptor;
|
||||
desc.depthCompareFunction = (MTLCompareFunction)vk_compare_op_to_mtl_compare_function(op);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_depth_stencil_descriptor_set_depth_write_enabled(mtl_depth_stencil_descriptor *descriptor, bool enable_write)
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLDepthStencilDescriptor *desc = (MTLDepthStencilDescriptor *)descriptor;
|
||||
desc.depthWriteEnabled = enable_write;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_depth_stencil_descriptor_set_back_face_stencil(mtl_depth_stencil_descriptor *descriptor, mtl_stencil_descriptor *stencil_descriptor)
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLDepthStencilDescriptor *desc = (MTLDepthStencilDescriptor *)descriptor;
|
||||
desc.backFaceStencil = (MTLStencilDescriptor *)stencil_descriptor;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_depth_stencil_descriptor_set_front_face_stencil(mtl_depth_stencil_descriptor *descriptor, mtl_stencil_descriptor *stencil_descriptor)
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLDepthStencilDescriptor *desc = (MTLDepthStencilDescriptor *)descriptor;
|
||||
desc.frontFaceStencil = (MTLStencilDescriptor *)stencil_descriptor;
|
||||
}
|
||||
}
|
||||
|
||||
mtl_depth_stencil_state *
|
||||
mtl_new_depth_stencil_state(mtl_device *device, mtl_depth_stencil_descriptor *descriptor)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLDevice> dev = (id<MTLDevice>)device;
|
||||
MTLDepthStencilDescriptor *desc = (MTLDepthStencilDescriptor *)descriptor;
|
||||
return [dev newDepthStencilStateWithDescriptor:desc];
|
||||
}
|
||||
}
|
||||
50
src/kosmickrisp/bridge/mtl_sampler.h
Normal file
50
src/kosmickrisp/bridge/mtl_sampler.h
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef MTL_SAMPLER_H
|
||||
#define MTL_SAMPLER_H 1
|
||||
|
||||
#include "mtl_types.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/* Sampler descriptor */
|
||||
mtl_sampler_descriptor *mtl_new_sampler_descriptor(void);
|
||||
|
||||
/* Sampler descriptor utils */
|
||||
void mtl_sampler_descriptor_set_normalized_coordinates(
|
||||
mtl_sampler_descriptor *descriptor, bool normalized_coordinates);
|
||||
void mtl_sampler_descriptor_set_address_mode(
|
||||
mtl_sampler_descriptor *descriptor,
|
||||
enum mtl_sampler_address_mode address_mode_u,
|
||||
enum mtl_sampler_address_mode address_mode_v,
|
||||
enum mtl_sampler_address_mode address_mode_w);
|
||||
void
|
||||
mtl_sampler_descriptor_set_border_color(mtl_sampler_descriptor *descriptor,
|
||||
enum mtl_sampler_border_color color);
|
||||
void
|
||||
mtl_sampler_descriptor_set_filters(mtl_sampler_descriptor *descriptor,
|
||||
enum mtl_sampler_min_mag_filter min_filter,
|
||||
enum mtl_sampler_min_mag_filter mag_filter,
|
||||
enum mtl_sampler_mip_filter mip_filter);
|
||||
void mtl_sampler_descriptor_set_lod_clamp(mtl_sampler_descriptor *descriptor,
|
||||
float min, float max);
|
||||
void
|
||||
mtl_sampler_descriptor_set_max_anisotropy(mtl_sampler_descriptor *descriptor,
|
||||
uint64_t max);
|
||||
void
|
||||
mtl_sampler_descriptor_set_compare_function(mtl_sampler_descriptor *descriptor,
|
||||
enum mtl_compare_function function);
|
||||
|
||||
/* Sampler */
|
||||
mtl_sampler *mtl_new_sampler(mtl_device *device,
|
||||
mtl_sampler_descriptor *descriptor);
|
||||
|
||||
/* Sampler utils */
|
||||
uint64_t mtl_sampler_get_gpu_resource_id(mtl_sampler *sampler);
|
||||
|
||||
#endif /* MTL_SAMPLER_H */
|
||||
118
src/kosmickrisp/bridge/mtl_sampler.m
Normal file
118
src/kosmickrisp/bridge/mtl_sampler.m
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "mtl_sampler.h"
|
||||
|
||||
#include <Metal/MTLSampler.h>
|
||||
|
||||
mtl_sampler_descriptor *
|
||||
mtl_new_sampler_descriptor()
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLSamplerDescriptor *descriptor = [MTLSamplerDescriptor new];
|
||||
/* Set common variables we don't expose */
|
||||
descriptor.lodAverage = false;
|
||||
descriptor.supportArgumentBuffers = true;
|
||||
return descriptor;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_sampler_descriptor_set_normalized_coordinates(mtl_sampler_descriptor *descriptor, bool normalized_coordinates)
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLSamplerDescriptor *desc = (MTLSamplerDescriptor *)descriptor;
|
||||
desc.normalizedCoordinates = normalized_coordinates;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_sampler_descriptor_set_address_mode(mtl_sampler_descriptor *descriptor,
|
||||
enum mtl_sampler_address_mode address_mode_u,
|
||||
enum mtl_sampler_address_mode address_mode_v,
|
||||
enum mtl_sampler_address_mode address_mode_w)
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLSamplerDescriptor *desc = (MTLSamplerDescriptor *)descriptor;
|
||||
desc.sAddressMode = (MTLSamplerAddressMode)address_mode_u;
|
||||
desc.tAddressMode = (MTLSamplerAddressMode)address_mode_v;
|
||||
desc.rAddressMode = (MTLSamplerAddressMode)address_mode_w;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_sampler_descriptor_set_border_color(mtl_sampler_descriptor *descriptor, enum mtl_sampler_border_color color)
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLSamplerDescriptor *desc = (MTLSamplerDescriptor *)descriptor;
|
||||
desc.borderColor = (MTLSamplerBorderColor)color;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_sampler_descriptor_set_filters(mtl_sampler_descriptor *descriptor,
|
||||
enum mtl_sampler_min_mag_filter min_filter,
|
||||
enum mtl_sampler_min_mag_filter mag_filter,
|
||||
enum mtl_sampler_mip_filter mip_filter)
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLSamplerDescriptor *desc = (MTLSamplerDescriptor *)descriptor;
|
||||
desc.minFilter = (MTLSamplerMinMagFilter)min_filter;
|
||||
desc.magFilter = (MTLSamplerMinMagFilter)mag_filter;
|
||||
desc.mipFilter = (MTLSamplerMipFilter)mip_filter;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_sampler_descriptor_set_lod_clamp(mtl_sampler_descriptor *descriptor,
|
||||
float min,
|
||||
float max)
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLSamplerDescriptor *desc = (MTLSamplerDescriptor *)descriptor;
|
||||
desc.lodMinClamp = min;
|
||||
desc.lodMaxClamp = max;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_sampler_descriptor_set_max_anisotropy(mtl_sampler_descriptor *descriptor,
|
||||
uint64_t max)
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLSamplerDescriptor *desc = (MTLSamplerDescriptor *)descriptor;
|
||||
desc.maxAnisotropy = max ? max : 1u; /* Metal requires a non-zero value */
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_sampler_descriptor_set_compare_function(mtl_sampler_descriptor *descriptor,
|
||||
enum mtl_compare_function function)
|
||||
{
|
||||
@autoreleasepool {
|
||||
MTLSamplerDescriptor *desc = (MTLSamplerDescriptor *)descriptor;
|
||||
desc.compareFunction = (MTLCompareFunction)function;
|
||||
}
|
||||
}
|
||||
|
||||
mtl_sampler *
|
||||
mtl_new_sampler(mtl_device *device, mtl_sampler_descriptor *descriptor)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLDevice> dev = (id<MTLDevice>)device;
|
||||
MTLSamplerDescriptor *desc = (MTLSamplerDescriptor *)descriptor;
|
||||
return [dev newSamplerStateWithDescriptor:desc];
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t
|
||||
mtl_sampler_get_gpu_resource_id(mtl_sampler *sampler)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLSamplerState> samp = (id<MTLSamplerState>)sampler;
|
||||
return [samp gpuResourceID]._impl;
|
||||
}
|
||||
}
|
||||
29
src/kosmickrisp/bridge/mtl_sync.h
Normal file
29
src/kosmickrisp/bridge/mtl_sync.h
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef MTL_SYNC_H
|
||||
#define MTL_SYNC_H 1
|
||||
|
||||
#include "mtl_types.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
/* MTLFence */
|
||||
mtl_fence *mtl_new_fence(mtl_device *device);
|
||||
|
||||
/* MTLEvent */
|
||||
mtl_event *mtl_new_event(mtl_device *device);
|
||||
|
||||
/* MTLSharedEvent */
|
||||
mtl_shared_event *mtl_new_shared_event(mtl_device *device);
|
||||
int mtl_shared_event_wait_until_signaled_value(mtl_shared_event *event_handle,
|
||||
uint64_t value,
|
||||
uint64_t timeout_ms);
|
||||
uint64_t mtl_shared_event_get_signaled_value(mtl_shared_event *event_handle);
|
||||
void mtl_shared_event_set_signaled_value(mtl_shared_event *event_handle,
|
||||
uint64_t value);
|
||||
|
||||
#endif /* MTL_SYNC_H */
|
||||
66
src/kosmickrisp/bridge/mtl_sync.m
Normal file
66
src/kosmickrisp/bridge/mtl_sync.m
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "mtl_sync.h"
|
||||
|
||||
#include <Metal/MTLEvent.h>
|
||||
|
||||
/* MTLFence */
|
||||
mtl_fence *
|
||||
mtl_new_fence(mtl_device *device)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLDevice> dev = (id<MTLDevice>)device;
|
||||
return (mtl_fence *)[dev newFence];
|
||||
}
|
||||
}
|
||||
|
||||
/* MTLEvent */
|
||||
mtl_event *
|
||||
mtl_new_event(mtl_device *device)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLDevice> dev = (id<MTLDevice>)device;
|
||||
return [dev newEvent];
|
||||
}
|
||||
}
|
||||
|
||||
/* MTLSharedEvent */
|
||||
mtl_shared_event *
|
||||
mtl_new_shared_event(mtl_device *device)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLDevice> dev = (id<MTLDevice>)device;
|
||||
return [dev newSharedEvent];
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
mtl_shared_event_wait_until_signaled_value(mtl_shared_event *event_handle, uint64_t value, uint64_t timeout_ms)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLSharedEvent> event = (id<MTLSharedEvent>)event_handle;
|
||||
return (int)[event waitUntilSignaledValue:value timeoutMS:timeout_ms];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mtl_shared_event_set_signaled_value(mtl_shared_event *event_handle, uint64_t value)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLSharedEvent> event = (id<MTLSharedEvent>)event_handle;
|
||||
event.signaledValue = value;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t
|
||||
mtl_shared_event_get_signaled_value(mtl_shared_event *event_handle)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLSharedEvent> event = (id<MTLSharedEvent>)event_handle;
|
||||
return event.signaledValue;
|
||||
}
|
||||
}
|
||||
27
src/kosmickrisp/bridge/mtl_texture.h
Normal file
27
src/kosmickrisp/bridge/mtl_texture.h
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef MTL_TEXTURE_H
|
||||
#define MTL_TEXTURE_H 1
|
||||
|
||||
#include "mtl_types.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
/* TODO_KOSMICKRISP Move this to bridge. */
|
||||
struct kk_view_layout;
|
||||
|
||||
/* Utils*/
|
||||
uint64_t mtl_texture_get_gpu_resource_id(mtl_texture *texture);
|
||||
|
||||
/* Texture view creation */
|
||||
mtl_texture *mtl_new_texture_view_with(mtl_texture *texture,
|
||||
const struct kk_view_layout *layout);
|
||||
mtl_texture *
|
||||
mtl_new_texture_view_with_no_swizzle(mtl_texture *texture,
|
||||
const struct kk_view_layout *layout);
|
||||
|
||||
#endif /* MTL_TEXTURE_H */
|
||||
94
src/kosmickrisp/bridge/mtl_texture.m
Normal file
94
src/kosmickrisp/bridge/mtl_texture.m
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "mtl_texture.h"
|
||||
|
||||
/* TODO_LUNARG Remove */
|
||||
#include "kk_image_layout.h"
|
||||
|
||||
/* TODO_LUNARG Remove */
|
||||
#include "vulkan/vulkan.h"
|
||||
|
||||
#include <Metal/MTLTexture.h>
|
||||
|
||||
uint64_t
|
||||
mtl_texture_get_gpu_resource_id(mtl_texture *texture)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLTexture> tex = (id<MTLTexture>)texture;
|
||||
return (uint64_t)[tex gpuResourceID]._impl;
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO_KOSMICKRISP This should be part of the mapping */
|
||||
static uint32_t
|
||||
mtl_texture_view_type(uint32_t type, uint8_t sample_count)
|
||||
{
|
||||
switch (type) {
|
||||
case VK_IMAGE_VIEW_TYPE_1D:
|
||||
return MTLTextureType1D;
|
||||
case VK_IMAGE_VIEW_TYPE_1D_ARRAY:
|
||||
return MTLTextureType1DArray;
|
||||
case VK_IMAGE_VIEW_TYPE_2D:
|
||||
return sample_count > 1u ? MTLTextureType2DMultisample : MTLTextureType2D;;
|
||||
case VK_IMAGE_VIEW_TYPE_CUBE:
|
||||
return MTLTextureTypeCube;
|
||||
case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY:
|
||||
return MTLTextureTypeCubeArray;
|
||||
case VK_IMAGE_VIEW_TYPE_2D_ARRAY:
|
||||
return sample_count > 1u ? MTLTextureType2DMultisampleArray : MTLTextureType2DArray;
|
||||
case VK_IMAGE_VIEW_TYPE_3D:
|
||||
return MTLTextureType3D;
|
||||
default:
|
||||
assert(false && "Unsupported VkViewType");
|
||||
return MTLTextureType1D;
|
||||
}
|
||||
}
|
||||
|
||||
static MTLTextureSwizzle
|
||||
mtl_texture_swizzle(enum pipe_swizzle swizzle)
|
||||
{
|
||||
const MTLTextureSwizzle map[] =
|
||||
{
|
||||
[PIPE_SWIZZLE_X] = MTLTextureSwizzleRed,
|
||||
[PIPE_SWIZZLE_Y] = MTLTextureSwizzleGreen,
|
||||
[PIPE_SWIZZLE_Z] = MTLTextureSwizzleBlue,
|
||||
[PIPE_SWIZZLE_W] = MTLTextureSwizzleAlpha,
|
||||
[PIPE_SWIZZLE_0] = MTLTextureSwizzleZero,
|
||||
[PIPE_SWIZZLE_1] = MTLTextureSwizzleOne,
|
||||
};
|
||||
|
||||
return map[swizzle];
|
||||
}
|
||||
|
||||
mtl_texture *
|
||||
mtl_new_texture_view_with(mtl_texture *texture, const struct kk_view_layout *layout)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLTexture> tex = (id<MTLTexture>)texture;
|
||||
MTLTextureType type = mtl_texture_view_type(layout->view_type, layout->sample_count_sa);
|
||||
NSRange levels = NSMakeRange(layout->base_level, layout->num_levels);
|
||||
NSRange slices = NSMakeRange(layout->base_array_layer, layout->array_len);
|
||||
MTLTextureSwizzleChannels swizzle = MTLTextureSwizzleChannelsMake(mtl_texture_swizzle(layout->swizzle.red),
|
||||
mtl_texture_swizzle(layout->swizzle.green),
|
||||
mtl_texture_swizzle(layout->swizzle.blue),
|
||||
mtl_texture_swizzle(layout->swizzle.alpha));
|
||||
return [tex newTextureViewWithPixelFormat:layout->format.mtl textureType:type levels:levels slices:slices swizzle:swizzle];
|
||||
}
|
||||
}
|
||||
|
||||
mtl_texture *
|
||||
mtl_new_texture_view_with_no_swizzle(mtl_texture *texture, const struct kk_view_layout *layout)
|
||||
{
|
||||
@autoreleasepool {
|
||||
id<MTLTexture> tex = (id<MTLTexture>)texture;
|
||||
MTLTextureType type = mtl_texture_view_type(layout->view_type, layout->sample_count_sa);
|
||||
NSRange levels = NSMakeRange(layout->base_level, layout->num_levels);
|
||||
NSRange slices = NSMakeRange(layout->base_array_layer, layout->array_len);
|
||||
return [tex newTextureViewWithPixelFormat:layout->format.mtl textureType:type levels:levels slices:slices];
|
||||
}
|
||||
}
|
||||
|
||||
272
src/kosmickrisp/bridge/mtl_types.h
Normal file
272
src/kosmickrisp/bridge/mtl_types.h
Normal file
|
|
@ -0,0 +1,272 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Structures and enums found in this file are a 1-1 mapping of Metal's
|
||||
* equivalents
|
||||
*/
|
||||
|
||||
#ifndef KK_MTL_TYPES_H
|
||||
#define KK_MTL_TYPES_H 1
|
||||
|
||||
#include <stddef.h> /* For size_t definition */
|
||||
|
||||
/** HANDLES */
|
||||
typedef void mtl_device;
|
||||
typedef void mtl_heap;
|
||||
typedef void mtl_buffer;
|
||||
typedef void mtl_texture;
|
||||
typedef void mtl_command_queue;
|
||||
typedef void mtl_command_buffer;
|
||||
typedef void mtl_command_encoder;
|
||||
typedef void mtl_blit_encoder;
|
||||
typedef void mtl_compute_encoder;
|
||||
typedef void mtl_render_encoder;
|
||||
typedef void mtl_event;
|
||||
typedef void mtl_shared_event;
|
||||
typedef void mtl_sampler_descriptor;
|
||||
typedef void mtl_sampler;
|
||||
typedef void mtl_compute_pipeline_state;
|
||||
typedef void mtl_library;
|
||||
typedef void mtl_render_pipeline_state;
|
||||
typedef void mtl_function;
|
||||
typedef void mtl_resource;
|
||||
typedef void mtl_render_pass_descriptor;
|
||||
typedef void mtl_render_pipeline_descriptor;
|
||||
typedef void mtl_fence;
|
||||
typedef void mtl_stencil_descriptor;
|
||||
typedef void mtl_depth_stencil_descriptor;
|
||||
typedef void mtl_depth_stencil_state;
|
||||
typedef void mtl_render_pass_attachment_descriptor;
|
||||
|
||||
/** ENUMS */
|
||||
enum mtl_cpu_cache_mode {
|
||||
MTL_CPU_CACHE_MODE_DEFAULT_CACHE = 0,
|
||||
MTL_CPU_CACHE_MODE_WRITE_COMBINED = 1,
|
||||
};
|
||||
|
||||
enum mtl_storage_mode {
|
||||
MTL_STORAGE_MODE_SHARED = 0,
|
||||
MTL_STORAGE_MODE_MANAGED = 1,
|
||||
MTL_STORAGE_MODE_PRIVATE = 2,
|
||||
MTL_STORAGE_MODE_MEMORYLESS = 3,
|
||||
};
|
||||
|
||||
enum mtl_hazard_tracking_mode {
|
||||
MTL_HAZARD_TRACKING_MODE_DFEAULT = 0,
|
||||
MTL_HAZARD_TRACKING_MODE_UNTRACKED = 1,
|
||||
MTL_HAZARD_TRACKING_MODE_TRACKED = 2,
|
||||
};
|
||||
|
||||
#define MTL_RESOURCE_CPU_CACHE_MODE_SHIFT 0
|
||||
#define MTL_RESOURCE_STORAGE_MODE_SHIFT 4
|
||||
#define MTL_RESOURCE_HAZARD_TRACKING_MODE_SHIFT 8
|
||||
enum mtl_resource_options {
|
||||
MTL_RESOURCE_CPU_CACHE_MODE_DEFAULT_CACHE =
|
||||
MTL_CPU_CACHE_MODE_DEFAULT_CACHE << MTL_RESOURCE_CPU_CACHE_MODE_SHIFT,
|
||||
MTL_RESOURCE_CPU_CACHE_MODE_WRITE_COMBINED =
|
||||
MTL_CPU_CACHE_MODE_WRITE_COMBINED << MTL_RESOURCE_CPU_CACHE_MODE_SHIFT,
|
||||
MTL_RESOURCE_STORAGE_MODE_SHARED = MTL_STORAGE_MODE_SHARED
|
||||
<< MTL_RESOURCE_STORAGE_MODE_SHIFT,
|
||||
MTL_RESOURCE_STORAGE_MODE_PRIVATE = MTL_STORAGE_MODE_PRIVATE
|
||||
<< MTL_RESOURCE_STORAGE_MODE_SHIFT,
|
||||
MTL_RESOURCE_TRACKING_MODE_DEFAULT =
|
||||
MTL_HAZARD_TRACKING_MODE_DFEAULT
|
||||
<< MTL_RESOURCE_HAZARD_TRACKING_MODE_SHIFT,
|
||||
MTL_RESOURCE_TRACKING_MODE_UNTRACKED =
|
||||
MTL_HAZARD_TRACKING_MODE_UNTRACKED
|
||||
<< MTL_RESOURCE_HAZARD_TRACKING_MODE_SHIFT,
|
||||
MTL_RESOURCE_TRACKING_MODE_TRACKED =
|
||||
MTL_HAZARD_TRACKING_MODE_TRACKED
|
||||
<< MTL_RESOURCE_HAZARD_TRACKING_MODE_SHIFT,
|
||||
};
|
||||
|
||||
enum mtl_blit_options {
|
||||
MTL_BLIT_OPTION_NONE = 0,
|
||||
MTL_BLIT_OPTION_DEPTH_FROM_DEPTH_STENCIL = 1 << 0,
|
||||
MTL_BLIT_OPTION_STENCIL_FROM_DEPTH_STENCIL = 1 << 1,
|
||||
};
|
||||
|
||||
enum mtl_resource_usage {
|
||||
MTL_RESOURCE_USAGE_READ = 1 << 0,
|
||||
MTL_RESOURCE_USAGE_WRITE = 1 << 1,
|
||||
};
|
||||
|
||||
enum mtl_primitive_type {
|
||||
MTL_PRIMITIVE_TYPE_POINT = 0,
|
||||
MTL_PRIMITIVE_TYPE_LINE = 1,
|
||||
MTL_PRIMITIVE_TYPE_LINE_STRIP = 2,
|
||||
MTL_PRIMITIVE_TYPE_TRIANGLE = 3,
|
||||
MTL_PRIMITIVE_TYPE_TRIANGLE_STRIP = 4,
|
||||
};
|
||||
|
||||
enum mtl_primitive_topology_class {
|
||||
MTL_PRIMITIVE_TOPOLOGY_CLASS_UNSPECIFIED = 0,
|
||||
MTL_PRIMITIVE_TOPOLOGY_CLASS_POINT = 1,
|
||||
MTL_PRIMITIVE_TOPOLOGY_CLASS_LINE = 2,
|
||||
MTL_PRIMITIVE_TOPOLOGY_CLASS_TRIANGLE = 3,
|
||||
};
|
||||
|
||||
enum mtl_texture_type {
|
||||
MTL_TEXTURE_TYPE_1D = 0u,
|
||||
MTL_TEXTURE_TYPE_1D_ARRAY = 1u,
|
||||
MTL_TEXTURE_TYPE_2D = 2u,
|
||||
MTL_TEXTURE_TYPE_2D_ARRAY = 3u,
|
||||
MTL_TEXTURE_TYPE_2D_MULTISAMPLE = 4u,
|
||||
MTL_TEXTURE_TYPE_CUBE = 5u,
|
||||
MTL_TEXTURE_TYPE_CUBE_ARRAY = 6u,
|
||||
MTL_TEXTURE_TYPE_3D = 7u,
|
||||
MTL_TEXTURE_TYPE_2D_ARRAY_MULTISAMPLE = 8u,
|
||||
MTL_TEXTURE_TYPE_TEXTURE_BUFFER = 9u,
|
||||
};
|
||||
|
||||
enum mtl_texture_usage {
|
||||
MTL_TEXTURE_USAGE_UNKNOWN = 0x0000,
|
||||
MTL_TEXTURE_USAGE_SHADER_READ = 0x0001,
|
||||
MTL_TEXTURE_USAGE_SHADER_WRITE = 0X0002,
|
||||
MTL_TEXTURE_USAGE_RENDER_TARGET = 0X0004,
|
||||
MTL_TEXTURE_USAGE_PIXEL_FORMAT_VIEW = 0X0010,
|
||||
MTL_TEXTURE_USAGE_SHADER_ATOMIC = 0X0020,
|
||||
};
|
||||
|
||||
enum mtl_load_action {
|
||||
MTL_LOAD_ACTION_DONT_CARE = 0u,
|
||||
MTL_LOAD_ACTION_LOAD = 1u,
|
||||
MTL_LOAD_ACTION_CLEAR = 2u,
|
||||
};
|
||||
|
||||
enum mtl_store_action {
|
||||
MTL_STORE_ACTION_DONT_CARE = 0u,
|
||||
MTL_STORE_ACTION_STORE = 1u,
|
||||
MTL_STORE_ACTION_MULTISAMPLE_RESOLVE = 2u,
|
||||
MTL_STORE_ACTION_STORE_AND_MULTISAMPLE_RESOLVE = 3u,
|
||||
MTL_STORE_ACTION_UNKNOWN = 4u,
|
||||
MTL_STORE_ACTION_CUSTOM_SAMPLE_DEPTH_STORE = 5u,
|
||||
};
|
||||
|
||||
enum mtl_texture_swizzle {
|
||||
MTL_TEXTURE_SWIZZLE_ZERO = 0,
|
||||
MTL_TEXTURE_SWIZZLE_ONE = 1,
|
||||
MTL_TEXTURE_SWIZZLE_RED = 2,
|
||||
MTL_TEXTURE_SWIZZLE_GREEN = 3,
|
||||
MTL_TEXTURE_SWIZZLE_BLUE = 4,
|
||||
MTL_TEXTURE_SWIZZLE_ALPHA = 5,
|
||||
};
|
||||
|
||||
enum mtl_index_type {
|
||||
MTL_INDEX_TYPE_UINT16 = 0,
|
||||
MTL_INDEX_TYPE_UINT32 = 1,
|
||||
};
|
||||
|
||||
enum mtl_sampler_address_mode {
|
||||
MTL_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE = 0,
|
||||
MTL_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE = 1,
|
||||
MTL_SAMPLER_ADDRESS_MODE_REPEAT = 2,
|
||||
MTL_SAMPLER_ADDRESS_MODE_MIRROR_REPEAT = 3,
|
||||
MTL_SAMPLER_ADDRESS_MODE_CLAMP_TO_ZERO = 4,
|
||||
MTL_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER_COLOR = 5,
|
||||
};
|
||||
|
||||
enum mtl_sampler_border_color {
|
||||
MTL_SAMPLER_BORDER_COLOR_TRANSPARENT_BLACK = 0,
|
||||
MTL_SAMPLER_BORDER_COLOR_OPAQUE_BLACK = 1,
|
||||
MTL_SAMPLER_BORDER_COLOR_OPAQUE_WHITE = 2,
|
||||
};
|
||||
|
||||
enum mtl_sampler_min_mag_filter {
|
||||
MTL_SAMPLER_MIN_MAG_FILTER_NEAREST = 0,
|
||||
MTL_SAMPLER_MIN_MAG_FILTER_LINEAR = 1,
|
||||
};
|
||||
|
||||
enum mtl_sampler_mip_filter {
|
||||
MTL_SAMPLER_MIP_FILTER_NOT_MIP_MAPPED = 0,
|
||||
MTL_SAMPLER_MIP_FILTER_NEAREST = 1,
|
||||
MTL_SAMPLER_MIP_FILTER_LINEAR = 2,
|
||||
};
|
||||
|
||||
enum mtl_compare_function {
|
||||
MTL_COMPARE_FUNCTION_NEVER = 0,
|
||||
MTL_COMPARE_FUNCTION_LESS = 1,
|
||||
MTL_COMPARE_FUNCTION_EQUAL = 2,
|
||||
MTL_COMPARE_FUNCTION_LESS_EQUAL = 3,
|
||||
MTL_COMPARE_FUNCTION_GREATER = 4,
|
||||
MTL_COMPARE_FUNCTION_NOT_EQUAL = 5,
|
||||
MTL_COMPARE_FUNCTION_GREATER_EQUAL = 6,
|
||||
MTL_COMPARE_FUNCTION_ALWAYS = 7,
|
||||
};
|
||||
|
||||
enum mtl_winding {
|
||||
MTL_WINDING_CLOCKWISE = 0,
|
||||
MTL_WINDING_COUNTER_CLOCKWISE = 1,
|
||||
};
|
||||
|
||||
enum mtl_cull_mode {
|
||||
MTL_CULL_MODE_NONE = 0,
|
||||
MTL_CULL_MODE_FRONT = 1,
|
||||
MTL_CULL_MODE_BACK = 2,
|
||||
};
|
||||
|
||||
enum mtl_visibility_result_mode {
|
||||
MTL_VISIBILITY_RESULT_MODE_DISABLED = 0,
|
||||
MTL_VISIBILITY_RESULT_MODE_BOOLEAN = 1,
|
||||
MTL_VISIBILITY_RESULT_MODE_COUNTING = 2,
|
||||
};
|
||||
|
||||
enum mtl_depth_clip_mode {
|
||||
MTL_DEPTH_CLIP_MODE_CLIP = 0,
|
||||
MTL_DEPTH_CLIP_MODE_CLAMP = 1,
|
||||
};
|
||||
|
||||
/** STRUCTURES */
|
||||
struct mtl_range {
|
||||
size_t offset;
|
||||
size_t length;
|
||||
};
|
||||
|
||||
struct mtl_origin {
|
||||
size_t x, y, z;
|
||||
};
|
||||
|
||||
struct mtl_size {
|
||||
size_t x, y, z;
|
||||
};
|
||||
|
||||
struct mtl_viewport {
|
||||
double originX, originY, width, height, znear, zfar;
|
||||
};
|
||||
|
||||
struct mtl_clear_color {
|
||||
union {
|
||||
struct {
|
||||
double red, green, blue, alpha;
|
||||
};
|
||||
double channel[4];
|
||||
};
|
||||
};
|
||||
|
||||
struct mtl_scissor_rect {
|
||||
size_t x, y, width, height;
|
||||
};
|
||||
|
||||
struct mtl_texture_swizzle_channels {
|
||||
enum mtl_texture_swizzle red;
|
||||
enum mtl_texture_swizzle green;
|
||||
enum mtl_texture_swizzle blue;
|
||||
enum mtl_texture_swizzle alpha;
|
||||
};
|
||||
|
||||
struct mtl_buffer_image_copy {
|
||||
struct mtl_size image_size;
|
||||
struct mtl_origin image_origin;
|
||||
mtl_buffer *buffer;
|
||||
mtl_texture *image;
|
||||
size_t buffer_offset_B;
|
||||
size_t buffer_stride_B;
|
||||
size_t buffer_2d_image_size_B;
|
||||
size_t image_slice;
|
||||
size_t image_level;
|
||||
enum mtl_blit_options options;
|
||||
};
|
||||
|
||||
#endif /* KK_MTL_TYPES_H */
|
||||
24
src/kosmickrisp/bridge/stubs/mtl_bridge.c
Normal file
24
src/kosmickrisp/bridge/stubs/mtl_bridge.c
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "mtl_bridge.h"
|
||||
|
||||
mtl_texture *
|
||||
mtl_drawable_get_texture(void *drawable_ptr)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *
|
||||
mtl_retain(void *handle)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
mtl_release(void *handle)
|
||||
{
|
||||
}
|
||||
33
src/kosmickrisp/bridge/stubs/mtl_buffer.c
Normal file
33
src/kosmickrisp/bridge/stubs/mtl_buffer.c
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "mtl_buffer.h"
|
||||
|
||||
uint64_t
|
||||
mtl_buffer_get_length(mtl_buffer *buffer)
|
||||
{
|
||||
return 0u;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
mtl_buffer_get_gpu_address(mtl_buffer *buffer)
|
||||
{
|
||||
return 0u;
|
||||
}
|
||||
|
||||
void *
|
||||
mtl_get_contents(mtl_buffer *buffer)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mtl_texture *
|
||||
mtl_new_texture_with_descriptor_linear(mtl_buffer *buffer,
|
||||
const struct kk_image_layout *layout,
|
||||
uint64_t offset)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
35
src/kosmickrisp/bridge/stubs/mtl_command_buffer.c
Normal file
35
src/kosmickrisp/bridge/stubs/mtl_command_buffer.c
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "mtl_command_buffer.h"
|
||||
|
||||
void
|
||||
mtl_encode_signal_event(mtl_command_buffer *cmd_buf_handle,
|
||||
mtl_event *event_handle, uint64_t value)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_encode_wait_for_event(mtl_command_buffer *cmd_buf_handle,
|
||||
mtl_event *event_handle, uint64_t value)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_add_completed_handler(mtl_command_buffer *cmd, void (*callback)(void *data),
|
||||
void *data)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_command_buffer_commit(mtl_command_buffer *cmd_buf)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_present_drawable(mtl_command_buffer *cmd_buf, void *drawable)
|
||||
{
|
||||
}
|
||||
19
src/kosmickrisp/bridge/stubs/mtl_command_queue.c
Normal file
19
src/kosmickrisp/bridge/stubs/mtl_command_queue.c
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "mtl_command_queue.h"
|
||||
|
||||
mtl_command_queue *
|
||||
mtl_new_command_queue(mtl_device *device, uint32_t cmd_buffer_count)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mtl_command_buffer *
|
||||
mtl_new_command_buffer(mtl_command_queue *cmd_queue)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
14
src/kosmickrisp/bridge/stubs/mtl_compute_state.c
Normal file
14
src/kosmickrisp/bridge/stubs/mtl_compute_state.c
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "mtl_compute_state.h"
|
||||
|
||||
mtl_compute_pipeline_state *
|
||||
mtl_new_compute_pipeline_state(mtl_device *device, mtl_function *function,
|
||||
uint64_t max_total_threads_per_threadgroup)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
73
src/kosmickrisp/bridge/stubs/mtl_device.c
Normal file
73
src/kosmickrisp/bridge/stubs/mtl_device.c
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "mtl_device.h"
|
||||
|
||||
/* Device creation */
|
||||
mtl_device *
|
||||
mtl_device_create(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Device operations */
|
||||
void
|
||||
mtl_start_gpu_capture(mtl_device *mtl_dev_handle)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_stop_gpu_capture(void)
|
||||
{
|
||||
}
|
||||
|
||||
/* Device feature query */
|
||||
void
|
||||
mtl_device_get_name(mtl_device *dev, char buffer[256])
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_device_get_architecture_name(mtl_device *dev, char buffer[256])
|
||||
{
|
||||
}
|
||||
|
||||
uint64_t
|
||||
mtl_device_get_peer_group_id(mtl_device *dev)
|
||||
{
|
||||
return 0u;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
mtl_device_get_peer_index(mtl_device *dev)
|
||||
{
|
||||
return 0u;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
mtl_device_get_registry_id(mtl_device *dev)
|
||||
{
|
||||
return 0u;
|
||||
}
|
||||
|
||||
struct mtl_size
|
||||
mtl_device_max_threads_per_threadgroup(mtl_device *dev)
|
||||
{
|
||||
return (struct mtl_size){};
|
||||
}
|
||||
|
||||
/* Resource queries */
|
||||
void
|
||||
mtl_heap_buffer_size_and_align_with_length(mtl_device *device, uint64_t *size_B,
|
||||
uint64_t *align_B)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_heap_texture_size_and_align_with_descriptor(mtl_device *device,
|
||||
struct kk_image_layout *layout)
|
||||
{
|
||||
}
|
||||
273
src/kosmickrisp/bridge/stubs/mtl_encoder.c
Normal file
273
src/kosmickrisp/bridge/stubs/mtl_encoder.c
Normal file
|
|
@ -0,0 +1,273 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "mtl_encoder.h"
|
||||
|
||||
/* Common encoder utils */
|
||||
void
|
||||
mtl_end_encoding(void *encoder)
|
||||
{
|
||||
}
|
||||
|
||||
/* MTLBlitEncoder */
|
||||
mtl_blit_encoder *
|
||||
mtl_new_blit_command_encoder(mtl_command_buffer *cmd_buffer)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
mtl_blit_update_fence(mtl_blit_encoder *encoder, mtl_fence *fence)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_blit_wait_for_fence(mtl_blit_encoder *encoder, mtl_fence *fence)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_copy_from_buffer_to_buffer(mtl_blit_encoder *blit_enc_handle,
|
||||
mtl_buffer *src_buf, size_t src_offset,
|
||||
mtl_buffer *dst_buf, size_t dst_offset,
|
||||
size_t size)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_copy_from_buffer_to_texture(mtl_blit_encoder *blit_enc_handle,
|
||||
struct mtl_buffer_image_copy *data)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_copy_from_texture_to_buffer(mtl_blit_encoder *blit_enc_handle,
|
||||
struct mtl_buffer_image_copy *data)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_copy_from_texture_to_texture(mtl_blit_encoder *blit_enc_handle,
|
||||
mtl_texture *src_tex_handle, size_t src_slice,
|
||||
size_t src_level, struct mtl_origin src_origin,
|
||||
struct mtl_size src_size,
|
||||
mtl_texture *dst_tex_handle, size_t dst_slice,
|
||||
size_t dst_level, struct mtl_origin dst_origin)
|
||||
{
|
||||
}
|
||||
|
||||
/* MTLComputeEncoder */
|
||||
mtl_compute_encoder *
|
||||
mtl_new_compute_command_encoder(mtl_command_buffer *cmd_buffer)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
mtl_compute_update_fence(mtl_compute_encoder *encoder, mtl_fence *fence)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_compute_wait_for_fence(mtl_compute_encoder *encoder, mtl_fence *fence)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_compute_set_pipeline_state(mtl_compute_encoder *encoder,
|
||||
mtl_compute_pipeline_state *state_handle)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_compute_set_buffer(mtl_compute_encoder *encoder, mtl_buffer *buffer,
|
||||
size_t offset, size_t index)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_compute_use_resource(mtl_compute_encoder *encoder, mtl_resource *res_handle,
|
||||
uint32_t usage)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_compute_use_resources(mtl_compute_encoder *encoder,
|
||||
mtl_resource **resource_handles, uint32_t count,
|
||||
enum mtl_resource_usage usage)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_compute_use_heaps(mtl_compute_encoder *encoder, mtl_heap **heaps,
|
||||
uint32_t count)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_dispatch_threads(mtl_compute_encoder *encoder, struct mtl_size grid_size,
|
||||
struct mtl_size local_size)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_dispatch_threadgroups_with_indirect_buffer(mtl_compute_encoder *encoder,
|
||||
mtl_buffer *buffer,
|
||||
uint32_t offset,
|
||||
struct mtl_size local_size)
|
||||
{
|
||||
}
|
||||
|
||||
/* MTLRenderEncoder */
|
||||
mtl_render_encoder *
|
||||
mtl_new_render_command_encoder_with_descriptor(
|
||||
mtl_command_buffer *command_buffer, mtl_render_pass_descriptor *descriptor)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_update_fence(mtl_render_encoder *encoder, mtl_fence *fence)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_wait_for_fence(mtl_render_encoder *encoder, mtl_fence *fence)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_set_viewports(mtl_render_encoder *encoder, struct mtl_viewport *viewports,
|
||||
uint32_t count)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_set_scissor_rects(mtl_render_encoder *encoder,
|
||||
struct mtl_scissor_rect *scissor_rects, uint32_t count)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_set_pipeline_state(mtl_render_encoder *encoder,
|
||||
mtl_render_pipeline_state *pipeline)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_set_depth_stencil_state(mtl_render_encoder *encoder,
|
||||
mtl_depth_stencil_state *state)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_set_stencil_references(mtl_render_encoder *encoder, uint32_t front,
|
||||
uint32_t back)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_set_front_face_winding(mtl_render_encoder *encoder,
|
||||
enum mtl_winding winding)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_set_cull_mode(mtl_render_encoder *encoder, enum mtl_cull_mode mode)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_set_visibility_result_mode(mtl_render_encoder *encoder,
|
||||
enum mtl_visibility_result_mode mode,
|
||||
size_t offset)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_set_depth_bias(mtl_render_encoder *encoder, float depth_bias,
|
||||
float slope_scale, float clamp)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_set_depth_clip_mode(mtl_render_encoder *encoder,
|
||||
enum mtl_depth_clip_mode mode)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_set_vertex_amplification_count(mtl_render_encoder *encoder,
|
||||
uint32_t *layer_ids, uint32_t id_count)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_set_vertex_buffer(mtl_render_encoder *encoder, mtl_buffer *buffer,
|
||||
uint32_t offset, uint32_t index)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_set_fragment_buffer(mtl_render_encoder *encoder, mtl_buffer *buffer,
|
||||
uint32_t offset, uint32_t index)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_draw_primitives(mtl_render_encoder *encoder,
|
||||
enum mtl_primitive_type primitve_type, uint32_t vertexStart,
|
||||
uint32_t vertexCount, uint32_t instanceCount,
|
||||
uint32_t baseInstance)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_draw_indexed_primitives(
|
||||
mtl_render_encoder *encoder, enum mtl_primitive_type primitve_type,
|
||||
uint32_t index_count, enum mtl_index_type index_type,
|
||||
mtl_buffer *index_buffer, uint32_t index_buffer_offset,
|
||||
uint32_t instance_count, int32_t base_vertex, uint32_t base_instance)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_draw_primitives_indirect(mtl_render_encoder *encoder,
|
||||
enum mtl_primitive_type primitve_type,
|
||||
mtl_buffer *indirect_buffer,
|
||||
uint64_t indirect_buffer_offset)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_draw_indexed_primitives_indirect(mtl_render_encoder *encoder,
|
||||
enum mtl_primitive_type primitve_type,
|
||||
enum mtl_index_type index_type,
|
||||
mtl_buffer *index_buffer,
|
||||
uint32_t index_buffer_offset,
|
||||
mtl_buffer *indirect_buffer,
|
||||
uint64_t indirect_buffer_offset)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_use_resource(mtl_compute_encoder *encoder, mtl_resource *res_handle,
|
||||
uint32_t usage)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_use_resources(mtl_render_encoder *encoder,
|
||||
mtl_resource **resource_handles, uint32_t count,
|
||||
enum mtl_resource_usage usage)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_use_heaps(mtl_render_encoder *encoder, mtl_heap **heaps,
|
||||
uint32_t count)
|
||||
{
|
||||
}
|
||||
37
src/kosmickrisp/bridge/stubs/mtl_heap.c
Normal file
37
src/kosmickrisp/bridge/stubs/mtl_heap.c
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "mtl_heap.h"
|
||||
|
||||
/* Creation */
|
||||
mtl_heap *
|
||||
mtl_new_heap(mtl_device *device, uint64_t size,
|
||||
enum mtl_resource_options resource_options)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Utils */
|
||||
uint64_t
|
||||
mtl_heap_get_size(mtl_heap *heap)
|
||||
{
|
||||
return 0u;
|
||||
}
|
||||
|
||||
/* Allocation from heap */
|
||||
mtl_buffer *
|
||||
mtl_new_buffer_with_length(mtl_heap *heap, uint64_t size_B, uint64_t offset_B)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mtl_texture *
|
||||
mtl_new_texture_with_descriptor(mtl_heap *heap,
|
||||
const struct kk_image_layout *layout,
|
||||
uint64_t offset)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
19
src/kosmickrisp/bridge/stubs/mtl_library.c
Normal file
19
src/kosmickrisp/bridge/stubs/mtl_library.c
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "mtl_library.h"
|
||||
|
||||
mtl_library *
|
||||
mtl_new_library(mtl_device *device, const char *src)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mtl_function *
|
||||
mtl_new_function_with_name(mtl_library *lib, const char *entry_point)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
288
src/kosmickrisp/bridge/stubs/mtl_render_state.c
Normal file
288
src/kosmickrisp/bridge/stubs/mtl_render_state.c
Normal file
|
|
@ -0,0 +1,288 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "mtl_render_state.h"
|
||||
|
||||
#include "mtl_format.h"
|
||||
|
||||
/* TODO_KOSMICKRISP Remove */
|
||||
#include "vulkan/vulkan.h"
|
||||
|
||||
/* Render pass descriptor */
|
||||
mtl_render_pass_descriptor *
|
||||
mtl_new_render_pass_descriptor(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mtl_render_pass_attachment_descriptor *
|
||||
mtl_render_pass_descriptor_get_color_attachment(
|
||||
mtl_render_pass_descriptor *descriptor, uint32_t index)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mtl_render_pass_attachment_descriptor *
|
||||
mtl_render_pass_descriptor_get_depth_attachment(
|
||||
mtl_render_pass_descriptor *descriptor)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mtl_render_pass_attachment_descriptor *
|
||||
mtl_render_pass_descriptor_get_stencil_attachment(
|
||||
mtl_render_pass_descriptor *descriptor)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_pass_attachment_descriptor_set_texture(
|
||||
mtl_render_pass_attachment_descriptor *descriptor, mtl_texture *texture)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_pass_attachment_descriptor_set_level(
|
||||
mtl_render_pass_attachment_descriptor *descriptor, uint32_t level)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_pass_attachment_descriptor_set_slice(
|
||||
mtl_render_pass_attachment_descriptor *descriptor, uint32_t slice)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_pass_attachment_descriptor_set_load_action(
|
||||
mtl_render_pass_attachment_descriptor *descriptor,
|
||||
enum mtl_load_action action)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_pass_attachment_descriptor_set_store_action(
|
||||
mtl_render_pass_attachment_descriptor *descriptor,
|
||||
enum mtl_store_action action)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_pass_attachment_descriptor_set_clear_color(
|
||||
mtl_render_pass_attachment_descriptor *descriptor,
|
||||
struct mtl_clear_color clear_color)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_pass_attachment_descriptor_set_clear_depth(
|
||||
mtl_render_pass_attachment_descriptor *descriptor, double depth)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_pass_attachment_descriptor_set_clear_stencil(
|
||||
mtl_render_pass_attachment_descriptor *descriptor, uint32_t stencil)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_pass_descriptor_set_render_target_array_length(
|
||||
mtl_render_pass_descriptor *descriptor, uint32_t length)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_pass_descriptor_set_render_target_width(
|
||||
mtl_render_pass_descriptor *descriptor, uint32_t width)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_pass_descriptor_set_render_target_height(
|
||||
mtl_render_pass_descriptor *descriptor, uint32_t height)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_pass_descriptor_set_default_raster_sample_count(
|
||||
mtl_render_pass_descriptor *descriptor, uint32_t sample_count)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_pass_descriptor_set_visibility_buffer(
|
||||
mtl_render_pass_descriptor *descriptor, mtl_buffer *visibility_buffer)
|
||||
{
|
||||
}
|
||||
|
||||
/* Render pipeline descriptor */
|
||||
mtl_render_pipeline_descriptor *
|
||||
mtl_new_render_pipeline_descriptor(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_pipeline_descriptor_set_vertex_shader(
|
||||
mtl_render_pass_descriptor *descriptor, mtl_function *shader)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_pipeline_descriptor_set_fragment_shader(
|
||||
mtl_render_pass_descriptor *descriptor, mtl_function *shader)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_pipeline_descriptor_set_input_primitive_topology(
|
||||
mtl_render_pass_descriptor *descriptor,
|
||||
enum mtl_primitive_topology_class topology_class)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_pipeline_descriptor_set_color_attachment_format(
|
||||
mtl_render_pass_descriptor *descriptor, uint8_t index,
|
||||
enum mtl_pixel_format format)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_pipeline_descriptor_set_depth_attachment_format(
|
||||
mtl_render_pass_descriptor *descriptor, enum mtl_pixel_format format)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_pipeline_descriptor_set_stencil_attachment_format(
|
||||
mtl_render_pass_descriptor *descriptor, enum mtl_pixel_format format)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_pipeline_descriptor_set_raster_sample_count(
|
||||
mtl_render_pass_descriptor *descriptor, uint32_t sample_count)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_pipeline_descriptor_set_alpha_to_coverage(
|
||||
mtl_render_pass_descriptor *descriptor, bool enabled)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_pipeline_descriptor_set_alpha_to_one(
|
||||
mtl_render_pass_descriptor *descriptor, bool enabled)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_pipeline_descriptor_set_rasterization_enabled(
|
||||
mtl_render_pass_descriptor *descriptor, bool enabled)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_render_pipeline_descriptor_set_max_vertex_amplification_count(
|
||||
mtl_render_pass_descriptor *descriptor, uint32_t count)
|
||||
{
|
||||
}
|
||||
|
||||
/* Render pipeline */
|
||||
mtl_render_pipeline_state *
|
||||
mtl_new_render_pipeline(mtl_device *device,
|
||||
mtl_render_pass_descriptor *descriptor)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Stencil descriptor */
|
||||
mtl_stencil_descriptor *
|
||||
mtl_new_stencil_descriptor(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
mtl_stencil_descriptor_set_stencil_failure_operation(
|
||||
mtl_stencil_descriptor *descriptor, enum VkStencilOp op)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_stencil_descriptor_set_depth_failure_operation(
|
||||
mtl_stencil_descriptor *descriptor, enum VkStencilOp op)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_stencil_descriptor_set_depth_stencil_pass_operation(
|
||||
mtl_stencil_descriptor *descriptor, enum VkStencilOp op)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_stencil_descriptor_set_stencil_compare_function(
|
||||
mtl_stencil_descriptor *descriptor, enum VkCompareOp op)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_stencil_descriptor_set_read_mask(mtl_stencil_descriptor *descriptor,
|
||||
uint32_t mask)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_stencil_descriptor_set_write_mask(mtl_stencil_descriptor *descriptor,
|
||||
uint32_t mask)
|
||||
{
|
||||
}
|
||||
|
||||
/* Depth stencil descriptor */
|
||||
mtl_depth_stencil_descriptor *
|
||||
mtl_new_depth_stencil_descriptor(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
mtl_depth_stencil_descriptor_set_depth_compare_function(
|
||||
mtl_depth_stencil_descriptor *descriptor, enum VkCompareOp op)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_depth_stencil_descriptor_set_depth_write_enabled(
|
||||
mtl_depth_stencil_descriptor *descriptor, bool enable_write)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_depth_stencil_descriptor_set_back_face_stencil(
|
||||
mtl_depth_stencil_descriptor *descriptor,
|
||||
mtl_stencil_descriptor *stencil_descriptor)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_depth_stencil_descriptor_set_front_face_stencil(
|
||||
mtl_depth_stencil_descriptor *descriptor,
|
||||
mtl_stencil_descriptor *stencil_descriptor)
|
||||
{
|
||||
}
|
||||
|
||||
/* Depth stencil state */
|
||||
mtl_depth_stencil_state *
|
||||
mtl_new_depth_stencil_state(mtl_device *device,
|
||||
mtl_depth_stencil_descriptor *descriptor)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
74
src/kosmickrisp/bridge/stubs/mtl_sampler.c
Normal file
74
src/kosmickrisp/bridge/stubs/mtl_sampler.c
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "mtl_sampler.h"
|
||||
|
||||
/* Sampler descriptor */
|
||||
mtl_sampler_descriptor *
|
||||
mtl_new_sampler_descriptor(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Sampler descriptor utils */
|
||||
void
|
||||
mtl_sampler_descriptor_set_normalized_coordinates(
|
||||
mtl_sampler_descriptor *descriptor, bool normalized_coordinates)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_sampler_descriptor_set_address_mode(
|
||||
mtl_sampler_descriptor *descriptor,
|
||||
enum mtl_sampler_address_mode address_mode_u,
|
||||
enum mtl_sampler_address_mode address_mode_v,
|
||||
enum mtl_sampler_address_mode address_mode_w)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_sampler_descriptor_set_border_color(mtl_sampler_descriptor *descriptor,
|
||||
enum mtl_sampler_border_color color)
|
||||
{
|
||||
}
|
||||
void
|
||||
mtl_sampler_descriptor_set_filters(mtl_sampler_descriptor *descriptor,
|
||||
enum mtl_sampler_min_mag_filter min_filter,
|
||||
enum mtl_sampler_min_mag_filter mag_filter,
|
||||
enum mtl_sampler_mip_filter mip_filter)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_sampler_descriptor_set_lod_clamp(mtl_sampler_descriptor *descriptor,
|
||||
float min, float max)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mtl_sampler_descriptor_set_max_anisotropy(mtl_sampler_descriptor *descriptor,
|
||||
uint64_t max)
|
||||
{
|
||||
}
|
||||
void
|
||||
mtl_sampler_descriptor_set_compare_function(mtl_sampler_descriptor *descriptor,
|
||||
enum mtl_compare_function function)
|
||||
{
|
||||
}
|
||||
|
||||
/* Sampler */
|
||||
mtl_sampler *
|
||||
mtl_new_sampler(mtl_device *device, mtl_sampler_descriptor *descriptor)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Sampler utils */
|
||||
uint64_t
|
||||
mtl_sampler_get_gpu_resource_id(mtl_sampler *sampler)
|
||||
{
|
||||
return 0u;
|
||||
}
|
||||
47
src/kosmickrisp/bridge/stubs/mtl_sync.c
Normal file
47
src/kosmickrisp/bridge/stubs/mtl_sync.c
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "mtl_sync.h"
|
||||
|
||||
/* MTLFence */
|
||||
mtl_fence *
|
||||
mtl_new_fence(mtl_device *device)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* MTLEvent */
|
||||
mtl_event *
|
||||
mtl_new_event(mtl_device *device)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* MTLSharedEvent */
|
||||
mtl_shared_event *
|
||||
mtl_new_shared_event(mtl_device *device)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
mtl_shared_event_wait_until_signaled_value(mtl_shared_event *event_handle,
|
||||
uint64_t value, uint64_t timeout_ms)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
mtl_shared_event_get_signaled_value(mtl_shared_event *event_handle)
|
||||
{
|
||||
return 0u;
|
||||
}
|
||||
|
||||
void
|
||||
mtl_shared_event_set_signaled_value(mtl_shared_event *event_handle,
|
||||
uint64_t value)
|
||||
{
|
||||
}
|
||||
29
src/kosmickrisp/bridge/stubs/mtl_texture.c
Normal file
29
src/kosmickrisp/bridge/stubs/mtl_texture.c
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "mtl_texture.h"
|
||||
|
||||
/* Utils*/
|
||||
uint64_t
|
||||
mtl_texture_get_gpu_resource_id(mtl_texture *texture)
|
||||
{
|
||||
return 0u;
|
||||
}
|
||||
|
||||
/* Texture view creation */
|
||||
mtl_texture *
|
||||
mtl_new_texture_view_with(mtl_texture *texture,
|
||||
const struct kk_view_layout *layout)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mtl_texture *
|
||||
mtl_new_texture_view_with_no_swizzle(mtl_texture *texture,
|
||||
const struct kk_view_layout *layout)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
251
src/kosmickrisp/bridge/vk_to_mtl_map.c
Normal file
251
src/kosmickrisp/bridge/vk_to_mtl_map.c
Normal file
|
|
@ -0,0 +1,251 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "vk_to_mtl_map.h"
|
||||
|
||||
#include "kosmickrisp/bridge/mtl_types.h"
|
||||
|
||||
#include "util/format/u_format.h"
|
||||
|
||||
#include "vulkan/vulkan.h"
|
||||
#include "vk_meta.h"
|
||||
|
||||
struct mtl_origin
|
||||
vk_offset_3d_to_mtl_origin(const struct VkOffset3D *offset)
|
||||
{
|
||||
struct mtl_origin ret = {
|
||||
.x = offset->x,
|
||||
.y = offset->y,
|
||||
.z = offset->z,
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct mtl_size
|
||||
vk_extent_3d_to_mtl_size(const struct VkExtent3D *extent)
|
||||
{
|
||||
struct mtl_size ret = {
|
||||
.x = extent->width,
|
||||
.y = extent->height,
|
||||
.z = extent->depth,
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
enum mtl_primitive_type
|
||||
vk_primitive_topology_to_mtl_primitive_type(enum VkPrimitiveTopology topology)
|
||||
{
|
||||
switch (topology) {
|
||||
case VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
|
||||
return MTL_PRIMITIVE_TYPE_POINT;
|
||||
case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
|
||||
return MTL_PRIMITIVE_TYPE_LINE;
|
||||
case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
|
||||
return MTL_PRIMITIVE_TYPE_LINE_STRIP;
|
||||
case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wswitch"
|
||||
case VK_PRIMITIVE_TOPOLOGY_META_RECT_LIST_MESA:
|
||||
#pragma GCC diagnostic pop
|
||||
/* Triangle fans are emulated meaning we'll translate the index buffer to
|
||||
* triangle list or generate a index buffer if there's none */
|
||||
case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
|
||||
return MTL_PRIMITIVE_TYPE_TRIANGLE;
|
||||
case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
|
||||
return MTL_PRIMITIVE_TYPE_TRIANGLE_STRIP;
|
||||
default:
|
||||
assert(0 && "Primitive topology not supported!");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
enum mtl_primitive_topology_class
|
||||
vk_primitive_topology_to_mtl_primitive_topology_class(
|
||||
enum VkPrimitiveTopology topology)
|
||||
{
|
||||
switch (topology) {
|
||||
case VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
|
||||
return MTL_PRIMITIVE_TOPOLOGY_CLASS_POINT;
|
||||
case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
|
||||
case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
|
||||
return MTL_PRIMITIVE_TOPOLOGY_CLASS_LINE;
|
||||
case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
|
||||
case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wswitch"
|
||||
case VK_PRIMITIVE_TOPOLOGY_META_RECT_LIST_MESA:
|
||||
#pragma GCC diagnostic pop
|
||||
return MTL_PRIMITIVE_TOPOLOGY_CLASS_TRIANGLE;
|
||||
default:
|
||||
return MTL_PRIMITIVE_TOPOLOGY_CLASS_UNSPECIFIED;
|
||||
}
|
||||
}
|
||||
|
||||
enum mtl_load_action
|
||||
vk_attachment_load_op_to_mtl_load_action(enum VkAttachmentLoadOp op)
|
||||
{
|
||||
switch (op) {
|
||||
case VK_ATTACHMENT_LOAD_OP_LOAD:
|
||||
return MTL_LOAD_ACTION_LOAD;
|
||||
case VK_ATTACHMENT_LOAD_OP_CLEAR:
|
||||
return MTL_LOAD_ACTION_CLEAR;
|
||||
case VK_ATTACHMENT_LOAD_OP_DONT_CARE:
|
||||
return MTL_LOAD_ACTION_DONT_CARE;
|
||||
default:
|
||||
assert(false && "Unsupported VkAttachmentLoadOp");
|
||||
return MTL_LOAD_ACTION_DONT_CARE;
|
||||
};
|
||||
}
|
||||
|
||||
enum mtl_store_action
|
||||
vk_attachment_store_op_to_mtl_store_action(enum VkAttachmentStoreOp op)
|
||||
{
|
||||
switch (op) {
|
||||
case VK_ATTACHMENT_STORE_OP_STORE:
|
||||
return MTL_STORE_ACTION_STORE;
|
||||
case VK_ATTACHMENT_STORE_OP_DONT_CARE:
|
||||
return MTL_STORE_ACTION_DONT_CARE;
|
||||
case VK_ATTACHMENT_STORE_OP_NONE:
|
||||
return MTL_STORE_ACTION_UNKNOWN;
|
||||
default:
|
||||
assert(false && "Unsupported VkAttachmentStoreOp");
|
||||
return MTL_STORE_ACTION_UNKNOWN;
|
||||
};
|
||||
}
|
||||
|
||||
enum mtl_sampler_address_mode
|
||||
vk_sampler_address_mode_to_mtl_sampler_address_mode(
|
||||
enum VkSamplerAddressMode mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case VK_SAMPLER_ADDRESS_MODE_REPEAT:
|
||||
return MTL_SAMPLER_ADDRESS_MODE_REPEAT;
|
||||
case VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT:
|
||||
return MTL_SAMPLER_ADDRESS_MODE_MIRROR_REPEAT;
|
||||
case VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE:
|
||||
return MTL_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
case VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER:
|
||||
return MTL_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER_COLOR;
|
||||
case VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE:
|
||||
return MTL_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE;
|
||||
default:
|
||||
UNREACHABLE("Unsupported address mode");
|
||||
}
|
||||
}
|
||||
|
||||
enum mtl_sampler_border_color
|
||||
vk_border_color_to_mtl_sampler_border_color(enum VkBorderColor color)
|
||||
{
|
||||
switch (color) {
|
||||
case VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK:
|
||||
case VK_BORDER_COLOR_INT_TRANSPARENT_BLACK:
|
||||
return MTL_SAMPLER_BORDER_COLOR_TRANSPARENT_BLACK;
|
||||
case VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK:
|
||||
case VK_BORDER_COLOR_INT_OPAQUE_BLACK:
|
||||
return MTL_SAMPLER_BORDER_COLOR_OPAQUE_BLACK;
|
||||
case VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE:
|
||||
case VK_BORDER_COLOR_INT_OPAQUE_WHITE:
|
||||
return MTL_SAMPLER_BORDER_COLOR_OPAQUE_WHITE;
|
||||
case VK_BORDER_COLOR_FLOAT_CUSTOM_EXT:
|
||||
case VK_BORDER_COLOR_INT_CUSTOM_EXT:
|
||||
return MTL_SAMPLER_BORDER_COLOR_OPAQUE_WHITE;
|
||||
default:
|
||||
UNREACHABLE("Unsupported address mode");
|
||||
}
|
||||
}
|
||||
|
||||
enum mtl_sampler_min_mag_filter
|
||||
vk_filter_to_mtl_sampler_min_mag_filter(enum VkFilter filter)
|
||||
{
|
||||
switch (filter) {
|
||||
case VK_FILTER_NEAREST:
|
||||
return MTL_SAMPLER_MIN_MAG_FILTER_NEAREST;
|
||||
case VK_FILTER_LINEAR:
|
||||
return MTL_SAMPLER_MIN_MAG_FILTER_LINEAR;
|
||||
default:
|
||||
UNREACHABLE("Unsupported address mode");
|
||||
}
|
||||
}
|
||||
|
||||
enum mtl_sampler_mip_filter
|
||||
vk_sampler_mipmap_mode_to_mtl_sampler_mip_filter(enum VkSamplerMipmapMode mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case VK_SAMPLER_MIPMAP_MODE_NEAREST:
|
||||
return MTL_SAMPLER_MIP_FILTER_NEAREST;
|
||||
case VK_SAMPLER_MIPMAP_MODE_LINEAR:
|
||||
return MTL_SAMPLER_MIP_FILTER_LINEAR;
|
||||
default:
|
||||
UNREACHABLE("Unsupported address mode");
|
||||
}
|
||||
}
|
||||
|
||||
enum mtl_compare_function
|
||||
vk_compare_op_to_mtl_compare_function(enum VkCompareOp op)
|
||||
{
|
||||
switch (op) {
|
||||
case VK_COMPARE_OP_NEVER:
|
||||
return MTL_COMPARE_FUNCTION_NEVER;
|
||||
case VK_COMPARE_OP_LESS:
|
||||
return MTL_COMPARE_FUNCTION_LESS;
|
||||
case VK_COMPARE_OP_EQUAL:
|
||||
return MTL_COMPARE_FUNCTION_EQUAL;
|
||||
case VK_COMPARE_OP_LESS_OR_EQUAL:
|
||||
return MTL_COMPARE_FUNCTION_LESS_EQUAL;
|
||||
case VK_COMPARE_OP_GREATER:
|
||||
return MTL_COMPARE_FUNCTION_GREATER;
|
||||
case VK_COMPARE_OP_NOT_EQUAL:
|
||||
return MTL_COMPARE_FUNCTION_NOT_EQUAL;
|
||||
case VK_COMPARE_OP_GREATER_OR_EQUAL:
|
||||
return MTL_COMPARE_FUNCTION_GREATER_EQUAL;
|
||||
case VK_COMPARE_OP_ALWAYS:
|
||||
return MTL_COMPARE_FUNCTION_ALWAYS;
|
||||
default:
|
||||
UNREACHABLE("Unsupported address mode");
|
||||
}
|
||||
}
|
||||
|
||||
enum mtl_winding
|
||||
vk_front_face_to_mtl_winding(enum VkFrontFace face)
|
||||
{
|
||||
switch (face) {
|
||||
case VK_FRONT_FACE_CLOCKWISE:
|
||||
return MTL_WINDING_CLOCKWISE;
|
||||
case VK_FRONT_FACE_COUNTER_CLOCKWISE:
|
||||
return MTL_WINDING_COUNTER_CLOCKWISE;
|
||||
default:
|
||||
assert(false && "Unsupported VkFrontFace");
|
||||
return MTL_WINDING_CLOCKWISE;
|
||||
}
|
||||
}
|
||||
|
||||
enum mtl_cull_mode
|
||||
vk_front_face_to_mtl_cull_mode(enum VkCullModeFlagBits mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case VK_CULL_MODE_NONE:
|
||||
return MTL_CULL_MODE_NONE;
|
||||
case VK_CULL_MODE_FRONT_BIT:
|
||||
return MTL_CULL_MODE_FRONT;
|
||||
case VK_CULL_MODE_BACK_BIT:
|
||||
return MTL_CULL_MODE_BACK;
|
||||
default:
|
||||
UNREACHABLE("Unsupported VkCullModeFlags");
|
||||
}
|
||||
}
|
||||
|
||||
enum mtl_index_type
|
||||
index_size_in_bytes_to_mtl_index_type(unsigned bytes)
|
||||
{
|
||||
switch (bytes) {
|
||||
case 2u:
|
||||
return MTL_INDEX_TYPE_UINT16;
|
||||
case 4u:
|
||||
return MTL_INDEX_TYPE_UINT32;
|
||||
default:
|
||||
UNREACHABLE("Unsupported byte size for index");
|
||||
}
|
||||
}
|
||||
81
src/kosmickrisp/bridge/vk_to_mtl_map.h
Normal file
81
src/kosmickrisp/bridge/vk_to_mtl_map.h
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
#ifndef KK_MTL_TO_VK_MAP_H
|
||||
#define KK_MTL_TO_VK_MAP_H 1
|
||||
|
||||
enum pipe_format;
|
||||
|
||||
struct mtl_origin;
|
||||
struct mtl_size;
|
||||
enum mtl_primitive_type;
|
||||
enum mtl_primitive_topology_class;
|
||||
enum mtl_load_action;
|
||||
enum mtl_store_action;
|
||||
enum mtl_sampler_address_mode;
|
||||
enum mtl_sampler_border_color;
|
||||
enum mtl_sampler_min_mag_filter;
|
||||
enum mtl_sampler_mip_filter;
|
||||
enum mtl_compare_function;
|
||||
enum mtl_winding;
|
||||
enum mtl_cull_mode;
|
||||
enum mtl_index_type;
|
||||
|
||||
struct VkOffset3D;
|
||||
struct VkExtent3D;
|
||||
union VkClearColorValue;
|
||||
enum VkPrimitiveTopology;
|
||||
enum VkAttachmentLoadOp;
|
||||
enum VkAttachmentStoreOp;
|
||||
enum VkSamplerAddressMode;
|
||||
enum VkBorderColor;
|
||||
enum VkFilter;
|
||||
enum VkSamplerMipmapMode;
|
||||
enum VkCompareOp;
|
||||
enum VkFrontFace;
|
||||
enum VkCullModeFlagBits;
|
||||
|
||||
/* STRUCTS */
|
||||
struct mtl_origin vk_offset_3d_to_mtl_origin(const struct VkOffset3D *offset);
|
||||
|
||||
struct mtl_size vk_extent_3d_to_mtl_size(const struct VkExtent3D *extent);
|
||||
|
||||
/* ENUMS */
|
||||
enum mtl_primitive_type
|
||||
vk_primitive_topology_to_mtl_primitive_type(enum VkPrimitiveTopology topology);
|
||||
|
||||
enum mtl_primitive_topology_class
|
||||
vk_primitive_topology_to_mtl_primitive_topology_class(
|
||||
enum VkPrimitiveTopology topology);
|
||||
|
||||
enum mtl_load_action
|
||||
vk_attachment_load_op_to_mtl_load_action(enum VkAttachmentLoadOp op);
|
||||
|
||||
enum mtl_store_action
|
||||
vk_attachment_store_op_to_mtl_store_action(enum VkAttachmentStoreOp op);
|
||||
|
||||
enum mtl_sampler_address_mode
|
||||
vk_sampler_address_mode_to_mtl_sampler_address_mode(
|
||||
enum VkSamplerAddressMode mode);
|
||||
|
||||
enum mtl_sampler_border_color
|
||||
vk_border_color_to_mtl_sampler_border_color(enum VkBorderColor color);
|
||||
|
||||
enum mtl_sampler_min_mag_filter
|
||||
vk_filter_to_mtl_sampler_min_mag_filter(enum VkFilter filter);
|
||||
|
||||
enum mtl_sampler_mip_filter
|
||||
vk_sampler_mipmap_mode_to_mtl_sampler_mip_filter(enum VkSamplerMipmapMode mode);
|
||||
|
||||
enum mtl_compare_function
|
||||
vk_compare_op_to_mtl_compare_function(enum VkCompareOp op);
|
||||
|
||||
enum mtl_winding vk_front_face_to_mtl_winding(enum VkFrontFace face);
|
||||
|
||||
enum mtl_cull_mode vk_front_face_to_mtl_cull_mode(enum VkCullModeFlagBits mode);
|
||||
|
||||
enum mtl_index_type index_size_in_bytes_to_mtl_index_type(unsigned bytes);
|
||||
|
||||
#endif /* KK_MTL_TO_VK_MAP_H */
|
||||
35
src/kosmickrisp/compiler/meson.build
Normal file
35
src/kosmickrisp/compiler/meson.build
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
# Copyright 2025 LunarG, Inc.
|
||||
# Copyright 2025 Google LLC
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
libmsl_compiler_files = files(
|
||||
'nir_to_msl.c',
|
||||
'msl_type_inference.c',
|
||||
'msl_iomap.c',
|
||||
'msl_nir_lower_common.c',
|
||||
'msl_nir_lower_subgroups.c',
|
||||
)
|
||||
|
||||
msl_nir_algebraic_c = custom_target(
|
||||
input : 'msl_nir_algebraic.py',
|
||||
output : 'msl_nir_algebraic.c',
|
||||
command : [
|
||||
prog_python, '@INPUT@', '-p', dir_compiler_nir,
|
||||
],
|
||||
capture : true,
|
||||
depend_files : nir_algebraic_depends,
|
||||
)
|
||||
|
||||
|
||||
libmsl_compiler = static_library(
|
||||
'msl_compiler',
|
||||
[libmsl_compiler_files, msl_nir_algebraic_c],
|
||||
dependencies : [idep_nir, idep_mesautil],
|
||||
gnu_symbol_visibility: 'hidden',
|
||||
build_by_default: false,
|
||||
)
|
||||
|
||||
idep_msl_to_nir = declare_dependency(
|
||||
link_with : libmsl_compiler,
|
||||
)
|
||||
|
||||
447
src/kosmickrisp/compiler/msl_iomap.c
Normal file
447
src/kosmickrisp/compiler/msl_iomap.c
Normal file
|
|
@ -0,0 +1,447 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/* This file primarily concerns itself with mapping from the NIR (and Vulkan)
|
||||
* model of I/O to the Metal one. */
|
||||
|
||||
#include "msl_private.h"
|
||||
|
||||
#include "nir_builder.h"
|
||||
|
||||
/* Mapping from alu type to Metal scalar type */
|
||||
static const char *
|
||||
alu_type_to_string(nir_alu_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case nir_type_uint8:
|
||||
return "uchar";
|
||||
case nir_type_uint16:
|
||||
return "ushort";
|
||||
case nir_type_uint32:
|
||||
return "uint";
|
||||
case nir_type_uint64:
|
||||
return "ulong";
|
||||
case nir_type_int8:
|
||||
return "char";
|
||||
case nir_type_int16:
|
||||
return "short";
|
||||
case nir_type_int32:
|
||||
return "int";
|
||||
case nir_type_int64:
|
||||
return "long";
|
||||
case nir_type_float16:
|
||||
return "half";
|
||||
case nir_type_float32:
|
||||
return "float";
|
||||
case nir_type_bool8:
|
||||
return "bool";
|
||||
default:
|
||||
UNREACHABLE("Unsupported nir_alu_type");
|
||||
}
|
||||
};
|
||||
|
||||
/* Type suffix for a vector of a given size. */
|
||||
static const char *vector_suffixes[] = {
|
||||
[1] = "",
|
||||
[2] = "2",
|
||||
[3] = "3",
|
||||
[4] = "4",
|
||||
};
|
||||
|
||||
/* The type names of the generated output structs */
|
||||
static const char *VERTEX_OUTPUT_TYPE = "VertexOut";
|
||||
static const char *FRAGMENT_OUTPUT_TYPE = "FragmentOut";
|
||||
|
||||
/* Mapping from NIR's varying slots to the generated struct member name */
|
||||
static const char *VARYING_SLOT_NAME[NUM_TOTAL_VARYING_SLOTS] = {
|
||||
[VARYING_SLOT_POS] = "position",
|
||||
[VARYING_SLOT_PSIZ] = "point_size",
|
||||
[VARYING_SLOT_PRIMITIVE_ID] = "primitive_id",
|
||||
[VARYING_SLOT_LAYER] = "layer",
|
||||
[VARYING_SLOT_VAR0] = "vary_00",
|
||||
[VARYING_SLOT_VAR1] = "vary_01",
|
||||
[VARYING_SLOT_VAR2] = "vary_02",
|
||||
[VARYING_SLOT_VAR3] = "vary_03",
|
||||
[VARYING_SLOT_VAR4] = "vary_04",
|
||||
[VARYING_SLOT_VAR5] = "vary_05",
|
||||
[VARYING_SLOT_VAR6] = "vary_06",
|
||||
[VARYING_SLOT_VAR7] = "vary_07",
|
||||
[VARYING_SLOT_VAR8] = "vary_08",
|
||||
[VARYING_SLOT_VAR9] = "vary_09",
|
||||
[VARYING_SLOT_VAR10] = "vary_10",
|
||||
[VARYING_SLOT_VAR11] = "vary_11",
|
||||
[VARYING_SLOT_VAR12] = "vary_12",
|
||||
[VARYING_SLOT_VAR13] = "vary_13",
|
||||
[VARYING_SLOT_VAR14] = "vary_14",
|
||||
[VARYING_SLOT_VAR15] = "vary_15",
|
||||
[VARYING_SLOT_VAR16] = "vary_16",
|
||||
[VARYING_SLOT_VAR17] = "vary_17",
|
||||
[VARYING_SLOT_VAR18] = "vary_18",
|
||||
[VARYING_SLOT_VAR19] = "vary_19",
|
||||
[VARYING_SLOT_VAR20] = "vary_20",
|
||||
[VARYING_SLOT_VAR21] = "vary_21",
|
||||
[VARYING_SLOT_VAR22] = "vary_22",
|
||||
[VARYING_SLOT_VAR23] = "vary_23",
|
||||
[VARYING_SLOT_VAR24] = "vary_24",
|
||||
[VARYING_SLOT_VAR25] = "vary_25",
|
||||
[VARYING_SLOT_VAR26] = "vary_26",
|
||||
[VARYING_SLOT_VAR27] = "vary_27",
|
||||
[VARYING_SLOT_VAR28] = "vary_28",
|
||||
[VARYING_SLOT_VAR29] = "vary_29",
|
||||
[VARYING_SLOT_VAR30] = "vary_30",
|
||||
[VARYING_SLOT_VAR31] = "vary_31",
|
||||
};
|
||||
|
||||
/* Mapping from NIR varying slot to the MSL struct member attribute. */
|
||||
static const char *VARYING_SLOT_SEMANTIC[NUM_TOTAL_VARYING_SLOTS] = {
|
||||
[VARYING_SLOT_POS] = "[[position]]",
|
||||
[VARYING_SLOT_PSIZ] = "[[point_size]]",
|
||||
[VARYING_SLOT_PRIMITIVE_ID] = "[[primitive_id]]",
|
||||
[VARYING_SLOT_LAYER] = "[[render_target_array_index]]",
|
||||
[VARYING_SLOT_VAR0] = "[[user(vary_00)]]",
|
||||
[VARYING_SLOT_VAR1] = "[[user(vary_01)]]",
|
||||
[VARYING_SLOT_VAR2] = "[[user(vary_02)]]",
|
||||
[VARYING_SLOT_VAR3] = "[[user(vary_03)]]",
|
||||
[VARYING_SLOT_VAR4] = "[[user(vary_04)]]",
|
||||
[VARYING_SLOT_VAR5] = "[[user(vary_05)]]",
|
||||
[VARYING_SLOT_VAR6] = "[[user(vary_06)]]",
|
||||
[VARYING_SLOT_VAR7] = "[[user(vary_07)]]",
|
||||
[VARYING_SLOT_VAR8] = "[[user(vary_08)]]",
|
||||
[VARYING_SLOT_VAR9] = "[[user(vary_09)]]",
|
||||
[VARYING_SLOT_VAR10] = "[[user(vary_10)]]",
|
||||
[VARYING_SLOT_VAR11] = "[[user(vary_11)]]",
|
||||
[VARYING_SLOT_VAR12] = "[[user(vary_12)]]",
|
||||
[VARYING_SLOT_VAR13] = "[[user(vary_13)]]",
|
||||
[VARYING_SLOT_VAR14] = "[[user(vary_14)]]",
|
||||
[VARYING_SLOT_VAR15] = "[[user(vary_15)]]",
|
||||
[VARYING_SLOT_VAR16] = "[[user(vary_16)]]",
|
||||
[VARYING_SLOT_VAR17] = "[[user(vary_17)]]",
|
||||
[VARYING_SLOT_VAR18] = "[[user(vary_18)]]",
|
||||
[VARYING_SLOT_VAR19] = "[[user(vary_19)]]",
|
||||
[VARYING_SLOT_VAR20] = "[[user(vary_20)]]",
|
||||
[VARYING_SLOT_VAR21] = "[[user(vary_21)]]",
|
||||
[VARYING_SLOT_VAR22] = "[[user(vary_22)]]",
|
||||
[VARYING_SLOT_VAR23] = "[[user(vary_23)]]",
|
||||
[VARYING_SLOT_VAR24] = "[[user(vary_24)]]",
|
||||
[VARYING_SLOT_VAR25] = "[[user(vary_25)]]",
|
||||
[VARYING_SLOT_VAR26] = "[[user(vary_26)]]",
|
||||
[VARYING_SLOT_VAR27] = "[[user(vary_27)]]",
|
||||
[VARYING_SLOT_VAR28] = "[[user(vary_28)]]",
|
||||
[VARYING_SLOT_VAR29] = "[[user(vary_29)]]",
|
||||
[VARYING_SLOT_VAR30] = "[[user(vary_30)]]",
|
||||
[VARYING_SLOT_VAR31] = "[[user(vary_31)]]",
|
||||
};
|
||||
|
||||
/* Mapping from NIR fragment output slot to MSL struct member name */
|
||||
static const char *FS_OUTPUT_NAME[] = {
|
||||
[FRAG_RESULT_DEPTH] = "depth_out",
|
||||
[FRAG_RESULT_STENCIL] = "stencil_out",
|
||||
[FRAG_RESULT_SAMPLE_MASK] = "sample_mask_out",
|
||||
[FRAG_RESULT_DATA0] = "color_0",
|
||||
[FRAG_RESULT_DATA1] = "color_1",
|
||||
[FRAG_RESULT_DATA2] = "color_2",
|
||||
[FRAG_RESULT_DATA3] = "color_3",
|
||||
[FRAG_RESULT_DATA4] = "color_4",
|
||||
[FRAG_RESULT_DATA5] = "color_5",
|
||||
[FRAG_RESULT_DATA6] = "color_6",
|
||||
[FRAG_RESULT_DATA7] = "color_7",
|
||||
};
|
||||
|
||||
/* Mapping from NIR fragment output slot to MSL struct member attribute */
|
||||
static const char *FS_OUTPUT_SEMANTIC[] = {
|
||||
[FRAG_RESULT_DEPTH] = "", // special case, depends on depth layout
|
||||
[FRAG_RESULT_STENCIL] = "stencil", [FRAG_RESULT_SAMPLE_MASK] = "sample_mask",
|
||||
[FRAG_RESULT_DATA0] = "color(0)", [FRAG_RESULT_DATA1] = "color(1)",
|
||||
[FRAG_RESULT_DATA2] = "color(2)", [FRAG_RESULT_DATA3] = "color(3)",
|
||||
[FRAG_RESULT_DATA4] = "color(4)", [FRAG_RESULT_DATA5] = "color(5)",
|
||||
[FRAG_RESULT_DATA6] = "color(6)", [FRAG_RESULT_DATA7] = "color(7)",
|
||||
};
|
||||
|
||||
const char *depth_layout_arg[8] = {
|
||||
[FRAG_DEPTH_LAYOUT_ANY] = "any",
|
||||
[FRAG_DEPTH_LAYOUT_GREATER] = "greater",
|
||||
[FRAG_DEPTH_LAYOUT_LESS] = "less",
|
||||
[FRAG_DEPTH_LAYOUT_UNCHANGED] = "any",
|
||||
};
|
||||
|
||||
/* Generate the struct definition for the vertex shader return value */
|
||||
static void
|
||||
vs_output_block(nir_shader *shader, struct nir_to_msl_ctx *ctx)
|
||||
{
|
||||
P(ctx, "struct %s {\n", VERTEX_OUTPUT_TYPE);
|
||||
ctx->indentlevel++;
|
||||
u_foreach_bit64(location, shader->info.outputs_written) {
|
||||
struct io_slot_info info = ctx->outputs_info[location];
|
||||
const char *type = alu_type_to_string(info.type);
|
||||
const char *vector_suffix = vector_suffixes[info.num_components];
|
||||
P_IND(ctx, "%s%s %s %s;\n", type, vector_suffix,
|
||||
VARYING_SLOT_NAME[location], VARYING_SLOT_SEMANTIC[location]);
|
||||
}
|
||||
|
||||
ctx->indentlevel--;
|
||||
P(ctx, "};\n");
|
||||
}
|
||||
|
||||
/* Generate the struct definition for the fragment shader input argument */
|
||||
static void
|
||||
fs_input_block(nir_shader *shader, struct nir_to_msl_ctx *ctx)
|
||||
{
|
||||
P(ctx, "struct FragmentIn {\n");
|
||||
ctx->indentlevel++;
|
||||
u_foreach_bit64(location, shader->info.inputs_read) {
|
||||
struct io_slot_info info = ctx->inputs_info[location];
|
||||
const char *type = alu_type_to_string(info.type);
|
||||
const char *vector_suffix = vector_suffixes[info.num_components];
|
||||
const char *interp = "";
|
||||
switch (info.interpolation) {
|
||||
case INTERP_MODE_NOPERSPECTIVE:
|
||||
if (info.centroid)
|
||||
interp = "[[centroid_no_perspective]]";
|
||||
else if (info.sample)
|
||||
interp = "[[sample_no_perspective]]";
|
||||
else
|
||||
interp = "[[center_no_perspective]]";
|
||||
break;
|
||||
case INTERP_MODE_FLAT:
|
||||
interp = "[[flat]]";
|
||||
break;
|
||||
default:
|
||||
if (info.centroid)
|
||||
interp = "[[centroid_perspective]]";
|
||||
else if (info.sample)
|
||||
interp = "[[sample_perspective]]";
|
||||
break;
|
||||
}
|
||||
P_IND(ctx, "%s%s %s %s %s;\n", type, vector_suffix,
|
||||
VARYING_SLOT_NAME[location], VARYING_SLOT_SEMANTIC[location],
|
||||
interp);
|
||||
}
|
||||
|
||||
/* Enable reading from framebuffer */
|
||||
u_foreach_bit64(location, shader->info.outputs_read) {
|
||||
struct io_slot_info info = ctx->outputs_info[location];
|
||||
const char *type = alu_type_to_string(info.type);
|
||||
const char *vector_suffix = vector_suffixes[info.num_components];
|
||||
P_IND(ctx, "%s%s ", type, vector_suffix);
|
||||
P(ctx, "%s [[%s, raster_order_group(0)]];\n", FS_OUTPUT_NAME[location],
|
||||
FS_OUTPUT_SEMANTIC[location]);
|
||||
}
|
||||
|
||||
ctx->indentlevel--;
|
||||
P(ctx, "};\n");
|
||||
}
|
||||
|
||||
/* Generate the struct definition for the fragment shader return value */
|
||||
static void
|
||||
fs_output_block(nir_shader *shader, struct nir_to_msl_ctx *ctx)
|
||||
{
|
||||
P_IND(ctx, "struct %s {\n", FRAGMENT_OUTPUT_TYPE);
|
||||
ctx->indentlevel++;
|
||||
u_foreach_bit64(location, shader->info.outputs_written) {
|
||||
struct io_slot_info info = ctx->outputs_info[location];
|
||||
const char *type = alu_type_to_string(info.type);
|
||||
const char *vector_suffix = vector_suffixes[info.num_components];
|
||||
P_IND(ctx, "%s%s ", type, vector_suffix);
|
||||
if (location == FRAG_RESULT_DEPTH) {
|
||||
enum gl_frag_depth_layout depth_layout = shader->info.fs.depth_layout;
|
||||
assert(depth_layout_arg[depth_layout]);
|
||||
P(ctx, "%s [[depth(%s)]];\n", FS_OUTPUT_NAME[location],
|
||||
depth_layout_arg[depth_layout]);
|
||||
} else {
|
||||
P(ctx, "%s [[%s]];\n", FS_OUTPUT_NAME[location],
|
||||
FS_OUTPUT_SEMANTIC[location]);
|
||||
}
|
||||
}
|
||||
ctx->indentlevel--;
|
||||
P_IND(ctx, "};\n")
|
||||
}
|
||||
|
||||
struct gather_ctx {
|
||||
struct io_slot_info *input;
|
||||
struct io_slot_info *output;
|
||||
};
|
||||
|
||||
static bool
|
||||
msl_nir_gather_io_info(nir_builder *b, nir_intrinsic_instr *intrin, void *data)
|
||||
{
|
||||
struct gather_ctx *ctx = (struct gather_ctx *)data;
|
||||
switch (intrin->intrinsic) {
|
||||
case nir_intrinsic_load_interpolated_input: {
|
||||
unsigned component = nir_intrinsic_component(intrin);
|
||||
struct nir_io_semantics io = nir_intrinsic_io_semantics(intrin);
|
||||
assert(io.num_slots == 1u && "We don't support arrays");
|
||||
|
||||
unsigned location = nir_src_as_uint(intrin->src[1u]) + io.location;
|
||||
ctx->input[location].type = nir_intrinsic_dest_type(intrin);
|
||||
ctx->input[location].num_components =
|
||||
MAX2(ctx->input[location].num_components,
|
||||
intrin->num_components + component);
|
||||
assert(ctx->input[location].num_components <= 4u &&
|
||||
"Cannot have more than a vec4");
|
||||
|
||||
nir_intrinsic_instr *interp_intrin =
|
||||
nir_src_as_intrinsic(intrin->src[0u]);
|
||||
ctx->input[location].interpolation =
|
||||
nir_intrinsic_interp_mode(interp_intrin);
|
||||
ctx->input[location].centroid =
|
||||
interp_intrin->intrinsic == nir_intrinsic_load_barycentric_centroid;
|
||||
ctx->input[location].sample =
|
||||
interp_intrin->intrinsic == nir_intrinsic_load_barycentric_sample;
|
||||
break;
|
||||
}
|
||||
case nir_intrinsic_load_input: {
|
||||
unsigned component = nir_intrinsic_component(intrin);
|
||||
struct nir_io_semantics io = nir_intrinsic_io_semantics(intrin);
|
||||
assert(io.num_slots == 1u && "We don't support arrays");
|
||||
|
||||
unsigned location = nir_src_as_uint(intrin->src[0u]) + io.location;
|
||||
ctx->input[location].type = nir_intrinsic_dest_type(intrin);
|
||||
ctx->input[location].interpolation = INTERP_MODE_FLAT;
|
||||
ctx->input[location].num_components =
|
||||
MAX2(ctx->input[location].num_components,
|
||||
intrin->num_components + component);
|
||||
assert(ctx->input[location].num_components <= 4u &&
|
||||
"Cannot have more than a vec4");
|
||||
break;
|
||||
}
|
||||
case nir_intrinsic_load_output: {
|
||||
unsigned component = nir_intrinsic_component(intrin);
|
||||
struct nir_io_semantics io = nir_intrinsic_io_semantics(intrin);
|
||||
assert(io.num_slots == 1u && "We don't support arrays");
|
||||
|
||||
unsigned location = nir_src_as_uint(intrin->src[0u]) + io.location;
|
||||
ctx->output[location].type = nir_intrinsic_dest_type(intrin);
|
||||
ctx->output[location].num_components =
|
||||
MAX2(ctx->output[location].num_components,
|
||||
intrin->num_components + component);
|
||||
assert(ctx->output[location].num_components <= 4u &&
|
||||
"Cannot have more than a vec4");
|
||||
break;
|
||||
}
|
||||
case nir_intrinsic_store_output: {
|
||||
unsigned component = nir_intrinsic_component(intrin);
|
||||
unsigned write_mask = nir_intrinsic_write_mask(intrin);
|
||||
struct nir_io_semantics io = nir_intrinsic_io_semantics(intrin);
|
||||
assert(io.num_slots == 1u && "We don't support arrays");
|
||||
|
||||
/* Due to nir_lower_blend that doesn't generate intrinsics with the same
|
||||
* num_components as destination, we need to compute current store's
|
||||
* num_components using offset and mask. */
|
||||
unsigned num_components = component + 1u;
|
||||
unsigned mask_left_most_index = 0u;
|
||||
for (unsigned i = 0u; i < intrin->num_components; ++i) {
|
||||
if ((write_mask >> i) & 1u)
|
||||
mask_left_most_index = i;
|
||||
}
|
||||
num_components += mask_left_most_index;
|
||||
unsigned location = nir_src_as_uint(intrin->src[1u]) + io.location;
|
||||
ctx->output[location].type = nir_intrinsic_src_type(intrin);
|
||||
ctx->output[location].num_components =
|
||||
MAX3(ctx->output[location].num_components, num_components,
|
||||
intrin->num_components);
|
||||
assert(ctx->output[location].num_components <= 4u &&
|
||||
"Cannot have more than a vec4");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
msl_gather_io_info(struct nir_to_msl_ctx *ctx,
|
||||
struct io_slot_info *info_array_input,
|
||||
struct io_slot_info *info_array_output)
|
||||
{
|
||||
struct gather_ctx gather_ctx = {
|
||||
.input = info_array_input,
|
||||
.output = info_array_output,
|
||||
};
|
||||
nir_shader_intrinsics_pass(ctx->shader, msl_nir_gather_io_info,
|
||||
nir_metadata_all, &gather_ctx);
|
||||
}
|
||||
|
||||
/* Generate all the struct definitions needed for shader I/O */
|
||||
void
|
||||
msl_emit_io_blocks(struct nir_to_msl_ctx *ctx, nir_shader *shader)
|
||||
{
|
||||
switch (ctx->shader->info.stage) {
|
||||
case MESA_SHADER_VERTEX:
|
||||
vs_output_block(shader, ctx);
|
||||
break;
|
||||
case MESA_SHADER_FRAGMENT:
|
||||
fs_input_block(shader, ctx);
|
||||
fs_output_block(shader, ctx);
|
||||
break;
|
||||
case MESA_SHADER_COMPUTE:
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
// TODO_KOSMICKRISP This should not exist. We need to create input structs in
|
||||
// nir that will later be translated
|
||||
P(ctx, "struct Buffer {\n");
|
||||
ctx->indentlevel++;
|
||||
P_IND(ctx, "uint64_t contents[1];\n"); // TODO_KOSMICKRISP This should not be
|
||||
// a cpu pointer
|
||||
ctx->indentlevel--;
|
||||
P(ctx, "};\n")
|
||||
|
||||
P(ctx, "struct SamplerTable {\n");
|
||||
ctx->indentlevel++;
|
||||
P_IND(ctx, "sampler handles[1024];\n");
|
||||
ctx->indentlevel--;
|
||||
P(ctx, "};\n")
|
||||
}
|
||||
|
||||
void
|
||||
msl_emit_output_var(struct nir_to_msl_ctx *ctx, nir_shader *shader)
|
||||
{
|
||||
switch (shader->info.stage) {
|
||||
case MESA_SHADER_VERTEX:
|
||||
P_IND(ctx, "%s out = {};\n", VERTEX_OUTPUT_TYPE);
|
||||
break;
|
||||
case MESA_SHADER_FRAGMENT:
|
||||
P_IND(ctx, "%s out = {};\n", FRAGMENT_OUTPUT_TYPE);
|
||||
|
||||
/* Load inputs to output */
|
||||
u_foreach_bit64(location, shader->info.outputs_read) {
|
||||
P_IND(ctx, "out.%s = in.%s;\n", FS_OUTPUT_NAME[location],
|
||||
FS_OUTPUT_NAME[location]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const char *
|
||||
msl_output_name(struct nir_to_msl_ctx *ctx, unsigned location)
|
||||
{
|
||||
switch (ctx->shader->info.stage) {
|
||||
case MESA_SHADER_VERTEX:
|
||||
return VARYING_SLOT_NAME[location];
|
||||
case MESA_SHADER_FRAGMENT:
|
||||
return FS_OUTPUT_NAME[location];
|
||||
default:
|
||||
assert(0);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
const char *
|
||||
msl_input_name(struct nir_to_msl_ctx *ctx, unsigned location)
|
||||
{
|
||||
switch (ctx->shader->info.stage) {
|
||||
case MESA_SHADER_FRAGMENT:
|
||||
return VARYING_SLOT_NAME[location];
|
||||
default:
|
||||
assert(0);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
38
src/kosmickrisp/compiler/msl_nir_algebraic.py
Normal file
38
src/kosmickrisp/compiler/msl_nir_algebraic.py
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
# Copyright 2025 LunarG, Inc.
|
||||
# Copyright 2025 Google LLC
|
||||
# Copyright 2022 Alyssa Rosenzweig
|
||||
# Copyright 2021 Collabora, Ltd.
|
||||
# Copyright 2016 Intel Corporation
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
import math
|
||||
|
||||
a = 'a'
|
||||
|
||||
lower_pack = [
|
||||
# Based on the VIR lowering
|
||||
(('f2f16_rtz', 'a@32'),
|
||||
('bcsel', ('flt', ('fabs', a), ('fabs', ('f2f32', ('f2f16_rtne', a)))),
|
||||
('isub', ('f2f16_rtne', a), 1), ('f2f16_rtne', a))),
|
||||
]
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('-p', '--import-path', required=True)
|
||||
args = parser.parse_args()
|
||||
sys.path.insert(0, args.import_path)
|
||||
run()
|
||||
|
||||
def run():
|
||||
import nir_algebraic # pylint: disable=import-error
|
||||
|
||||
print('#include "msl_private.h"')
|
||||
|
||||
print(nir_algebraic.AlgebraicPass("msl_nir_lower_algebraic_late", lower_pack).render())
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
255
src/kosmickrisp/compiler/msl_nir_lower_common.c
Normal file
255
src/kosmickrisp/compiler/msl_nir_lower_common.c
Normal file
|
|
@ -0,0 +1,255 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
#include "nir_to_msl.h"
|
||||
|
||||
#include "nir.h"
|
||||
#include "nir_builder.h"
|
||||
|
||||
#include "util/format/u_format.h"
|
||||
|
||||
bool
|
||||
msl_nir_vs_remove_point_size_write(nir_builder *b, nir_intrinsic_instr *intrin,
|
||||
void *data)
|
||||
{
|
||||
if (intrin->intrinsic != nir_intrinsic_store_output)
|
||||
return false;
|
||||
|
||||
nir_io_semantics io = nir_intrinsic_io_semantics(intrin);
|
||||
if (io.location == VARYING_SLOT_PSIZ) {
|
||||
return nir_remove_sysval_output(intrin, MESA_SHADER_FRAGMENT);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
msl_nir_fs_remove_depth_write(nir_builder *b, nir_intrinsic_instr *intrin,
|
||||
void *data)
|
||||
{
|
||||
if (intrin->intrinsic != nir_intrinsic_store_output)
|
||||
return false;
|
||||
|
||||
nir_io_semantics io = nir_intrinsic_io_semantics(intrin);
|
||||
if (io.location == FRAG_RESULT_DEPTH) {
|
||||
return nir_remove_sysval_output(intrin, MESA_SHADER_FRAGMENT);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
msl_nir_fs_force_output_signedness(
|
||||
nir_shader *nir, enum pipe_format render_target_formats[MAX_DRAW_BUFFERS])
|
||||
{
|
||||
assert(nir->info.stage == MESA_SHADER_FRAGMENT);
|
||||
|
||||
bool update_derefs = false;
|
||||
nir_foreach_variable_with_modes(var, nir, nir_var_shader_out) {
|
||||
if (FRAG_RESULT_DATA0 <= var->data.location &&
|
||||
var->data.location <= FRAG_RESULT_DATA7 &&
|
||||
glsl_type_is_integer(var->type)) {
|
||||
unsigned int slot = var->data.location - FRAG_RESULT_DATA0;
|
||||
|
||||
if (glsl_type_is_uint_16_32_64(var->type) &&
|
||||
util_format_is_pure_sint(render_target_formats[slot])) {
|
||||
var->type = glsl_ivec_type(var->type->vector_elements);
|
||||
update_derefs = true;
|
||||
} else if (glsl_type_is_int_16_32_64(var->type) &&
|
||||
util_format_is_pure_uint(render_target_formats[slot])) {
|
||||
var->type = glsl_uvec_type(var->type->vector_elements);
|
||||
update_derefs = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (update_derefs) {
|
||||
nir_foreach_function_impl(impl, nir) {
|
||||
nir_foreach_block(block, impl) {
|
||||
nir_foreach_instr(instr, block) {
|
||||
switch (instr->type) {
|
||||
case nir_instr_type_deref: {
|
||||
nir_deref_instr *deref = nir_instr_as_deref(instr);
|
||||
if (deref->deref_type == nir_deref_type_var) {
|
||||
deref->type = deref->var->type;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
nir_progress(update_derefs, impl, nir_metadata_control_flow);
|
||||
}
|
||||
}
|
||||
|
||||
return update_derefs;
|
||||
}
|
||||
|
||||
bool
|
||||
msl_lower_textures(nir_shader *nir)
|
||||
{
|
||||
bool progress = false;
|
||||
nir_lower_tex_options lower_tex_options = {
|
||||
.lower_txp = ~0u,
|
||||
.lower_sampler_lod_bias = true,
|
||||
|
||||
/* We don't use 1D textures because they are really limited in Metal */
|
||||
.lower_1d = true,
|
||||
|
||||
/* Metal does not support tg4 with individual offsets for each sample */
|
||||
.lower_tg4_offsets = true,
|
||||
|
||||
/* Metal does not natively support offsets for texture.read operations */
|
||||
.lower_txf_offset = true,
|
||||
.lower_txd_cube_map = true,
|
||||
};
|
||||
|
||||
NIR_PASS(progress, nir, nir_lower_tex, &lower_tex_options);
|
||||
return progress;
|
||||
}
|
||||
|
||||
static bool
|
||||
replace_sample_id_for_sample_mask(nir_builder *b, nir_intrinsic_instr *intrin,
|
||||
void *data)
|
||||
{
|
||||
if (intrin->intrinsic != nir_intrinsic_load_sample_mask_in)
|
||||
return false;
|
||||
|
||||
nir_def_replace(nir_instr_def(&intrin->instr), (nir_def *)data);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
msl_replace_load_sample_mask_in_for_static_sample_mask(
|
||||
nir_builder *b, nir_intrinsic_instr *intr, void *data)
|
||||
{
|
||||
if (intr->intrinsic != nir_intrinsic_load_sample_mask_in)
|
||||
return false;
|
||||
|
||||
nir_def *sample_mask = (nir_def *)data;
|
||||
nir_def_rewrite_uses(&intr->def, sample_mask);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
msl_lower_static_sample_mask(nir_shader *nir, uint32_t sample_mask)
|
||||
{
|
||||
/* Only support vertex for now */
|
||||
assert(nir->info.stage == MESA_SHADER_FRAGMENT);
|
||||
|
||||
/* Embed sample mask */
|
||||
nir_function_impl *entrypoint = nir_shader_get_entrypoint(nir);
|
||||
nir_builder b = nir_builder_at(nir_before_impl(entrypoint));
|
||||
|
||||
struct nir_io_semantics io_semantics = {
|
||||
.location = FRAG_RESULT_SAMPLE_MASK,
|
||||
.num_slots = 1u,
|
||||
};
|
||||
nir_def *sample_mask_def = nir_imm_int(&b, sample_mask);
|
||||
nir_store_output(&b, sample_mask_def, nir_imm_int(&b, 0u), .base = 0u,
|
||||
.range = 1u, .write_mask = 0x1, .component = 0u,
|
||||
.src_type = nir_type_uint32, .io_semantics = io_semantics);
|
||||
|
||||
return nir_shader_intrinsics_pass(
|
||||
nir, msl_replace_load_sample_mask_in_for_static_sample_mask,
|
||||
nir_metadata_control_flow, sample_mask_def);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
msl_ensure_depth_write(nir_shader *nir)
|
||||
{
|
||||
assert(nir->info.stage == MESA_SHADER_FRAGMENT);
|
||||
|
||||
bool has_depth_write =
|
||||
nir->info.outputs_written & BITFIELD64_BIT(FRAG_RESULT_DEPTH);
|
||||
if (!has_depth_write) {
|
||||
nir_variable *depth_var = nir_create_variable_with_location(
|
||||
nir, nir_var_shader_out, FRAG_RESULT_DEPTH, glsl_float_type());
|
||||
|
||||
/* Write to depth at the very beginning */
|
||||
nir_function_impl *entrypoint = nir_shader_get_entrypoint(nir);
|
||||
nir_builder b = nir_builder_at(nir_before_impl(entrypoint));
|
||||
|
||||
nir_deref_instr *depth_deref = nir_build_deref_var(&b, depth_var);
|
||||
nir_def *position = nir_load_frag_coord(&b);
|
||||
nir_store_deref(&b, depth_deref, nir_channel(&b, position, 2u),
|
||||
0xFFFFFFFF);
|
||||
|
||||
nir->info.outputs_written |= BITFIELD64_BIT(FRAG_RESULT_DEPTH);
|
||||
nir->info.fs.depth_layout = FRAG_DEPTH_LAYOUT_ANY;
|
||||
return nir_progress(true, entrypoint, nir_metadata_control_flow);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
msl_ensure_vertex_position_output(nir_shader *nir)
|
||||
{
|
||||
assert(nir->info.stage == MESA_SHADER_VERTEX);
|
||||
|
||||
bool has_position_write =
|
||||
nir->info.outputs_written & BITFIELD64_BIT(VARYING_SLOT_POS);
|
||||
if (!has_position_write) {
|
||||
nir_variable *position_var = nir_create_variable_with_location(
|
||||
nir, nir_var_shader_out, VARYING_SLOT_POS, glsl_vec4_type());
|
||||
|
||||
/* Write to depth at the very beginning */
|
||||
nir_function_impl *entrypoint = nir_shader_get_entrypoint(nir);
|
||||
nir_builder b = nir_builder_at(nir_before_impl(entrypoint));
|
||||
|
||||
nir_deref_instr *position_deref = nir_build_deref_var(&b, position_var);
|
||||
nir_def *zero = nir_imm_float(&b, 0.0f);
|
||||
nir_store_deref(&b, position_deref, nir_vec4(&b, zero, zero, zero, zero),
|
||||
0xFFFFFFFF);
|
||||
|
||||
nir->info.outputs_written |= BITFIELD64_BIT(VARYING_SLOT_POS);
|
||||
return nir_progress(true, entrypoint, nir_metadata_control_flow);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
msl_sample_mask_uint(nir_builder *b, nir_intrinsic_instr *intr, void *data)
|
||||
{
|
||||
if (intr->intrinsic == nir_intrinsic_store_output) {
|
||||
struct nir_io_semantics io = nir_intrinsic_io_semantics(intr);
|
||||
if (io.location == FRAG_RESULT_SAMPLE_MASK)
|
||||
nir_intrinsic_set_src_type(intr, nir_type_uint32);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
msl_nir_sample_mask_type(nir_shader *nir)
|
||||
{
|
||||
assert(nir->info.stage == MESA_SHADER_FRAGMENT);
|
||||
return nir_shader_intrinsics_pass(nir, msl_sample_mask_uint,
|
||||
nir_metadata_all, NULL);
|
||||
}
|
||||
|
||||
static bool
|
||||
msl_layer_id_uint(nir_builder *b, nir_intrinsic_instr *intr, void *data)
|
||||
{
|
||||
if (intr->intrinsic == nir_intrinsic_store_output) {
|
||||
struct nir_io_semantics io = nir_intrinsic_io_semantics(intr);
|
||||
if (io.location == VARYING_SLOT_LAYER)
|
||||
nir_intrinsic_set_src_type(intr, nir_type_uint32);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
msl_nir_layer_id_type(nir_shader *nir)
|
||||
{
|
||||
assert(nir->info.stage == MESA_SHADER_VERTEX);
|
||||
return nir_shader_intrinsics_pass(nir, msl_layer_id_uint, nir_metadata_all,
|
||||
NULL);
|
||||
}
|
||||
98
src/kosmickrisp/compiler/msl_nir_lower_subgroups.c
Normal file
98
src/kosmickrisp/compiler/msl_nir_lower_subgroups.c
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* Copyright 2023 Valve Corporation
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "msl_private.h"
|
||||
#include "nir.h"
|
||||
#include "nir_builder.h"
|
||||
|
||||
static bool
|
||||
needs_bool_widening(nir_intrinsic_instr *intrin)
|
||||
{
|
||||
switch (intrin->intrinsic) {
|
||||
case nir_intrinsic_read_invocation:
|
||||
case nir_intrinsic_read_first_invocation:
|
||||
case nir_intrinsic_reduce:
|
||||
case nir_intrinsic_quad_broadcast:
|
||||
case nir_intrinsic_quad_swap_horizontal:
|
||||
case nir_intrinsic_quad_swap_vertical:
|
||||
case nir_intrinsic_quad_swap_diagonal:
|
||||
case nir_intrinsic_shuffle:
|
||||
case nir_intrinsic_shuffle_down:
|
||||
case nir_intrinsic_shuffle_up:
|
||||
case nir_intrinsic_shuffle_xor:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
lower_bool_ops(nir_builder *b, nir_intrinsic_instr *intrin, void *_unused)
|
||||
{
|
||||
if (!needs_bool_widening(intrin))
|
||||
return false;
|
||||
|
||||
if (intrin->def.bit_size != 1)
|
||||
return false;
|
||||
|
||||
b->cursor = nir_before_instr(&intrin->instr);
|
||||
nir_def *widen = nir_b2i32(b, intrin->src[0].ssa);
|
||||
nir_src_rewrite(&intrin->src[0], widen);
|
||||
intrin->def.bit_size = 32;
|
||||
b->cursor = nir_after_instr(&intrin->instr);
|
||||
nir_def *narrow = nir_b2b1(b, &intrin->def);
|
||||
nir_def_rewrite_uses_after(&intrin->def, narrow);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
lower(nir_builder *b, nir_intrinsic_instr *intr, void *data)
|
||||
{
|
||||
b->cursor = nir_before_instr(&intr->instr);
|
||||
|
||||
switch (intr->intrinsic) {
|
||||
case nir_intrinsic_vote_any: {
|
||||
/* We don't have vote instructions, but we have efficient ballots */
|
||||
nir_def *ballot = nir_ballot(b, 1, 32, intr->src[0].ssa);
|
||||
nir_def_rewrite_uses(&intr->def, nir_ine_imm(b, ballot, 0));
|
||||
return true;
|
||||
}
|
||||
|
||||
case nir_intrinsic_vote_all: {
|
||||
nir_def *ballot = nir_ballot(b, 1, 32, nir_inot(b, intr->src[0].ssa));
|
||||
nir_def_rewrite_uses(&intr->def, nir_ieq_imm(b, ballot, 0));
|
||||
return true;
|
||||
}
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
msl_nir_lower_subgroups(nir_shader *nir)
|
||||
{
|
||||
const nir_lower_subgroups_options subgroups_options = {
|
||||
.subgroup_size = 32,
|
||||
.ballot_bit_size = 32,
|
||||
.ballot_components = 1,
|
||||
.lower_subgroup_masks = true,
|
||||
.lower_vote_ieq = true,
|
||||
.lower_vote_feq = true,
|
||||
.lower_vote_bool_eq = true,
|
||||
.lower_inverse_ballot = true,
|
||||
.lower_relative_shuffle = true,
|
||||
.lower_quad = true,
|
||||
.lower_reduce = true,
|
||||
};
|
||||
NIR_PASS(_, nir, nir_lower_subgroups, &subgroups_options);
|
||||
NIR_PASS(_, nir, nir_shader_intrinsics_pass, lower,
|
||||
nir_metadata_control_flow, NULL);
|
||||
NIR_PASS(_, nir, nir_shader_intrinsics_pass, lower_bool_ops,
|
||||
nir_metadata_control_flow, NULL);
|
||||
}
|
||||
77
src/kosmickrisp/compiler/msl_private.h
Normal file
77
src/kosmickrisp/compiler/msl_private.h
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "util/string_buffer.h"
|
||||
#include "nir.h"
|
||||
|
||||
struct io_slot_info {
|
||||
nir_alu_type type;
|
||||
uint32_t interpolation;
|
||||
unsigned num_components;
|
||||
bool centroid;
|
||||
bool sample;
|
||||
};
|
||||
|
||||
struct nir_to_msl_ctx {
|
||||
FILE *output;
|
||||
struct hash_table *types;
|
||||
nir_shader *shader;
|
||||
struct _mesa_string_buffer *text;
|
||||
unsigned short indentlevel;
|
||||
struct io_slot_info inputs_info[NUM_TOTAL_VARYING_SLOTS];
|
||||
struct io_slot_info outputs_info[NUM_TOTAL_VARYING_SLOTS];
|
||||
};
|
||||
|
||||
#define P_IND(ctx, ...) \
|
||||
do { \
|
||||
for (unsigned i = 0; i < (ctx)->indentlevel; i++) \
|
||||
_mesa_string_buffer_append((ctx)->text, " "); \
|
||||
_mesa_string_buffer_printf((ctx)->text, __VA_ARGS__); \
|
||||
} while (0);
|
||||
|
||||
#define P(ctx, ...) _mesa_string_buffer_printf((ctx)->text, __VA_ARGS__);
|
||||
|
||||
#define P_INDENT(ctx) \
|
||||
do { \
|
||||
for (unsigned i = 0; i < (ctx)->indentlevel; i++) \
|
||||
_mesa_string_buffer_append((ctx)->text, " "); \
|
||||
} while (0)
|
||||
|
||||
/* Perform type inference. The returned value is a
|
||||
* map from nir_def* to base type.*/
|
||||
|
||||
struct hash_table *msl_infer_types(nir_shader *shader);
|
||||
|
||||
const char *msl_type_for_def(struct hash_table *types, nir_def *def);
|
||||
|
||||
const char *msl_uint_type(uint8_t bit_size, uint8_t num_components);
|
||||
|
||||
const char *msl_type_for_src(struct hash_table *types, nir_src *src);
|
||||
|
||||
const char *msl_bitcast_for_src(struct hash_table *types, nir_src *src);
|
||||
|
||||
void msl_src_as_const(struct nir_to_msl_ctx *ctx, nir_src *src);
|
||||
|
||||
void msl_emit_io_blocks(struct nir_to_msl_ctx *ctx, nir_shader *shader);
|
||||
|
||||
void msl_emit_output_var(struct nir_to_msl_ctx *ctx, nir_shader *shader);
|
||||
|
||||
void msl_gather_io_info(struct nir_to_msl_ctx *ctx,
|
||||
struct io_slot_info *info_array_input,
|
||||
struct io_slot_info *info_array_output);
|
||||
|
||||
const char *msl_input_name(struct nir_to_msl_ctx *ctx, unsigned location);
|
||||
|
||||
const char *msl_output_name(struct nir_to_msl_ctx *ctx, unsigned location);
|
||||
|
||||
bool msl_src_is_float(struct nir_to_msl_ctx *ctx, nir_src *src);
|
||||
bool msl_def_is_sampler(struct nir_to_msl_ctx *ctx, nir_def *def);
|
||||
|
||||
void msl_nir_lower_subgroups(nir_shader *nir);
|
||||
|
||||
bool msl_nir_lower_algebraic_late(nir_shader *shader);
|
||||
857
src/kosmickrisp/compiler/msl_type_inference.c
Normal file
857
src/kosmickrisp/compiler/msl_type_inference.c
Normal file
|
|
@ -0,0 +1,857 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "vulkan/vulkan_core.h"
|
||||
#include "msl_private.h"
|
||||
|
||||
typedef enum ti_type {
|
||||
/* We haven't been able to assign a type yet */
|
||||
TYPE_NONE = 0,
|
||||
/* All we know is that this is used in I/O, we
|
||||
* can treat it as an opaque value (i.e. uint) */
|
||||
TYPE_GENERIC_DATA,
|
||||
/* A generic int used in ALU operations but also can a bool for bitwise ops */
|
||||
TYPE_GENERIC_INT_OR_BOOL,
|
||||
/* A generic int used in ALU operations that can be int or uint */
|
||||
TYPE_GENERIC_INT,
|
||||
/* These are actual concrete types. */
|
||||
TYPE_INT,
|
||||
TYPE_UINT,
|
||||
TYPE_BOOL,
|
||||
TYPE_FLOAT,
|
||||
TYPE_SAMPLER,
|
||||
} ti_type;
|
||||
|
||||
static ti_type
|
||||
unify_types(ti_type t1, ti_type t2)
|
||||
{
|
||||
ti_type generic = MIN2(t1, t2);
|
||||
ti_type specific = MAX2(t1, t2);
|
||||
if (t1 == t2)
|
||||
return TYPE_NONE;
|
||||
// NONE or GENERIC_DATA can be upgraded into any concrete type
|
||||
if (generic == TYPE_GENERIC_DATA || generic == TYPE_NONE)
|
||||
return specific;
|
||||
if ((generic == TYPE_GENERIC_INT_OR_BOOL) &&
|
||||
((specific == TYPE_INT) || (specific == TYPE_UINT) ||
|
||||
(specific == TYPE_BOOL)))
|
||||
return specific;
|
||||
if ((generic == TYPE_GENERIC_INT) &&
|
||||
((specific == TYPE_INT) || (specific == TYPE_UINT)))
|
||||
return specific;
|
||||
return TYPE_NONE;
|
||||
}
|
||||
|
||||
static ti_type
|
||||
ti_type_from_nir(nir_alu_type nir_type)
|
||||
{
|
||||
switch (nir_alu_type_get_base_type(nir_type)) {
|
||||
case nir_type_int:
|
||||
return TYPE_INT;
|
||||
case nir_type_uint:
|
||||
return TYPE_UINT;
|
||||
case nir_type_float:
|
||||
return TYPE_FLOAT;
|
||||
case nir_type_bool:
|
||||
return TYPE_BOOL;
|
||||
default:
|
||||
assert(0);
|
||||
return TYPE_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
static ti_type
|
||||
ti_type_from_pipe_format(enum pipe_format format)
|
||||
{
|
||||
switch (format) {
|
||||
case PIPE_FORMAT_R16_FLOAT:
|
||||
case PIPE_FORMAT_R32_FLOAT:
|
||||
return TYPE_FLOAT;
|
||||
case PIPE_FORMAT_R8_UINT:
|
||||
case PIPE_FORMAT_R16_UINT:
|
||||
case PIPE_FORMAT_R32_UINT:
|
||||
case PIPE_FORMAT_R64_UINT:
|
||||
return TYPE_UINT;
|
||||
case PIPE_FORMAT_R8_SINT:
|
||||
case PIPE_FORMAT_R16_SINT:
|
||||
case PIPE_FORMAT_R32_SINT:
|
||||
case PIPE_FORMAT_R64_SINT:
|
||||
return TYPE_INT;
|
||||
default:
|
||||
assert(0);
|
||||
return 0u;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
set_type(struct hash_table *types, void *key, ti_type type)
|
||||
{
|
||||
// convert nir_type
|
||||
_mesa_hash_table_insert(types, key, (void *)type);
|
||||
}
|
||||
|
||||
static ti_type
|
||||
get_type(struct hash_table *types, void *key)
|
||||
{
|
||||
struct hash_entry *entry = _mesa_hash_table_search(types, key);
|
||||
if (!entry)
|
||||
return TYPE_NONE;
|
||||
return (ti_type)(intptr_t)(entry->data);
|
||||
}
|
||||
|
||||
static bool
|
||||
update_instr_type(struct hash_table *types, nir_instr *instr, ti_type type)
|
||||
{
|
||||
if (instr->type == nir_instr_type_alu) {
|
||||
nir_alu_instr *alu = nir_instr_as_alu(instr);
|
||||
switch (alu->op) {
|
||||
case nir_op_iadd:
|
||||
case nir_op_isub:
|
||||
case nir_op_ishl:
|
||||
case nir_op_iand:
|
||||
case nir_op_ior:
|
||||
case nir_op_ixor:
|
||||
set_type(types, &alu->def, type);
|
||||
set_type(types, &alu->src[0].src, type);
|
||||
set_type(types, &alu->src[1].src, type);
|
||||
return true;
|
||||
case nir_op_inot:
|
||||
set_type(types, &alu->def, type);
|
||||
set_type(types, &alu->src[0].src, type);
|
||||
return true;
|
||||
case nir_op_ieq:
|
||||
case nir_op_ine:
|
||||
set_type(types, &alu->src[0].src, type);
|
||||
set_type(types, &alu->src[1].src, type);
|
||||
return true;
|
||||
case nir_op_bcsel:
|
||||
set_type(types, &alu->def, type);
|
||||
set_type(types, &alu->src[1].src, type);
|
||||
set_type(types, &alu->src[2].src, type);
|
||||
return true;
|
||||
case nir_op_mov:
|
||||
case nir_op_vec2:
|
||||
case nir_op_vec3:
|
||||
case nir_op_vec4:
|
||||
set_type(types, &alu->def, type);
|
||||
for (int i = 0; i < nir_op_infos[alu->op].num_inputs; i++)
|
||||
set_type(types, &alu->src[i].src, type);
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
} else if (instr->type == nir_instr_type_intrinsic) {
|
||||
nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
|
||||
nir_intrinsic_info info = nir_intrinsic_infos[intr->intrinsic];
|
||||
switch (intr->intrinsic) {
|
||||
case nir_intrinsic_load_reg:
|
||||
set_type(types, &intr->def, type);
|
||||
set_type(types, &intr->src[0], type);
|
||||
return true;
|
||||
case nir_intrinsic_store_reg:
|
||||
set_type(types, &intr->src[0], type);
|
||||
set_type(types, &intr->src[1], type);
|
||||
return true;
|
||||
case nir_intrinsic_decl_reg:
|
||||
set_type(types, &intr->def, type);
|
||||
return true;
|
||||
case nir_intrinsic_load_global:
|
||||
case nir_intrinsic_load_global_constant:
|
||||
case nir_intrinsic_load_global_constant_bounded:
|
||||
case nir_intrinsic_load_global_constant_offset:
|
||||
case nir_intrinsic_load_push_constant:
|
||||
set_type(types, &intr->def, type);
|
||||
return true;
|
||||
/* Scratch and shared are always UINT */
|
||||
case nir_intrinsic_load_scratch:
|
||||
case nir_intrinsic_store_scratch:
|
||||
case nir_intrinsic_load_shared:
|
||||
case nir_intrinsic_store_shared:
|
||||
return false;
|
||||
case nir_intrinsic_store_global:
|
||||
set_type(types, &intr->src[0], type);
|
||||
return true;
|
||||
case nir_intrinsic_read_first_invocation:
|
||||
case nir_intrinsic_read_invocation:
|
||||
case nir_intrinsic_quad_broadcast:
|
||||
case nir_intrinsic_quad_swap_horizontal:
|
||||
case nir_intrinsic_quad_swap_vertical:
|
||||
case nir_intrinsic_quad_swap_diagonal:
|
||||
case nir_intrinsic_shuffle:
|
||||
case nir_intrinsic_shuffle_down:
|
||||
case nir_intrinsic_shuffle_up:
|
||||
case nir_intrinsic_shuffle_xor:
|
||||
set_type(types, &intr->src[0], type);
|
||||
set_type(types, &intr->def, type);
|
||||
return true;
|
||||
default:
|
||||
if (info.has_dest && info.num_srcs == 0) {
|
||||
set_type(types, &intr->def, type);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
infer_types_from_alu(struct hash_table *types, nir_alu_instr *alu)
|
||||
{
|
||||
// for most types, we infer the type from the nir_op_info,
|
||||
// but some ALU instructions are the same for int and uint. Those
|
||||
// have their sources and defs get marked by TYPE_GENERIC_INT.
|
||||
switch (alu->op) {
|
||||
case nir_op_iadd:
|
||||
case nir_op_isub:
|
||||
case nir_op_ishl:
|
||||
// (N, N) -> N
|
||||
set_type(types, &alu->def, TYPE_GENERIC_INT);
|
||||
set_type(types, &alu->src[0].src, TYPE_GENERIC_INT);
|
||||
set_type(types, &alu->src[1].src, TYPE_GENERIC_INT);
|
||||
break;
|
||||
case nir_op_iand:
|
||||
case nir_op_ior:
|
||||
case nir_op_ixor:
|
||||
set_type(types, &alu->def, TYPE_GENERIC_INT_OR_BOOL);
|
||||
set_type(types, &alu->src[0].src, TYPE_GENERIC_INT_OR_BOOL);
|
||||
set_type(types, &alu->src[1].src, TYPE_GENERIC_INT_OR_BOOL);
|
||||
break;
|
||||
case nir_op_inot:
|
||||
// N -> N
|
||||
set_type(types, &alu->def, TYPE_GENERIC_INT_OR_BOOL);
|
||||
set_type(types, &alu->src[0].src, TYPE_GENERIC_INT_OR_BOOL);
|
||||
break;
|
||||
case nir_op_ieq:
|
||||
case nir_op_ine:
|
||||
// (N, N) -> bool
|
||||
set_type(types, &alu->def, TYPE_BOOL);
|
||||
set_type(types, &alu->src[0].src, TYPE_GENERIC_INT_OR_BOOL);
|
||||
set_type(types, &alu->src[1].src, TYPE_GENERIC_INT_OR_BOOL);
|
||||
break;
|
||||
case nir_op_bcsel:
|
||||
// (bool, T, T) -> T
|
||||
set_type(types, &alu->def, TYPE_GENERIC_DATA);
|
||||
set_type(types, &alu->src[0].src, TYPE_BOOL);
|
||||
set_type(types, &alu->src[1].src, TYPE_GENERIC_DATA);
|
||||
set_type(types, &alu->src[2].src, TYPE_GENERIC_DATA);
|
||||
break;
|
||||
// These don't provide any type information, we rely on type propagation
|
||||
// to fill in the type data
|
||||
case nir_op_mov:
|
||||
case nir_op_vec2:
|
||||
case nir_op_vec3:
|
||||
case nir_op_vec4:
|
||||
break;
|
||||
/* We don't have 32-bit width boolean, those are uints. */
|
||||
case nir_op_b2b32:
|
||||
set_type(types, &alu->def, TYPE_UINT);
|
||||
set_type(types, &alu->src[0].src, TYPE_UINT);
|
||||
break;
|
||||
|
||||
default: {
|
||||
// set type for def
|
||||
const nir_op_info *info = &nir_op_infos[alu->op];
|
||||
set_type(types, &alu->def, ti_type_from_nir(info->output_type));
|
||||
for (int i = 0; i < info->num_inputs; i++) {
|
||||
// set type for src
|
||||
set_type(types, &alu->src[i].src,
|
||||
ti_type_from_nir(info->input_types[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
infer_types_from_intrinsic(struct hash_table *types, nir_intrinsic_instr *instr)
|
||||
{
|
||||
switch (instr->intrinsic) {
|
||||
case nir_intrinsic_load_input:
|
||||
case nir_intrinsic_load_interpolated_input:
|
||||
case nir_intrinsic_load_output: {
|
||||
ti_type ty = ti_type_from_nir(nir_intrinsic_dest_type(instr));
|
||||
set_type(types, &instr->def, ty);
|
||||
break;
|
||||
}
|
||||
case nir_intrinsic_load_global_constant:
|
||||
set_type(types, &instr->def, TYPE_GENERIC_DATA);
|
||||
set_type(types, &instr->src[0], TYPE_UINT);
|
||||
break;
|
||||
case nir_intrinsic_load_global_constant_bounded:
|
||||
set_type(types, &instr->def, TYPE_GENERIC_DATA);
|
||||
set_type(types, &instr->src[0], TYPE_UINT);
|
||||
set_type(types, &instr->src[1], TYPE_UINT);
|
||||
set_type(types, &instr->src[2], TYPE_UINT);
|
||||
break;
|
||||
case nir_intrinsic_load_global_constant_offset:
|
||||
set_type(types, &instr->def, TYPE_GENERIC_DATA);
|
||||
set_type(types, &instr->src[0], TYPE_UINT);
|
||||
set_type(types, &instr->src[1], TYPE_UINT);
|
||||
break;
|
||||
case nir_intrinsic_load_global:
|
||||
case nir_intrinsic_load_push_constant:
|
||||
set_type(types, &instr->def, TYPE_GENERIC_DATA);
|
||||
set_type(types, &instr->src[0], TYPE_UINT);
|
||||
break;
|
||||
|
||||
case nir_intrinsic_global_atomic:
|
||||
case nir_intrinsic_global_atomic_swap:
|
||||
case nir_intrinsic_shared_atomic:
|
||||
case nir_intrinsic_shared_atomic_swap: {
|
||||
ti_type type =
|
||||
ti_type_from_nir(nir_atomic_op_type(nir_intrinsic_atomic_op(instr)));
|
||||
set_type(types, &instr->def, type);
|
||||
set_type(types, &instr->src[0], TYPE_UINT);
|
||||
set_type(types, &instr->src[1], type);
|
||||
set_type(types, &instr->src[2], type);
|
||||
break;
|
||||
}
|
||||
case nir_intrinsic_store_global:
|
||||
set_type(types, &instr->src[0], TYPE_GENERIC_DATA);
|
||||
set_type(types, &instr->src[1], TYPE_UINT);
|
||||
break;
|
||||
case nir_intrinsic_store_output: {
|
||||
ti_type ty = ti_type_from_nir(nir_intrinsic_src_type(instr));
|
||||
set_type(types, &instr->src[0], ty);
|
||||
break;
|
||||
}
|
||||
case nir_intrinsic_decl_reg:
|
||||
if (nir_intrinsic_bit_size(instr) == 1)
|
||||
set_type(types, &instr->def, TYPE_BOOL);
|
||||
else
|
||||
set_type(types, &instr->def, TYPE_NONE);
|
||||
break;
|
||||
case nir_intrinsic_store_reg:
|
||||
set_type(types, &instr->src[0], TYPE_NONE);
|
||||
set_type(types, &instr->src[1], TYPE_NONE);
|
||||
break;
|
||||
case nir_intrinsic_load_reg:
|
||||
set_type(types, &instr->src[0], TYPE_NONE);
|
||||
set_type(types, &instr->def, TYPE_NONE);
|
||||
break;
|
||||
case nir_intrinsic_load_scratch:
|
||||
case nir_intrinsic_load_shared:
|
||||
set_type(types, &instr->def, TYPE_UINT);
|
||||
set_type(types, &instr->src[0], TYPE_UINT);
|
||||
break;
|
||||
case nir_intrinsic_store_scratch:
|
||||
case nir_intrinsic_store_shared:
|
||||
set_type(types, &instr->src[0], TYPE_UINT);
|
||||
set_type(types, &instr->src[1], TYPE_UINT);
|
||||
break;
|
||||
case nir_intrinsic_load_workgroup_id:
|
||||
case nir_intrinsic_load_subgroup_id:
|
||||
case nir_intrinsic_load_local_invocation_id:
|
||||
case nir_intrinsic_load_global_invocation_id:
|
||||
case nir_intrinsic_load_num_workgroups:
|
||||
case nir_intrinsic_load_num_subgroups:
|
||||
case nir_intrinsic_load_subgroup_size:
|
||||
case nir_intrinsic_load_sample_id:
|
||||
case nir_intrinsic_load_sample_mask:
|
||||
case nir_intrinsic_load_subgroup_invocation:
|
||||
case nir_intrinsic_load_amplification_id_kk:
|
||||
set_type(types, &instr->def, TYPE_UINT);
|
||||
break;
|
||||
case nir_intrinsic_load_vulkan_descriptor:
|
||||
set_type(types, &instr->src[0], TYPE_UINT);
|
||||
set_type(types, &instr->def, TYPE_UINT);
|
||||
break;
|
||||
case nir_intrinsic_load_buffer_ptr_kk:
|
||||
set_type(types, &instr->def, TYPE_UINT);
|
||||
break;
|
||||
// The defs of these instructions don't participate in type inference
|
||||
// but their sources are pointers (i.e. uints).
|
||||
case nir_intrinsic_load_texture_handle_kk:
|
||||
case nir_intrinsic_load_depth_texture_kk:
|
||||
set_type(types, &instr->src[0], TYPE_UINT);
|
||||
break;
|
||||
case nir_intrinsic_load_sampler_handle_kk:
|
||||
set_type(types, &instr->def, TYPE_SAMPLER);
|
||||
break;
|
||||
case nir_intrinsic_ddx:
|
||||
case nir_intrinsic_ddy:
|
||||
case nir_intrinsic_ddx_coarse:
|
||||
case nir_intrinsic_ddy_coarse:
|
||||
case nir_intrinsic_ddx_fine:
|
||||
case nir_intrinsic_ddy_fine:
|
||||
set_type(types, &instr->src[0], TYPE_FLOAT);
|
||||
set_type(types, &instr->def, TYPE_FLOAT);
|
||||
break;
|
||||
case nir_intrinsic_load_point_coord:
|
||||
set_type(types, &instr->def, TYPE_FLOAT);
|
||||
break;
|
||||
case nir_intrinsic_load_front_face:
|
||||
case nir_intrinsic_elect:
|
||||
case nir_intrinsic_load_helper_invocation:
|
||||
case nir_intrinsic_is_helper_invocation:
|
||||
set_type(types, &instr->def, TYPE_BOOL);
|
||||
break;
|
||||
case nir_intrinsic_load_constant_agx:
|
||||
set_type(types, &instr->src[0], TYPE_UINT);
|
||||
set_type(types, &instr->src[1], TYPE_UINT);
|
||||
set_type(types, &instr->def,
|
||||
ti_type_from_pipe_format(nir_intrinsic_format(instr)));
|
||||
break;
|
||||
case nir_intrinsic_bindless_image_load:
|
||||
set_type(types, &instr->def,
|
||||
ti_type_from_nir(nir_intrinsic_dest_type(instr)));
|
||||
set_type(types, &instr->src[1], TYPE_UINT); // coords
|
||||
set_type(types, &instr->src[3], TYPE_UINT); // level
|
||||
break;
|
||||
case nir_intrinsic_bindless_image_store:
|
||||
set_type(types, &instr->src[1], TYPE_UINT); // coords
|
||||
set_type(types, &instr->src[3],
|
||||
ti_type_from_nir(nir_intrinsic_src_type(instr)));
|
||||
set_type(types, &instr->src[4], TYPE_UINT); // level
|
||||
break;
|
||||
case nir_intrinsic_demote_if:
|
||||
case nir_intrinsic_terminate_if:
|
||||
set_type(types, &instr->src[0], TYPE_BOOL);
|
||||
break;
|
||||
case nir_intrinsic_bindless_image_atomic:
|
||||
case nir_intrinsic_bindless_image_atomic_swap: {
|
||||
set_type(types, &instr->src[1], TYPE_UINT); // coords
|
||||
set_type(types, &instr->src[2], TYPE_UINT); // level
|
||||
ti_type type =
|
||||
ti_type_from_nir(nir_atomic_op_type(nir_intrinsic_atomic_op(instr)));
|
||||
set_type(types, &instr->src[3], type);
|
||||
if (instr->intrinsic == nir_intrinsic_bindless_image_atomic_swap)
|
||||
set_type(types, &instr->src[4], type);
|
||||
set_type(types, &instr->def, type);
|
||||
break;
|
||||
}
|
||||
case nir_intrinsic_ballot:
|
||||
set_type(types, &instr->src[0], TYPE_BOOL);
|
||||
set_type(types, &instr->def, TYPE_UINT);
|
||||
break;
|
||||
case nir_intrinsic_vote_all:
|
||||
case nir_intrinsic_vote_any:
|
||||
set_type(types, &instr->src[0], TYPE_BOOL);
|
||||
set_type(types, &instr->def, TYPE_BOOL);
|
||||
break;
|
||||
case nir_intrinsic_read_first_invocation:
|
||||
case nir_intrinsic_quad_swap_horizontal:
|
||||
case nir_intrinsic_quad_swap_vertical:
|
||||
case nir_intrinsic_quad_swap_diagonal:
|
||||
set_type(types, &instr->src[0], TYPE_GENERIC_DATA);
|
||||
set_type(types, &instr->def, TYPE_GENERIC_DATA);
|
||||
break;
|
||||
case nir_intrinsic_read_invocation:
|
||||
case nir_intrinsic_quad_broadcast:
|
||||
case nir_intrinsic_shuffle:
|
||||
case nir_intrinsic_shuffle_down:
|
||||
case nir_intrinsic_shuffle_up:
|
||||
case nir_intrinsic_shuffle_xor:
|
||||
set_type(types, &instr->src[0], TYPE_GENERIC_DATA);
|
||||
set_type(types, &instr->def, TYPE_GENERIC_DATA);
|
||||
set_type(types, &instr->src[1], TYPE_UINT);
|
||||
break;
|
||||
case nir_intrinsic_reduce:
|
||||
switch (nir_intrinsic_reduction_op(instr)) {
|
||||
case nir_op_iand:
|
||||
case nir_op_ior:
|
||||
case nir_op_ixor:
|
||||
case nir_op_iadd:
|
||||
case nir_op_imul:
|
||||
set_type(types, &instr->src[0], TYPE_GENERIC_INT);
|
||||
set_type(types, &instr->def, TYPE_GENERIC_INT);
|
||||
break;
|
||||
case nir_op_imax:
|
||||
case nir_op_imin:
|
||||
set_type(types, &instr->src[0], TYPE_INT);
|
||||
set_type(types, &instr->def, TYPE_INT);
|
||||
break;
|
||||
case nir_op_umax:
|
||||
case nir_op_umin:
|
||||
set_type(types, &instr->src[0], TYPE_UINT);
|
||||
set_type(types, &instr->def, TYPE_UINT);
|
||||
break;
|
||||
case nir_op_fadd:
|
||||
case nir_op_fmax:
|
||||
case nir_op_fmin:
|
||||
case nir_op_fmul:
|
||||
set_type(types, &instr->src[0], TYPE_FLOAT);
|
||||
set_type(types, &instr->def, TYPE_FLOAT);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
infer_types_from_tex(struct hash_table *types, nir_tex_instr *tex)
|
||||
{
|
||||
set_type(types, &tex->def, ti_type_from_nir(tex->dest_type));
|
||||
for (int i = 0; i < tex->num_srcs; i++) {
|
||||
nir_src *src = &tex->src[i].src;
|
||||
switch (tex->src[i].src_type) {
|
||||
case nir_tex_src_coord:
|
||||
if (tex->op == nir_texop_txf || tex->op == nir_texop_txf_ms)
|
||||
set_type(types, src, TYPE_UINT);
|
||||
else
|
||||
set_type(types, src, TYPE_FLOAT);
|
||||
break;
|
||||
case nir_tex_src_comparator:
|
||||
set_type(types, src, TYPE_FLOAT);
|
||||
break;
|
||||
case nir_tex_src_offset:
|
||||
set_type(types, src, TYPE_INT);
|
||||
break;
|
||||
case nir_tex_src_bias:
|
||||
set_type(types, src, TYPE_FLOAT);
|
||||
break;
|
||||
case nir_tex_src_lod:
|
||||
if (tex->op == nir_texop_txf || tex->op == nir_texop_txf_ms ||
|
||||
tex->op == nir_texop_txs)
|
||||
set_type(types, src, TYPE_UINT);
|
||||
else
|
||||
set_type(types, src, TYPE_FLOAT);
|
||||
break;
|
||||
case nir_tex_src_min_lod:
|
||||
set_type(types, src, TYPE_FLOAT);
|
||||
break;
|
||||
case nir_tex_src_ms_index:
|
||||
set_type(types, src, TYPE_UINT);
|
||||
break;
|
||||
case nir_tex_src_ddx:
|
||||
case nir_tex_src_ddy:
|
||||
set_type(types, src, TYPE_FLOAT);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
infer_types_from_instr(struct hash_table *types, nir_instr *instr)
|
||||
{
|
||||
switch (instr->type) {
|
||||
case nir_instr_type_alu:
|
||||
infer_types_from_alu(types, nir_instr_as_alu(instr));
|
||||
return;
|
||||
case nir_instr_type_intrinsic:
|
||||
infer_types_from_intrinsic(types, nir_instr_as_intrinsic(instr));
|
||||
return;
|
||||
case nir_instr_type_tex:
|
||||
infer_types_from_tex(types, nir_instr_as_tex(instr));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
propagate_types(struct hash_table *types, nir_instr *instr)
|
||||
{
|
||||
bool progress = false;
|
||||
switch (instr->type) {
|
||||
case nir_instr_type_alu: {
|
||||
nir_alu_instr *alu = nir_instr_as_alu(instr);
|
||||
nir_op_info info = nir_op_infos[alu->op];
|
||||
for (int i = 0; i < info.num_inputs; i++) {
|
||||
ti_type src_type = get_type(types, &alu->src[i].src);
|
||||
ti_type def_type = get_type(types, alu->src[i].src.ssa);
|
||||
ti_type unified_type = unify_types(src_type, def_type);
|
||||
nir_instr *parent_instr = alu->src[i].src.ssa->parent_instr;
|
||||
if (unified_type > src_type) {
|
||||
progress |= update_instr_type(types, instr, unified_type);
|
||||
} else if (unified_type > def_type) {
|
||||
progress |= update_instr_type(types, parent_instr, unified_type);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case nir_instr_type_intrinsic: {
|
||||
nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
|
||||
nir_intrinsic_info info = nir_intrinsic_infos[intr->intrinsic];
|
||||
for (int i = 0; i < info.num_srcs; i++) {
|
||||
ti_type src_type = get_type(types, &intr->src[i]);
|
||||
ti_type def_type = get_type(types, intr->src[i].ssa);
|
||||
ti_type unified_type = unify_types(src_type, def_type);
|
||||
nir_instr *parent_instr = intr->src[i].ssa->parent_instr;
|
||||
if (unified_type > src_type) {
|
||||
progress |= update_instr_type(types, instr, unified_type);
|
||||
} else if (unified_type > def_type) {
|
||||
progress |= update_instr_type(types, parent_instr, unified_type);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case nir_instr_type_tex: {
|
||||
nir_tex_instr *tex = nir_instr_as_tex(instr);
|
||||
for (int i = 0; i < tex->num_srcs; i++) {
|
||||
ti_type src_type = get_type(types, &tex->src[i].src);
|
||||
ti_type def_type = get_type(types, tex->src[i].src.ssa);
|
||||
ti_type unified_type = unify_types(src_type, def_type);
|
||||
if (src_type == 0)
|
||||
continue;
|
||||
nir_instr *parent_instr = tex->src[i].src.ssa->parent_instr;
|
||||
if (unified_type > def_type) {
|
||||
progress |= update_instr_type(types, parent_instr, unified_type);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return progress;
|
||||
}
|
||||
|
||||
static const char *float_names[] = {"float", "float2", "float3", "float4"};
|
||||
static const char *half_names[] = {"half", "half2", "half3", "half4"};
|
||||
static const char *bool_names[] = {"bool", "bool2", "bool3", "bool4"};
|
||||
static const char *int8_names[] = {"char", "char2", "char3", "char4"};
|
||||
static const char *uint8_names[] = {"uchar", "uchar2", "uchar3", "uchar4"};
|
||||
static const char *int16_names[] = {"short", "short2", "short3", "short4"};
|
||||
static const char *uint16_names[] = {"ushort", "ushort2", "ushort3", "ushort4"};
|
||||
static const char *int32_names[] = {"int", "int2", "int3", "int4"};
|
||||
static const char *uint32_names[] = {"uint", "uint2", "uint3", "uint4"};
|
||||
static const char *int64_names[] = {"long", "long2", "long3", "long4"};
|
||||
static const char *uint64_names[] = {"ulong", "ulong2", "ulong3", "ulong4"};
|
||||
|
||||
static const char *
|
||||
ti_type_to_msl_type(ti_type type, uint8_t bit_width, uint8_t num_components)
|
||||
{
|
||||
switch (type) {
|
||||
case TYPE_GENERIC_DATA:
|
||||
case TYPE_GENERIC_INT:
|
||||
case TYPE_GENERIC_INT_OR_BOOL:
|
||||
case TYPE_UINT:
|
||||
switch (bit_width) {
|
||||
case 1:
|
||||
return bool_names[num_components - 1];
|
||||
case 8:
|
||||
return uint8_names[num_components - 1];
|
||||
case 16:
|
||||
return uint16_names[num_components - 1];
|
||||
case 32:
|
||||
return uint32_names[num_components - 1];
|
||||
case 64:
|
||||
return uint64_names[num_components - 1];
|
||||
default:
|
||||
assert(!"Bad uint length");
|
||||
}
|
||||
break;
|
||||
case TYPE_BOOL:
|
||||
return bool_names[num_components - 1];
|
||||
case TYPE_INT:
|
||||
switch (bit_width) {
|
||||
case 8:
|
||||
return int8_names[num_components - 1];
|
||||
case 16:
|
||||
return int16_names[num_components - 1];
|
||||
case 32:
|
||||
return int32_names[num_components - 1];
|
||||
case 64:
|
||||
return int64_names[num_components - 1];
|
||||
default:
|
||||
assert(!"Bad uint length");
|
||||
}
|
||||
break;
|
||||
case TYPE_FLOAT:
|
||||
switch (bit_width) {
|
||||
case 16:
|
||||
return half_names[num_components - 1];
|
||||
case 32:
|
||||
return float_names[num_components - 1];
|
||||
default:
|
||||
assert(!"Bad float length");
|
||||
}
|
||||
break;
|
||||
case TYPE_SAMPLER:
|
||||
return "sampler";
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *
|
||||
msl_uint_type(uint8_t bit_size, uint8_t num_components)
|
||||
{
|
||||
return ti_type_to_msl_type(TYPE_UINT, bit_size, num_components);
|
||||
}
|
||||
|
||||
const char *
|
||||
msl_type_for_def(struct hash_table *types, nir_def *def)
|
||||
{
|
||||
ti_type type = get_type(types, def);
|
||||
return ti_type_to_msl_type(type, def->bit_size, def->num_components);
|
||||
}
|
||||
|
||||
const char *
|
||||
msl_type_for_src(struct hash_table *types, nir_src *src)
|
||||
{
|
||||
ti_type type = get_type(types, src);
|
||||
// This won't necessarily work for alu srcs but for intrinsics it's fine.
|
||||
return ti_type_to_msl_type(type, src->ssa->bit_size,
|
||||
src->ssa->num_components);
|
||||
}
|
||||
|
||||
const char *
|
||||
msl_bitcast_for_src(struct hash_table *types, nir_src *src)
|
||||
{
|
||||
ti_type src_type = get_type(types, src);
|
||||
ti_type def_type = get_type(types, src->ssa);
|
||||
if (nir_src_is_if(src))
|
||||
return NULL;
|
||||
if (src_type != def_type) {
|
||||
/* bool types cannot use as_type casting */
|
||||
if (src_type == TYPE_BOOL || def_type == TYPE_BOOL)
|
||||
return NULL;
|
||||
|
||||
// produce bitcast _into_ src_type
|
||||
return ti_type_to_msl_type(src_type, src->ssa->bit_size,
|
||||
src->ssa->num_components);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
emit_src_component(struct nir_to_msl_ctx *ctx, nir_src *src, unsigned comp)
|
||||
{
|
||||
ti_type type = get_type(ctx->types, src);
|
||||
switch (type) {
|
||||
case TYPE_FLOAT: {
|
||||
double v = nir_src_comp_as_float(*src, comp);
|
||||
if (isinf(v)) {
|
||||
P(ctx, "(INFINITY");
|
||||
} else if (isnan(v)) {
|
||||
P(ctx, "(NAN");
|
||||
} else {
|
||||
/* Building the types explicitly is required since the MSL compiler is
|
||||
* too dumb to understand that "max(as_type<int>(t53), -2147483648)" is
|
||||
* not ambiguous since both are ints and there's no room for longs.
|
||||
* From CTS test:
|
||||
* dEQP-VK.renderpass.suballocation.multisample.r32_sint.samples_2 */
|
||||
if (src->ssa->bit_size == 16) {
|
||||
P(ctx, "half(");
|
||||
} else {
|
||||
P(ctx, "float(");
|
||||
}
|
||||
P(ctx, "%.*le", DBL_DECIMAL_DIG, nir_src_comp_as_float(*src, comp));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TYPE_BOOL:
|
||||
P(ctx, "bool(%d", nir_src_comp_as_bool(*src, comp));
|
||||
break;
|
||||
case TYPE_INT:
|
||||
switch (src->ssa->bit_size) {
|
||||
case 8:
|
||||
P(ctx, "char(");
|
||||
break;
|
||||
case 16:
|
||||
P(ctx, "short(");
|
||||
break;
|
||||
case 32:
|
||||
P(ctx, "int(");
|
||||
break;
|
||||
case 64:
|
||||
P(ctx, "long(");
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE("Incorrect bit_size for TYPE_INT");
|
||||
}
|
||||
P(ctx, "%" PRId64, nir_src_comp_as_int(*src, comp));
|
||||
break;
|
||||
case TYPE_UINT:
|
||||
case TYPE_GENERIC_DATA:
|
||||
case TYPE_GENERIC_INT:
|
||||
case TYPE_GENERIC_INT_OR_BOOL:
|
||||
switch (src->ssa->bit_size) {
|
||||
case 8:
|
||||
P(ctx, "uchar(");
|
||||
break;
|
||||
case 16:
|
||||
P(ctx, "ushort(");
|
||||
break;
|
||||
case 32:
|
||||
P(ctx, "uint(");
|
||||
break;
|
||||
case 64:
|
||||
P(ctx, "ulong(");
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE("Incorrect bit_size for TYPE_UINT");
|
||||
}
|
||||
P(ctx, "%" PRIu64 "u", nir_src_comp_as_uint(*src, comp));
|
||||
break;
|
||||
case TYPE_NONE:
|
||||
assert(0);
|
||||
P(ctx, "UNTYPED!");
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
P(ctx, ")");
|
||||
}
|
||||
|
||||
void
|
||||
msl_src_as_const(struct nir_to_msl_ctx *ctx, nir_src *src)
|
||||
{
|
||||
ti_type type = get_type(ctx->types, src);
|
||||
if (src->ssa->num_components == 1) {
|
||||
emit_src_component(ctx, src, 0);
|
||||
} else {
|
||||
P(ctx, "%s(",
|
||||
ti_type_to_msl_type(type, src->ssa->bit_size,
|
||||
src->ssa->num_components));
|
||||
for (int i = 0; i < src->ssa->num_components; i++) {
|
||||
if (i)
|
||||
P(ctx, ", ");
|
||||
emit_src_component(ctx, src, i);
|
||||
}
|
||||
P(ctx, ")");
|
||||
}
|
||||
}
|
||||
|
||||
struct hash_table *
|
||||
msl_infer_types(nir_shader *shader)
|
||||
{
|
||||
struct hash_table *types = _mesa_pointer_hash_table_create(NULL);
|
||||
bool progress = false;
|
||||
// First, seed the types for every instruction for every source and def
|
||||
nir_foreach_function_impl(impl, shader) {
|
||||
nir_foreach_block(block, impl) {
|
||||
nir_foreach_instr(instr, block) {
|
||||
infer_types_from_instr(types, instr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
progress = false;
|
||||
nir_foreach_function_impl(impl, shader) {
|
||||
nir_foreach_block(block, impl) {
|
||||
nir_foreach_instr(instr, block) {
|
||||
progress |= propagate_types(types, instr);
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (progress);
|
||||
return types;
|
||||
}
|
||||
|
||||
bool
|
||||
msl_src_is_float(struct nir_to_msl_ctx *ctx, nir_src *src)
|
||||
{
|
||||
return get_type(ctx->types, src) == TYPE_FLOAT;
|
||||
}
|
||||
|
||||
bool
|
||||
msl_def_is_sampler(struct nir_to_msl_ctx *ctx, nir_def *def)
|
||||
{
|
||||
return get_type(ctx->types, def) == TYPE_SAMPLER;
|
||||
}
|
||||
2051
src/kosmickrisp/compiler/nir_to_msl.c
Normal file
2051
src/kosmickrisp/compiler/nir_to_msl.c
Normal file
File diff suppressed because it is too large
Load diff
56
src/kosmickrisp/compiler/nir_to_msl.h
Normal file
56
src/kosmickrisp/compiler/nir_to_msl.h
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "nir.h"
|
||||
|
||||
enum pipe_format;
|
||||
|
||||
/* Assumes nir_shader_gather_info has been called beforehand. */
|
||||
char *nir_to_msl(nir_shader *shader, void *mem_ctx);
|
||||
|
||||
/* Call this after all API-specific lowerings. It will bring the NIR out of SSA
|
||||
* at the end */
|
||||
bool msl_optimize_nir(struct nir_shader *nir);
|
||||
|
||||
/* Call this before all API-speicific lowerings, it will */
|
||||
void msl_preprocess_nir(struct nir_shader *nir);
|
||||
|
||||
enum msl_tex_access_flag {
|
||||
MSL_ACCESS_SAMPLE = 0,
|
||||
MSL_ACCESS_READ,
|
||||
MSL_ACCESS_WRITE,
|
||||
MSL_ACCESS_READ_WRITE,
|
||||
};
|
||||
|
||||
static inline enum msl_tex_access_flag
|
||||
msl_convert_access_flag(enum gl_access_qualifier qual)
|
||||
{
|
||||
if (qual & ACCESS_NON_WRITEABLE)
|
||||
return MSL_ACCESS_READ;
|
||||
if (qual & ACCESS_NON_READABLE)
|
||||
return MSL_ACCESS_WRITE;
|
||||
return MSL_ACCESS_READ_WRITE;
|
||||
}
|
||||
|
||||
bool msl_nir_fs_force_output_signedness(
|
||||
nir_shader *nir, enum pipe_format render_target_formats[MAX_DRAW_BUFFERS]);
|
||||
|
||||
bool msl_nir_vs_remove_point_size_write(nir_builder *b,
|
||||
nir_intrinsic_instr *intrin,
|
||||
void *data);
|
||||
|
||||
bool msl_nir_fs_remove_depth_write(nir_builder *b, nir_intrinsic_instr *intrin,
|
||||
void *data);
|
||||
|
||||
bool msl_lower_textures(nir_shader *s);
|
||||
|
||||
bool msl_lower_static_sample_mask(nir_shader *nir, uint32_t sample_mask);
|
||||
bool msl_ensure_depth_write(nir_shader *nir);
|
||||
bool msl_ensure_vertex_position_output(nir_shader *nir);
|
||||
bool msl_nir_sample_mask_type(nir_shader *nir);
|
||||
bool msl_nir_layer_id_type(nir_shader *nir);
|
||||
187
src/kosmickrisp/kosmicomp.c
Normal file
187
src/kosmickrisp/kosmicomp.c
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "compiler/nir_to_msl.h"
|
||||
#include "spirv/nir_spirv.h"
|
||||
|
||||
static int
|
||||
load_spirv(const char *filename, uint32_t **words, size_t *nwords)
|
||||
{
|
||||
const size_t CHUNK_SIZE = 4096;
|
||||
uint32_t buf[CHUNK_SIZE];
|
||||
FILE *input = fopen(filename, "r");
|
||||
if (!input) {
|
||||
fprintf(stderr, "Could not open file %s: %s\n", filename,
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
*nwords = 0;
|
||||
*words = malloc(CHUNK_SIZE * sizeof(buf[0]));
|
||||
size_t read_size;
|
||||
while (1) {
|
||||
read_size = fread(buf, sizeof(buf[0]), CHUNK_SIZE, input);
|
||||
if (read_size == 0)
|
||||
break;
|
||||
*words = realloc(*words, (*nwords + read_size) * sizeof(buf[0]));
|
||||
memcpy(*words + *nwords, buf, sizeof(buf[0]) * read_size);
|
||||
*nwords += read_size;
|
||||
};
|
||||
|
||||
if (*words[0] != 0x07230203) {
|
||||
fprintf(stderr, "%s is not a SPIR-V file?\n", filename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
debug_callback(void *priv, enum nir_spirv_debug_level debuglevel, size_t offset,
|
||||
const char *message)
|
||||
{
|
||||
fprintf(stderr, "<%d> at %ld %s\n", debuglevel, offset, message);
|
||||
}
|
||||
|
||||
static int
|
||||
type_size_vec4(const struct glsl_type *type, bool bindless)
|
||||
{
|
||||
return glsl_count_attribute_slots(type, false);
|
||||
}
|
||||
|
||||
static void
|
||||
shared_var_info(const struct glsl_type *type, unsigned *size, unsigned *align)
|
||||
{
|
||||
assert(glsl_type_is_vector_or_scalar(type));
|
||||
|
||||
uint32_t comp_size =
|
||||
glsl_type_is_boolean(type) ? 4 : glsl_get_bit_size(type) / 8;
|
||||
unsigned length = glsl_get_vector_elements(type);
|
||||
*size = comp_size * length, *align = comp_size;
|
||||
}
|
||||
|
||||
static void
|
||||
optimize(nir_shader *nir)
|
||||
{
|
||||
msl_preprocess_nir(nir);
|
||||
|
||||
NIR_PASS(_, nir, nir_lower_explicit_io, nir_var_mem_push_const,
|
||||
nir_address_format_32bit_offset);
|
||||
NIR_PASS(_, nir, nir_lower_explicit_io,
|
||||
nir_var_mem_global | nir_var_mem_ubo | nir_var_mem_ssbo,
|
||||
nir_address_format_64bit_global);
|
||||
if (nir->info.stage == MESA_SHADER_COMPUTE) {
|
||||
if (!nir->info.shared_memory_explicit_layout) {
|
||||
/* There may be garbage in shared_size, but it's the job of
|
||||
* nir_lower_vars_to_explicit_types to allocate it. We have to reset to
|
||||
* avoid overallocation.
|
||||
*/
|
||||
nir->info.shared_size = 0;
|
||||
|
||||
NIR_PASS(_, nir, nir_lower_vars_to_explicit_types, nir_var_mem_shared,
|
||||
shared_var_info);
|
||||
}
|
||||
NIR_PASS(_, nir, nir_lower_explicit_io, nir_var_mem_shared,
|
||||
nir_address_format_32bit_offset);
|
||||
}
|
||||
|
||||
NIR_PASS(_, nir, nir_lower_io, nir_var_shader_in | nir_var_shader_out,
|
||||
type_size_vec4, (nir_lower_io_options)0);
|
||||
|
||||
NIR_PASS(_, nir, nir_lower_variable_initializers, ~nir_var_function_temp);
|
||||
NIR_PASS(_, nir, nir_remove_dead_variables,
|
||||
nir_var_shader_in | nir_var_shader_out | nir_var_system_value,
|
||||
NULL);
|
||||
NIR_PASS(_, nir, nir_lower_io_vars_to_temporaries,
|
||||
nir_shader_get_entrypoint(nir), true, false);
|
||||
nir_lower_compute_system_values_options options = {
|
||||
.has_base_global_invocation_id = 0,
|
||||
};
|
||||
NIR_PASS(_, nir, nir_lower_system_values);
|
||||
NIR_PASS(_, nir, nir_lower_compute_system_values, &options);
|
||||
NIR_PASS(_, nir, nir_lower_global_vars_to_local);
|
||||
NIR_PASS(_, nir, nir_lower_load_const_to_scalar);
|
||||
|
||||
msl_optimize_nir(nir);
|
||||
}
|
||||
|
||||
static mesa_shader_stage
|
||||
stage_from_filename(const char *filename)
|
||||
{
|
||||
struct StageMapping {
|
||||
char *name;
|
||||
mesa_shader_stage stage;
|
||||
};
|
||||
struct StageMapping stage_mappings[] = {
|
||||
{.name = ".frag.", .stage = MESA_SHADER_FRAGMENT},
|
||||
{.name = ".vert.", .stage = MESA_SHADER_VERTEX},
|
||||
{.name = ".comp.", .stage = MESA_SHADER_COMPUTE},
|
||||
};
|
||||
for (int i = 0; i < ARRAY_SIZE(stage_mappings); i++) {
|
||||
if (strstr(filename, stage_mappings[i].name))
|
||||
return stage_mappings[i].stage;
|
||||
}
|
||||
return MESA_SHADER_NONE;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "Usage: kosmicomp filename.spv\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// read file
|
||||
size_t nwords = 0;
|
||||
uint32_t *words = NULL;
|
||||
int result = load_spirv(argv[1], &words, &nwords);
|
||||
if (result == -1) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
// run spirv_to_nir
|
||||
struct spirv_to_nir_options options = {
|
||||
.environment = NIR_SPIRV_VULKAN,
|
||||
.debug =
|
||||
{
|
||||
.func = &debug_callback,
|
||||
.private_data = NULL,
|
||||
},
|
||||
.ubo_addr_format = nir_address_format_64bit_global,
|
||||
.ssbo_addr_format = nir_address_format_64bit_global,
|
||||
.phys_ssbo_addr_format = nir_address_format_64bit_global,
|
||||
};
|
||||
glsl_type_singleton_init_or_ref();
|
||||
struct nir_shader_compiler_options nir_options = {
|
||||
.lower_fdph = 1,
|
||||
};
|
||||
mesa_shader_stage stage = stage_from_filename(argv[1]);
|
||||
if (stage == MESA_SHADER_NONE) {
|
||||
fprintf(stderr, "Couldn't guess shader stage from %s\n", argv[1]);
|
||||
return 4;
|
||||
}
|
||||
nir_shader *shader = spirv_to_nir(words, nwords, NULL, 0, stage, "main",
|
||||
&options, &nir_options);
|
||||
if (!shader) {
|
||||
fprintf(stderr, "Compilation failed!\n");
|
||||
return 3;
|
||||
}
|
||||
// print nir
|
||||
nir_print_shader(shader, stdout);
|
||||
optimize(shader);
|
||||
nir_print_shader(shader, stdout);
|
||||
|
||||
char *msl_text = nir_to_msl(shader, shader);
|
||||
|
||||
fputs(msl_text, stdout);
|
||||
|
||||
ralloc_free(msl_text);
|
||||
|
||||
return 0;
|
||||
}
|
||||
16
src/kosmickrisp/meson.build
Normal file
16
src/kosmickrisp/meson.build
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
# Copyright 2025 LunarG, Inc.
|
||||
# Copyright 2025 Google LLC
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
subdir('bridge')
|
||||
subdir('compiler')
|
||||
subdir('util')
|
||||
subdir('vulkan')
|
||||
|
||||
executable(
|
||||
'kosmicomp',
|
||||
files('kosmicomp.c'),
|
||||
dependencies : [idep_nir, idep_vtn, idep_vulkan_runtime_headers, idep_vulkan_util_headers],
|
||||
link_with: [libkk],
|
||||
link_args: ['-Wl,-undefined,dynamic_lookup'],
|
||||
)
|
||||
195
src/kosmickrisp/util/kk_dispatch_trampolines_gen.py
Normal file
195
src/kosmickrisp/util/kk_dispatch_trampolines_gen.py
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
# coding=utf-8
|
||||
COPYRIGHT = """\
|
||||
/*
|
||||
* Copyright 2020 Intel Corporation
|
||||
* Copyright 2025 LunarG, Inc
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sub license, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial portions
|
||||
* of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
|
||||
* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
|
||||
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import os
|
||||
|
||||
from mako.template import Template
|
||||
|
||||
# Mesa-local imports must be declared in meson variable
|
||||
# '{file_without_suffix}_depend_files'.
|
||||
from vk_entrypoints import get_entrypoints_from_xml
|
||||
|
||||
TEMPLATE_H = Template(COPYRIGHT + """\
|
||||
/* This file generated from ${filename}, don't edit directly. */
|
||||
|
||||
#ifndef VK_DISPATCH_TRAMPOLINES_H
|
||||
#define VK_DISPATCH_TRAMPOLINES_H
|
||||
|
||||
#include "vk_dispatch_table.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern struct vk_physical_device_dispatch_table kk_physical_device_trampolines;
|
||||
extern struct vk_device_dispatch_table kk_device_trampolines;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* VK_DISPATCH_TRAMPOLINES_H */
|
||||
""")
|
||||
|
||||
TEMPLATE_C = Template(COPYRIGHT + """\
|
||||
/* This file generated from ${filename}, don't edit directly. */
|
||||
|
||||
#include "kk_device.h"
|
||||
#include "kk_dispatch_trampolines.h"
|
||||
#include "vk_object.h"
|
||||
#include "vk_physical_device.h"
|
||||
|
||||
% for e in entrypoints:
|
||||
% if not e.is_physical_device_entrypoint() or e.alias:
|
||||
<% continue %>
|
||||
% endif
|
||||
% if e.guard is not None:
|
||||
#ifdef ${e.guard}
|
||||
% endif
|
||||
static VKAPI_ATTR ${e.return_type} VKAPI_CALL
|
||||
${e.prefixed_name('kk_tramp')}(${e.decl_params()})
|
||||
{
|
||||
<% assert e.params[0].type == 'VkPhysicalDevice' %>
|
||||
VK_FROM_HANDLE(vk_physical_device, vk_physical_device, ${e.params[0].name});
|
||||
% if e.return_type == 'void':
|
||||
vk_physical_device->dispatch_table.${e.name}(${e.call_params()});
|
||||
% else:
|
||||
return vk_physical_device->dispatch_table.${e.name}(${e.call_params()});
|
||||
% endif
|
||||
}
|
||||
% if e.guard is not None:
|
||||
#endif
|
||||
% endif
|
||||
% endfor
|
||||
|
||||
struct vk_physical_device_dispatch_table kk_physical_device_trampolines = {
|
||||
% for e in entrypoints:
|
||||
% if not e.is_physical_device_entrypoint() or e.alias:
|
||||
<% continue %>
|
||||
% endif
|
||||
% if e.guard is not None:
|
||||
#ifdef ${e.guard}
|
||||
% endif
|
||||
.${e.name} = ${e.prefixed_name('kk_tramp')},
|
||||
% if e.guard is not None:
|
||||
#endif
|
||||
% endif
|
||||
% endfor
|
||||
};
|
||||
|
||||
% for e in entrypoints:
|
||||
% if not e.is_device_entrypoint() or e.alias:
|
||||
<% continue %>
|
||||
% endif
|
||||
% if e.guard is not None:
|
||||
#ifdef ${e.guard}
|
||||
% endif
|
||||
static VKAPI_ATTR ${e.return_type} VKAPI_CALL
|
||||
${e.prefixed_name('kk_tramp')}(${e.decl_params()})
|
||||
{
|
||||
% if e.params[0].type == 'VkDevice':
|
||||
VK_FROM_HANDLE(kk_device, kk_device, ${e.params[0].name});
|
||||
% if e.return_type == 'void':
|
||||
kk_device->exposed_dispatch_table.${e.name}(${e.call_params()});
|
||||
% else:
|
||||
return kk_device->exposed_dispatch_table.${e.name}(${e.call_params()});
|
||||
% endif
|
||||
% elif e.params[0].type in ('VkCommandBuffer', 'VkQueue'):
|
||||
struct vk_object_base *vk_object = (struct vk_object_base *)${e.params[0].name};
|
||||
struct kk_device *kk_device = container_of(vk_object->device, struct kk_device, vk);
|
||||
% if e.return_type == 'void':
|
||||
kk_device->exposed_dispatch_table.${e.name}(${e.call_params()});
|
||||
% else:
|
||||
return kk_device->exposed_dispatch_table.${e.name}(${e.call_params()});
|
||||
% endif
|
||||
% else:
|
||||
assert(!"Unhandled device child trampoline case: ${e.params[0].type}");
|
||||
% endif
|
||||
}
|
||||
% if e.guard is not None:
|
||||
#endif
|
||||
% endif
|
||||
% endfor
|
||||
|
||||
struct vk_device_dispatch_table kk_device_trampolines = {
|
||||
% for e in entrypoints:
|
||||
% if not e.is_device_entrypoint() or e.alias:
|
||||
<% continue %>
|
||||
% endif
|
||||
% if e.guard is not None:
|
||||
#ifdef ${e.guard}
|
||||
% endif
|
||||
.${e.name} = ${e.prefixed_name('kk_tramp')},
|
||||
% if e.guard is not None:
|
||||
#endif
|
||||
% endif
|
||||
% endfor
|
||||
};
|
||||
""")
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--out-c', help='Output C file.')
|
||||
parser.add_argument('--out-h', help='Output H file.')
|
||||
parser.add_argument('--beta', required=True, help='Enable beta extensions.')
|
||||
parser.add_argument('--xml',
|
||||
help='Vulkan API XML file.',
|
||||
required=True,
|
||||
action='append',
|
||||
dest='xml_files')
|
||||
args = parser.parse_args()
|
||||
|
||||
entrypoints = get_entrypoints_from_xml(args.xml_files, args.beta)
|
||||
|
||||
# For outputting entrypoints.h we generate a anv_EntryPoint() prototype
|
||||
# per entry point.
|
||||
try:
|
||||
if args.out_h:
|
||||
with open(args.out_h, 'w', encoding='utf-8') as f:
|
||||
f.write(TEMPLATE_H.render(entrypoints=entrypoints,
|
||||
filename=os.path.basename(__file__)))
|
||||
if args.out_c:
|
||||
with open(args.out_c, 'w', encoding='utf-8') as f:
|
||||
f.write(TEMPLATE_C.render(entrypoints=entrypoints,
|
||||
filename=os.path.basename(__file__)))
|
||||
except Exception:
|
||||
# In the event there's an error, this imports some helpers from mako
|
||||
# to print a useful stack trace and prints it, then exits with
|
||||
# status 1, if python is run with debug; otherwise it just raises
|
||||
# the exception
|
||||
if __debug__:
|
||||
import sys
|
||||
from mako import exceptions
|
||||
sys.stderr.write(exceptions.text_error_template().render() + '\n')
|
||||
sys.exit(1)
|
||||
raise
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
16
src/kosmickrisp/util/meson.build
Normal file
16
src/kosmickrisp/util/meson.build
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
# Copyright © 2025 LunarG, Inc
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
kk_dispatch_trampolines_gen = files('kk_dispatch_trampolines_gen.py')
|
||||
|
||||
kk_dispatch_trampolines = custom_target(
|
||||
'kk_dispatch_trampolines',
|
||||
input : [kk_dispatch_trampolines_gen, vk_api_xml],
|
||||
output : ['kk_dispatch_trampolines.c', 'kk_dispatch_trampolines.h'],
|
||||
command : [
|
||||
prog_python, '@INPUT0@', '--xml', '@INPUT1@',
|
||||
'--out-c', '@OUTPUT0@', '--out-h', '@OUTPUT1@',
|
||||
'--beta', with_vulkan_beta.to_string()
|
||||
],
|
||||
depend_files : vk_dispatch_trampolines_gen_depend_files,
|
||||
)
|
||||
147
src/kosmickrisp/util/vk_entrypoints.py
Normal file
147
src/kosmickrisp/util/vk_entrypoints.py
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
# Copyright 2020 Intel Corporation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a
|
||||
# copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sub license, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice (including the
|
||||
# next paragraph) shall be included in all copies or substantial portions
|
||||
# of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
|
||||
# IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
|
||||
# ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import xml.etree.ElementTree as et
|
||||
|
||||
from collections import OrderedDict, namedtuple
|
||||
|
||||
# Mesa-local imports must be declared in meson variable
|
||||
# '{file_without_suffix}_depend_files'.
|
||||
from vk_extensions import get_all_required, filter_api
|
||||
|
||||
EntrypointParam = namedtuple('EntrypointParam', 'type name decl len')
|
||||
|
||||
class EntrypointBase:
|
||||
def __init__(self, name):
|
||||
assert name.startswith('vk')
|
||||
self.name = name[2:]
|
||||
self.alias = None
|
||||
self.guard = None
|
||||
self.entry_table_index = None
|
||||
# Extensions which require this entrypoint
|
||||
self.core_version = None
|
||||
self.extensions = []
|
||||
|
||||
def prefixed_name(self, prefix):
|
||||
return prefix + '_' + self.name
|
||||
|
||||
class Entrypoint(EntrypointBase):
|
||||
def __init__(self, name, return_type, params):
|
||||
super(Entrypoint, self).__init__(name)
|
||||
self.return_type = return_type
|
||||
self.params = params
|
||||
self.guard = None
|
||||
self.aliases = []
|
||||
self.disp_table_index = None
|
||||
|
||||
def is_physical_device_entrypoint(self):
|
||||
return self.params[0].type in ('VkPhysicalDevice', )
|
||||
|
||||
def is_device_entrypoint(self):
|
||||
return self.params[0].type in ('VkDevice', 'VkCommandBuffer', 'VkQueue')
|
||||
|
||||
def decl_params(self, start=0):
|
||||
return ', '.join(p.decl for p in self.params[start:])
|
||||
|
||||
def call_params(self, start=0):
|
||||
return ', '.join(p.name for p in self.params[start:])
|
||||
|
||||
class EntrypointAlias(EntrypointBase):
|
||||
def __init__(self, name, entrypoint):
|
||||
super(EntrypointAlias, self).__init__(name)
|
||||
self.alias = entrypoint
|
||||
entrypoint.aliases.append(self)
|
||||
|
||||
def is_physical_device_entrypoint(self):
|
||||
return self.alias.is_physical_device_entrypoint()
|
||||
|
||||
def is_device_entrypoint(self):
|
||||
return self.alias.is_device_entrypoint()
|
||||
|
||||
def prefixed_name(self, prefix):
|
||||
return self.alias.prefixed_name(prefix)
|
||||
|
||||
@property
|
||||
def params(self):
|
||||
return self.alias.params
|
||||
|
||||
@property
|
||||
def return_type(self):
|
||||
return self.alias.return_type
|
||||
|
||||
@property
|
||||
def disp_table_index(self):
|
||||
return self.alias.disp_table_index
|
||||
|
||||
def decl_params(self):
|
||||
return self.alias.decl_params()
|
||||
|
||||
def call_params(self):
|
||||
return self.alias.call_params()
|
||||
|
||||
def get_entrypoints(doc, api, beta):
|
||||
"""Extract the entry points from the registry."""
|
||||
entrypoints = OrderedDict()
|
||||
|
||||
required = get_all_required(doc, 'command', api, beta)
|
||||
|
||||
for command in doc.findall('./commands/command'):
|
||||
if not filter_api(command, api):
|
||||
continue
|
||||
|
||||
if 'alias' in command.attrib:
|
||||
name = command.attrib['name']
|
||||
target = command.attrib['alias']
|
||||
e = EntrypointAlias(name, entrypoints[target])
|
||||
else:
|
||||
name = command.find('./proto/name').text
|
||||
ret_type = command.find('./proto/type').text
|
||||
params = [EntrypointParam(
|
||||
type=p.find('./type').text,
|
||||
name=p.find('./name').text,
|
||||
decl=''.join(p.itertext()),
|
||||
len=p.attrib.get('altlen', p.attrib.get('len', None))
|
||||
) for p in command.findall('./param') if filter_api(p, api)]
|
||||
# They really need to be unique
|
||||
e = Entrypoint(name, ret_type, params)
|
||||
|
||||
if name not in required:
|
||||
continue
|
||||
|
||||
r = required[name]
|
||||
e.core_version = r.core_version
|
||||
e.extensions = r.extensions
|
||||
e.guard = r.guard
|
||||
|
||||
assert name not in entrypoints, name
|
||||
entrypoints[name] = e
|
||||
|
||||
return entrypoints.values()
|
||||
|
||||
def get_entrypoints_from_xml(xml_files, beta, api='vulkan'):
|
||||
entrypoints = []
|
||||
|
||||
for filename in xml_files:
|
||||
doc = et.parse(filename)
|
||||
entrypoints += get_entrypoints(doc, api, beta)
|
||||
|
||||
return entrypoints
|
||||
371
src/kosmickrisp/util/vk_extensions.py
Normal file
371
src/kosmickrisp/util/vk_extensions.py
Normal file
|
|
@ -0,0 +1,371 @@
|
|||
import copy
|
||||
import re
|
||||
import xml.etree.ElementTree as et
|
||||
|
||||
def get_api_list(s):
|
||||
apis = []
|
||||
for a in s.split(','):
|
||||
if a == 'disabled':
|
||||
continue
|
||||
assert a in ('vulkan', 'vulkansc')
|
||||
apis.append(a)
|
||||
return apis
|
||||
|
||||
class Extension:
|
||||
def __init__(self, name, number, ext_version):
|
||||
self.name = name
|
||||
self.type = None
|
||||
self.number = number
|
||||
self.platform = None
|
||||
self.provisional = False
|
||||
self.ext_version = int(ext_version)
|
||||
self.supported = []
|
||||
|
||||
def from_xml(ext_elem):
|
||||
name = ext_elem.attrib['name']
|
||||
number = int(ext_elem.attrib['number'])
|
||||
supported = get_api_list(ext_elem.attrib['supported'])
|
||||
if name == 'VK_ANDROID_native_buffer':
|
||||
assert not supported
|
||||
supported = ['vulkan']
|
||||
|
||||
if not supported:
|
||||
return Extension(name, number, 0)
|
||||
|
||||
version = None
|
||||
for enum_elem in ext_elem.findall('.require/enum'):
|
||||
if enum_elem.attrib['name'].endswith('_SPEC_VERSION'):
|
||||
# Skip alias SPEC_VERSIONs
|
||||
if 'value' in enum_elem.attrib:
|
||||
assert version is None
|
||||
version = int(enum_elem.attrib['value'])
|
||||
|
||||
assert version is not None
|
||||
ext = Extension(name, number, version)
|
||||
ext.type = ext_elem.attrib['type']
|
||||
ext.platform = ext_elem.attrib.get('platform', None)
|
||||
ext.provisional = ext_elem.attrib.get('provisional', False)
|
||||
ext.supported = supported
|
||||
|
||||
return ext
|
||||
|
||||
def c_android_condition(self):
|
||||
# if it's an EXT or vendor extension, it's allowed
|
||||
if not self.name.startswith(ANDROID_EXTENSION_WHITELIST_PREFIXES):
|
||||
return 'true'
|
||||
|
||||
allowed_version = ALLOWED_ANDROID_VERSION.get(self.name, None)
|
||||
if allowed_version is None:
|
||||
return 'false'
|
||||
|
||||
return 'ANDROID_API_LEVEL >= %d' % (allowed_version)
|
||||
|
||||
class ApiVersion:
|
||||
def __init__(self, version):
|
||||
self.version = version
|
||||
|
||||
class VkVersion:
|
||||
def __init__(self, string):
|
||||
split = string.split('.')
|
||||
self.major = int(split[0])
|
||||
self.minor = int(split[1])
|
||||
if len(split) > 2:
|
||||
assert len(split) == 3
|
||||
self.patch = int(split[2])
|
||||
else:
|
||||
self.patch = None
|
||||
|
||||
# Sanity check. The range bits are required by the definition of the
|
||||
# VK_MAKE_VERSION macro
|
||||
assert self.major < 1024 and self.minor < 1024
|
||||
assert self.patch is None or self.patch < 4096
|
||||
assert str(self) == string
|
||||
|
||||
def __str__(self):
|
||||
ver_list = [str(self.major), str(self.minor)]
|
||||
if self.patch is not None:
|
||||
ver_list.append(str(self.patch))
|
||||
return '.'.join(ver_list)
|
||||
|
||||
def c_vk_version(self):
|
||||
ver_list = [str(self.major), str(self.minor), str(self.patch or 0)]
|
||||
return 'VK_MAKE_VERSION(' + ', '.join(ver_list) + ')'
|
||||
|
||||
def __int_ver(self):
|
||||
# This is just an expansion of VK_VERSION
|
||||
return (self.major << 22) | (self.minor << 12) | (self.patch or 0)
|
||||
|
||||
def __gt__(self, other):
|
||||
# If only one of them has a patch version, "ignore" it by making
|
||||
# other's patch version match self.
|
||||
if (self.patch is None) != (other.patch is None):
|
||||
other = copy.copy(other)
|
||||
other.patch = self.patch
|
||||
|
||||
return self.__int_ver() > other.__int_ver()
|
||||
|
||||
# Sort the extension list the way we expect: KHR, then EXT, then vendors
|
||||
# alphabetically. For digits, read them as a whole number sort that.
|
||||
# eg.: VK_KHR_8bit_storage < VK_KHR_16bit_storage < VK_EXT_acquire_xlib_display
|
||||
def extension_order(ext):
|
||||
order = []
|
||||
for substring in re.split('(KHR|EXT|[0-9]+)', ext.name):
|
||||
if substring == 'KHR':
|
||||
order.append(1)
|
||||
if substring == 'EXT':
|
||||
order.append(2)
|
||||
elif substring.isdigit():
|
||||
order.append(int(substring))
|
||||
else:
|
||||
order.append(substring)
|
||||
return order
|
||||
|
||||
def get_all_exts_from_xml(xml, api='vulkan'):
|
||||
""" Get a list of all Vulkan extensions. """
|
||||
|
||||
xml = et.parse(xml)
|
||||
|
||||
extensions = []
|
||||
for ext_elem in xml.findall('.extensions/extension'):
|
||||
ext = Extension.from_xml(ext_elem)
|
||||
if api in ext.supported:
|
||||
extensions.append(ext)
|
||||
|
||||
return sorted(extensions, key=extension_order)
|
||||
|
||||
def init_exts_from_xml(xml, extensions, platform_defines):
|
||||
""" Walk the Vulkan XML and fill out extra extension information. """
|
||||
|
||||
xml = et.parse(xml)
|
||||
|
||||
ext_name_map = {}
|
||||
for ext in extensions:
|
||||
ext_name_map[ext.name] = ext
|
||||
|
||||
# KHR_display is missing from the list.
|
||||
platform_defines.append('VK_USE_PLATFORM_DISPLAY_KHR')
|
||||
for platform in xml.findall('./platforms/platform'):
|
||||
platform_defines.append(platform.attrib['protect'])
|
||||
|
||||
for ext_elem in xml.findall('.extensions/extension'):
|
||||
ext_name = ext_elem.attrib['name']
|
||||
if ext_name not in ext_name_map:
|
||||
continue
|
||||
|
||||
ext = ext_name_map[ext_name]
|
||||
ext.type = ext_elem.attrib['type']
|
||||
|
||||
class Requirements:
|
||||
def __init__(self, core_version=None):
|
||||
self.core_version = core_version
|
||||
self.extensions = []
|
||||
self.guard = None
|
||||
|
||||
def add_extension(self, ext):
|
||||
for e in self.extensions:
|
||||
if e == ext:
|
||||
return;
|
||||
assert e.name != ext.name
|
||||
|
||||
self.extensions.append(ext)
|
||||
|
||||
def filter_api(elem, api):
|
||||
if 'api' not in elem.attrib:
|
||||
return True
|
||||
|
||||
return api in elem.attrib['api'].split(',')
|
||||
|
||||
def get_alias(aliases, name):
|
||||
if name in aliases:
|
||||
# in case the spec registry adds an alias chain later
|
||||
return get_alias(aliases, aliases[name])
|
||||
return name
|
||||
|
||||
def get_all_required(xml, thing, api, beta):
|
||||
things = {}
|
||||
aliases = {}
|
||||
for struct in xml.findall('./types/type[@category="struct"][@alias]'):
|
||||
if not filter_api(struct, api):
|
||||
continue
|
||||
|
||||
name = struct.attrib['name']
|
||||
alias = struct.attrib['alias']
|
||||
aliases[name] = alias
|
||||
|
||||
for feature in xml.findall('./feature'):
|
||||
if not filter_api(feature, api):
|
||||
continue
|
||||
|
||||
version = VkVersion(feature.attrib['number'])
|
||||
for t in feature.findall('./require/' + thing):
|
||||
name = t.attrib['name']
|
||||
assert name not in things
|
||||
things[name] = Requirements(core_version=version)
|
||||
|
||||
for extension in xml.findall('.extensions/extension'):
|
||||
ext = Extension.from_xml(extension)
|
||||
if api not in ext.supported:
|
||||
continue
|
||||
|
||||
if beta != 'true' and ext.provisional:
|
||||
continue
|
||||
|
||||
for require in extension.findall('./require'):
|
||||
if not filter_api(require, api):
|
||||
continue
|
||||
|
||||
for t in require.findall('./' + thing):
|
||||
name = get_alias(aliases, t.attrib['name'])
|
||||
r = things.setdefault(name, Requirements())
|
||||
r.add_extension(ext)
|
||||
|
||||
platform_defines = {}
|
||||
for platform in xml.findall('./platforms/platform'):
|
||||
name = platform.attrib['name']
|
||||
define = platform.attrib['protect']
|
||||
platform_defines[name] = define
|
||||
|
||||
for req in things.values():
|
||||
if req.core_version is not None:
|
||||
continue
|
||||
|
||||
for ext in req.extensions:
|
||||
if ext.platform in platform_defines:
|
||||
req.guard = platform_defines[ext.platform]
|
||||
break
|
||||
|
||||
return things
|
||||
|
||||
# Mapping between extension name and the android version in which the extension
|
||||
# was whitelisted in Android CTS's dEQP-VK.info.device_extensions and
|
||||
# dEQP-VK.api.info.android.no_unknown_extensions, excluding those blocked by
|
||||
# android.graphics.cts.VulkanFeaturesTest#testVulkanBlockedExtensions.
|
||||
ALLOWED_ANDROID_VERSION = {
|
||||
# checkInstanceExtensions on oreo-cts-release
|
||||
"VK_KHR_surface": 26,
|
||||
"VK_KHR_display": 26,
|
||||
"VK_KHR_android_surface": 26,
|
||||
"VK_KHR_mir_surface": 26,
|
||||
"VK_KHR_wayland_surface": 26,
|
||||
"VK_KHR_win32_surface": 26,
|
||||
"VK_KHR_xcb_surface": 26,
|
||||
"VK_KHR_xlib_surface": 26,
|
||||
"VK_KHR_get_physical_device_properties2": 26,
|
||||
"VK_KHR_get_surface_capabilities2": 26,
|
||||
"VK_KHR_external_memory_capabilities": 26,
|
||||
"VK_KHR_external_semaphore_capabilities": 26,
|
||||
"VK_KHR_external_fence_capabilities": 26,
|
||||
# on pie-cts-release
|
||||
"VK_KHR_device_group_creation": 28,
|
||||
"VK_KHR_get_display_properties2": 28,
|
||||
# on android10-tests-release
|
||||
"VK_KHR_surface_protected_capabilities": 29,
|
||||
# on android13-tests-release
|
||||
"VK_KHR_portability_enumeration": 33,
|
||||
|
||||
# checkDeviceExtensions on oreo-cts-release
|
||||
"VK_KHR_swapchain": 26,
|
||||
"VK_KHR_display_swapchain": 26,
|
||||
"VK_KHR_sampler_mirror_clamp_to_edge": 26,
|
||||
"VK_KHR_shader_draw_parameters": 26,
|
||||
"VK_KHR_maintenance1": 26,
|
||||
"VK_KHR_push_descriptor": 26,
|
||||
"VK_KHR_descriptor_update_template": 26,
|
||||
"VK_KHR_incremental_present": 26,
|
||||
"VK_KHR_shared_presentable_image": 26,
|
||||
"VK_KHR_storage_buffer_storage_class": 26,
|
||||
"VK_KHR_16bit_storage": 26,
|
||||
"VK_KHR_get_memory_requirements2": 26,
|
||||
"VK_KHR_external_memory": 26,
|
||||
"VK_KHR_external_memory_fd": 26,
|
||||
"VK_KHR_external_memory_win32": 26,
|
||||
"VK_KHR_external_semaphore": 26,
|
||||
"VK_KHR_external_semaphore_fd": 26,
|
||||
"VK_KHR_external_semaphore_win32": 26,
|
||||
"VK_KHR_external_fence": 26,
|
||||
"VK_KHR_external_fence_fd": 26,
|
||||
"VK_KHR_external_fence_win32": 26,
|
||||
"VK_KHR_win32_keyed_mutex": 26,
|
||||
"VK_KHR_dedicated_allocation": 26,
|
||||
"VK_KHR_variable_pointers": 26,
|
||||
"VK_KHR_relaxed_block_layout": 26,
|
||||
"VK_KHR_bind_memory2": 26,
|
||||
"VK_KHR_maintenance2": 26,
|
||||
"VK_KHR_image_format_list": 26,
|
||||
"VK_KHR_sampler_ycbcr_conversion": 26,
|
||||
# on oreo-mr1-cts-release
|
||||
"VK_KHR_draw_indirect_count": 27,
|
||||
# on pie-cts-release
|
||||
"VK_KHR_device_group": 28,
|
||||
"VK_KHR_multiview": 28,
|
||||
"VK_KHR_maintenance3": 28,
|
||||
"VK_KHR_create_renderpass2": 28,
|
||||
"VK_KHR_driver_properties": 28,
|
||||
# on android10-tests-release
|
||||
"VK_KHR_shader_float_controls": 29,
|
||||
"VK_KHR_shader_float16_int8": 29,
|
||||
"VK_KHR_8bit_storage": 29,
|
||||
"VK_KHR_depth_stencil_resolve": 29,
|
||||
"VK_KHR_swapchain_mutable_format": 29,
|
||||
"VK_KHR_shader_atomic_int64": 29,
|
||||
"VK_KHR_vulkan_memory_model": 29,
|
||||
"VK_KHR_swapchain_mutable_format": 29,
|
||||
"VK_KHR_uniform_buffer_standard_layout": 29,
|
||||
# on android11-tests-release
|
||||
"VK_KHR_imageless_framebuffer": 30,
|
||||
"VK_KHR_shader_subgroup_extended_types": 30,
|
||||
"VK_KHR_buffer_device_address": 30,
|
||||
"VK_KHR_separate_depth_stencil_layouts": 30,
|
||||
"VK_KHR_timeline_semaphore": 30,
|
||||
"VK_KHR_spirv_1_4": 30,
|
||||
"VK_KHR_pipeline_executable_properties": 30,
|
||||
"VK_KHR_shader_clock": 30,
|
||||
# blocked by testVulkanBlockedExtensions
|
||||
# "VK_KHR_performance_query": 30,
|
||||
"VK_KHR_shader_non_semantic_info": 30,
|
||||
"VK_KHR_copy_commands2": 30,
|
||||
# on android12-tests-release
|
||||
"VK_KHR_shader_terminate_invocation": 31,
|
||||
"VK_KHR_ray_tracing_pipeline": 31,
|
||||
"VK_KHR_ray_query": 31,
|
||||
"VK_KHR_acceleration_structure": 31,
|
||||
"VK_KHR_pipeline_library": 31,
|
||||
"VK_KHR_deferred_host_operations": 31,
|
||||
"VK_KHR_fragment_shading_rate": 31,
|
||||
"VK_KHR_zero_initialize_workgroup_memory": 31,
|
||||
"VK_KHR_workgroup_memory_explicit_layout": 31,
|
||||
"VK_KHR_synchronization2": 31,
|
||||
"VK_KHR_shader_integer_dot_product": 31,
|
||||
# on android13-tests-release
|
||||
"VK_KHR_dynamic_rendering": 33,
|
||||
"VK_KHR_format_feature_flags2": 33,
|
||||
"VK_KHR_global_priority": 33,
|
||||
"VK_KHR_maintenance4": 33,
|
||||
"VK_KHR_portability_subset": 33,
|
||||
"VK_KHR_present_id": 33,
|
||||
"VK_KHR_present_wait": 33,
|
||||
"VK_KHR_shader_subgroup_uniform_control_flow": 33,
|
||||
|
||||
# testNoUnknownExtensions on oreo-cts-release
|
||||
"VK_GOOGLE_display_timing": 26,
|
||||
# on pie-cts-release
|
||||
"VK_ANDROID_external_memory_android_hardware_buffer": 28,
|
||||
# on android11-tests-release
|
||||
"VK_GOOGLE_decorate_string": 30,
|
||||
"VK_GOOGLE_hlsl_functionality1": 30,
|
||||
# on android13-tests-release
|
||||
"VK_GOOGLE_surfaceless_query": 33,
|
||||
|
||||
# this HAL extension is always allowed and will be filtered out by the
|
||||
# loader
|
||||
"VK_ANDROID_native_buffer": 26,
|
||||
}
|
||||
|
||||
# Extensions with these prefixes are checked in Android CTS, and thus must be
|
||||
# whitelisted per the preceding dict.
|
||||
ANDROID_EXTENSION_WHITELIST_PREFIXES = (
|
||||
"VK_KHX",
|
||||
"VK_KHR",
|
||||
"VK_GOOGLE",
|
||||
"VK_ANDROID"
|
||||
)
|
||||
50
src/kosmickrisp/vulkan/cl/kk_query.cl
Normal file
50
src/kosmickrisp/vulkan/cl/kk_query.cl
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright © 2022 Collabora Ltd. and Red Hat Inc.
|
||||
* Copyright © 2024 Alyssa Rosenzweig
|
||||
* Copyright © 2024 Valve Corporation
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
#include "compiler/libcl/libcl_vk.h"
|
||||
|
||||
#include "kk_query.h"
|
||||
|
||||
void
|
||||
libkk_write_u64(global struct libkk_imm_write *write_array)
|
||||
{
|
||||
*write_array[cl_group_id.x].address = write_array[cl_group_id.x].value;
|
||||
}
|
||||
|
||||
void
|
||||
libkk_copy_queries(global uint64_t *availability, global uint64_t *results,
|
||||
global uint16_t *oq_index, uint64_t dst_addr,
|
||||
uint64_t dst_stride, uint32_t first_query,
|
||||
VkQueryResultFlagBits flags, uint16_t reports_per_query)
|
||||
{
|
||||
uint index = cl_group_id.x;
|
||||
uint64_t dst = dst_addr + (((uint64_t)index) * dst_stride);
|
||||
uint32_t query = first_query + index;
|
||||
|
||||
bool available;
|
||||
if (availability)
|
||||
available = availability[query];
|
||||
else
|
||||
available = (results[query] != LIBKK_QUERY_UNAVAILABLE);
|
||||
|
||||
if (available || (flags & VK_QUERY_RESULT_PARTIAL_BIT)) {
|
||||
/* For occlusion queries, results[] points to the device global heap. We
|
||||
* need to remap indices according to the query pool's allocation.
|
||||
*/
|
||||
uint result_index = oq_index ? oq_index[query] : query;
|
||||
uint idx = result_index * reports_per_query;
|
||||
|
||||
for (unsigned i = 0; i < reports_per_query; ++i) {
|
||||
vk_write_query(dst, i, flags, results[idx + i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & VK_QUERY_RESULT_WITH_AVAILABILITY_BIT) {
|
||||
vk_write_query(dst, reports_per_query, flags, available);
|
||||
}
|
||||
}
|
||||
21
src/kosmickrisp/vulkan/cl/kk_query.h
Normal file
21
src/kosmickrisp/vulkan/cl/kk_query.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright © 2022 Collabora Ltd. and Red Hat Inc.
|
||||
* Copyright © 2024 Alyssa Rosenzweig
|
||||
* Copyright © 2024 Valve Corporation
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
#ifndef KK_QUERY_H
|
||||
#define KK_QUERY_H
|
||||
|
||||
#include "compiler/libcl/libcl.h"
|
||||
|
||||
struct libkk_imm_write {
|
||||
DEVICE(uint64_t) address;
|
||||
uint64_t value;
|
||||
};
|
||||
|
||||
#define LIBKK_QUERY_UNAVAILABLE (uint64_t)((int64_t)-1)
|
||||
|
||||
#endif /* KK_QUERY_H */
|
||||
283
src/kosmickrisp/vulkan/cl/kk_triangle_fan.cl
Normal file
283
src/kosmickrisp/vulkan/cl/kk_triangle_fan.cl
Normal file
|
|
@ -0,0 +1,283 @@
|
|||
/*
|
||||
* Copyright 2023 Alyssa Rosenzweig
|
||||
* Copyright 2023 Valve Corporation
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
#include "compiler/libcl/libcl_vk.h"
|
||||
#include "compiler/shader_enums.h"
|
||||
|
||||
static uint
|
||||
libkk_vertex_id_for_line_loop(uint prim, uint vert, uint num_prims)
|
||||
{
|
||||
/* (0, 1), (1, 2), (2, 0) */
|
||||
if (prim == (num_prims - 1) && vert == 1)
|
||||
return 0;
|
||||
else
|
||||
return prim + vert;
|
||||
}
|
||||
|
||||
/* Swap the two non-provoking vertices third vert in odd triangles. This
|
||||
* generates a vertex ID list with a consistent winding order.
|
||||
*
|
||||
* With prim and flatshade_first, the map : [0, 1, 2] -> [0, 1, 2] is its own
|
||||
* inverse. This lets us reuse it for both vertex fetch and transform feedback.
|
||||
*/
|
||||
static uint
|
||||
libagx_map_vertex_in_tri_strip(uint prim, uint vert, bool flatshade_first)
|
||||
{
|
||||
unsigned pv = flatshade_first ? 0 : 2;
|
||||
|
||||
bool even = (prim & 1) == 0;
|
||||
bool provoking = vert == pv;
|
||||
|
||||
return (provoking || even) ? vert : ((3 - pv) - vert);
|
||||
}
|
||||
|
||||
static uint
|
||||
libkk_vertex_id_for_tri_fan(uint prim, uint vert, bool flatshade_first)
|
||||
{
|
||||
/* Vulkan spec section 20.1.7 gives (i + 1, i + 2, 0) for a provoking
|
||||
* first. OpenGL instead wants (0, i + 1, i + 2) with a provoking last.
|
||||
* Piglit clipflat expects us to switch between these orders depending on
|
||||
* provoking vertex, to avoid trivializing the fan.
|
||||
*
|
||||
* Rotate accordingly.
|
||||
*/
|
||||
if (flatshade_first) {
|
||||
vert = (vert == 2) ? 0 : (vert + 1);
|
||||
}
|
||||
|
||||
/* The simpler form assuming last is provoking. */
|
||||
return (vert == 0) ? 0 : prim + vert;
|
||||
}
|
||||
|
||||
static uint
|
||||
libkk_vertex_id_for_tri_strip_adj(uint prim, uint vert, uint num_prims,
|
||||
bool flatshade_first)
|
||||
{
|
||||
/* See Vulkan spec section 20.1.11 "Triangle Strips With Adjancency".
|
||||
*
|
||||
* There are different cases for first/middle/last/only primitives and for
|
||||
* odd/even primitives. Determine which case we're in.
|
||||
*/
|
||||
bool last = prim == (num_prims - 1);
|
||||
bool first = prim == 0;
|
||||
bool even = (prim & 1) == 0;
|
||||
bool even_or_first = even || first;
|
||||
|
||||
/* When the last vertex is provoking, we rotate the primitives
|
||||
* accordingly. This seems required for OpenGL.
|
||||
*/
|
||||
if (!flatshade_first && !even_or_first) {
|
||||
vert = (vert + 4u) % 6u;
|
||||
}
|
||||
|
||||
/* Offsets per the spec. The spec lists 6 cases with 6 offsets. Luckily,
|
||||
* there are lots of patterns we can exploit, avoiding a full 6x6 LUT.
|
||||
*
|
||||
* Here we assume the first vertex is provoking, the Vulkan default.
|
||||
*/
|
||||
uint offsets[6] = {
|
||||
0,
|
||||
first ? 1 : (even ? -2 : 3),
|
||||
even_or_first ? 2 : 4,
|
||||
last ? 5 : 6,
|
||||
even_or_first ? 4 : 2,
|
||||
even_or_first ? 3 : -2,
|
||||
};
|
||||
|
||||
/* Ensure NIR can see thru the local array */
|
||||
uint offset = 0;
|
||||
for (uint i = 1; i < 6; ++i) {
|
||||
if (i == vert)
|
||||
offset = offsets[i];
|
||||
}
|
||||
|
||||
/* Finally add to the base of the primitive */
|
||||
return (prim * 2) + offset;
|
||||
}
|
||||
|
||||
static uint
|
||||
vertex_id_for_topology(enum mesa_prim mode, bool flatshade_first, uint prim,
|
||||
uint vert, uint num_prims)
|
||||
{
|
||||
switch (mode) {
|
||||
case MESA_PRIM_POINTS:
|
||||
case MESA_PRIM_LINES:
|
||||
case MESA_PRIM_TRIANGLES:
|
||||
case MESA_PRIM_LINES_ADJACENCY:
|
||||
case MESA_PRIM_TRIANGLES_ADJACENCY:
|
||||
/* Regular primitive: every N vertices defines a primitive */
|
||||
return (prim * mesa_vertices_per_prim(mode)) + vert;
|
||||
|
||||
case MESA_PRIM_LINE_LOOP:
|
||||
return libkk_vertex_id_for_line_loop(prim, vert, num_prims);
|
||||
|
||||
case MESA_PRIM_LINE_STRIP:
|
||||
case MESA_PRIM_LINE_STRIP_ADJACENCY:
|
||||
/* (i, i + 1) or (i, ..., i + 3) */
|
||||
return prim + vert;
|
||||
|
||||
case MESA_PRIM_TRIANGLE_STRIP: {
|
||||
/* Order depends on the provoking vert.
|
||||
*
|
||||
* First: (0, 1, 2), (1, 3, 2), (2, 3, 4).
|
||||
* Last: (0, 1, 2), (2, 1, 3), (2, 3, 4).
|
||||
*
|
||||
* Pull the (maybe swapped) vert from the corresponding primitive
|
||||
*/
|
||||
return prim + libagx_map_vertex_in_tri_strip(prim, vert, flatshade_first);
|
||||
}
|
||||
|
||||
case MESA_PRIM_TRIANGLE_FAN:
|
||||
return libkk_vertex_id_for_tri_fan(prim, vert, flatshade_first);
|
||||
|
||||
case MESA_PRIM_TRIANGLE_STRIP_ADJACENCY:
|
||||
return libkk_vertex_id_for_tri_strip_adj(prim, vert, num_prims,
|
||||
flatshade_first);
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
store_index(global uint8_t *index_buffer, uint index_size_B, uint id,
|
||||
uint value)
|
||||
{
|
||||
global uint32_t *out_32 = (global uint32_t *)index_buffer;
|
||||
global uint16_t *out_16 = (global uint16_t *)index_buffer;
|
||||
global uint8_t *out_8 = (global uint8_t *)index_buffer;
|
||||
|
||||
if (index_size_B == 4)
|
||||
out_32[id] = value;
|
||||
else if (index_size_B == 2)
|
||||
out_16[id] = value;
|
||||
else
|
||||
out_8[id] = value;
|
||||
}
|
||||
|
||||
static uint
|
||||
load_index(constant uint8_t *index_buffer, uint32_t index_buffer_range_el,
|
||||
uint id, uint index_size)
|
||||
{
|
||||
/* We have no index buffer, index is the id */
|
||||
if (index_buffer == 0u)
|
||||
return id;
|
||||
|
||||
/* When no index_buffer is present, index_buffer_range_el is vtx count */
|
||||
bool oob = id >= index_buffer_range_el;
|
||||
|
||||
/* If the load would be out-of-bounds, load the first element which is
|
||||
* assumed valid. If the application index buffer is empty with robustness2,
|
||||
* index_buffer will point to a zero sink where only the first is valid.
|
||||
*/
|
||||
if (oob) {
|
||||
id = 0u;
|
||||
}
|
||||
|
||||
uint el;
|
||||
if (index_size == 1) {
|
||||
el = ((constant uint8_t *)index_buffer)[id];
|
||||
} else if (index_size == 2) {
|
||||
el = ((constant uint16_t *)index_buffer)[id];
|
||||
} else {
|
||||
el = ((constant uint32_t *)index_buffer)[id];
|
||||
}
|
||||
|
||||
/* D3D robustness semantics. TODO: Optimize? */
|
||||
if (oob) {
|
||||
el = 0;
|
||||
}
|
||||
|
||||
return el;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the ID of the first thread in the workgroup where cond is true, or
|
||||
* 1024 if cond is false across the workgroup.
|
||||
*/
|
||||
static uint
|
||||
first_true_thread_in_workgroup(bool cond, local uint *scratch)
|
||||
{
|
||||
barrier(CLK_LOCAL_MEM_FENCE);
|
||||
scratch[get_sub_group_id()] = sub_group_ballot(cond)[0];
|
||||
barrier(CLK_LOCAL_MEM_FENCE);
|
||||
|
||||
uint first_group =
|
||||
ctz(sub_group_ballot(scratch[get_sub_group_local_id()])[0]);
|
||||
uint off = ctz(first_group < 32 ? scratch[first_group] : 0);
|
||||
return (first_group * 32) + off;
|
||||
}
|
||||
|
||||
// TODO_KOSMICKRISP
|
||||
// KERNEL(1024)
|
||||
void
|
||||
libkk_unroll_geometry_and_restart(
|
||||
constant uint8_t *index_buffer, global uint8_t *out_ptr,
|
||||
constant uint32_t *in_draw, global uint32_t *out_draw,
|
||||
uint32_t restart_index, uint32_t index_buffer_size_el, uint32_t in_el_size_B,
|
||||
uint32_t out_el_size_B, uint32_t flatshade_first, uint32_t mode)
|
||||
{
|
||||
uint tid = cl_local_id.x;
|
||||
uint count = in_draw[0];
|
||||
|
||||
constant uint8_t *in_ptr =
|
||||
index_buffer ? index_buffer + (in_draw[2] * in_el_size_B) : index_buffer;
|
||||
|
||||
// local uint scratch[32];
|
||||
|
||||
uint out_prims = 0;
|
||||
uint needle = 0;
|
||||
uint per_prim = mesa_vertices_per_prim(mode);
|
||||
while (needle < count) {
|
||||
/* Search for next restart or the end. Lanes load in parallel. */
|
||||
uint next_restart = needle;
|
||||
for (;;) {
|
||||
uint idx = next_restart + tid;
|
||||
bool restart =
|
||||
idx >= count || load_index(in_ptr, index_buffer_size_el, idx,
|
||||
in_el_size_B) == restart_index;
|
||||
|
||||
// uint next_offs = first_true_thread_in_workgroup(restart, scratch);
|
||||
|
||||
// next_restart += next_offs;
|
||||
// if (next_offs < 1024)
|
||||
// break;
|
||||
if (restart)
|
||||
break;
|
||||
next_restart++;
|
||||
}
|
||||
|
||||
/* Emit up to the next restart. Lanes output in parallel */
|
||||
uint subcount = next_restart - needle;
|
||||
uint subprims = u_decomposed_prims_for_vertices(mode, subcount);
|
||||
uint out_prims_base = out_prims;
|
||||
for (uint i = tid; i < subprims; /*i += 1024*/ ++i) {
|
||||
for (uint vtx = 0; vtx < per_prim; ++vtx) {
|
||||
uint id =
|
||||
vertex_id_for_topology(mode, flatshade_first, i, vtx, subprims);
|
||||
uint offset = needle + id;
|
||||
|
||||
uint x = ((out_prims_base + i) * per_prim) + vtx;
|
||||
uint y =
|
||||
load_index(in_ptr, index_buffer_size_el, offset, in_el_size_B);
|
||||
|
||||
store_index(out_ptr, out_el_size_B, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
out_prims += subprims;
|
||||
needle = next_restart + 1;
|
||||
}
|
||||
|
||||
if (tid == 0) {
|
||||
out_draw[0] = out_prims * per_prim; /* indexCount */
|
||||
out_draw[1] = in_draw[1]; /* instanceCount */
|
||||
out_draw[2] = 0u; /* firstIndex */
|
||||
out_draw[3] = index_buffer ? in_draw[3] : in_draw[2]; /* vertexOffset */
|
||||
out_draw[4] = index_buffer ? in_draw[4] : in_draw[3]; /* firstInstance */
|
||||
}
|
||||
}
|
||||
70
src/kosmickrisp/vulkan/kk_bo.c
Normal file
70
src/kosmickrisp/vulkan/kk_bo.c
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "kk_bo.h"
|
||||
|
||||
#include "kk_device.h"
|
||||
|
||||
#include "kosmickrisp/bridge/mtl_bridge.h"
|
||||
|
||||
#include "util/u_memory.h"
|
||||
|
||||
VkResult
|
||||
kk_alloc_bo(struct kk_device *dev, struct vk_object_base *log_obj,
|
||||
uint64_t size_B, uint64_t align_B, struct kk_bo **bo_out)
|
||||
{
|
||||
VkResult result = VK_SUCCESS;
|
||||
|
||||
// TODO_KOSMICKRISP: Probably requires handling the buffer maximum 256MB
|
||||
uint64_t minimum_alignment = 0u;
|
||||
mtl_heap_buffer_size_and_align_with_length(dev->mtl_handle, &size_B,
|
||||
&minimum_alignment);
|
||||
minimum_alignment = MAX2(minimum_alignment, align_B);
|
||||
size_B = align64(size_B, minimum_alignment);
|
||||
mtl_heap *handle =
|
||||
mtl_new_heap(dev->mtl_handle, size_B, KK_MTL_RESOURCE_OPTIONS);
|
||||
if (handle == NULL) {
|
||||
result = vk_errorf(log_obj, VK_ERROR_OUT_OF_DEVICE_MEMORY, "%m");
|
||||
goto fail_heap;
|
||||
}
|
||||
|
||||
mtl_buffer *map = mtl_new_buffer_with_length(handle, size_B, 0u);
|
||||
if (map == NULL) {
|
||||
result = vk_errorf(log_obj, VK_ERROR_OUT_OF_DEVICE_MEMORY, "%m");
|
||||
goto fail_map;
|
||||
}
|
||||
|
||||
struct kk_bo *bo = CALLOC_STRUCT(kk_bo);
|
||||
|
||||
if (bo == NULL) {
|
||||
result = vk_errorf(log_obj, VK_ERROR_OUT_OF_HOST_MEMORY, "%m");
|
||||
goto fail_alloc;
|
||||
}
|
||||
|
||||
bo->mtl_handle = handle;
|
||||
bo->size_B = size_B;
|
||||
bo->map = map;
|
||||
bo->gpu = mtl_buffer_get_gpu_address(map);
|
||||
bo->cpu = mtl_get_contents(map);
|
||||
|
||||
*bo_out = bo;
|
||||
return result;
|
||||
|
||||
fail_alloc:
|
||||
mtl_release(map);
|
||||
fail_map:
|
||||
mtl_release(handle);
|
||||
fail_heap:
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
kk_destroy_bo(struct kk_device *dev, struct kk_bo *bo)
|
||||
{
|
||||
mtl_release(bo->map);
|
||||
mtl_release(bo->mtl_handle);
|
||||
FREE(bo);
|
||||
}
|
||||
32
src/kosmickrisp/vulkan/kk_bo.h
Normal file
32
src/kosmickrisp/vulkan/kk_bo.h
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright © 2025 LunarG, Inc
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef KK_BO_H
|
||||
#define KK_BO_H 1
|
||||
|
||||
#include "kosmickrisp/bridge/mtl_types.h"
|
||||
|
||||
#include "vulkan/vulkan_core.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
struct kk_device;
|
||||
struct vk_object_base;
|
||||
|
||||
struct kk_bo {
|
||||
mtl_heap *mtl_handle;
|
||||
mtl_buffer *map;
|
||||
uint64_t size_B;
|
||||
uint64_t gpu; // GPU address
|
||||
void *cpu; // CPU address
|
||||
};
|
||||
|
||||
VkResult kk_alloc_bo(struct kk_device *dev, struct vk_object_base *log_obj,
|
||||
uint64_t size_B, uint64_t align_B, struct kk_bo **bo_out);
|
||||
|
||||
void kk_destroy_bo(struct kk_device *dev, struct kk_bo *bo);
|
||||
|
||||
#endif /* KK_BO_H */
|
||||
209
src/kosmickrisp/vulkan/kk_buffer.c
Normal file
209
src/kosmickrisp/vulkan/kk_buffer.c
Normal file
|
|
@ -0,0 +1,209 @@
|
|||
/*
|
||||
* Copyright © 2022 Collabora Ltd. and Red Hat Inc.
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "kk_buffer.h"
|
||||
|
||||
#include "kk_device.h"
|
||||
#include "kk_entrypoints.h"
|
||||
#include "kk_physical_device.h"
|
||||
|
||||
#include "kosmickrisp/bridge/mtl_bridge.h"
|
||||
|
||||
static uint64_t
|
||||
kk_get_buffer_alignment(const struct kk_physical_device *pdev, uint64_t size,
|
||||
VkBufferUsageFlags2KHR usage_flags,
|
||||
VkBufferCreateFlags create_flags)
|
||||
{
|
||||
uint64_t alignment;
|
||||
mtl_heap_buffer_size_and_align_with_length(pdev->mtl_dev_handle, &size,
|
||||
&alignment);
|
||||
|
||||
/** TODO_KOSMICKRISP Metal requires that texel buffers be aligned to the
|
||||
* format they'll use. Since we won't be able to know the format until the
|
||||
* view is created, we should align to the worst case scenario. For this, we
|
||||
* need to request all supported format alignments and take the largest one.
|
||||
*/
|
||||
return alignment;
|
||||
}
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL
|
||||
kk_CreateBuffer(VkDevice device, const VkBufferCreateInfo *pCreateInfo,
|
||||
const VkAllocationCallbacks *pAllocator, VkBuffer *pBuffer)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_device, dev, device);
|
||||
struct kk_buffer *buffer;
|
||||
|
||||
if (pCreateInfo->size > KK_MAX_BUFFER_SIZE)
|
||||
return vk_error(dev, VK_ERROR_OUT_OF_DEVICE_MEMORY);
|
||||
|
||||
buffer =
|
||||
vk_buffer_create(&dev->vk, pCreateInfo, pAllocator, sizeof(*buffer));
|
||||
if (!buffer)
|
||||
return vk_error(dev, VK_ERROR_OUT_OF_HOST_MEMORY);
|
||||
|
||||
*pBuffer = kk_buffer_to_handle(buffer);
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
kk_DestroyBuffer(VkDevice device, VkBuffer _buffer,
|
||||
const VkAllocationCallbacks *pAllocator)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_device, dev, device);
|
||||
VK_FROM_HANDLE(kk_buffer, buffer, _buffer);
|
||||
|
||||
if (!buffer)
|
||||
return;
|
||||
|
||||
if (buffer->mtl_handle)
|
||||
mtl_release(buffer->mtl_handle);
|
||||
|
||||
vk_buffer_destroy(&dev->vk, pAllocator, &buffer->vk);
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
kk_GetDeviceBufferMemoryRequirements(
|
||||
VkDevice device, const VkDeviceBufferMemoryRequirements *pInfo,
|
||||
VkMemoryRequirements2 *pMemoryRequirements)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_device, dev, device);
|
||||
struct kk_physical_device *pdev = kk_device_physical(dev);
|
||||
|
||||
const uint64_t alignment = kk_get_buffer_alignment(
|
||||
pdev, pInfo->pCreateInfo->size, pInfo->pCreateInfo->usage,
|
||||
pInfo->pCreateInfo->flags);
|
||||
|
||||
pMemoryRequirements->memoryRequirements = (VkMemoryRequirements){
|
||||
.size = align64(pInfo->pCreateInfo->size, alignment),
|
||||
.alignment = alignment,
|
||||
.memoryTypeBits = BITFIELD_MASK(pdev->mem_type_count),
|
||||
};
|
||||
|
||||
vk_foreach_struct_const(ext, pMemoryRequirements->pNext) {
|
||||
switch (ext->sType) {
|
||||
case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS: {
|
||||
VkMemoryDedicatedRequirements *dedicated = (void *)ext;
|
||||
dedicated->prefersDedicatedAllocation = false;
|
||||
dedicated->requiresDedicatedAllocation = false;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
vk_debug_ignored_stype(ext->sType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
kk_GetPhysicalDeviceExternalBufferProperties(
|
||||
VkPhysicalDevice physicalDevice,
|
||||
const VkPhysicalDeviceExternalBufferInfo *pExternalBufferInfo,
|
||||
VkExternalBufferProperties *pExternalBufferProperties)
|
||||
{
|
||||
/* The Vulkan 1.3.256 spec says:
|
||||
*
|
||||
* VUID-VkPhysicalDeviceExternalBufferInfo-handleType-parameter
|
||||
*
|
||||
* "handleType must be a valid VkExternalMemoryHandleTypeFlagBits value"
|
||||
*
|
||||
* This differs from VkPhysicalDeviceExternalImageFormatInfo, which
|
||||
* surprisingly permits handleType == 0.
|
||||
*/
|
||||
assert(pExternalBufferInfo->handleType != 0);
|
||||
|
||||
/* All of the current flags are for sparse which we don't support yet.
|
||||
* Even when we do support it, doing sparse on external memory sounds
|
||||
* sketchy. Also, just disallowing flags is the safe option.
|
||||
*/
|
||||
if (pExternalBufferInfo->flags)
|
||||
goto unsupported;
|
||||
|
||||
switch (pExternalBufferInfo->handleType) {
|
||||
case VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLHEAP_BIT_EXT:
|
||||
pExternalBufferProperties->externalMemoryProperties =
|
||||
kk_mtlheap_mem_props;
|
||||
return;
|
||||
default:
|
||||
goto unsupported;
|
||||
}
|
||||
|
||||
unsupported:
|
||||
/* From the Vulkan 1.3.256 spec:
|
||||
*
|
||||
* compatibleHandleTypes must include at least handleType.
|
||||
*/
|
||||
pExternalBufferProperties->externalMemoryProperties =
|
||||
(VkExternalMemoryProperties){
|
||||
.compatibleHandleTypes = pExternalBufferInfo->handleType,
|
||||
};
|
||||
}
|
||||
|
||||
static VkResult
|
||||
kk_bind_buffer_memory(struct kk_device *dev, const VkBindBufferMemoryInfo *info)
|
||||
{
|
||||
// Do the actual memory binding
|
||||
VK_FROM_HANDLE(kk_device_memory, mem, info->memory);
|
||||
VK_FROM_HANDLE(kk_buffer, buffer, info->buffer);
|
||||
|
||||
buffer->mtl_handle = mtl_new_buffer_with_length(
|
||||
mem->bo->mtl_handle, buffer->vk.size, info->memoryOffset);
|
||||
buffer->vk.device_address = mtl_buffer_get_gpu_address(buffer->mtl_handle);
|
||||
/* We need Metal to give us a CPU mapping so it correctly captures the
|
||||
* data in the GPU debugger... */
|
||||
mtl_get_contents(buffer->mtl_handle);
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL
|
||||
kk_BindBufferMemory2(VkDevice device, uint32_t bindInfoCount,
|
||||
const VkBindBufferMemoryInfo *pBindInfos)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_device, dev, device);
|
||||
VkResult first_error_or_success = VK_SUCCESS;
|
||||
|
||||
for (uint32_t i = 0; i < bindInfoCount; ++i) {
|
||||
VkResult result = kk_bind_buffer_memory(dev, &pBindInfos[i]);
|
||||
|
||||
const VkBindMemoryStatusKHR *status =
|
||||
vk_find_struct_const(pBindInfos[i].pNext, BIND_MEMORY_STATUS_KHR);
|
||||
if (status != NULL && status->pResult != NULL)
|
||||
*status->pResult = result;
|
||||
|
||||
if (first_error_or_success == VK_SUCCESS)
|
||||
first_error_or_success = result;
|
||||
}
|
||||
|
||||
return first_error_or_success;
|
||||
}
|
||||
|
||||
VKAPI_ATTR VkDeviceAddress VKAPI_CALL
|
||||
kk_GetBufferDeviceAddress(UNUSED VkDevice device,
|
||||
const VkBufferDeviceAddressInfo *pInfo)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_buffer, buffer, pInfo->buffer);
|
||||
|
||||
return vk_buffer_address(&buffer->vk, 0);
|
||||
}
|
||||
|
||||
VKAPI_ATTR uint64_t VKAPI_CALL
|
||||
kk_GetBufferOpaqueCaptureAddress(UNUSED VkDevice device,
|
||||
const VkBufferDeviceAddressInfo *pInfo)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_buffer, buffer, pInfo->buffer);
|
||||
|
||||
return vk_buffer_address(&buffer->vk, 0);
|
||||
}
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL
|
||||
kk_GetBufferOpaqueCaptureDescriptorDataEXT(
|
||||
VkDevice device, const VkBufferCaptureDescriptorDataInfoEXT *pInfo,
|
||||
void *pData)
|
||||
{
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
48
src/kosmickrisp/vulkan/kk_buffer.h
Normal file
48
src/kosmickrisp/vulkan/kk_buffer.h
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright © 2022 Collabora Ltd. and Red Hat Inc.
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef KK_BUFFER_H
|
||||
#define KK_BUFFER_H 1
|
||||
|
||||
#include "kk_device_memory.h"
|
||||
#include "kk_private.h"
|
||||
|
||||
#include "kosmickrisp/bridge/mtl_types.h"
|
||||
|
||||
#include "vk_buffer.h"
|
||||
|
||||
struct kk_buffer {
|
||||
struct vk_buffer vk;
|
||||
mtl_buffer *mtl_handle;
|
||||
};
|
||||
|
||||
VK_DEFINE_NONDISP_HANDLE_CASTS(kk_buffer, vk.base, VkBuffer,
|
||||
VK_OBJECT_TYPE_BUFFER)
|
||||
|
||||
static inline struct kk_addr_range
|
||||
kk_buffer_addr_range(const struct kk_buffer *buffer, uint64_t offset,
|
||||
uint64_t range)
|
||||
{
|
||||
if (buffer == NULL)
|
||||
return (struct kk_addr_range){.range = 0};
|
||||
|
||||
return (struct kk_addr_range){
|
||||
.addr = vk_buffer_address(&buffer->vk, offset),
|
||||
.range = vk_buffer_range(&buffer->vk, offset, range),
|
||||
};
|
||||
}
|
||||
|
||||
static inline mtl_resource *
|
||||
kk_buffer_to_mtl_resource(const struct kk_buffer *buffer)
|
||||
{
|
||||
if (buffer != NULL) {
|
||||
return (mtl_resource *)buffer->mtl_handle;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif // KK_BUFFER_H
|
||||
124
src/kosmickrisp/vulkan/kk_buffer_view.c
Normal file
124
src/kosmickrisp/vulkan/kk_buffer_view.c
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* Copyright © 2022 Collabora Ltd. and Red Hat Inc.
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "kk_buffer_view.h"
|
||||
|
||||
#include "kk_buffer.h"
|
||||
#include "kk_device.h"
|
||||
#include "kk_entrypoints.h"
|
||||
#include "kk_format.h"
|
||||
#include "kk_image_layout.h"
|
||||
#include "kk_nir_lower_vbo.h"
|
||||
#include "kk_physical_device.h"
|
||||
|
||||
#include "kosmickrisp/bridge/mtl_bridge.h"
|
||||
#include "kosmickrisp/bridge/mtl_format.h"
|
||||
|
||||
#include "vk_format.h"
|
||||
|
||||
VkFormatFeatureFlags2
|
||||
kk_get_buffer_format_features(struct kk_physical_device *pdev,
|
||||
VkFormat vk_format)
|
||||
{
|
||||
VkFormatFeatureFlags2 features = 0;
|
||||
enum pipe_format p_format = vk_format_to_pipe_format(vk_format);
|
||||
|
||||
if (p_format == PIPE_FORMAT_NONE)
|
||||
return 0;
|
||||
|
||||
const struct kk_va_format *format = kk_get_va_format(p_format);
|
||||
if (format) {
|
||||
if (format->texel_buffer.read)
|
||||
features |= VK_FORMAT_FEATURE_2_UNIFORM_TEXEL_BUFFER_BIT;
|
||||
|
||||
if (format->texel_buffer.write)
|
||||
features |= VK_FORMAT_FEATURE_2_STORAGE_TEXEL_BUFFER_BIT;
|
||||
|
||||
/* Only these formats allow atomics for texel buffers */
|
||||
if (vk_format == VK_FORMAT_R32_UINT || vk_format == VK_FORMAT_R32_SINT)
|
||||
features |= VK_FORMAT_FEATURE_2_STORAGE_TEXEL_BUFFER_ATOMIC_BIT;
|
||||
}
|
||||
|
||||
if (kk_vbo_supports_format(p_format))
|
||||
features |= VK_FORMAT_FEATURE_2_VERTEX_BUFFER_BIT;
|
||||
|
||||
return features;
|
||||
}
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL
|
||||
kk_CreateBufferView(VkDevice _device, const VkBufferViewCreateInfo *pCreateInfo,
|
||||
const VkAllocationCallbacks *pAllocator,
|
||||
VkBufferView *pBufferView)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_device, dev, _device);
|
||||
struct kk_buffer_view *view =
|
||||
vk_buffer_view_create(&dev->vk, pCreateInfo, pAllocator, sizeof(*view));
|
||||
if (!view)
|
||||
return vk_error(dev, VK_ERROR_OUT_OF_HOST_MEMORY);
|
||||
|
||||
enum pipe_format p_format = vk_format_to_pipe_format(view->vk.format);
|
||||
const struct kk_va_format *supported_format = kk_get_va_format(p_format);
|
||||
|
||||
/* If we reached here, we support reading at least */
|
||||
enum mtl_texture_usage usage = MTL_TEXTURE_USAGE_SHADER_READ;
|
||||
if (supported_format->texel_buffer.write)
|
||||
usage |= MTL_TEXTURE_USAGE_SHADER_WRITE;
|
||||
|
||||
/* Only these formats allow atomics for texel buffers */
|
||||
if (view->vk.format == VK_FORMAT_R32_UINT ||
|
||||
view->vk.format == VK_FORMAT_R32_SINT)
|
||||
usage |= MTL_TEXTURE_USAGE_SHADER_ATOMIC;
|
||||
|
||||
struct kk_image_layout layout = {
|
||||
.width_px = view->vk.elements,
|
||||
.height_px = 1u,
|
||||
.depth_px = 1u,
|
||||
.layers = 1u,
|
||||
.type = MTL_TEXTURE_TYPE_TEXTURE_BUFFER,
|
||||
.sample_count_sa = 1u,
|
||||
.levels = 1u,
|
||||
.optimized_layout = false,
|
||||
.usage = usage,
|
||||
.format = {.pipe = p_format, .mtl = supported_format->mtl_pixel_format},
|
||||
.swizzle =
|
||||
{
|
||||
.red = supported_format->swizzle.red,
|
||||
.green = supported_format->swizzle.green,
|
||||
.blue = supported_format->swizzle.blue,
|
||||
.alpha = supported_format->swizzle.alpha,
|
||||
},
|
||||
.linear_stride_B = view->vk.range,
|
||||
};
|
||||
struct kk_buffer *buffer =
|
||||
container_of(view->vk.buffer, struct kk_buffer, vk);
|
||||
view->mtl_texel_buffer_handle = mtl_new_texture_with_descriptor_linear(
|
||||
buffer->mtl_handle, &layout, view->vk.offset);
|
||||
if (!view->mtl_texel_buffer_handle) {
|
||||
vk_buffer_view_destroy(&dev->vk, pAllocator, &view->vk);
|
||||
return vk_error(dev, VK_ERROR_OUT_OF_DEVICE_MEMORY);
|
||||
}
|
||||
view->texel_buffer_gpu_id =
|
||||
mtl_texture_get_gpu_resource_id(view->mtl_texel_buffer_handle);
|
||||
|
||||
*pBufferView = kk_buffer_view_to_handle(view);
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
kk_DestroyBufferView(VkDevice _device, VkBufferView bufferView,
|
||||
const VkAllocationCallbacks *pAllocator)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_device, dev, _device);
|
||||
VK_FROM_HANDLE(kk_buffer_view, view, bufferView);
|
||||
|
||||
if (!view)
|
||||
return;
|
||||
|
||||
mtl_release(view->mtl_texel_buffer_handle);
|
||||
vk_buffer_view_destroy(&dev->vk, pAllocator, &view->vk);
|
||||
}
|
||||
31
src/kosmickrisp/vulkan/kk_buffer_view.h
Normal file
31
src/kosmickrisp/vulkan/kk_buffer_view.h
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright © 2022 Collabora Ltd. and Red Hat Inc.
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef KK_BUFFER_VIEW_H
|
||||
#define KK_BUFFER_VIEW_H 1
|
||||
|
||||
#include "kk_private.h"
|
||||
|
||||
#include "kosmickrisp/bridge/mtl_types.h"
|
||||
|
||||
#include "vk_buffer_view.h"
|
||||
|
||||
struct kk_physical_device;
|
||||
|
||||
VkFormatFeatureFlags2
|
||||
kk_get_buffer_format_features(struct kk_physical_device *pdev, VkFormat format);
|
||||
|
||||
struct kk_buffer_view {
|
||||
struct vk_buffer_view vk;
|
||||
mtl_texture *mtl_texel_buffer_handle;
|
||||
uint64_t texel_buffer_gpu_id;
|
||||
};
|
||||
|
||||
VK_DEFINE_NONDISP_HANDLE_CASTS(kk_buffer_view, vk.base, VkBufferView,
|
||||
VK_OBJECT_TYPE_BUFFER_VIEW)
|
||||
|
||||
#endif
|
||||
533
src/kosmickrisp/vulkan/kk_cmd_buffer.c
Normal file
533
src/kosmickrisp/vulkan/kk_cmd_buffer.c
Normal file
|
|
@ -0,0 +1,533 @@
|
|||
/*
|
||||
* Copyright © 2022 Collabora Ltd. and Red Hat Inc.
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "kk_cmd_buffer.h"
|
||||
|
||||
#include "kk_buffer.h"
|
||||
#include "kk_cmd_pool.h"
|
||||
#include "kk_descriptor_set_layout.h"
|
||||
#include "kk_encoder.h"
|
||||
#include "kk_entrypoints.h"
|
||||
|
||||
#include "kosmickrisp/bridge/mtl_bridge.h"
|
||||
|
||||
#include "vk_alloc.h"
|
||||
#include "vk_pipeline_layout.h"
|
||||
|
||||
static void
|
||||
kk_descriptor_state_fini(struct kk_cmd_buffer *cmd,
|
||||
struct kk_descriptor_state *desc)
|
||||
{
|
||||
struct kk_cmd_pool *pool = kk_cmd_buffer_pool(cmd);
|
||||
|
||||
for (unsigned i = 0; i < KK_MAX_SETS; i++) {
|
||||
vk_free(&pool->vk.alloc, desc->push[i]);
|
||||
desc->push[i] = NULL;
|
||||
desc->sets[i] = NULL; /* We also need to set sets to NULL so state doesn't
|
||||
propagate if we reset it */
|
||||
desc->sets_not_resident = 0u;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
kk_cmd_release_resources(struct kk_device *dev, struct kk_cmd_buffer *cmd)
|
||||
{
|
||||
kk_cmd_release_dynamic_ds_state(cmd);
|
||||
kk_descriptor_state_fini(cmd, &cmd->state.gfx.descriptors);
|
||||
kk_descriptor_state_fini(cmd, &cmd->state.cs.descriptors);
|
||||
|
||||
/* Release all BOs used as descriptor buffers for submissions */
|
||||
util_dynarray_foreach(&cmd->large_bos, struct kk_bo *, bo) {
|
||||
kk_destroy_bo(dev, *bo);
|
||||
}
|
||||
util_dynarray_clear(&cmd->large_bos);
|
||||
}
|
||||
|
||||
static void
|
||||
kk_destroy_cmd_buffer(struct vk_command_buffer *vk_cmd_buffer)
|
||||
{
|
||||
struct kk_cmd_buffer *cmd =
|
||||
container_of(vk_cmd_buffer, struct kk_cmd_buffer, vk);
|
||||
struct kk_cmd_pool *pool = kk_cmd_buffer_pool(cmd);
|
||||
|
||||
vk_command_buffer_finish(&cmd->vk);
|
||||
struct kk_device *dev = kk_cmd_buffer_device(cmd);
|
||||
|
||||
kk_cmd_release_resources(dev, cmd);
|
||||
|
||||
vk_free(&pool->vk.alloc, cmd);
|
||||
}
|
||||
|
||||
static VkResult
|
||||
kk_create_cmd_buffer(struct vk_command_pool *vk_pool,
|
||||
VkCommandBufferLevel level,
|
||||
struct vk_command_buffer **cmd_buffer_out)
|
||||
{
|
||||
struct kk_cmd_pool *pool = container_of(vk_pool, struct kk_cmd_pool, vk);
|
||||
struct kk_device *dev = kk_cmd_pool_device(pool);
|
||||
struct kk_cmd_buffer *cmd;
|
||||
VkResult result;
|
||||
|
||||
cmd = vk_zalloc(&pool->vk.alloc, sizeof(*cmd), 8,
|
||||
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
|
||||
if (cmd == NULL)
|
||||
return vk_error(dev, VK_ERROR_OUT_OF_HOST_MEMORY);
|
||||
|
||||
result =
|
||||
vk_command_buffer_init(&pool->vk, &cmd->vk, &kk_cmd_buffer_ops, level);
|
||||
if (result != VK_SUCCESS) {
|
||||
vk_free(&pool->vk.alloc, cmd);
|
||||
return result;
|
||||
}
|
||||
|
||||
util_dynarray_init(&cmd->large_bos, NULL);
|
||||
|
||||
cmd->vk.dynamic_graphics_state.vi = &cmd->state.gfx._dynamic_vi;
|
||||
cmd->vk.dynamic_graphics_state.ms.sample_locations =
|
||||
&cmd->state.gfx._dynamic_sl;
|
||||
|
||||
*cmd_buffer_out = &cmd->vk;
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
kk_reset_cmd_buffer(struct vk_command_buffer *vk_cmd_buffer,
|
||||
UNUSED VkCommandBufferResetFlags flags)
|
||||
{
|
||||
struct kk_cmd_buffer *cmd =
|
||||
container_of(vk_cmd_buffer, struct kk_cmd_buffer, vk);
|
||||
struct kk_device *dev = kk_cmd_buffer_device(cmd);
|
||||
|
||||
vk_command_buffer_reset(&cmd->vk);
|
||||
kk_cmd_release_resources(dev, cmd);
|
||||
}
|
||||
|
||||
const struct vk_command_buffer_ops kk_cmd_buffer_ops = {
|
||||
.create = kk_create_cmd_buffer,
|
||||
.reset = kk_reset_cmd_buffer,
|
||||
.destroy = kk_destroy_cmd_buffer,
|
||||
};
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL
|
||||
kk_BeginCommandBuffer(VkCommandBuffer commandBuffer,
|
||||
const VkCommandBufferBeginInfo *pBeginInfo)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_cmd_buffer, cmd, commandBuffer);
|
||||
|
||||
kk_reset_cmd_buffer(&cmd->vk, 0u);
|
||||
vk_command_buffer_begin(&cmd->vk, pBeginInfo);
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL
|
||||
kk_EndCommandBuffer(VkCommandBuffer commandBuffer)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_cmd_buffer, cmd, commandBuffer);
|
||||
|
||||
return vk_command_buffer_end(&cmd->vk);
|
||||
}
|
||||
|
||||
static bool
|
||||
kk_can_ignore_barrier(VkAccessFlags2 access, VkPipelineStageFlags2 stage)
|
||||
{
|
||||
if (access == VK_ACCESS_2_NONE || stage == VK_PIPELINE_STAGE_2_NONE)
|
||||
return true;
|
||||
|
||||
const VkAccessFlags2 ignore_access =
|
||||
VK_ACCESS_2_HOST_READ_BIT | VK_ACCESS_2_HOST_WRITE_BIT;
|
||||
const VkPipelineStageFlags2 ignore_stage = VK_PIPELINE_STAGE_2_HOST_BIT;
|
||||
return (!(access ^ ignore_access)) || (!(stage ^ ignore_stage));
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
kk_CmdPipelineBarrier2(VkCommandBuffer commandBuffer,
|
||||
const VkDependencyInfo *pDependencyInfo)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_cmd_buffer, cmd, commandBuffer);
|
||||
enum kk_encoder_type last_used = cmd->encoder->main.last_used;
|
||||
kk_encoder_signal_fence_and_end(cmd);
|
||||
|
||||
/* If we were inside a render pass, restart it loading attachments */
|
||||
if (last_used == KK_ENC_RENDER) {
|
||||
struct kk_graphics_state *state = &cmd->state.gfx;
|
||||
assert(state->render_pass_descriptor);
|
||||
kk_encoder_start_render(cmd, state->render_pass_descriptor,
|
||||
state->render.view_mask);
|
||||
kk_cmd_buffer_dirty_all_gfx(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
kk_bind_descriptor_sets(struct kk_descriptor_state *desc,
|
||||
const VkBindDescriptorSetsInfoKHR *info)
|
||||
{
|
||||
VK_FROM_HANDLE(vk_pipeline_layout, pipeline_layout, info->layout);
|
||||
|
||||
/* From the Vulkan 1.3.275 spec:
|
||||
*
|
||||
* "When binding a descriptor set (see Descriptor Set Binding) to
|
||||
* set number N...
|
||||
*
|
||||
* If, additionally, the previously bound descriptor set for set
|
||||
* N was bound using a pipeline layout not compatible for set N,
|
||||
* then all bindings in sets numbered greater than N are
|
||||
* disturbed."
|
||||
*
|
||||
* This means that, if some earlier set gets bound in such a way that
|
||||
* it changes set_dynamic_buffer_start[s], this binding is implicitly
|
||||
* invalidated. Therefore, we can always look at the current value
|
||||
* of set_dynamic_buffer_start[s] as the base of our dynamic buffer
|
||||
* range and it's only our responsibility to adjust all
|
||||
* set_dynamic_buffer_start[p] for p > s as needed.
|
||||
*/
|
||||
uint8_t dyn_buffer_start =
|
||||
desc->root.set_dynamic_buffer_start[info->firstSet];
|
||||
|
||||
uint32_t next_dyn_offset = 0;
|
||||
for (uint32_t i = 0; i < info->descriptorSetCount; ++i) {
|
||||
unsigned s = i + info->firstSet;
|
||||
VK_FROM_HANDLE(kk_descriptor_set, set, info->pDescriptorSets[i]);
|
||||
|
||||
if (desc->sets[s] != set) {
|
||||
if (set != NULL) {
|
||||
desc->root.sets[s] = set->addr;
|
||||
desc->set_sizes[s] = set->size;
|
||||
} else {
|
||||
desc->root.sets[s] = 0;
|
||||
desc->set_sizes[s] = 0;
|
||||
}
|
||||
desc->sets[s] = set;
|
||||
|
||||
desc->sets_not_resident |= BITFIELD_BIT(s);
|
||||
|
||||
/* Binding descriptors invalidates push descriptors */
|
||||
desc->push_dirty &= ~BITFIELD_BIT(s);
|
||||
}
|
||||
|
||||
if (pipeline_layout->set_layouts[s] != NULL) {
|
||||
const struct kk_descriptor_set_layout *set_layout =
|
||||
vk_to_kk_descriptor_set_layout(pipeline_layout->set_layouts[s]);
|
||||
|
||||
if (set != NULL && set_layout->dynamic_buffer_count > 0) {
|
||||
for (uint32_t j = 0; j < set_layout->dynamic_buffer_count; j++) {
|
||||
struct kk_buffer_address addr = set->dynamic_buffers[j];
|
||||
addr.base_addr += info->pDynamicOffsets[next_dyn_offset + j];
|
||||
desc->root.dynamic_buffers[dyn_buffer_start + j] = addr;
|
||||
}
|
||||
next_dyn_offset += set->layout->dynamic_buffer_count;
|
||||
}
|
||||
|
||||
dyn_buffer_start += set_layout->dynamic_buffer_count;
|
||||
} else {
|
||||
assert(set == NULL);
|
||||
}
|
||||
}
|
||||
assert(dyn_buffer_start <= KK_MAX_DYNAMIC_BUFFERS);
|
||||
assert(next_dyn_offset <= info->dynamicOffsetCount);
|
||||
|
||||
for (uint32_t s = info->firstSet + info->descriptorSetCount; s < KK_MAX_SETS;
|
||||
s++)
|
||||
desc->root.set_dynamic_buffer_start[s] = dyn_buffer_start;
|
||||
|
||||
desc->root_dirty = true;
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
kk_CmdBindDescriptorSets2KHR(
|
||||
VkCommandBuffer commandBuffer,
|
||||
const VkBindDescriptorSetsInfoKHR *pBindDescriptorSetsInfo)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_cmd_buffer, cmd, commandBuffer);
|
||||
|
||||
if (pBindDescriptorSetsInfo->stageFlags & VK_SHADER_STAGE_ALL_GRAPHICS) {
|
||||
kk_bind_descriptor_sets(&cmd->state.gfx.descriptors,
|
||||
pBindDescriptorSetsInfo);
|
||||
}
|
||||
|
||||
if (pBindDescriptorSetsInfo->stageFlags & VK_SHADER_STAGE_COMPUTE_BIT) {
|
||||
kk_bind_descriptor_sets(&cmd->state.cs.descriptors,
|
||||
pBindDescriptorSetsInfo);
|
||||
}
|
||||
}
|
||||
|
||||
static struct kk_push_descriptor_set *
|
||||
kk_cmd_push_descriptors(struct kk_cmd_buffer *cmd,
|
||||
struct kk_descriptor_state *desc,
|
||||
struct kk_descriptor_set_layout *set_layout,
|
||||
uint32_t set)
|
||||
{
|
||||
struct kk_device *dev = kk_cmd_buffer_device(cmd);
|
||||
assert(set < KK_MAX_SETS);
|
||||
if (unlikely(desc->push[set] == NULL)) {
|
||||
size_t size = sizeof(*desc->push[set]) +
|
||||
(sizeof(mtl_resource *) * set_layout->descriptor_count);
|
||||
desc->push[set] = vk_zalloc(&cmd->vk.pool->alloc, size, 8,
|
||||
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
|
||||
if (unlikely(desc->push[set] == NULL)) {
|
||||
vk_command_buffer_set_error(&cmd->vk, VK_ERROR_OUT_OF_HOST_MEMORY);
|
||||
return NULL;
|
||||
}
|
||||
desc->push[set]->layout = set_layout;
|
||||
for (uint32_t i = 0u; i < set_layout->descriptor_count; ++i)
|
||||
desc->push[set]->mtl_resources[i] = dev->null_descriptor->map;
|
||||
}
|
||||
|
||||
/* Pushing descriptors replaces whatever sets are bound */
|
||||
desc->sets[set] = NULL;
|
||||
desc->push_dirty |= BITFIELD_BIT(set);
|
||||
desc->sets_not_resident |= BITFIELD_BIT(set);
|
||||
|
||||
return desc->push[set];
|
||||
}
|
||||
|
||||
static void
|
||||
kk_push_descriptor_set(struct kk_cmd_buffer *cmd,
|
||||
struct kk_descriptor_state *desc,
|
||||
const VkPushDescriptorSetInfoKHR *info)
|
||||
{
|
||||
VK_FROM_HANDLE(vk_pipeline_layout, pipeline_layout, info->layout);
|
||||
|
||||
struct kk_descriptor_set_layout *set_layout =
|
||||
vk_to_kk_descriptor_set_layout(pipeline_layout->set_layouts[info->set]);
|
||||
|
||||
struct kk_push_descriptor_set *push_set =
|
||||
kk_cmd_push_descriptors(cmd, desc, set_layout, info->set);
|
||||
if (unlikely(push_set == NULL))
|
||||
return;
|
||||
|
||||
kk_push_descriptor_set_update(push_set, info->descriptorWriteCount,
|
||||
info->pDescriptorWrites);
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
kk_CmdPushDescriptorSet2KHR(
|
||||
VkCommandBuffer commandBuffer,
|
||||
const VkPushDescriptorSetInfoKHR *pPushDescriptorSetInfo)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_cmd_buffer, cmd, commandBuffer);
|
||||
|
||||
if (pPushDescriptorSetInfo->stageFlags & VK_SHADER_STAGE_ALL_GRAPHICS) {
|
||||
kk_push_descriptor_set(cmd, &cmd->state.gfx.descriptors,
|
||||
pPushDescriptorSetInfo);
|
||||
}
|
||||
|
||||
if (pPushDescriptorSetInfo->stageFlags & VK_SHADER_STAGE_COMPUTE_BIT) {
|
||||
kk_push_descriptor_set(cmd, &cmd->state.cs.descriptors,
|
||||
pPushDescriptorSetInfo);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
kk_push_constants(UNUSED struct kk_cmd_buffer *cmd,
|
||||
struct kk_descriptor_state *desc,
|
||||
const VkPushConstantsInfoKHR *info)
|
||||
{
|
||||
memcpy(desc->root.push + info->offset, info->pValues, info->size);
|
||||
desc->root_dirty = true;
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
kk_CmdPushConstants2KHR(VkCommandBuffer commandBuffer,
|
||||
const VkPushConstantsInfoKHR *pPushConstantsInfo)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_cmd_buffer, cmd, commandBuffer);
|
||||
|
||||
if (pPushConstantsInfo->stageFlags & VK_SHADER_STAGE_ALL_GRAPHICS)
|
||||
kk_push_constants(cmd, &cmd->state.gfx.descriptors, pPushConstantsInfo);
|
||||
|
||||
if (pPushConstantsInfo->stageFlags & VK_SHADER_STAGE_COMPUTE_BIT)
|
||||
kk_push_constants(cmd, &cmd->state.cs.descriptors, pPushConstantsInfo);
|
||||
}
|
||||
|
||||
void
|
||||
kk_cmd_buffer_write_descriptor_buffer(struct kk_cmd_buffer *cmd,
|
||||
struct kk_descriptor_state *desc,
|
||||
size_t size, size_t offset)
|
||||
{
|
||||
assert(size + offset <= sizeof(desc->root.sets));
|
||||
|
||||
struct kk_bo *root_buffer = desc->root.root_buffer;
|
||||
|
||||
memcpy(root_buffer->cpu, (uint8_t *)desc->root.sets + offset, size);
|
||||
}
|
||||
|
||||
void
|
||||
kk_cmd_release_dynamic_ds_state(struct kk_cmd_buffer *cmd)
|
||||
{
|
||||
if (cmd->state.gfx.is_depth_stencil_dynamic &&
|
||||
cmd->state.gfx.depth_stencil_state)
|
||||
mtl_release(cmd->state.gfx.depth_stencil_state);
|
||||
cmd->state.gfx.depth_stencil_state = NULL;
|
||||
}
|
||||
|
||||
struct kk_bo *
|
||||
kk_cmd_allocate_buffer(struct kk_cmd_buffer *cmd, size_t size_B,
|
||||
size_t alignment_B)
|
||||
{
|
||||
struct kk_bo *buffer = NULL;
|
||||
|
||||
VkResult result = kk_alloc_bo(kk_cmd_buffer_device(cmd), &cmd->vk.base,
|
||||
size_B, alignment_B, &buffer);
|
||||
if (result != VK_SUCCESS) {
|
||||
vk_command_buffer_set_error(&cmd->vk, result);
|
||||
return NULL;
|
||||
}
|
||||
util_dynarray_append(&cmd->large_bos, struct kk_bo *, buffer);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
struct kk_pool
|
||||
kk_pool_upload(struct kk_cmd_buffer *cmd, void *data, size_t size_B,
|
||||
size_t alignment_B)
|
||||
{
|
||||
struct kk_bo *bo = kk_cmd_allocate_buffer(cmd, size_B, alignment_B);
|
||||
if (!bo)
|
||||
return (struct kk_pool){};
|
||||
|
||||
memcpy(bo->cpu, data, size_B);
|
||||
struct kk_pool pool = {.handle = bo->map, .gpu = bo->gpu, .cpu = bo->cpu};
|
||||
|
||||
return pool;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
kk_upload_descriptor_root(struct kk_cmd_buffer *cmd,
|
||||
VkPipelineBindPoint bind_point)
|
||||
{
|
||||
struct kk_descriptor_state *desc = kk_get_descriptors_state(cmd, bind_point);
|
||||
struct kk_root_descriptor_table *root = &desc->root;
|
||||
struct kk_bo *bo = kk_cmd_allocate_buffer(cmd, sizeof(*root), 8u);
|
||||
if (bo == NULL)
|
||||
return 0u;
|
||||
|
||||
memcpy(bo->cpu, root, sizeof(*root));
|
||||
root->root_buffer = bo;
|
||||
|
||||
return bo->gpu;
|
||||
}
|
||||
|
||||
void
|
||||
kk_cmd_buffer_flush_push_descriptors(struct kk_cmd_buffer *cmd,
|
||||
struct kk_descriptor_state *desc)
|
||||
{
|
||||
u_foreach_bit(set_idx, desc->push_dirty) {
|
||||
struct kk_push_descriptor_set *push_set = desc->push[set_idx];
|
||||
struct kk_bo *bo = kk_cmd_allocate_buffer(cmd, sizeof(push_set->data),
|
||||
KK_MIN_UBO_ALIGNMENT);
|
||||
if (bo == NULL)
|
||||
return;
|
||||
|
||||
memcpy(bo->cpu, push_set->data, sizeof(push_set->data));
|
||||
push_set->mtl_descriptor_buffer = bo->map;
|
||||
desc->root.sets[set_idx] = bo->gpu;
|
||||
desc->set_sizes[set_idx] = sizeof(push_set->data);
|
||||
}
|
||||
|
||||
desc->root_dirty = true;
|
||||
desc->push_dirty = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
kk_make_graphics_descriptor_resources_resident(struct kk_cmd_buffer *cmd)
|
||||
{
|
||||
struct kk_descriptor_state *desc = &cmd->state.gfx.descriptors;
|
||||
mtl_render_encoder *encoder = kk_render_encoder(cmd);
|
||||
/* Make resources resident as required by Metal */
|
||||
u_foreach_bit(set_index, desc->sets_not_resident) {
|
||||
mtl_resource *descriptor_buffer = NULL;
|
||||
|
||||
/* If we have no set, it means it was a push set */
|
||||
if (desc->sets[set_index]) {
|
||||
struct kk_descriptor_set *set = desc->sets[set_index];
|
||||
descriptor_buffer = set->mtl_descriptor_buffer;
|
||||
} else {
|
||||
struct kk_push_descriptor_set *push_set = desc->push[set_index];
|
||||
descriptor_buffer = push_set->mtl_descriptor_buffer;
|
||||
}
|
||||
|
||||
/* We could have empty descriptor sets for some reason... */
|
||||
if (descriptor_buffer) {
|
||||
mtl_render_use_resource(encoder, descriptor_buffer,
|
||||
MTL_RESOURCE_USAGE_READ);
|
||||
}
|
||||
}
|
||||
|
||||
desc->sets_not_resident = 0u;
|
||||
}
|
||||
|
||||
static void
|
||||
kk_make_compute_descriptor_resources_resident(struct kk_cmd_buffer *cmd)
|
||||
{
|
||||
struct kk_descriptor_state *desc = &cmd->state.cs.descriptors;
|
||||
mtl_compute_encoder *encoder = kk_compute_encoder(cmd);
|
||||
u_foreach_bit(set_index, desc->sets_not_resident) {
|
||||
/* Make resources resident as required by Metal */
|
||||
mtl_resource *descriptor_buffer = NULL;
|
||||
if (desc->sets[set_index]) {
|
||||
struct kk_descriptor_set *set = desc->sets[set_index];
|
||||
descriptor_buffer = set->mtl_descriptor_buffer;
|
||||
} else {
|
||||
struct kk_push_descriptor_set *push_set = desc->push[set_index];
|
||||
descriptor_buffer = push_set->mtl_descriptor_buffer;
|
||||
}
|
||||
|
||||
/* We could have empty descriptor sets for some reason... */
|
||||
if (descriptor_buffer) {
|
||||
mtl_compute_use_resource(encoder, descriptor_buffer,
|
||||
MTL_RESOURCE_USAGE_READ);
|
||||
}
|
||||
}
|
||||
|
||||
desc->sets_not_resident = 0u;
|
||||
}
|
||||
|
||||
void
|
||||
kk_make_descriptor_resources_resident(struct kk_cmd_buffer *cmd,
|
||||
VkPipelineBindPoint bind_point)
|
||||
{
|
||||
if (bind_point == VK_PIPELINE_BIND_POINT_GRAPHICS)
|
||||
kk_make_graphics_descriptor_resources_resident(cmd);
|
||||
else if (bind_point == VK_PIPELINE_BIND_POINT_COMPUTE)
|
||||
kk_make_compute_descriptor_resources_resident(cmd);
|
||||
}
|
||||
|
||||
void
|
||||
kk_cmd_write(struct kk_cmd_buffer *cmd, mtl_buffer *buffer, uint64_t addr,
|
||||
uint64_t value)
|
||||
{
|
||||
util_dynarray_append(&cmd->encoder->imm_writes, uint64_t, addr);
|
||||
util_dynarray_append(&cmd->encoder->imm_writes, uint64_t, value);
|
||||
util_dynarray_append(&cmd->encoder->resident_buffers, mtl_buffer *, buffer);
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
kk_CmdPushDescriptorSetWithTemplate2KHR(
|
||||
VkCommandBuffer commandBuffer, const VkPushDescriptorSetWithTemplateInfoKHR
|
||||
*pPushDescriptorSetWithTemplateInfo)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_cmd_buffer, cmd, commandBuffer);
|
||||
VK_FROM_HANDLE(vk_descriptor_update_template, template,
|
||||
pPushDescriptorSetWithTemplateInfo->descriptorUpdateTemplate);
|
||||
VK_FROM_HANDLE(vk_pipeline_layout, pipeline_layout,
|
||||
pPushDescriptorSetWithTemplateInfo->layout);
|
||||
|
||||
struct kk_descriptor_state *desc =
|
||||
kk_get_descriptors_state(cmd, template->bind_point);
|
||||
struct kk_descriptor_set_layout *set_layout = vk_to_kk_descriptor_set_layout(
|
||||
pipeline_layout->set_layouts[pPushDescriptorSetWithTemplateInfo->set]);
|
||||
struct kk_push_descriptor_set *push_set = kk_cmd_push_descriptors(
|
||||
cmd, desc, set_layout, pPushDescriptorSetWithTemplateInfo->set);
|
||||
if (unlikely(push_set == NULL))
|
||||
return;
|
||||
|
||||
kk_push_descriptor_set_update_template(
|
||||
push_set, set_layout, template,
|
||||
pPushDescriptorSetWithTemplateInfo->pData);
|
||||
}
|
||||
270
src/kosmickrisp/vulkan/kk_cmd_buffer.h
Normal file
270
src/kosmickrisp/vulkan/kk_cmd_buffer.h
Normal file
|
|
@ -0,0 +1,270 @@
|
|||
/*
|
||||
* Copyright © 2022 Collabora Ltd. and Red Hat Inc.
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef KK_CMD_BUFFER_H
|
||||
#define KK_CMD_BUFFER_H 1
|
||||
|
||||
#include "kk_private.h"
|
||||
|
||||
#include "kk_descriptor_set.h"
|
||||
#include "kk_image.h"
|
||||
#include "kk_nir_lower_vbo.h"
|
||||
#include "kk_shader.h"
|
||||
|
||||
#include "kosmickrisp/bridge/mtl_types.h"
|
||||
|
||||
#include "util/u_dynarray.h"
|
||||
|
||||
#include "vk_command_buffer.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
struct kk_query_pool;
|
||||
|
||||
struct kk_root_descriptor_table {
|
||||
struct kk_bo *root_buffer;
|
||||
|
||||
union {
|
||||
struct {
|
||||
/* Vertex input state */
|
||||
uint32_t buffer_strides[KK_MAX_VBUFS];
|
||||
uint64_t attrib_base[KK_MAX_ATTRIBS];
|
||||
uint32_t attrib_clamps[KK_MAX_ATTRIBS];
|
||||
float blend_constant[4];
|
||||
} draw;
|
||||
struct {
|
||||
uint32_t base_group[3];
|
||||
} cs;
|
||||
};
|
||||
|
||||
/* Client push constants */
|
||||
uint8_t push[KK_MAX_PUSH_SIZE];
|
||||
|
||||
/* Descriptor set base addresses */
|
||||
uint64_t sets[KK_MAX_SETS];
|
||||
|
||||
/* Dynamic buffer bindings */
|
||||
struct kk_buffer_address dynamic_buffers[KK_MAX_DYNAMIC_BUFFERS];
|
||||
|
||||
/* Start index in dynamic_buffers where each set starts */
|
||||
uint8_t set_dynamic_buffer_start[KK_MAX_SETS];
|
||||
};
|
||||
|
||||
struct kk_descriptor_state {
|
||||
bool root_dirty;
|
||||
struct kk_root_descriptor_table root;
|
||||
|
||||
uint32_t set_sizes[KK_MAX_SETS];
|
||||
struct kk_descriptor_set *sets[KK_MAX_SETS];
|
||||
mtl_resource **resources[KK_MAX_SETS];
|
||||
/* Non resident sets can either be sets or push. If sets[index] == NULL, then
|
||||
* push[index] != NULL */
|
||||
uint32_t sets_not_resident;
|
||||
|
||||
uint32_t push_dirty;
|
||||
struct kk_push_descriptor_set *push[KK_MAX_SETS];
|
||||
};
|
||||
|
||||
struct kk_attachment {
|
||||
VkFormat vk_format;
|
||||
struct kk_image_view *iview;
|
||||
|
||||
VkResolveModeFlagBits resolve_mode;
|
||||
struct kk_image_view *resolve_iview;
|
||||
|
||||
/* Needed to track the value of storeOp in case we need to copy images for
|
||||
* the DRM_FORMAT_MOD_LINEAR case */
|
||||
VkAttachmentStoreOp store_op;
|
||||
};
|
||||
|
||||
struct kk_rendering_state {
|
||||
VkRenderingFlagBits flags;
|
||||
|
||||
VkRect2D area;
|
||||
uint32_t layer_count;
|
||||
uint32_t view_mask;
|
||||
uint32_t samples;
|
||||
|
||||
uint32_t color_att_count;
|
||||
struct kk_attachment color_att[KK_MAX_RTS];
|
||||
struct kk_attachment depth_att;
|
||||
struct kk_attachment stencil_att;
|
||||
struct kk_attachment fsr_att;
|
||||
};
|
||||
|
||||
/* Dirty tracking bits for state not tracked by vk_dynamic_graphics_state or
|
||||
* shaders_dirty.
|
||||
*/
|
||||
enum kk_dirty {
|
||||
KK_DIRTY_INDEX = BITFIELD_BIT(0),
|
||||
KK_DIRTY_VB = BITFIELD_BIT(1),
|
||||
KK_DIRTY_OCCLUSION = BITFIELD_BIT(2),
|
||||
KK_DIRTY_PROVOKING = BITFIELD_BIT(3),
|
||||
KK_DIRTY_VARYINGS = BITFIELD_BIT(4),
|
||||
KK_DIRTY_PIPELINE = BITFIELD_BIT(5),
|
||||
};
|
||||
|
||||
struct kk_graphics_state {
|
||||
struct kk_rendering_state render;
|
||||
struct kk_descriptor_state descriptors;
|
||||
|
||||
mtl_render_pipeline_state *pipeline_state;
|
||||
mtl_depth_stencil_state *depth_stencil_state;
|
||||
mtl_render_pass_descriptor *render_pass_descriptor;
|
||||
bool is_depth_stencil_dynamic;
|
||||
bool is_cull_front_and_back;
|
||||
bool restart_disabled;
|
||||
|
||||
enum mtl_primitive_type primitive_type;
|
||||
enum mesa_prim prim;
|
||||
enum kk_dirty dirty;
|
||||
|
||||
struct {
|
||||
enum mtl_visibility_result_mode mode;
|
||||
|
||||
/* If enabled, index of the current occlusion query in the occlusion heap.
|
||||
* There can only be one active at a time (hardware constraint).
|
||||
*/
|
||||
uint16_t index;
|
||||
} occlusion;
|
||||
|
||||
/* Index buffer */
|
||||
struct {
|
||||
mtl_buffer *handle;
|
||||
uint32_t size;
|
||||
uint32_t offset;
|
||||
uint32_t restart;
|
||||
uint8_t bytes_per_index;
|
||||
} index;
|
||||
|
||||
/* Vertex buffers */
|
||||
struct {
|
||||
struct kk_addr_range addr_range[KK_MAX_VBUFS];
|
||||
mtl_buffer *handles[KK_MAX_VBUFS];
|
||||
uint32_t attribs_read;
|
||||
/* Required to understand maximum size of index buffer if primitive is
|
||||
* triangle fans */
|
||||
uint32_t max_vertices;
|
||||
} vb;
|
||||
|
||||
/* Needed by vk_command_buffer::dynamic_graphics_state */
|
||||
struct vk_vertex_input_state _dynamic_vi;
|
||||
struct vk_sample_locations_state _dynamic_sl;
|
||||
};
|
||||
|
||||
struct kk_compute_state {
|
||||
struct kk_descriptor_state descriptors;
|
||||
mtl_compute_pipeline_state *pipeline_state;
|
||||
struct mtl_size local_size;
|
||||
enum kk_dirty dirty;
|
||||
};
|
||||
|
||||
struct kk_encoder;
|
||||
|
||||
struct kk_cmd_buffer {
|
||||
struct vk_command_buffer vk;
|
||||
|
||||
struct kk_encoder *encoder;
|
||||
void *drawable;
|
||||
|
||||
struct {
|
||||
struct kk_graphics_state gfx;
|
||||
struct kk_compute_state cs;
|
||||
} state;
|
||||
|
||||
/* Owned large BOs */
|
||||
struct util_dynarray large_bos;
|
||||
};
|
||||
|
||||
VK_DEFINE_HANDLE_CASTS(kk_cmd_buffer, vk.base, VkCommandBuffer,
|
||||
VK_OBJECT_TYPE_COMMAND_BUFFER)
|
||||
|
||||
extern const struct vk_command_buffer_ops kk_cmd_buffer_ops;
|
||||
|
||||
static inline struct kk_device *
|
||||
kk_cmd_buffer_device(struct kk_cmd_buffer *cmd)
|
||||
{
|
||||
return (struct kk_device *)cmd->vk.base.device;
|
||||
}
|
||||
|
||||
static inline struct kk_cmd_pool *
|
||||
kk_cmd_buffer_pool(struct kk_cmd_buffer *cmd)
|
||||
{
|
||||
return (struct kk_cmd_pool *)cmd->vk.pool;
|
||||
}
|
||||
|
||||
static inline struct kk_descriptor_state *
|
||||
kk_get_descriptors_state(struct kk_cmd_buffer *cmd,
|
||||
VkPipelineBindPoint bind_point)
|
||||
{
|
||||
switch (bind_point) {
|
||||
case VK_PIPELINE_BIND_POINT_GRAPHICS:
|
||||
return &cmd->state.gfx.descriptors;
|
||||
case VK_PIPELINE_BIND_POINT_COMPUTE:
|
||||
return &cmd->state.cs.descriptors;
|
||||
default:
|
||||
UNREACHABLE("Unhandled bind point");
|
||||
}
|
||||
};
|
||||
|
||||
void kk_cmd_release_resources(struct kk_device *dev, struct kk_cmd_buffer *cmd);
|
||||
|
||||
static void
|
||||
kk_cmd_buffer_dirty_all_gfx(struct kk_cmd_buffer *cmd)
|
||||
{
|
||||
/* Ensure we flush all graphics state */
|
||||
vk_dynamic_graphics_state_dirty_all(&cmd->vk.dynamic_graphics_state);
|
||||
cmd->state.gfx.dirty = ~0u;
|
||||
}
|
||||
|
||||
void kk_cmd_release_dynamic_ds_state(struct kk_cmd_buffer *cmd);
|
||||
|
||||
mtl_depth_stencil_state *
|
||||
kk_compile_depth_stencil_state(struct kk_device *device,
|
||||
const struct vk_depth_stencil_state *ds,
|
||||
bool has_depth, bool has_stencil);
|
||||
|
||||
void kk_meta_resolve_rendering(struct kk_cmd_buffer *cmd,
|
||||
const VkRenderingInfo *pRenderingInfo);
|
||||
|
||||
void kk_cmd_buffer_write_descriptor_buffer(struct kk_cmd_buffer *cmd,
|
||||
struct kk_descriptor_state *desc,
|
||||
size_t size, size_t offset);
|
||||
|
||||
/* Allocates temporary buffer that will be released once the command buffer has
|
||||
* completed */
|
||||
struct kk_bo *kk_cmd_allocate_buffer(struct kk_cmd_buffer *cmd, size_t size_B,
|
||||
size_t alignment_B);
|
||||
|
||||
struct kk_pool {
|
||||
mtl_buffer *handle;
|
||||
uint64_t gpu;
|
||||
void *cpu;
|
||||
};
|
||||
struct kk_pool kk_pool_upload(struct kk_cmd_buffer *cmd, void *data,
|
||||
size_t size_B, size_t alignment_B);
|
||||
|
||||
uint64_t kk_upload_descriptor_root(struct kk_cmd_buffer *cmd,
|
||||
VkPipelineBindPoint bind_point);
|
||||
|
||||
void kk_cmd_buffer_flush_push_descriptors(struct kk_cmd_buffer *cmd,
|
||||
struct kk_descriptor_state *desc);
|
||||
|
||||
void kk_make_descriptor_resources_resident(struct kk_cmd_buffer *cmd,
|
||||
VkPipelineBindPoint bind_point);
|
||||
|
||||
void kk_cmd_write(struct kk_cmd_buffer *cmd, mtl_buffer *buffer, uint64_t addr,
|
||||
uint64_t value);
|
||||
|
||||
void kk_cmd_dispatch_pipeline(struct kk_cmd_buffer *cmd,
|
||||
mtl_compute_encoder *encoder,
|
||||
mtl_compute_pipeline_state *pipeline,
|
||||
const void *push_data, size_t push_size,
|
||||
uint32_t groupCountX, uint32_t groupCountY,
|
||||
uint32_t groupCountZ);
|
||||
|
||||
#endif
|
||||
169
src/kosmickrisp/vulkan/kk_cmd_clear.c
Normal file
169
src/kosmickrisp/vulkan/kk_cmd_clear.c
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
* Copyright 2024 Valve Corporation
|
||||
* Copyright 2024 Alyssa Rosenzweig
|
||||
* Copyright 2022-2023 Collabora Ltd. and Red Hat Inc.
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
#include "kk_cmd_buffer.h"
|
||||
|
||||
#include "kk_device.h"
|
||||
#include "kk_entrypoints.h"
|
||||
#include "kk_image.h"
|
||||
#include "kk_image_view.h"
|
||||
#include "kk_physical_device.h"
|
||||
|
||||
#include "vk_format.h"
|
||||
#include "vk_meta.h"
|
||||
|
||||
static VkImageViewType
|
||||
render_view_type(VkImageType image_type, unsigned layer_count)
|
||||
{
|
||||
switch (image_type) {
|
||||
case VK_IMAGE_TYPE_1D:
|
||||
return layer_count == 1 ? VK_IMAGE_VIEW_TYPE_1D
|
||||
: VK_IMAGE_VIEW_TYPE_1D_ARRAY;
|
||||
case VK_IMAGE_TYPE_2D:
|
||||
return layer_count == 1 ? VK_IMAGE_VIEW_TYPE_2D
|
||||
: VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
case VK_IMAGE_TYPE_3D:
|
||||
return VK_IMAGE_VIEW_TYPE_3D;
|
||||
default:
|
||||
UNREACHABLE("Invalid image type");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
clear_image(struct kk_cmd_buffer *cmd, struct kk_image *image,
|
||||
VkImageLayout image_layout, VkFormat format,
|
||||
const VkClearValue *clear_value, uint32_t range_count,
|
||||
const VkImageSubresourceRange *ranges)
|
||||
{
|
||||
struct kk_device *dev = kk_cmd_buffer_device(cmd);
|
||||
ASSERTED VkResult result;
|
||||
|
||||
for (uint32_t r = 0; r < range_count; r++) {
|
||||
const uint32_t level_count =
|
||||
vk_image_subresource_level_count(&image->vk, &ranges[r]);
|
||||
|
||||
for (uint32_t l = 0; l < level_count; l++) {
|
||||
const uint32_t level = ranges[r].baseMipLevel + l;
|
||||
|
||||
const VkExtent3D level_extent =
|
||||
vk_image_mip_level_extent(&image->vk, level);
|
||||
|
||||
uint32_t base_array_layer, layer_count;
|
||||
if (image->vk.image_type == VK_IMAGE_TYPE_3D) {
|
||||
base_array_layer = 0;
|
||||
layer_count = level_extent.depth;
|
||||
} else {
|
||||
base_array_layer = ranges[r].baseArrayLayer;
|
||||
layer_count =
|
||||
vk_image_subresource_layer_count(&image->vk, &ranges[r]);
|
||||
}
|
||||
|
||||
const VkImageViewUsageCreateInfo view_usage_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO,
|
||||
.usage = (ranges[r].aspectMask & VK_IMAGE_ASPECT_COLOR_BIT)
|
||||
? VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
|
||||
: VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
|
||||
};
|
||||
const VkImageViewCreateInfo view_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
||||
.flags = VK_IMAGE_VIEW_CREATE_DRIVER_INTERNAL_BIT_MESA,
|
||||
.pNext = &view_usage_info,
|
||||
.image = kk_image_to_handle(image),
|
||||
.viewType = render_view_type(image->vk.image_type, layer_count),
|
||||
.format = format,
|
||||
.subresourceRange =
|
||||
{
|
||||
.aspectMask = image->vk.aspects,
|
||||
.baseMipLevel = level,
|
||||
.levelCount = 1,
|
||||
.baseArrayLayer = base_array_layer,
|
||||
.layerCount = layer_count,
|
||||
},
|
||||
};
|
||||
|
||||
/* We use vk_meta_create_image_view here for lifetime managemnt */
|
||||
VkImageView view;
|
||||
result =
|
||||
vk_meta_create_image_view(&cmd->vk, &dev->meta, &view_info, &view);
|
||||
assert(result == VK_SUCCESS);
|
||||
|
||||
VkRenderingInfo render = {
|
||||
.sType = VK_STRUCTURE_TYPE_RENDERING_INFO,
|
||||
.renderArea =
|
||||
{
|
||||
.offset = {0, 0},
|
||||
.extent = {level_extent.width, level_extent.height},
|
||||
},
|
||||
.layerCount = layer_count,
|
||||
};
|
||||
|
||||
VkRenderingAttachmentInfo vk_att = {
|
||||
.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
|
||||
.imageView = view,
|
||||
.imageLayout = image_layout,
|
||||
.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
|
||||
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
|
||||
.clearValue = *clear_value,
|
||||
};
|
||||
|
||||
if (ranges[r].aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) {
|
||||
render.colorAttachmentCount = 1;
|
||||
render.pColorAttachments = &vk_att;
|
||||
}
|
||||
if (ranges[r].aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT)
|
||||
render.pDepthAttachment = &vk_att;
|
||||
if (ranges[r].aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT)
|
||||
render.pStencilAttachment = &vk_att;
|
||||
|
||||
kk_CmdBeginRendering(kk_cmd_buffer_to_handle(cmd), &render);
|
||||
kk_CmdEndRendering(kk_cmd_buffer_to_handle(cmd));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
kk_CmdClearColorImage(VkCommandBuffer commandBuffer, VkImage _image,
|
||||
VkImageLayout imageLayout,
|
||||
const VkClearColorValue *pColor, uint32_t rangeCount,
|
||||
const VkImageSubresourceRange *pRanges)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_cmd_buffer, cmd, commandBuffer);
|
||||
VK_FROM_HANDLE(kk_image, image, _image);
|
||||
|
||||
VkClearValue clear_value = {
|
||||
.color = *pColor,
|
||||
};
|
||||
|
||||
VkFormat vk_format = image->vk.format;
|
||||
if (vk_format == VK_FORMAT_R64_UINT || vk_format == VK_FORMAT_R64_SINT)
|
||||
vk_format = VK_FORMAT_R32G32_UINT;
|
||||
|
||||
enum pipe_format p_format = vk_format_to_pipe_format(vk_format);
|
||||
assert(p_format != PIPE_FORMAT_NONE);
|
||||
|
||||
clear_image(cmd, image, imageLayout, vk_format, &clear_value, rangeCount,
|
||||
pRanges);
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
kk_CmdClearDepthStencilImage(VkCommandBuffer commandBuffer, VkImage _image,
|
||||
VkImageLayout imageLayout,
|
||||
const VkClearDepthStencilValue *pDepthStencil,
|
||||
uint32_t rangeCount,
|
||||
const VkImageSubresourceRange *pRanges)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_cmd_buffer, cmd, commandBuffer);
|
||||
VK_FROM_HANDLE(kk_image, image, _image);
|
||||
|
||||
const VkClearValue clear_value = {
|
||||
.depthStencil = *pDepthStencil,
|
||||
};
|
||||
|
||||
clear_image(cmd, image, imageLayout, image->vk.format, &clear_value,
|
||||
rangeCount, pRanges);
|
||||
}
|
||||
355
src/kosmickrisp/vulkan/kk_cmd_copy.c
Normal file
355
src/kosmickrisp/vulkan/kk_cmd_copy.c
Normal file
|
|
@ -0,0 +1,355 @@
|
|||
/*
|
||||
* Copyright © 2022 Collabora Ltd. and Red Hat Inc.
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "kk_cmd_buffer.h"
|
||||
|
||||
#include "kk_bo.h"
|
||||
#include "kk_buffer.h"
|
||||
#include "kk_device.h"
|
||||
#include "kk_encoder.h"
|
||||
#include "kk_entrypoints.h"
|
||||
#include "kk_physical_device.h"
|
||||
|
||||
#include "kosmickrisp/bridge/mtl_bridge.h"
|
||||
#include "kosmickrisp/bridge/vk_to_mtl_map.h"
|
||||
|
||||
#include "util/format/u_format.h"
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
kk_CmdCopyBuffer2(VkCommandBuffer commandBuffer,
|
||||
const VkCopyBufferInfo2 *pCopyBufferInfo)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_cmd_buffer, cmd, commandBuffer);
|
||||
VK_FROM_HANDLE(kk_buffer, src, pCopyBufferInfo->srcBuffer);
|
||||
VK_FROM_HANDLE(kk_buffer, dst, pCopyBufferInfo->dstBuffer);
|
||||
|
||||
mtl_blit_encoder *blit = kk_blit_encoder(cmd);
|
||||
for (uint32_t i = 0; i < pCopyBufferInfo->regionCount; i++) {
|
||||
const VkBufferCopy2 *region = &pCopyBufferInfo->pRegions[i];
|
||||
mtl_copy_from_buffer_to_buffer(blit, src->mtl_handle, region->srcOffset,
|
||||
dst->mtl_handle, region->dstOffset,
|
||||
region->size);
|
||||
}
|
||||
}
|
||||
|
||||
struct kk_buffer_image_copy_info {
|
||||
struct mtl_buffer_image_copy mtl_data;
|
||||
size_t buffer_slice_size_B;
|
||||
};
|
||||
|
||||
static struct kk_buffer_image_copy_info
|
||||
vk_buffer_image_copy_to_mtl_buffer_image_copy(
|
||||
const VkBufferImageCopy2 *region, const struct kk_image_plane *plane)
|
||||
{
|
||||
struct kk_buffer_image_copy_info copy;
|
||||
enum pipe_format p_format = plane->layout.format.pipe;
|
||||
if (region->imageSubresource.aspectMask == VK_IMAGE_ASPECT_DEPTH_BIT) {
|
||||
copy.mtl_data.options = MTL_BLIT_OPTION_DEPTH_FROM_DEPTH_STENCIL;
|
||||
p_format = util_format_get_depth_only(p_format);
|
||||
} else if (region->imageSubresource.aspectMask ==
|
||||
VK_IMAGE_ASPECT_STENCIL_BIT) {
|
||||
copy.mtl_data.options = MTL_BLIT_OPTION_STENCIL_FROM_DEPTH_STENCIL;
|
||||
p_format = PIPE_FORMAT_S8_UINT;
|
||||
} else
|
||||
copy.mtl_data.options = MTL_BLIT_OPTION_NONE;
|
||||
|
||||
const uint32_t buffer_width = region->bufferRowLength
|
||||
? region->bufferRowLength
|
||||
: region->imageExtent.width;
|
||||
const uint32_t buffer_height = region->bufferImageHeight
|
||||
? region->bufferImageHeight
|
||||
: region->imageExtent.height;
|
||||
|
||||
const uint32_t buffer_stride_B =
|
||||
util_format_get_stride(p_format, buffer_width);
|
||||
const uint32_t buffer_size_2d_B =
|
||||
util_format_get_2d_size(p_format, buffer_stride_B, buffer_height);
|
||||
|
||||
/* Metal requires this value to be 0 for 2D images, otherwise the number of
|
||||
* bytes between each 2D image of a 3D texture */
|
||||
copy.mtl_data.buffer_2d_image_size_B =
|
||||
plane->layout.depth_px == 1u ? 0u : buffer_size_2d_B;
|
||||
copy.mtl_data.buffer_stride_B = buffer_stride_B;
|
||||
copy.mtl_data.image_size = vk_extent_3d_to_mtl_size(®ion->imageExtent);
|
||||
copy.mtl_data.image_origin =
|
||||
vk_offset_3d_to_mtl_origin(®ion->imageOffset);
|
||||
copy.mtl_data.image_level = region->imageSubresource.mipLevel;
|
||||
copy.buffer_slice_size_B = buffer_size_2d_B;
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
#define kk_foreach_slice(ndx, image, subresource_member) \
|
||||
for (uint32_t ndx = region->subresource_member.baseArrayLayer; \
|
||||
ndx < (region->subresource_member.baseArrayLayer + \
|
||||
vk_image_subresource_layer_count(&image->vk, \
|
||||
®ion->subresource_member)); \
|
||||
++ndx)
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
kk_CmdCopyBufferToImage2(VkCommandBuffer commandBuffer,
|
||||
const VkCopyBufferToImageInfo2 *pCopyBufferToImageInfo)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_cmd_buffer, cmd, commandBuffer);
|
||||
VK_FROM_HANDLE(kk_buffer, buffer, pCopyBufferToImageInfo->srcBuffer);
|
||||
VK_FROM_HANDLE(kk_image, image, pCopyBufferToImageInfo->dstImage);
|
||||
|
||||
mtl_blit_encoder *blit = kk_blit_encoder(cmd);
|
||||
for (int r = 0; r < pCopyBufferToImageInfo->regionCount; r++) {
|
||||
const VkBufferImageCopy2 *region = &pCopyBufferToImageInfo->pRegions[r];
|
||||
const uint8_t plane_index = kk_image_memory_aspects_to_plane(
|
||||
image, region->imageSubresource.aspectMask);
|
||||
struct kk_image_plane *plane = &image->planes[plane_index];
|
||||
struct kk_buffer_image_copy_info info =
|
||||
vk_buffer_image_copy_to_mtl_buffer_image_copy(region, plane);
|
||||
info.mtl_data.buffer = buffer->mtl_handle;
|
||||
info.mtl_data.image = plane->mtl_handle;
|
||||
size_t buffer_offset = region->bufferOffset;
|
||||
|
||||
kk_foreach_slice(slice, image, imageSubresource)
|
||||
{
|
||||
info.mtl_data.image_slice = slice;
|
||||
info.mtl_data.buffer_offset_B = buffer_offset;
|
||||
mtl_copy_from_buffer_to_texture(blit, &info.mtl_data);
|
||||
buffer_offset += info.buffer_slice_size_B;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
kk_CmdCopyImageToBuffer2(VkCommandBuffer commandBuffer,
|
||||
const VkCopyImageToBufferInfo2 *pCopyImageToBufferInfo)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_cmd_buffer, cmd, commandBuffer);
|
||||
VK_FROM_HANDLE(kk_image, image, pCopyImageToBufferInfo->srcImage);
|
||||
VK_FROM_HANDLE(kk_buffer, buffer, pCopyImageToBufferInfo->dstBuffer);
|
||||
|
||||
mtl_blit_encoder *blit = kk_blit_encoder(cmd);
|
||||
for (unsigned r = 0; r < pCopyImageToBufferInfo->regionCount; r++) {
|
||||
const VkBufferImageCopy2 *region = &pCopyImageToBufferInfo->pRegions[r];
|
||||
const uint8_t plane_index = kk_image_memory_aspects_to_plane(
|
||||
image, region->imageSubresource.aspectMask);
|
||||
struct kk_image_plane *plane = &image->planes[plane_index];
|
||||
struct kk_buffer_image_copy_info info =
|
||||
vk_buffer_image_copy_to_mtl_buffer_image_copy(region, plane);
|
||||
info.mtl_data.buffer = buffer->mtl_handle;
|
||||
info.mtl_data.image = plane->mtl_handle;
|
||||
size_t buffer_offset = region->bufferOffset;
|
||||
|
||||
kk_foreach_slice(slice, image, imageSubresource)
|
||||
{
|
||||
info.mtl_data.image_slice = slice;
|
||||
info.mtl_data.buffer_offset_B = buffer_offset;
|
||||
mtl_copy_from_texture_to_buffer(blit, &info.mtl_data);
|
||||
buffer_offset += info.buffer_slice_size_B;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct copy_image_data {
|
||||
struct kk_cmd_buffer *cmd;
|
||||
struct kk_image *src;
|
||||
struct kk_image *dst;
|
||||
const VkImageCopy2 *regions;
|
||||
uint32_t plane_index;
|
||||
uint32_t region_count;
|
||||
};
|
||||
|
||||
/* Copies images by doing a texture->buffer->texture transfer. This is required
|
||||
* for compressed formats */
|
||||
static void
|
||||
copy_through_buffer(struct copy_image_data *data)
|
||||
{
|
||||
struct kk_image *src = data->src;
|
||||
struct kk_image *dst = data->dst;
|
||||
struct kk_image_plane *src_plane = &src->planes[data->plane_index];
|
||||
struct kk_image_plane *dst_plane = &dst->planes[data->plane_index];
|
||||
enum pipe_format src_format = src_plane->layout.format.pipe;
|
||||
enum pipe_format dst_format = dst_plane->layout.format.pipe;
|
||||
bool is_src_compressed = util_format_is_compressed(src_format);
|
||||
bool is_dst_compressed = util_format_is_compressed(dst_format);
|
||||
/* We shouldn't do any depth/stencil through this path */
|
||||
assert(!util_format_is_depth_or_stencil(src_format) ||
|
||||
!util_format_is_depth_or_stencil(dst_format));
|
||||
mtl_blit_encoder *blit = kk_blit_encoder(data->cmd);
|
||||
|
||||
size_t buffer_size = 0u;
|
||||
for (unsigned r = 0; r < data->region_count; r++) {
|
||||
const VkImageCopy2 *region = &data->regions[r];
|
||||
const uint32_t buffer_stride_B =
|
||||
util_format_get_stride(src_format, region->extent.width);
|
||||
const uint32_t buffer_size_2d_B = util_format_get_2d_size(
|
||||
src_format, buffer_stride_B, region->extent.height);
|
||||
const uint32_t layer_count =
|
||||
vk_image_subresource_layer_count(&src->vk, ®ion->srcSubresource);
|
||||
buffer_size += buffer_size_2d_B * layer_count;
|
||||
}
|
||||
struct kk_bo *bo = kk_cmd_allocate_buffer(data->cmd, buffer_size, 8);
|
||||
|
||||
size_t buffer_offset = 0u;
|
||||
for (unsigned r = 0; r < data->region_count; r++) {
|
||||
const VkImageCopy2 *region = &data->regions[r];
|
||||
uint32_t mip_level = region->srcSubresource.mipLevel;
|
||||
const uint32_t mip_width =
|
||||
u_minify(src_plane->layout.width_px, mip_level);
|
||||
const uint32_t mip_height =
|
||||
u_minify(src_plane->layout.height_px, mip_level);
|
||||
const uint32_t stride_B = util_format_get_stride(src_format, mip_width);
|
||||
const uint32_t size_2d_B =
|
||||
util_format_get_2d_size(src_format, stride_B, mip_height);
|
||||
const uint32_t buffer_stride_B =
|
||||
util_format_get_stride(src_format, region->extent.width);
|
||||
const uint32_t buffer_size_2d_B = util_format_get_2d_size(
|
||||
src_format, buffer_stride_B, region->extent.height);
|
||||
|
||||
struct kk_buffer_image_copy_info info;
|
||||
|
||||
/* Metal requires this value to be 0 for 2D images, otherwise the number
|
||||
* of bytes between each 2D image of a 3D texture */
|
||||
info.mtl_data.buffer_2d_image_size_B =
|
||||
src_plane->layout.depth_px == 1u ? 0u : size_2d_B;
|
||||
info.mtl_data.buffer_stride_B = buffer_stride_B;
|
||||
info.mtl_data.image_level = mip_level;
|
||||
info.mtl_data.buffer = bo->map;
|
||||
info.mtl_data.options = MTL_BLIT_OPTION_NONE;
|
||||
info.buffer_slice_size_B = buffer_size_2d_B;
|
||||
struct mtl_size src_size = vk_extent_3d_to_mtl_size(®ion->extent);
|
||||
struct mtl_size dst_size = vk_extent_3d_to_mtl_size(®ion->extent);
|
||||
/* Need to adjust size to block dimensions */
|
||||
if (is_src_compressed) {
|
||||
dst_size.x /= util_format_get_blockwidth(src_format);
|
||||
dst_size.y /= util_format_get_blockheight(src_format);
|
||||
dst_size.z /= util_format_get_blockdepth(src_format);
|
||||
}
|
||||
if (is_dst_compressed) {
|
||||
dst_size.x *= util_format_get_blockwidth(dst_format);
|
||||
dst_size.y *= util_format_get_blockheight(dst_format);
|
||||
dst_size.z *= util_format_get_blockdepth(dst_format);
|
||||
}
|
||||
struct mtl_origin src_origin =
|
||||
vk_offset_3d_to_mtl_origin(®ion->srcOffset);
|
||||
struct mtl_origin dst_origin =
|
||||
vk_offset_3d_to_mtl_origin(®ion->dstOffset);
|
||||
|
||||
/* Texture->Buffer->Texture */
|
||||
// TODO_KOSMICKRISP We don't handle 3D to 2D array nor vice-versa in this
|
||||
// path. Unsure if it's even needed, can compressed textures be 3D?
|
||||
kk_foreach_slice(slice, src, srcSubresource)
|
||||
{
|
||||
info.mtl_data.image = src_plane->mtl_handle;
|
||||
info.mtl_data.image_size = src_size;
|
||||
info.mtl_data.image_origin = src_origin;
|
||||
info.mtl_data.image_slice = slice;
|
||||
info.mtl_data.buffer_offset_B = buffer_offset;
|
||||
mtl_copy_from_texture_to_buffer(blit, &info.mtl_data);
|
||||
|
||||
info.mtl_data.image = dst_plane->mtl_handle;
|
||||
info.mtl_data.image_size = dst_size;
|
||||
info.mtl_data.image_origin = dst_origin;
|
||||
mtl_copy_from_buffer_to_texture(blit, &info.mtl_data);
|
||||
|
||||
buffer_offset += info.buffer_slice_size_B;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Copies images through Metal's texture->texture copy mechanism */
|
||||
static void
|
||||
copy_image(struct copy_image_data *data)
|
||||
{
|
||||
mtl_blit_encoder *blit = kk_blit_encoder(data->cmd);
|
||||
for (unsigned r = 0; r < data->region_count; r++) {
|
||||
const VkImageCopy2 *region = &data->regions[r];
|
||||
uint8_t src_plane_index = kk_image_aspects_to_plane(
|
||||
data->src, region->srcSubresource.aspectMask);
|
||||
if (data->plane_index != src_plane_index)
|
||||
continue;
|
||||
|
||||
uint8_t dst_plane_index = kk_image_aspects_to_plane(
|
||||
data->dst, region->dstSubresource.aspectMask);
|
||||
struct kk_image *src = data->src;
|
||||
struct kk_image *dst = data->dst;
|
||||
struct kk_image_plane *src_plane = &src->planes[src_plane_index];
|
||||
struct kk_image_plane *dst_plane = &dst->planes[dst_plane_index];
|
||||
|
||||
/* From the Vulkan 1.3.217 spec:
|
||||
*
|
||||
* "When copying between compressed and uncompressed formats the
|
||||
* extent members represent the texel dimensions of the source image
|
||||
* and not the destination."
|
||||
*/
|
||||
const VkExtent3D extent_px =
|
||||
vk_image_sanitize_extent(&src->vk, region->extent);
|
||||
|
||||
size_t src_slice = region->srcSubresource.baseArrayLayer;
|
||||
size_t src_level = region->srcSubresource.mipLevel;
|
||||
struct mtl_origin src_origin =
|
||||
vk_offset_3d_to_mtl_origin(®ion->srcOffset);
|
||||
struct mtl_size size = {.x = extent_px.width,
|
||||
.y = extent_px.height,
|
||||
.z = extent_px.depth};
|
||||
size_t dst_slice = region->dstSubresource.baseArrayLayer;
|
||||
size_t dst_level = region->dstSubresource.mipLevel;
|
||||
struct mtl_origin dst_origin =
|
||||
vk_offset_3d_to_mtl_origin(®ion->dstOffset);
|
||||
|
||||
/* When copying 3D to 2D layered or vice-versa, we need to change the 3D
|
||||
* size to 2D and iterate on the layer count of the 2D image (which is the
|
||||
* same as the depth of the 3D) and adjust origin and slice accordingly */
|
||||
uint32_t layer_count =
|
||||
vk_image_subresource_layer_count(&src->vk, ®ion->srcSubresource);
|
||||
const uint32_t dst_layer_count =
|
||||
vk_image_subresource_layer_count(&dst->vk, ®ion->dstSubresource);
|
||||
size_t *src_increase = &src_slice;
|
||||
size_t *dst_increase = &dst_slice;
|
||||
|
||||
if (layer_count < dst_layer_count) { /* 3D to 2D layered */
|
||||
layer_count = dst_layer_count;
|
||||
src_increase = &src_origin.z;
|
||||
size.z = 1u;
|
||||
} else if (dst_layer_count < layer_count) { /* 2D layered to 3D */
|
||||
dst_increase = &dst_origin.z;
|
||||
size.z = 1u;
|
||||
}
|
||||
for (uint32_t l = 0; l < layer_count;
|
||||
++l, ++(*src_increase), ++(*dst_increase)) {
|
||||
mtl_copy_from_texture_to_texture(
|
||||
blit, src_plane->mtl_handle, src_slice, src_level, src_origin, size,
|
||||
dst_plane->mtl_handle, dst_slice, dst_level, dst_origin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
kk_CmdCopyImage2(VkCommandBuffer commandBuffer,
|
||||
const VkCopyImageInfo2 *pCopyImageInfo)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_cmd_buffer, cmd, commandBuffer);
|
||||
VK_FROM_HANDLE(kk_image, src, pCopyImageInfo->srcImage);
|
||||
VK_FROM_HANDLE(kk_image, dst, pCopyImageInfo->dstImage);
|
||||
|
||||
for (uint32_t i = 0u; i < src->plane_count; ++i) {
|
||||
struct kk_image_plane *src_plane = &src->planes[i];
|
||||
struct kk_image_plane *dst_plane = &dst->planes[i];
|
||||
enum pipe_format src_format = src_plane->layout.format.pipe;
|
||||
enum pipe_format dst_format = dst_plane->layout.format.pipe;
|
||||
struct copy_image_data data = {
|
||||
.cmd = cmd,
|
||||
.src = src,
|
||||
.dst = dst,
|
||||
.regions = pCopyImageInfo->pRegions,
|
||||
.plane_index = i,
|
||||
.region_count = pCopyImageInfo->regionCount,
|
||||
};
|
||||
bool is_src_compressed = util_format_is_compressed(src_format);
|
||||
bool is_dst_compressed = util_format_is_compressed(dst_format);
|
||||
if (src_format != dst_format && (is_src_compressed || is_dst_compressed))
|
||||
copy_through_buffer(&data);
|
||||
else
|
||||
copy_image(&data);
|
||||
}
|
||||
}
|
||||
152
src/kosmickrisp/vulkan/kk_cmd_dispatch.c
Normal file
152
src/kosmickrisp/vulkan/kk_cmd_dispatch.c
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
* Copyright © 2025 LunarG, Inc
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "vulkan/vulkan_core.h"
|
||||
|
||||
#include "kk_buffer.h"
|
||||
#include "kk_cmd_buffer.h"
|
||||
#include "kk_descriptor_set_layout.h"
|
||||
#include "kk_device.h"
|
||||
#include "kk_encoder.h"
|
||||
#include "kk_entrypoints.h"
|
||||
#include "kk_shader.h"
|
||||
|
||||
#include "kosmickrisp/bridge/mtl_bridge.h"
|
||||
|
||||
#include "vk_common_entrypoints.h"
|
||||
|
||||
void
|
||||
kk_cmd_dispatch_pipeline(struct kk_cmd_buffer *cmd,
|
||||
mtl_compute_encoder *encoder,
|
||||
mtl_compute_pipeline_state *pipeline,
|
||||
const void *push_data, size_t push_size,
|
||||
uint32_t groupCountX, uint32_t groupCountY,
|
||||
uint32_t groupCountZ)
|
||||
{
|
||||
struct kk_root_descriptor_table *root = NULL;
|
||||
struct kk_bo *bo = kk_cmd_allocate_buffer(cmd, sizeof(*root), 8u);
|
||||
/* kk_cmd_allocate_buffer already sets the error, we can just exit */
|
||||
if (!bo)
|
||||
return;
|
||||
|
||||
root = bo->cpu;
|
||||
assert(push_size <= sizeof(root->push));
|
||||
memcpy(root->push, push_data, push_size);
|
||||
root->cs.base_group[0] = 1; /* TODO_KOSMICKRISP This is hard-coded because we
|
||||
know this is the size we create them with */
|
||||
root->cs.base_group[1] = 1;
|
||||
root->cs.base_group[2] = 1;
|
||||
|
||||
mtl_compute_set_buffer(encoder, bo->map, 0, 0);
|
||||
mtl_compute_set_pipeline_state(encoder, pipeline);
|
||||
|
||||
struct mtl_size grid_size = {
|
||||
.x = groupCountX,
|
||||
.y = groupCountY,
|
||||
.z = groupCountZ,
|
||||
};
|
||||
struct mtl_size local_size = {
|
||||
.x = 1,
|
||||
.y = 1,
|
||||
.z = 1,
|
||||
};
|
||||
mtl_dispatch_threads(encoder, grid_size, local_size);
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
kk_CmdDispatch(VkCommandBuffer commandBuffer, uint32_t groupCountX,
|
||||
uint32_t groupCountY, uint32_t groupCountZ)
|
||||
{
|
||||
kk_CmdDispatchBase(commandBuffer, 0, 0, 0, groupCountX, groupCountY,
|
||||
groupCountZ);
|
||||
}
|
||||
|
||||
static void
|
||||
kk_flush_compute_state(struct kk_cmd_buffer *cmd)
|
||||
{
|
||||
mtl_compute_encoder *enc = kk_compute_encoder(cmd);
|
||||
struct kk_device *dev = kk_cmd_buffer_device(cmd);
|
||||
|
||||
// Fill Metal argument buffer with descriptor set addresses
|
||||
struct kk_descriptor_state *desc = &cmd->state.cs.descriptors;
|
||||
|
||||
if (desc->push_dirty)
|
||||
kk_cmd_buffer_flush_push_descriptors(cmd, desc);
|
||||
/* After push descriptors' buffers are created. Otherwise, the buffer where
|
||||
* they live will not be created and cannot make it resident */
|
||||
if (desc->sets_not_resident)
|
||||
kk_make_descriptor_resources_resident(cmd,
|
||||
VK_PIPELINE_BIND_POINT_COMPUTE);
|
||||
if (desc->root_dirty)
|
||||
kk_upload_descriptor_root(cmd, VK_PIPELINE_BIND_POINT_COMPUTE);
|
||||
|
||||
/* Make user allocated heaps resident */
|
||||
simple_mtx_lock(&dev->user_heap_cache.mutex);
|
||||
if (cmd->encoder->main.user_heap_hash != dev->user_heap_cache.hash) {
|
||||
cmd->encoder->main.user_heap_hash = dev->user_heap_cache.hash;
|
||||
mtl_heap **heaps = util_dynarray_begin(&dev->user_heap_cache.handles);
|
||||
uint32_t count =
|
||||
util_dynarray_num_elements(&dev->user_heap_cache.handles, mtl_heap *);
|
||||
mtl_compute_use_heaps(enc, heaps, count);
|
||||
}
|
||||
simple_mtx_unlock(&dev->user_heap_cache.mutex);
|
||||
|
||||
struct kk_bo *root_buffer = desc->root.root_buffer;
|
||||
if (root_buffer)
|
||||
mtl_compute_set_buffer(enc, root_buffer->map, 0, 0);
|
||||
|
||||
mtl_compute_set_pipeline_state(enc, cmd->state.cs.pipeline_state);
|
||||
cmd->state.cs.dirty = 0u;
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
kk_CmdDispatchBase(VkCommandBuffer commandBuffer, uint32_t baseGroupX,
|
||||
uint32_t baseGroupY, uint32_t baseGroupZ,
|
||||
uint32_t groupCountX, uint32_t groupCountY,
|
||||
uint32_t groupCountZ)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_cmd_buffer, cmd, commandBuffer);
|
||||
|
||||
struct kk_descriptor_state *desc = &cmd->state.cs.descriptors;
|
||||
desc->root_dirty |= desc->root.cs.base_group[0] != baseGroupX;
|
||||
desc->root_dirty |= desc->root.cs.base_group[1] != baseGroupY;
|
||||
desc->root_dirty |= desc->root.cs.base_group[2] != baseGroupZ;
|
||||
desc->root.cs.base_group[0] = baseGroupX;
|
||||
desc->root.cs.base_group[1] = baseGroupY;
|
||||
desc->root.cs.base_group[2] = baseGroupZ;
|
||||
|
||||
kk_flush_compute_state(cmd);
|
||||
|
||||
struct mtl_size grid_size = {
|
||||
.x = groupCountX,
|
||||
.y = groupCountY,
|
||||
.z = groupCountZ,
|
||||
};
|
||||
mtl_compute_encoder *enc = kk_compute_encoder(cmd);
|
||||
mtl_dispatch_threads(enc, grid_size, cmd->state.cs.local_size);
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
kk_CmdDispatchIndirect(VkCommandBuffer commandBuffer, VkBuffer _buffer,
|
||||
VkDeviceSize offset)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_cmd_buffer, cmd, commandBuffer);
|
||||
VK_FROM_HANDLE(kk_buffer, buffer, _buffer);
|
||||
|
||||
struct kk_descriptor_state *desc = &cmd->state.cs.descriptors;
|
||||
desc->root_dirty |= desc->root.cs.base_group[0] != 0;
|
||||
desc->root_dirty |= desc->root.cs.base_group[1] != 0;
|
||||
desc->root_dirty |= desc->root.cs.base_group[2] != 0;
|
||||
desc->root.cs.base_group[0] = 0;
|
||||
desc->root.cs.base_group[1] = 0;
|
||||
desc->root.cs.base_group[2] = 0;
|
||||
|
||||
kk_flush_compute_state(cmd);
|
||||
|
||||
mtl_compute_encoder *enc = kk_compute_encoder(cmd);
|
||||
mtl_dispatch_threadgroups_with_indirect_buffer(
|
||||
enc, buffer->mtl_handle, offset, cmd->state.cs.local_size);
|
||||
}
|
||||
1010
src/kosmickrisp/vulkan/kk_cmd_draw.c
Normal file
1010
src/kosmickrisp/vulkan/kk_cmd_draw.c
Normal file
File diff suppressed because it is too large
Load diff
318
src/kosmickrisp/vulkan/kk_cmd_meta.c
Normal file
318
src/kosmickrisp/vulkan/kk_cmd_meta.c
Normal file
|
|
@ -0,0 +1,318 @@
|
|||
/*
|
||||
* Copyright 2024 Valve Corporation
|
||||
* Copyright 2024 Alyssa Rosenzweig
|
||||
* Copyright © 2022 Collabora Ltd. and Red Hat Inc.
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "kk_private.h"
|
||||
|
||||
#include "kk_buffer.h"
|
||||
#include "kk_cmd_buffer.h"
|
||||
#include "kk_encoder.h"
|
||||
|
||||
#include "kosmickrisp/bridge/mtl_bridge.h"
|
||||
|
||||
#include "kk_entrypoints.h"
|
||||
|
||||
static VkResult
|
||||
kk_cmd_bind_map_buffer(struct vk_command_buffer *vk_cmd,
|
||||
struct vk_meta_device *meta, VkBuffer _buffer,
|
||||
void **map_out)
|
||||
{
|
||||
struct kk_cmd_buffer *cmd = container_of(vk_cmd, struct kk_cmd_buffer, vk);
|
||||
VK_FROM_HANDLE(kk_buffer, buffer, _buffer);
|
||||
|
||||
assert(buffer->vk.size < UINT_MAX);
|
||||
struct kk_bo *bo = kk_cmd_allocate_buffer(cmd, buffer->vk.size, 16u);
|
||||
if (unlikely(bo == NULL))
|
||||
return VK_ERROR_OUT_OF_POOL_MEMORY;
|
||||
|
||||
/* Need to retain since VkBuffers release the mtl_handle too */
|
||||
mtl_retain(bo->map);
|
||||
buffer->mtl_handle = bo->map;
|
||||
buffer->vk.device_address = bo->gpu;
|
||||
*map_out = bo->cpu;
|
||||
mtl_compute_use_resource(cmd->encoder->main.encoder, buffer->mtl_handle,
|
||||
MTL_RESOURCE_USAGE_WRITE | MTL_RESOURCE_USAGE_READ);
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VkResult
|
||||
kk_device_init_meta(struct kk_device *dev)
|
||||
{
|
||||
VkResult result = vk_meta_device_init(&dev->vk, &dev->meta);
|
||||
if (result != VK_SUCCESS)
|
||||
return result;
|
||||
|
||||
dev->meta.use_gs_for_layer = false;
|
||||
dev->meta.use_stencil_export = true;
|
||||
dev->meta.use_rect_list_pipeline = true;
|
||||
dev->meta.cmd_bind_map_buffer = kk_cmd_bind_map_buffer;
|
||||
dev->meta.max_bind_map_buffer_size_B = 64 * 1024;
|
||||
|
||||
for (unsigned i = 0; i < VK_META_BUFFER_CHUNK_SIZE_COUNT; ++i) {
|
||||
dev->meta.buffer_access.optimal_wg_size[i] = 64;
|
||||
}
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
void
|
||||
kk_device_finish_meta(struct kk_device *dev)
|
||||
{
|
||||
vk_meta_device_finish(&dev->vk, &dev->meta);
|
||||
}
|
||||
|
||||
struct kk_meta_save {
|
||||
struct vk_vertex_input_state _dynamic_vi;
|
||||
struct vk_sample_locations_state _dynamic_sl;
|
||||
struct vk_dynamic_graphics_state dynamic;
|
||||
struct {
|
||||
union {
|
||||
struct {
|
||||
mtl_render_pipeline_state *ps;
|
||||
mtl_depth_stencil_state *ds;
|
||||
uint32_t attribs_read;
|
||||
enum mtl_primitive_type primitive_type;
|
||||
enum mtl_visibility_result_mode occlusion;
|
||||
bool is_ds_dynamic;
|
||||
} gfx;
|
||||
struct {
|
||||
mtl_compute_pipeline_state *pipeline_state;
|
||||
struct mtl_size local_size;
|
||||
} cs;
|
||||
};
|
||||
} pipeline;
|
||||
struct kk_descriptor_set *desc0;
|
||||
struct kk_push_descriptor_set *push_desc0;
|
||||
mtl_buffer *vb0_handle;
|
||||
struct kk_addr_range vb0;
|
||||
struct kk_buffer_address desc0_set_addr;
|
||||
bool has_push_desc0;
|
||||
uint8_t push[KK_MAX_PUSH_SIZE];
|
||||
};
|
||||
|
||||
static void
|
||||
kk_meta_begin(struct kk_cmd_buffer *cmd, struct kk_meta_save *save,
|
||||
VkPipelineBindPoint bind_point)
|
||||
{
|
||||
struct kk_descriptor_state *desc = kk_get_descriptors_state(cmd, bind_point);
|
||||
|
||||
if (bind_point == VK_PIPELINE_BIND_POINT_GRAPHICS) {
|
||||
save->dynamic = cmd->vk.dynamic_graphics_state;
|
||||
save->_dynamic_vi = cmd->state.gfx._dynamic_vi;
|
||||
save->_dynamic_sl = cmd->state.gfx._dynamic_sl;
|
||||
save->pipeline.gfx.ps = cmd->state.gfx.pipeline_state;
|
||||
save->pipeline.gfx.ds = cmd->state.gfx.depth_stencil_state;
|
||||
save->pipeline.gfx.attribs_read = cmd->state.gfx.vb.attribs_read;
|
||||
save->pipeline.gfx.primitive_type = cmd->state.gfx.primitive_type;
|
||||
save->pipeline.gfx.occlusion = cmd->state.gfx.occlusion.mode;
|
||||
save->pipeline.gfx.is_ds_dynamic =
|
||||
cmd->state.gfx.is_depth_stencil_dynamic;
|
||||
|
||||
cmd->state.gfx.is_depth_stencil_dynamic = false;
|
||||
cmd->state.gfx.depth_stencil_state = NULL;
|
||||
cmd->state.gfx.occlusion.mode = MTL_VISIBILITY_RESULT_MODE_DISABLED;
|
||||
cmd->state.gfx.dirty |= KK_DIRTY_OCCLUSION;
|
||||
desc->root_dirty = true;
|
||||
} else {
|
||||
save->pipeline.cs.pipeline_state = cmd->state.cs.pipeline_state;
|
||||
save->pipeline.cs.local_size = cmd->state.cs.local_size;
|
||||
}
|
||||
|
||||
save->vb0_handle = cmd->state.gfx.vb.handles[0];
|
||||
save->vb0 = cmd->state.gfx.vb.addr_range[0];
|
||||
|
||||
save->desc0 = desc->sets[0];
|
||||
save->has_push_desc0 = desc->push[0];
|
||||
if (save->has_push_desc0)
|
||||
save->push_desc0 = desc->push[0];
|
||||
|
||||
static_assert(sizeof(save->push) == sizeof(desc->root.push),
|
||||
"Size mismatch for push in meta_save");
|
||||
memcpy(save->push, desc->root.push, sizeof(save->push));
|
||||
}
|
||||
|
||||
static void
|
||||
kk_meta_end(struct kk_cmd_buffer *cmd, struct kk_meta_save *save,
|
||||
VkPipelineBindPoint bind_point)
|
||||
{
|
||||
struct kk_descriptor_state *desc = kk_get_descriptors_state(cmd, bind_point);
|
||||
desc->root_dirty = true;
|
||||
|
||||
if (save->desc0) {
|
||||
desc->sets[0] = save->desc0;
|
||||
desc->root.sets[0] = save->desc0->addr;
|
||||
desc->set_sizes[0] = save->desc0->size;
|
||||
desc->sets_not_resident |= BITFIELD_BIT(0);
|
||||
desc->push_dirty &= ~BITFIELD_BIT(0);
|
||||
} else if (save->has_push_desc0) {
|
||||
desc->push[0] = save->push_desc0;
|
||||
desc->sets_not_resident |= BITFIELD_BIT(0);
|
||||
desc->push_dirty |= BITFIELD_BIT(0);
|
||||
}
|
||||
|
||||
if (bind_point == VK_PIPELINE_BIND_POINT_GRAPHICS) {
|
||||
/* Restore the dynamic state */
|
||||
assert(save->dynamic.vi == &cmd->state.gfx._dynamic_vi);
|
||||
assert(save->dynamic.ms.sample_locations == &cmd->state.gfx._dynamic_sl);
|
||||
cmd->vk.dynamic_graphics_state = save->dynamic;
|
||||
cmd->state.gfx._dynamic_vi = save->_dynamic_vi;
|
||||
cmd->state.gfx._dynamic_sl = save->_dynamic_sl;
|
||||
memcpy(cmd->vk.dynamic_graphics_state.dirty,
|
||||
cmd->vk.dynamic_graphics_state.set,
|
||||
sizeof(cmd->vk.dynamic_graphics_state.set));
|
||||
|
||||
if (cmd->state.gfx.is_depth_stencil_dynamic)
|
||||
mtl_release(cmd->state.gfx.depth_stencil_state);
|
||||
cmd->state.gfx.pipeline_state = save->pipeline.gfx.ps;
|
||||
cmd->state.gfx.depth_stencil_state = save->pipeline.gfx.ds;
|
||||
cmd->state.gfx.primitive_type = save->pipeline.gfx.primitive_type;
|
||||
cmd->state.gfx.vb.attribs_read = save->pipeline.gfx.attribs_read;
|
||||
cmd->state.gfx.is_depth_stencil_dynamic =
|
||||
save->pipeline.gfx.is_ds_dynamic;
|
||||
cmd->state.gfx.dirty |= KK_DIRTY_PIPELINE;
|
||||
|
||||
cmd->state.gfx.vb.addr_range[0] = save->vb0;
|
||||
cmd->state.gfx.vb.handles[0] = save->vb0_handle;
|
||||
cmd->state.gfx.dirty |= KK_DIRTY_VB;
|
||||
|
||||
cmd->state.gfx.occlusion.mode = save->pipeline.gfx.occlusion;
|
||||
cmd->state.gfx.dirty |= KK_DIRTY_OCCLUSION;
|
||||
|
||||
desc->root_dirty = true;
|
||||
} else {
|
||||
cmd->state.cs.local_size = save->pipeline.cs.local_size;
|
||||
cmd->state.cs.pipeline_state = save->pipeline.cs.pipeline_state;
|
||||
}
|
||||
|
||||
memcpy(desc->root.push, save->push, sizeof(save->push));
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
kk_CmdFillBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer,
|
||||
VkDeviceSize dstOffset, VkDeviceSize dstRange, uint32_t data)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_cmd_buffer, cmd, commandBuffer);
|
||||
VK_FROM_HANDLE(kk_buffer, buf, dstBuffer);
|
||||
struct kk_device *dev = kk_cmd_buffer_device(cmd);
|
||||
|
||||
struct kk_meta_save save;
|
||||
kk_meta_begin(cmd, &save, VK_PIPELINE_BIND_POINT_COMPUTE);
|
||||
mtl_compute_use_resource(kk_compute_encoder(cmd), buf->mtl_handle,
|
||||
MTL_RESOURCE_USAGE_WRITE);
|
||||
vk_meta_fill_buffer(&cmd->vk, &dev->meta, dstBuffer, dstOffset, dstRange,
|
||||
data);
|
||||
kk_meta_end(cmd, &save, VK_PIPELINE_BIND_POINT_COMPUTE);
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
kk_CmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer,
|
||||
VkDeviceSize dstOffset, VkDeviceSize dstRange,
|
||||
const void *pData)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_cmd_buffer, cmd, commandBuffer);
|
||||
VK_FROM_HANDLE(kk_buffer, buf, dstBuffer);
|
||||
struct kk_device *dev = kk_cmd_buffer_device(cmd);
|
||||
|
||||
struct kk_meta_save save;
|
||||
kk_meta_begin(cmd, &save, VK_PIPELINE_BIND_POINT_COMPUTE);
|
||||
mtl_compute_use_resource(kk_compute_encoder(cmd), buf->mtl_handle,
|
||||
MTL_RESOURCE_USAGE_WRITE);
|
||||
vk_meta_update_buffer(&cmd->vk, &dev->meta, dstBuffer, dstOffset, dstRange,
|
||||
pData);
|
||||
kk_meta_end(cmd, &save, VK_PIPELINE_BIND_POINT_COMPUTE);
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
kk_CmdBlitImage2(VkCommandBuffer commandBuffer,
|
||||
const VkBlitImageInfo2 *pBlitImageInfo)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_cmd_buffer, cmd, commandBuffer);
|
||||
struct kk_device *dev = kk_cmd_buffer_device(cmd);
|
||||
|
||||
struct kk_meta_save save;
|
||||
kk_meta_begin(cmd, &save, VK_PIPELINE_BIND_POINT_GRAPHICS);
|
||||
vk_meta_blit_image2(&cmd->vk, &dev->meta, pBlitImageInfo);
|
||||
kk_meta_end(cmd, &save, VK_PIPELINE_BIND_POINT_GRAPHICS);
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
kk_CmdResolveImage2(VkCommandBuffer commandBuffer,
|
||||
const VkResolveImageInfo2 *pResolveImageInfo)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_cmd_buffer, cmd, commandBuffer);
|
||||
struct kk_device *dev = kk_cmd_buffer_device(cmd);
|
||||
|
||||
struct kk_meta_save save;
|
||||
kk_meta_begin(cmd, &save, VK_PIPELINE_BIND_POINT_GRAPHICS);
|
||||
vk_meta_resolve_image2(&cmd->vk, &dev->meta, pResolveImageInfo);
|
||||
kk_meta_end(cmd, &save, VK_PIPELINE_BIND_POINT_GRAPHICS);
|
||||
}
|
||||
|
||||
static void
|
||||
kk_meta_init_render(struct kk_cmd_buffer *cmd,
|
||||
struct vk_meta_rendering_info *info)
|
||||
{
|
||||
const struct kk_rendering_state *render = &cmd->state.gfx.render;
|
||||
|
||||
*info = (struct vk_meta_rendering_info){
|
||||
.samples = MAX2(render->samples, 1),
|
||||
.view_mask = render->view_mask,
|
||||
.color_attachment_count = render->color_att_count,
|
||||
.depth_attachment_format = render->depth_att.vk_format,
|
||||
.stencil_attachment_format = render->stencil_att.vk_format,
|
||||
};
|
||||
for (uint32_t a = 0; a < render->color_att_count; a++) {
|
||||
info->color_attachment_formats[a] = render->color_att[a].vk_format;
|
||||
info->color_attachment_write_masks[a] =
|
||||
VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
|
||||
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
|
||||
}
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
kk_CmdClearAttachments(VkCommandBuffer commandBuffer, uint32_t attachmentCount,
|
||||
const VkClearAttachment *pAttachments,
|
||||
uint32_t rectCount, const VkClearRect *pRects)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_cmd_buffer, cmd, commandBuffer);
|
||||
struct kk_device *dev = kk_cmd_buffer_device(cmd);
|
||||
|
||||
struct vk_meta_rendering_info render_info;
|
||||
kk_meta_init_render(cmd, &render_info);
|
||||
|
||||
uint32_t view_mask = cmd->state.gfx.render.view_mask;
|
||||
struct kk_encoder *encoder = cmd->encoder;
|
||||
uint32_t layer_ids[KK_MAX_MULTIVIEW_VIEW_COUNT] = {};
|
||||
mtl_set_vertex_amplification_count(encoder->main.encoder, layer_ids, 1u);
|
||||
|
||||
struct kk_meta_save save;
|
||||
kk_meta_begin(cmd, &save, VK_PIPELINE_BIND_POINT_GRAPHICS);
|
||||
vk_meta_clear_attachments(&cmd->vk, &dev->meta, &render_info,
|
||||
attachmentCount, pAttachments, rectCount, pRects);
|
||||
kk_meta_end(cmd, &save, VK_PIPELINE_BIND_POINT_GRAPHICS);
|
||||
|
||||
uint32_t count = 0u;
|
||||
u_foreach_bit(id, view_mask)
|
||||
layer_ids[count++] = id;
|
||||
if (view_mask == 0u) {
|
||||
layer_ids[count++] = 0;
|
||||
}
|
||||
mtl_set_vertex_amplification_count(encoder->main.encoder, layer_ids, count);
|
||||
}
|
||||
|
||||
void
|
||||
kk_meta_resolve_rendering(struct kk_cmd_buffer *cmd,
|
||||
const VkRenderingInfo *pRenderingInfo)
|
||||
{
|
||||
struct kk_device *dev = kk_cmd_buffer_device(cmd);
|
||||
|
||||
struct kk_meta_save save;
|
||||
kk_meta_begin(cmd, &save, VK_PIPELINE_BIND_POINT_GRAPHICS);
|
||||
vk_meta_resolve_rendering(&cmd->vk, &dev->meta, pRenderingInfo);
|
||||
kk_meta_end(cmd, &save, VK_PIPELINE_BIND_POINT_GRAPHICS);
|
||||
}
|
||||
64
src/kosmickrisp/vulkan/kk_cmd_pool.c
Normal file
64
src/kosmickrisp/vulkan/kk_cmd_pool.c
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright © 2022 Collabora Ltd. and Red Hat Inc.
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "kk_cmd_pool.h"
|
||||
|
||||
#include "kk_device.h"
|
||||
#include "kk_entrypoints.h"
|
||||
#include "kk_physical_device.h"
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL
|
||||
kk_CreateCommandPool(VkDevice _device,
|
||||
const VkCommandPoolCreateInfo *pCreateInfo,
|
||||
const VkAllocationCallbacks *pAllocator,
|
||||
VkCommandPool *pCmdPool)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_device, device, _device);
|
||||
struct kk_cmd_pool *pool;
|
||||
|
||||
pool = vk_alloc2(&device->vk.alloc, pAllocator, sizeof(*pool), 8,
|
||||
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
|
||||
if (pool == NULL)
|
||||
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
|
||||
|
||||
VkResult result =
|
||||
vk_command_pool_init(&device->vk, &pool->vk, pCreateInfo, pAllocator);
|
||||
if (result != VK_SUCCESS) {
|
||||
vk_free2(&device->vk.alloc, pAllocator, pool);
|
||||
return result;
|
||||
}
|
||||
|
||||
list_inithead(&pool->free_mem);
|
||||
list_inithead(&pool->free_gart_mem);
|
||||
|
||||
*pCmdPool = kk_cmd_pool_to_handle(pool);
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
kk_DestroyCommandPool(VkDevice _device, VkCommandPool commandPool,
|
||||
const VkAllocationCallbacks *pAllocator)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_device, device, _device);
|
||||
VK_FROM_HANDLE(kk_cmd_pool, pool, commandPool);
|
||||
|
||||
if (!pool)
|
||||
return;
|
||||
|
||||
vk_command_pool_finish(&pool->vk);
|
||||
vk_free2(&device->vk.alloc, pAllocator, pool);
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
kk_TrimCommandPool(VkDevice device, VkCommandPool commandPool,
|
||||
VkCommandPoolTrimFlags flags)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_cmd_pool, pool, commandPool);
|
||||
|
||||
vk_command_pool_trim(&pool->vk, flags);
|
||||
}
|
||||
32
src/kosmickrisp/vulkan/kk_cmd_pool.h
Normal file
32
src/kosmickrisp/vulkan/kk_cmd_pool.h
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright © 2022 Collabora Ltd. and Red Hat Inc.
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef KK_CMD_POOL_H
|
||||
#define KK_CMD_POOL_H
|
||||
|
||||
#include "kk_private.h"
|
||||
|
||||
#include "vk_command_pool.h"
|
||||
|
||||
struct kk_cmd_pool {
|
||||
struct vk_command_pool vk;
|
||||
|
||||
/** List of nvk_cmd_mem */
|
||||
struct list_head free_mem;
|
||||
struct list_head free_gart_mem;
|
||||
};
|
||||
|
||||
VK_DEFINE_NONDISP_HANDLE_CASTS(kk_cmd_pool, vk.base, VkCommandPool,
|
||||
VK_OBJECT_TYPE_COMMAND_POOL)
|
||||
|
||||
static inline struct kk_device *
|
||||
kk_cmd_pool_device(struct kk_cmd_pool *pool)
|
||||
{
|
||||
return (struct kk_device *)pool->vk.base.device;
|
||||
}
|
||||
|
||||
#endif /* KK_CMD_POOL_H */
|
||||
22
src/kosmickrisp/vulkan/kk_debug.c
Normal file
22
src/kosmickrisp/vulkan/kk_debug.c
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
#include "kk_debug.h"
|
||||
#include "util/u_debug.h"
|
||||
|
||||
enum kk_debug kk_mesa_debug_flags = 0;
|
||||
|
||||
const struct debug_named_value flags[] = {
|
||||
{"nir", KK_DEBUG_NIR},
|
||||
{"msl", KK_DEBUG_MSL},
|
||||
{NULL, 0},
|
||||
};
|
||||
|
||||
DEBUG_GET_ONCE_FLAGS_OPTION(mesa_kk_debug, "MESA_KK_DEBUG", flags, 0);
|
||||
|
||||
void
|
||||
kk_process_debug_variable(void)
|
||||
{
|
||||
kk_mesa_debug_flags = debug_get_option_mesa_kk_debug();
|
||||
}
|
||||
21
src/kosmickrisp/vulkan/kk_debug.h
Normal file
21
src/kosmickrisp/vulkan/kk_debug.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
#ifndef KK_DEBUG_H
|
||||
#define KK_DEBUG_H 1
|
||||
|
||||
enum kk_debug {
|
||||
/* Print out the NIR from the compiler */
|
||||
KK_DEBUG_NIR = 1ull << 0,
|
||||
/* Print out the generated MSL source code from the compiler */
|
||||
KK_DEBUG_MSL = 1ull << 1,
|
||||
};
|
||||
|
||||
extern enum kk_debug kk_mesa_debug_flags;
|
||||
|
||||
#define KK_DEBUG(flag) unlikely(kk_mesa_debug_flags &KK_DEBUG_##flag)
|
||||
|
||||
extern void kk_process_debug_variable(void);
|
||||
|
||||
#endif /* KK_DEBUG_H */
|
||||
806
src/kosmickrisp/vulkan/kk_descriptor_set.c
Normal file
806
src/kosmickrisp/vulkan/kk_descriptor_set.c
Normal file
|
|
@ -0,0 +1,806 @@
|
|||
/*
|
||||
* Copyright © 2022 Collabora Ltd. and Red Hat Inc.
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "kk_descriptor_set.h"
|
||||
|
||||
#include "kk_bo.h"
|
||||
#include "kk_buffer.h"
|
||||
#include "kk_buffer_view.h"
|
||||
#include "kk_descriptor_set_layout.h"
|
||||
#include "kk_device.h"
|
||||
#include "kk_entrypoints.h"
|
||||
#include "kk_image_view.h"
|
||||
#include "kk_physical_device.h"
|
||||
#include "kk_sampler.h"
|
||||
|
||||
#include "util/format/u_format.h"
|
||||
|
||||
static inline uint32_t
|
||||
align_u32(uint32_t v, uint32_t a)
|
||||
{
|
||||
assert(a != 0 && a == (a & -a));
|
||||
return (v + a - 1) & ~(a - 1);
|
||||
}
|
||||
|
||||
static inline void *
|
||||
desc_ubo_data(struct kk_descriptor_set *set, uint32_t binding, uint32_t elem,
|
||||
uint32_t *size_out)
|
||||
{
|
||||
const struct kk_descriptor_set_binding_layout *binding_layout =
|
||||
&set->layout->binding[binding];
|
||||
|
||||
uint32_t offset = binding_layout->offset + elem * binding_layout->stride;
|
||||
assert(offset < set->size);
|
||||
|
||||
if (size_out != NULL)
|
||||
*size_out = set->size - offset;
|
||||
|
||||
return (char *)set->mapped_ptr + offset;
|
||||
}
|
||||
|
||||
static void
|
||||
write_desc(struct kk_descriptor_set *set, uint32_t binding, uint32_t elem,
|
||||
const void *desc_data, size_t desc_size)
|
||||
{
|
||||
ASSERTED uint32_t dst_size;
|
||||
void *dst = desc_ubo_data(set, binding, elem, &dst_size);
|
||||
assert(desc_size <= dst_size);
|
||||
memcpy(dst, desc_data, desc_size);
|
||||
}
|
||||
|
||||
static void
|
||||
get_sampled_image_view_desc(VkDescriptorType descriptor_type,
|
||||
const VkDescriptorImageInfo *const info, void *dst,
|
||||
size_t dst_size, bool is_input_attachment)
|
||||
{
|
||||
struct kk_sampled_image_descriptor desc[3] = {};
|
||||
uint8_t plane_count = 1;
|
||||
|
||||
if (descriptor_type != VK_DESCRIPTOR_TYPE_SAMPLER && info &&
|
||||
info->imageView != VK_NULL_HANDLE) {
|
||||
VK_FROM_HANDLE(kk_image_view, view, info->imageView);
|
||||
|
||||
plane_count = view->plane_count;
|
||||
for (uint8_t plane = 0; plane < plane_count; plane++) {
|
||||
if (is_input_attachment) {
|
||||
assert(view->planes[plane].sampled_gpu_resource_id);
|
||||
desc[plane].image_gpu_resource_id =
|
||||
view->planes[plane].input_gpu_resource_id;
|
||||
} else {
|
||||
assert(view->planes[plane].sampled_gpu_resource_id);
|
||||
desc[plane].image_gpu_resource_id =
|
||||
view->planes[plane].sampled_gpu_resource_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (descriptor_type == VK_DESCRIPTOR_TYPE_SAMPLER ||
|
||||
descriptor_type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) {
|
||||
VK_FROM_HANDLE(kk_sampler, sampler, info->sampler);
|
||||
|
||||
plane_count = MAX2(plane_count, sampler->plane_count);
|
||||
|
||||
for (uint8_t plane = 0; plane < plane_count; plane++) {
|
||||
/* We need to replicate the last sampler plane out to all image
|
||||
* planes due to sampler table entry limitations. See
|
||||
* nvk_CreateSampler in nvk_sampler.c for more details.
|
||||
*/
|
||||
uint8_t sampler_plane = MIN2(plane, sampler->plane_count - 1u);
|
||||
assert(sampler->planes[sampler_plane].hw->handle);
|
||||
desc[plane].sampler_index = sampler->planes[sampler_plane].hw->index;
|
||||
desc[plane].lod_bias_fp16 = sampler->lod_bias_fp16;
|
||||
desc[plane].lod_min_fp16 = sampler->lod_min_fp16;
|
||||
desc[plane].lod_max_fp16 = sampler->lod_max_fp16;
|
||||
}
|
||||
}
|
||||
|
||||
assert(sizeof(desc[0]) * plane_count <= dst_size);
|
||||
memcpy(dst, desc, sizeof(desc[0]) * plane_count);
|
||||
}
|
||||
|
||||
static void
|
||||
write_sampled_image_view_desc(struct kk_descriptor_set *set,
|
||||
const VkDescriptorImageInfo *const _info,
|
||||
uint32_t binding, uint32_t elem,
|
||||
VkDescriptorType descriptor_type)
|
||||
{
|
||||
VkDescriptorImageInfo info = *_info;
|
||||
|
||||
struct kk_descriptor_set_binding_layout *binding_layout =
|
||||
&set->layout->binding[binding];
|
||||
if (descriptor_type == VK_DESCRIPTOR_TYPE_SAMPLER ||
|
||||
descriptor_type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) {
|
||||
if (binding_layout->immutable_samplers != NULL) {
|
||||
info.sampler =
|
||||
kk_sampler_to_handle(binding_layout->immutable_samplers[elem]);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t dst_size;
|
||||
void *dst = desc_ubo_data(set, binding, elem, &dst_size);
|
||||
get_sampled_image_view_desc(
|
||||
descriptor_type, &info, dst, dst_size,
|
||||
descriptor_type == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT);
|
||||
}
|
||||
|
||||
static void
|
||||
get_storage_image_view_desc(
|
||||
struct kk_descriptor_set_binding_layout *binding_layout,
|
||||
const VkDescriptorImageInfo *const info, void *dst, size_t dst_size)
|
||||
{
|
||||
struct kk_storage_image_descriptor desc = {};
|
||||
|
||||
if (info && info->imageView != VK_NULL_HANDLE) {
|
||||
VK_FROM_HANDLE(kk_image_view, view, info->imageView);
|
||||
|
||||
/* Storage images are always single plane */
|
||||
assert(view->plane_count == 1);
|
||||
uint8_t plane = 0;
|
||||
|
||||
assert(view->planes[plane].storage_gpu_resource_id);
|
||||
desc.image_gpu_resource_id = view->planes[plane].storage_gpu_resource_id;
|
||||
}
|
||||
|
||||
assert(sizeof(desc) <= dst_size);
|
||||
memcpy(dst, &desc, sizeof(desc));
|
||||
}
|
||||
|
||||
static void
|
||||
write_storage_image_view_desc(struct kk_descriptor_set *set,
|
||||
const VkDescriptorImageInfo *const info,
|
||||
uint32_t binding, uint32_t elem)
|
||||
{
|
||||
uint32_t dst_size;
|
||||
void *dst = desc_ubo_data(set, binding, elem, &dst_size);
|
||||
struct kk_descriptor_set_binding_layout *binding_layout =
|
||||
&set->layout->binding[binding];
|
||||
get_storage_image_view_desc(binding_layout, info, dst, dst_size);
|
||||
}
|
||||
|
||||
static void
|
||||
write_buffer_desc(struct kk_descriptor_set *set,
|
||||
const VkDescriptorBufferInfo *const info, uint32_t binding,
|
||||
uint32_t elem)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_buffer, buffer, info->buffer);
|
||||
|
||||
const struct kk_addr_range addr_range =
|
||||
kk_buffer_addr_range(buffer, info->offset, info->range);
|
||||
assert(addr_range.range <= UINT32_MAX);
|
||||
|
||||
const struct kk_buffer_address desc = {
|
||||
.base_addr = addr_range.addr,
|
||||
.size = addr_range.range,
|
||||
};
|
||||
write_desc(set, binding, elem, &desc, sizeof(desc));
|
||||
}
|
||||
|
||||
static void
|
||||
write_dynamic_buffer_desc(struct kk_descriptor_set *set,
|
||||
const VkDescriptorBufferInfo *const info,
|
||||
uint32_t binding, uint32_t elem)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_buffer, buffer, info->buffer);
|
||||
const struct kk_descriptor_set_binding_layout *binding_layout =
|
||||
&set->layout->binding[binding];
|
||||
|
||||
const struct kk_addr_range addr_range =
|
||||
kk_buffer_addr_range(buffer, info->offset, info->range);
|
||||
assert(addr_range.range <= UINT32_MAX);
|
||||
|
||||
struct kk_buffer_address *desc =
|
||||
&set->dynamic_buffers[binding_layout->dynamic_buffer_index + elem];
|
||||
*desc = (struct kk_buffer_address){
|
||||
.base_addr = addr_range.addr,
|
||||
.size = addr_range.range,
|
||||
};
|
||||
}
|
||||
|
||||
static void
|
||||
write_buffer_view_desc(struct kk_descriptor_set *set,
|
||||
const VkBufferView bufferView, uint32_t binding,
|
||||
uint32_t elem)
|
||||
{
|
||||
struct kk_storage_image_descriptor desc = {};
|
||||
if (bufferView != VK_NULL_HANDLE) {
|
||||
VK_FROM_HANDLE(kk_buffer_view, view, bufferView);
|
||||
|
||||
assert(view->mtl_texel_buffer_handle);
|
||||
assert(view->texel_buffer_gpu_id);
|
||||
|
||||
desc.image_gpu_resource_id = view->texel_buffer_gpu_id;
|
||||
}
|
||||
write_desc(set, binding, elem, &desc, sizeof(desc));
|
||||
}
|
||||
|
||||
static void
|
||||
write_inline_uniform_data(struct kk_descriptor_set *set,
|
||||
const VkWriteDescriptorSetInlineUniformBlock *info,
|
||||
uint32_t binding, uint32_t offset)
|
||||
{
|
||||
assert(set->layout->binding[binding].stride == 1);
|
||||
write_desc(set, binding, offset, info->pData, info->dataSize);
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
kk_UpdateDescriptorSets(VkDevice device, uint32_t descriptorWriteCount,
|
||||
const VkWriteDescriptorSet *pDescriptorWrites,
|
||||
uint32_t descriptorCopyCount,
|
||||
const VkCopyDescriptorSet *pDescriptorCopies)
|
||||
{
|
||||
for (uint32_t w = 0; w < descriptorWriteCount; w++) {
|
||||
const VkWriteDescriptorSet *write = &pDescriptorWrites[w];
|
||||
VK_FROM_HANDLE(kk_descriptor_set, set, write->dstSet);
|
||||
|
||||
switch (write->descriptorType) {
|
||||
case VK_DESCRIPTOR_TYPE_SAMPLER:
|
||||
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
|
||||
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
|
||||
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
|
||||
for (uint32_t j = 0; j < write->descriptorCount; j++) {
|
||||
write_sampled_image_view_desc(
|
||||
set, write->pImageInfo + j, write->dstBinding,
|
||||
write->dstArrayElement + j, write->descriptorType);
|
||||
}
|
||||
break;
|
||||
|
||||
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
|
||||
for (uint32_t j = 0; j < write->descriptorCount; j++) {
|
||||
write_storage_image_view_desc(set, write->pImageInfo + j,
|
||||
write->dstBinding,
|
||||
write->dstArrayElement + j);
|
||||
}
|
||||
break;
|
||||
|
||||
case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
|
||||
case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
|
||||
for (uint32_t j = 0; j < write->descriptorCount; j++) {
|
||||
write_buffer_view_desc(set, write->pTexelBufferView[j],
|
||||
write->dstBinding,
|
||||
write->dstArrayElement + j);
|
||||
}
|
||||
break;
|
||||
|
||||
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
|
||||
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
|
||||
for (uint32_t j = 0; j < write->descriptorCount; j++) {
|
||||
write_buffer_desc(set, write->pBufferInfo + j, write->dstBinding,
|
||||
write->dstArrayElement + j);
|
||||
}
|
||||
break;
|
||||
|
||||
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
|
||||
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
|
||||
for (uint32_t j = 0; j < write->descriptorCount; j++) {
|
||||
write_dynamic_buffer_desc(set, write->pBufferInfo + j,
|
||||
write->dstBinding,
|
||||
write->dstArrayElement + j);
|
||||
}
|
||||
break;
|
||||
|
||||
case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK: {
|
||||
const VkWriteDescriptorSetInlineUniformBlock *write_inline =
|
||||
vk_find_struct_const(write->pNext,
|
||||
WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK);
|
||||
assert(write_inline->dataSize == write->descriptorCount);
|
||||
write_inline_uniform_data(set, write_inline, write->dstBinding,
|
||||
write->dstArrayElement);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < descriptorCopyCount; i++) {
|
||||
const VkCopyDescriptorSet *copy = &pDescriptorCopies[i];
|
||||
VK_FROM_HANDLE(kk_descriptor_set, src, copy->srcSet);
|
||||
VK_FROM_HANDLE(kk_descriptor_set, dst, copy->dstSet);
|
||||
|
||||
const struct kk_descriptor_set_binding_layout *src_binding_layout =
|
||||
&src->layout->binding[copy->srcBinding];
|
||||
const struct kk_descriptor_set_binding_layout *dst_binding_layout =
|
||||
&dst->layout->binding[copy->dstBinding];
|
||||
|
||||
if (dst_binding_layout->stride > 0 && src_binding_layout->stride > 0) {
|
||||
for (uint32_t j = 0; j < copy->descriptorCount; j++) {
|
||||
ASSERTED uint32_t dst_max_size, src_max_size;
|
||||
void *dst_map = desc_ubo_data(
|
||||
dst, copy->dstBinding, copy->dstArrayElement + j, &dst_max_size);
|
||||
const void *src_map = desc_ubo_data(
|
||||
src, copy->srcBinding, copy->srcArrayElement + j, &src_max_size);
|
||||
const uint32_t copy_size =
|
||||
MIN2(dst_binding_layout->stride, src_binding_layout->stride);
|
||||
assert(copy_size <= dst_max_size && copy_size <= src_max_size);
|
||||
memcpy(dst_map, src_map, copy_size);
|
||||
}
|
||||
}
|
||||
|
||||
switch (src_binding_layout->type) {
|
||||
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
|
||||
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: {
|
||||
const uint32_t dst_dyn_start =
|
||||
dst_binding_layout->dynamic_buffer_index + copy->dstArrayElement;
|
||||
const uint32_t src_dyn_start =
|
||||
src_binding_layout->dynamic_buffer_index + copy->srcArrayElement;
|
||||
typed_memcpy(&dst->dynamic_buffers[dst_dyn_start],
|
||||
&src->dynamic_buffers[src_dyn_start],
|
||||
copy->descriptorCount);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
kk_push_descriptor_set_update(struct kk_push_descriptor_set *push_set,
|
||||
uint32_t write_count,
|
||||
const VkWriteDescriptorSet *writes)
|
||||
{
|
||||
struct kk_descriptor_set_layout *layout = push_set->layout;
|
||||
assert(layout->non_variable_descriptor_buffer_size < sizeof(push_set->data));
|
||||
struct kk_descriptor_set set = {
|
||||
.layout = push_set->layout,
|
||||
.size = sizeof(push_set->data),
|
||||
.mapped_ptr = push_set->data,
|
||||
};
|
||||
|
||||
for (uint32_t w = 0; w < write_count; w++) {
|
||||
const VkWriteDescriptorSet *write = &writes[w];
|
||||
assert(write->dstSet == VK_NULL_HANDLE);
|
||||
|
||||
switch (write->descriptorType) {
|
||||
case VK_DESCRIPTOR_TYPE_SAMPLER:
|
||||
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
|
||||
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
|
||||
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
|
||||
for (uint32_t j = 0; j < write->descriptorCount; j++) {
|
||||
write_sampled_image_view_desc(
|
||||
&set, write->pImageInfo + j, write->dstBinding,
|
||||
write->dstArrayElement + j, write->descriptorType);
|
||||
}
|
||||
break;
|
||||
|
||||
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
|
||||
for (uint32_t j = 0; j < write->descriptorCount; j++) {
|
||||
write_storage_image_view_desc(&set, write->pImageInfo + j,
|
||||
write->dstBinding,
|
||||
write->dstArrayElement + j);
|
||||
}
|
||||
break;
|
||||
|
||||
case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
|
||||
case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
|
||||
for (uint32_t j = 0; j < write->descriptorCount; j++) {
|
||||
write_buffer_view_desc(&set, write->pTexelBufferView[j],
|
||||
write->dstBinding,
|
||||
write->dstArrayElement + j);
|
||||
}
|
||||
break;
|
||||
|
||||
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
|
||||
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
|
||||
for (uint32_t j = 0; j < write->descriptorCount; j++) {
|
||||
write_buffer_desc(&set, write->pBufferInfo + j, write->dstBinding,
|
||||
write->dstArrayElement + j);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void kk_descriptor_pool_free(struct kk_descriptor_pool *pool,
|
||||
uint64_t addr, uint64_t size);
|
||||
|
||||
static void
|
||||
kk_descriptor_set_destroy(struct kk_device *dev,
|
||||
struct kk_descriptor_pool *pool,
|
||||
struct kk_descriptor_set *set)
|
||||
{
|
||||
list_del(&set->link);
|
||||
if (set->size > 0)
|
||||
kk_descriptor_pool_free(pool, set->addr, set->size);
|
||||
vk_descriptor_set_layout_unref(&dev->vk, &set->layout->vk);
|
||||
|
||||
vk_object_free(&dev->vk, NULL, set);
|
||||
}
|
||||
|
||||
static void
|
||||
kk_destroy_descriptor_pool(struct kk_device *dev,
|
||||
const VkAllocationCallbacks *pAllocator,
|
||||
struct kk_descriptor_pool *pool)
|
||||
{
|
||||
list_for_each_entry_safe(struct kk_descriptor_set, set, &pool->sets, link)
|
||||
kk_descriptor_set_destroy(dev, pool, set);
|
||||
|
||||
util_vma_heap_finish(&pool->heap);
|
||||
|
||||
if (pool->bo != NULL)
|
||||
kk_destroy_bo(dev, pool->bo);
|
||||
|
||||
vk_object_free(&dev->vk, pAllocator, pool);
|
||||
}
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL
|
||||
kk_CreateDescriptorPool(VkDevice _device,
|
||||
const VkDescriptorPoolCreateInfo *pCreateInfo,
|
||||
const VkAllocationCallbacks *pAllocator,
|
||||
VkDescriptorPool *pDescriptorPool)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_device, dev, _device);
|
||||
struct kk_descriptor_pool *pool;
|
||||
VkResult result = VK_SUCCESS;
|
||||
|
||||
pool = vk_object_zalloc(&dev->vk, pAllocator, sizeof(*pool),
|
||||
VK_OBJECT_TYPE_DESCRIPTOR_POOL);
|
||||
if (!pool)
|
||||
return vk_error(dev, VK_ERROR_OUT_OF_HOST_MEMORY);
|
||||
|
||||
list_inithead(&pool->sets);
|
||||
|
||||
const VkMutableDescriptorTypeCreateInfoEXT *mutable_info =
|
||||
vk_find_struct_const(pCreateInfo->pNext,
|
||||
MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_EXT);
|
||||
|
||||
uint32_t max_align = 0;
|
||||
for (unsigned i = 0; i < pCreateInfo->poolSizeCount; ++i) {
|
||||
const VkMutableDescriptorTypeListEXT *type_list = NULL;
|
||||
if (pCreateInfo->pPoolSizes[i].type == VK_DESCRIPTOR_TYPE_MUTABLE_EXT &&
|
||||
mutable_info && i < mutable_info->mutableDescriptorTypeListCount)
|
||||
type_list = &mutable_info->pMutableDescriptorTypeLists[i];
|
||||
|
||||
uint32_t stride, alignment;
|
||||
kk_descriptor_stride_align_for_type(pCreateInfo->pPoolSizes[i].type,
|
||||
type_list, &stride, &alignment);
|
||||
max_align = MAX2(max_align, alignment);
|
||||
}
|
||||
|
||||
uint64_t mem_size = 0;
|
||||
for (unsigned i = 0; i < pCreateInfo->poolSizeCount; ++i) {
|
||||
const VkMutableDescriptorTypeListEXT *type_list = NULL;
|
||||
if (pCreateInfo->pPoolSizes[i].type == VK_DESCRIPTOR_TYPE_MUTABLE_EXT &&
|
||||
mutable_info && i < mutable_info->mutableDescriptorTypeListCount)
|
||||
type_list = &mutable_info->pMutableDescriptorTypeLists[i];
|
||||
|
||||
uint32_t stride, alignment;
|
||||
kk_descriptor_stride_align_for_type(pCreateInfo->pPoolSizes[i].type,
|
||||
type_list, &stride, &alignment);
|
||||
mem_size +=
|
||||
MAX2(stride, max_align) * pCreateInfo->pPoolSizes[i].descriptorCount;
|
||||
}
|
||||
|
||||
/* Individual descriptor sets are aligned to the min UBO alignment to
|
||||
* ensure that we don't end up with unaligned data access in any shaders.
|
||||
* This means that each descriptor buffer allocated may burn up to 16B of
|
||||
* extra space to get the right alignment. (Technically, it's at most 28B
|
||||
* because we're always going to start at least 4B aligned but we're being
|
||||
* conservative here.) Allocate enough extra space that we can chop it
|
||||
* into maxSets pieces and align each one of them to 32B.
|
||||
*/
|
||||
mem_size += kk_min_cbuf_alignment() * pCreateInfo->maxSets;
|
||||
|
||||
if (mem_size) {
|
||||
result = kk_alloc_bo(dev, &dev->vk.base, mem_size, 0u, &pool->bo);
|
||||
if (result != VK_SUCCESS) {
|
||||
kk_destroy_descriptor_pool(dev, pAllocator, pool);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* The BO may be larger thanks to GPU page alignment. We may as well
|
||||
* make that extra space available to the client.
|
||||
*/
|
||||
assert(pool->bo->size_B >= mem_size);
|
||||
util_vma_heap_init(&pool->heap, pool->bo->gpu, pool->bo->size_B);
|
||||
} else {
|
||||
util_vma_heap_init(&pool->heap, 0, 0);
|
||||
}
|
||||
|
||||
*pDescriptorPool = kk_descriptor_pool_to_handle(pool);
|
||||
return result;
|
||||
}
|
||||
|
||||
static VkResult
|
||||
kk_descriptor_pool_alloc(struct kk_descriptor_pool *pool, uint64_t size,
|
||||
uint64_t alignment, uint64_t *addr_out, void **map_out)
|
||||
{
|
||||
assert(size > 0);
|
||||
assert(size % alignment == 0);
|
||||
|
||||
if (size > pool->heap.free_size)
|
||||
return VK_ERROR_OUT_OF_POOL_MEMORY;
|
||||
|
||||
uint64_t addr = util_vma_heap_alloc(&pool->heap, size, alignment);
|
||||
if (addr == 0)
|
||||
return VK_ERROR_FRAGMENTED_POOL;
|
||||
|
||||
assert(addr >= pool->bo->gpu);
|
||||
assert(addr + size <= pool->bo->gpu + pool->bo->size_B);
|
||||
uint64_t offset = addr - pool->bo->gpu;
|
||||
|
||||
*addr_out = addr;
|
||||
*map_out = pool->bo->cpu + offset;
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
kk_descriptor_pool_free(struct kk_descriptor_pool *pool, uint64_t addr,
|
||||
uint64_t size)
|
||||
{
|
||||
assert(size > 0);
|
||||
assert(addr >= pool->bo->gpu);
|
||||
assert(addr + size <= pool->bo->gpu + pool->bo->size_B);
|
||||
util_vma_heap_free(&pool->heap, addr, size);
|
||||
}
|
||||
|
||||
static VkResult
|
||||
kk_descriptor_set_create(struct kk_device *dev, struct kk_descriptor_pool *pool,
|
||||
struct kk_descriptor_set_layout *layout,
|
||||
uint32_t variable_count,
|
||||
struct kk_descriptor_set **out_set)
|
||||
{
|
||||
struct kk_descriptor_set *set;
|
||||
VkResult result = VK_SUCCESS;
|
||||
|
||||
uint32_t mem_size =
|
||||
sizeof(struct kk_descriptor_set) +
|
||||
layout->dynamic_buffer_count * sizeof(struct kk_buffer_address);
|
||||
set =
|
||||
vk_object_zalloc(&dev->vk, NULL, mem_size, VK_OBJECT_TYPE_DESCRIPTOR_SET);
|
||||
if (!set)
|
||||
return vk_error(dev, VK_ERROR_OUT_OF_HOST_MEMORY);
|
||||
|
||||
set->size = layout->non_variable_descriptor_buffer_size;
|
||||
|
||||
if (layout->binding_count > 0 &&
|
||||
(layout->binding[layout->binding_count - 1].flags &
|
||||
VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT)) {
|
||||
uint32_t stride = layout->binding[layout->binding_count - 1].stride;
|
||||
set->size += stride * variable_count;
|
||||
}
|
||||
|
||||
uint32_t alignment = kk_min_cbuf_alignment();
|
||||
set->size = align64(set->size, alignment);
|
||||
|
||||
if (set->size > 0) {
|
||||
result = kk_descriptor_pool_alloc(pool, set->size, alignment, &set->addr,
|
||||
&set->mapped_ptr);
|
||||
if (result != VK_SUCCESS) {
|
||||
vk_object_free(&dev->vk, NULL, set);
|
||||
return result;
|
||||
}
|
||||
set->mtl_descriptor_buffer = pool->bo->map;
|
||||
}
|
||||
|
||||
vk_descriptor_set_layout_ref(&layout->vk);
|
||||
set->layout = layout;
|
||||
|
||||
for (uint32_t b = 0; b < layout->binding_count; b++) {
|
||||
if (layout->binding[b].type != VK_DESCRIPTOR_TYPE_SAMPLER &&
|
||||
layout->binding[b].type != VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
|
||||
continue;
|
||||
|
||||
if (layout->binding[b].immutable_samplers == NULL)
|
||||
continue;
|
||||
|
||||
uint32_t array_size = layout->binding[b].array_size;
|
||||
if (layout->binding[b].flags &
|
||||
VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT)
|
||||
array_size = variable_count;
|
||||
|
||||
const VkDescriptorImageInfo empty = {};
|
||||
for (uint32_t j = 0; j < array_size; j++) {
|
||||
write_sampled_image_view_desc(set, &empty, b, j,
|
||||
layout->binding[b].type);
|
||||
}
|
||||
}
|
||||
|
||||
list_addtail(&set->link, &pool->sets);
|
||||
*out_set = set;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL
|
||||
kk_AllocateDescriptorSets(VkDevice device,
|
||||
const VkDescriptorSetAllocateInfo *pAllocateInfo,
|
||||
VkDescriptorSet *pDescriptorSets)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_device, dev, device);
|
||||
VK_FROM_HANDLE(kk_descriptor_pool, pool, pAllocateInfo->descriptorPool);
|
||||
|
||||
VkResult result = VK_SUCCESS;
|
||||
uint32_t i;
|
||||
|
||||
struct kk_descriptor_set *set = NULL;
|
||||
|
||||
const VkDescriptorSetVariableDescriptorCountAllocateInfo *var_desc_count =
|
||||
vk_find_struct_const(
|
||||
pAllocateInfo->pNext,
|
||||
DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO);
|
||||
|
||||
/* allocate a set of buffers for each shader to contain descriptors */
|
||||
for (i = 0; i < pAllocateInfo->descriptorSetCount; i++) {
|
||||
VK_FROM_HANDLE(kk_descriptor_set_layout, layout,
|
||||
pAllocateInfo->pSetLayouts[i]);
|
||||
/* If descriptorSetCount is zero or this structure is not included in
|
||||
* the pNext chain, then the variable lengths are considered to be zero.
|
||||
*/
|
||||
const uint32_t variable_count =
|
||||
var_desc_count && var_desc_count->descriptorSetCount > 0
|
||||
? var_desc_count->pDescriptorCounts[i]
|
||||
: 0;
|
||||
|
||||
result =
|
||||
kk_descriptor_set_create(dev, pool, layout, variable_count, &set);
|
||||
if (result != VK_SUCCESS)
|
||||
break;
|
||||
|
||||
pDescriptorSets[i] = kk_descriptor_set_to_handle(set);
|
||||
}
|
||||
|
||||
if (result != VK_SUCCESS) {
|
||||
kk_FreeDescriptorSets(device, pAllocateInfo->descriptorPool, i,
|
||||
pDescriptorSets);
|
||||
for (i = 0; i < pAllocateInfo->descriptorSetCount; i++) {
|
||||
pDescriptorSets[i] = VK_NULL_HANDLE;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL
|
||||
kk_FreeDescriptorSets(VkDevice device, VkDescriptorPool descriptorPool,
|
||||
uint32_t descriptorSetCount,
|
||||
const VkDescriptorSet *pDescriptorSets)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_device, dev, device);
|
||||
VK_FROM_HANDLE(kk_descriptor_pool, pool, descriptorPool);
|
||||
|
||||
for (uint32_t i = 0; i < descriptorSetCount; i++) {
|
||||
VK_FROM_HANDLE(kk_descriptor_set, set, pDescriptorSets[i]);
|
||||
|
||||
if (set)
|
||||
kk_descriptor_set_destroy(dev, pool, set);
|
||||
}
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
kk_DestroyDescriptorPool(VkDevice device, VkDescriptorPool _pool,
|
||||
const VkAllocationCallbacks *pAllocator)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_device, dev, device);
|
||||
VK_FROM_HANDLE(kk_descriptor_pool, pool, _pool);
|
||||
|
||||
if (!_pool)
|
||||
return;
|
||||
|
||||
kk_destroy_descriptor_pool(dev, pAllocator, pool);
|
||||
}
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL
|
||||
kk_ResetDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool,
|
||||
VkDescriptorPoolResetFlags flags)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_device, dev, device);
|
||||
VK_FROM_HANDLE(kk_descriptor_pool, pool, descriptorPool);
|
||||
|
||||
list_for_each_entry_safe(struct kk_descriptor_set, set, &pool->sets, link)
|
||||
kk_descriptor_set_destroy(dev, pool, set);
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
kk_descriptor_set_write_template(
|
||||
struct kk_descriptor_set *set,
|
||||
const struct vk_descriptor_update_template *template, const void *data)
|
||||
{
|
||||
for (uint32_t i = 0; i < template->entry_count; i++) {
|
||||
const struct vk_descriptor_template_entry *entry = &template->entries[i];
|
||||
|
||||
switch (entry->type) {
|
||||
case VK_DESCRIPTOR_TYPE_SAMPLER:
|
||||
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
|
||||
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
|
||||
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
|
||||
for (uint32_t j = 0; j < entry->array_count; j++) {
|
||||
const VkDescriptorImageInfo *info =
|
||||
data + entry->offset + j * entry->stride;
|
||||
|
||||
write_sampled_image_view_desc(set, info, entry->binding,
|
||||
entry->array_element + j,
|
||||
entry->type);
|
||||
}
|
||||
break;
|
||||
|
||||
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
|
||||
for (uint32_t j = 0; j < entry->array_count; j++) {
|
||||
const VkDescriptorImageInfo *info =
|
||||
data + entry->offset + j * entry->stride;
|
||||
|
||||
write_storage_image_view_desc(set, info, entry->binding,
|
||||
entry->array_element + j);
|
||||
}
|
||||
break;
|
||||
|
||||
case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
|
||||
case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
|
||||
for (uint32_t j = 0; j < entry->array_count; j++) {
|
||||
const VkBufferView *bview =
|
||||
data + entry->offset + j * entry->stride;
|
||||
|
||||
write_buffer_view_desc(set, *bview, entry->binding,
|
||||
entry->array_element + j);
|
||||
}
|
||||
break;
|
||||
|
||||
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
|
||||
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
|
||||
for (uint32_t j = 0; j < entry->array_count; j++) {
|
||||
const VkDescriptorBufferInfo *info =
|
||||
data + entry->offset + j * entry->stride;
|
||||
|
||||
write_buffer_desc(set, info, entry->binding,
|
||||
entry->array_element + j);
|
||||
}
|
||||
break;
|
||||
|
||||
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
|
||||
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
|
||||
for (uint32_t j = 0; j < entry->array_count; j++) {
|
||||
const VkDescriptorBufferInfo *info =
|
||||
data + entry->offset + j * entry->stride;
|
||||
|
||||
write_dynamic_buffer_desc(set, info, entry->binding,
|
||||
entry->array_element + j);
|
||||
}
|
||||
break;
|
||||
|
||||
case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK:
|
||||
write_desc(set, entry->binding, entry->array_element,
|
||||
data + entry->offset, entry->array_count);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
kk_UpdateDescriptorSetWithTemplate(
|
||||
VkDevice device, VkDescriptorSet descriptorSet,
|
||||
VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void *pData)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_descriptor_set, set, descriptorSet);
|
||||
VK_FROM_HANDLE(vk_descriptor_update_template, template,
|
||||
descriptorUpdateTemplate);
|
||||
|
||||
kk_descriptor_set_write_template(set, template, pData);
|
||||
}
|
||||
|
||||
void
|
||||
kk_push_descriptor_set_update_template(
|
||||
struct kk_push_descriptor_set *push_set,
|
||||
struct kk_descriptor_set_layout *layout,
|
||||
const struct vk_descriptor_update_template *template, const void *data)
|
||||
{
|
||||
struct kk_descriptor_set tmp_set = {
|
||||
.layout = layout,
|
||||
.size = sizeof(push_set->data),
|
||||
.mapped_ptr = push_set->data,
|
||||
};
|
||||
kk_descriptor_set_write_template(&tmp_set, template, data);
|
||||
}
|
||||
81
src/kosmickrisp/vulkan/kk_descriptor_set.h
Normal file
81
src/kosmickrisp/vulkan/kk_descriptor_set.h
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* Copyright © 2022 Collabora Ltd. and Red Hat Inc.
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef KK_DESCRIPTOR_SET
|
||||
#define KK_DESCRIPTOR_SET 1
|
||||
|
||||
#include "kk_private.h"
|
||||
|
||||
#include "kk_descriptor_types.h"
|
||||
#include "kk_device.h"
|
||||
|
||||
#include "vk_descriptor_update_template.h"
|
||||
#include "vk_object.h"
|
||||
|
||||
#include "util/list.h"
|
||||
#include "util/vma.h"
|
||||
|
||||
struct kk_descriptor_set_layout;
|
||||
struct kk_bo;
|
||||
|
||||
struct kk_descriptor_pool {
|
||||
struct vk_object_base base;
|
||||
|
||||
struct list_head sets;
|
||||
|
||||
struct kk_bo *bo;
|
||||
struct util_vma_heap heap;
|
||||
};
|
||||
|
||||
VK_DEFINE_NONDISP_HANDLE_CASTS(kk_descriptor_pool, base, VkDescriptorPool,
|
||||
VK_OBJECT_TYPE_DESCRIPTOR_POOL)
|
||||
|
||||
struct kk_descriptor_set {
|
||||
struct vk_object_base base;
|
||||
|
||||
/* Link in kk_descriptor_pool::sets */
|
||||
struct list_head link;
|
||||
|
||||
struct kk_descriptor_set_layout *layout;
|
||||
mtl_resource *mtl_descriptor_buffer;
|
||||
void *mapped_ptr;
|
||||
uint64_t addr;
|
||||
uint32_t size;
|
||||
|
||||
struct kk_buffer_address dynamic_buffers[];
|
||||
};
|
||||
|
||||
VK_DEFINE_NONDISP_HANDLE_CASTS(kk_descriptor_set, base, VkDescriptorSet,
|
||||
VK_OBJECT_TYPE_DESCRIPTOR_SET)
|
||||
|
||||
static inline struct kk_buffer_address
|
||||
kk_descriptor_set_addr(const struct kk_descriptor_set *set)
|
||||
{
|
||||
return (struct kk_buffer_address){
|
||||
.base_addr = set->addr,
|
||||
.size = set->size,
|
||||
};
|
||||
}
|
||||
|
||||
struct kk_push_descriptor_set {
|
||||
uint8_t data[KK_PUSH_DESCRIPTOR_SET_SIZE];
|
||||
struct kk_descriptor_set_layout *layout;
|
||||
mtl_resource *mtl_descriptor_buffer;
|
||||
uint32_t resource_count;
|
||||
mtl_resource *mtl_resources[];
|
||||
};
|
||||
|
||||
void kk_push_descriptor_set_update(struct kk_push_descriptor_set *push_set,
|
||||
uint32_t write_count,
|
||||
const VkWriteDescriptorSet *writes);
|
||||
|
||||
void kk_push_descriptor_set_update_template(
|
||||
struct kk_push_descriptor_set *push_set,
|
||||
struct kk_descriptor_set_layout *layout,
|
||||
const struct vk_descriptor_update_template *template, const void *data);
|
||||
|
||||
#endif
|
||||
496
src/kosmickrisp/vulkan/kk_descriptor_set_layout.c
Normal file
496
src/kosmickrisp/vulkan/kk_descriptor_set_layout.c
Normal file
|
|
@ -0,0 +1,496 @@
|
|||
/*
|
||||
* Copyright © 2022 Collabora Ltd. and Red Hat Inc.
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "kk_descriptor_set_layout.h"
|
||||
|
||||
#include "kk_descriptor_types.h"
|
||||
#include "kk_device.h"
|
||||
#include "kk_entrypoints.h"
|
||||
#include "kk_physical_device.h"
|
||||
#include "kk_sampler.h"
|
||||
|
||||
#include "vk_pipeline_layout.h"
|
||||
|
||||
static bool
|
||||
binding_has_immutable_samplers(const VkDescriptorSetLayoutBinding *binding)
|
||||
{
|
||||
switch (binding->descriptorType) {
|
||||
case VK_DESCRIPTOR_TYPE_SAMPLER:
|
||||
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
|
||||
return binding->pImmutableSamplers != NULL;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
kk_descriptor_stride_align_for_type(
|
||||
VkDescriptorType type, const VkMutableDescriptorTypeListEXT *type_list,
|
||||
uint32_t *stride, uint32_t *alignment)
|
||||
{
|
||||
switch (type) {
|
||||
case VK_DESCRIPTOR_TYPE_SAMPLER:
|
||||
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
|
||||
/* TODO: How do samplers work? */
|
||||
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
|
||||
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
|
||||
*stride = *alignment = sizeof(struct kk_sampled_image_descriptor);
|
||||
break;
|
||||
|
||||
case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
|
||||
case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
|
||||
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
|
||||
*stride = *alignment = sizeof(struct kk_storage_image_descriptor);
|
||||
break;
|
||||
|
||||
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
|
||||
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
|
||||
*stride = *alignment = sizeof(struct kk_buffer_address);
|
||||
break;
|
||||
|
||||
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
|
||||
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
|
||||
*stride = *alignment = 0; /* These don't take up buffer space */
|
||||
break;
|
||||
|
||||
case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK:
|
||||
*stride = 1; /* Array size is bytes */
|
||||
*alignment = kk_min_cbuf_alignment();
|
||||
break;
|
||||
|
||||
case VK_DESCRIPTOR_TYPE_MUTABLE_EXT:
|
||||
*stride = *alignment = 0;
|
||||
if (type_list == NULL)
|
||||
*stride = *alignment = KK_MAX_DESCRIPTOR_SIZE;
|
||||
for (unsigned i = 0; type_list && i < type_list->descriptorTypeCount;
|
||||
i++) {
|
||||
/* This shouldn't recurse */
|
||||
assert(type_list->pDescriptorTypes[i] !=
|
||||
VK_DESCRIPTOR_TYPE_MUTABLE_EXT);
|
||||
uint32_t desc_stride, desc_align;
|
||||
kk_descriptor_stride_align_for_type(type_list->pDescriptorTypes[i],
|
||||
NULL, &desc_stride, &desc_align);
|
||||
*stride = MAX2(*stride, desc_stride);
|
||||
*alignment = MAX2(*alignment, desc_align);
|
||||
}
|
||||
*stride = ALIGN(*stride, *alignment);
|
||||
break;
|
||||
|
||||
default:
|
||||
UNREACHABLE("Invalid descriptor type");
|
||||
}
|
||||
|
||||
assert(*stride <= KK_MAX_DESCRIPTOR_SIZE);
|
||||
}
|
||||
|
||||
static const VkMutableDescriptorTypeListEXT *
|
||||
kk_descriptor_get_type_list(VkDescriptorType type,
|
||||
const VkMutableDescriptorTypeCreateInfoEXT *info,
|
||||
const uint32_t info_idx)
|
||||
{
|
||||
const VkMutableDescriptorTypeListEXT *type_list = NULL;
|
||||
if (type == VK_DESCRIPTOR_TYPE_MUTABLE_EXT) {
|
||||
assert(info != NULL);
|
||||
assert(info_idx < info->mutableDescriptorTypeListCount);
|
||||
type_list = &info->pMutableDescriptorTypeLists[info_idx];
|
||||
}
|
||||
return type_list;
|
||||
}
|
||||
|
||||
static void
|
||||
kk_descriptor_set_layout_destroy(struct vk_device *vk_dev,
|
||||
struct vk_descriptor_set_layout *vk_layout)
|
||||
{
|
||||
struct kk_device *dev = container_of(vk_dev, struct kk_device, vk);
|
||||
struct kk_descriptor_set_layout *layout =
|
||||
vk_to_kk_descriptor_set_layout(vk_layout);
|
||||
|
||||
vk_object_free(&dev->vk, NULL, layout);
|
||||
}
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL
|
||||
kk_CreateDescriptorSetLayout(VkDevice device,
|
||||
const VkDescriptorSetLayoutCreateInfo *pCreateInfo,
|
||||
const VkAllocationCallbacks *pAllocator,
|
||||
VkDescriptorSetLayout *pSetLayout)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_device, dev, device);
|
||||
|
||||
uint32_t num_bindings = 0;
|
||||
uint32_t immutable_sampler_count = 0;
|
||||
for (uint32_t j = 0; j < pCreateInfo->bindingCount; j++) {
|
||||
const VkDescriptorSetLayoutBinding *binding = &pCreateInfo->pBindings[j];
|
||||
num_bindings = MAX2(num_bindings, binding->binding + 1);
|
||||
|
||||
/* From the Vulkan 1.1.97 spec for VkDescriptorSetLayoutBinding:
|
||||
*
|
||||
* "If descriptorType specifies a VK_DESCRIPTOR_TYPE_SAMPLER or
|
||||
* VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER type descriptor, then
|
||||
* pImmutableSamplers can be used to initialize a set of immutable
|
||||
* samplers. [...] If descriptorType is not one of these descriptor
|
||||
* types, then pImmutableSamplers is ignored.
|
||||
*
|
||||
* We need to be careful here and only parse pImmutableSamplers if we
|
||||
* have one of the right descriptor types.
|
||||
*/
|
||||
if (binding_has_immutable_samplers(binding))
|
||||
immutable_sampler_count += binding->descriptorCount;
|
||||
}
|
||||
|
||||
VK_MULTIALLOC(ma);
|
||||
VK_MULTIALLOC_DECL(&ma, struct kk_descriptor_set_layout, layout, 1);
|
||||
VK_MULTIALLOC_DECL(&ma, struct kk_descriptor_set_binding_layout, bindings,
|
||||
num_bindings);
|
||||
VK_MULTIALLOC_DECL(&ma, struct kk_sampler *, samplers,
|
||||
immutable_sampler_count);
|
||||
|
||||
if (!vk_descriptor_set_layout_multizalloc(&dev->vk, &ma, pCreateInfo))
|
||||
return vk_error(dev, VK_ERROR_OUT_OF_HOST_MEMORY);
|
||||
|
||||
layout->vk.destroy = kk_descriptor_set_layout_destroy;
|
||||
layout->flags = pCreateInfo->flags;
|
||||
layout->binding_count = num_bindings;
|
||||
|
||||
for (uint32_t j = 0; j < pCreateInfo->bindingCount; j++) {
|
||||
const VkDescriptorSetLayoutBinding *binding = &pCreateInfo->pBindings[j];
|
||||
uint32_t b = binding->binding;
|
||||
/* We temporarily store pCreateInfo->pBindings[] index (plus one) in the
|
||||
* immutable_samplers pointer. This provides us with a quick-and-dirty
|
||||
* way to sort the bindings by binding number.
|
||||
*/
|
||||
layout->binding[b].immutable_samplers = (void *)(uintptr_t)(j + 1);
|
||||
}
|
||||
|
||||
const VkDescriptorSetLayoutBindingFlagsCreateInfo *binding_flags_info =
|
||||
vk_find_struct_const(pCreateInfo->pNext,
|
||||
DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO);
|
||||
const VkMutableDescriptorTypeCreateInfoEXT *mutable_info =
|
||||
vk_find_struct_const(pCreateInfo->pNext,
|
||||
MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_EXT);
|
||||
|
||||
uint32_t buffer_size = 0;
|
||||
uint32_t max_variable_descriptor_size = 0;
|
||||
uint8_t dynamic_buffer_count = 0;
|
||||
uint32_t total_descriptor_count = 0u;
|
||||
for (uint32_t b = 0; b < num_bindings; b++) {
|
||||
/* We stashed the pCreateInfo->pBindings[] index (plus one) in the
|
||||
* immutable_samplers pointer. Check for NULL (empty binding) and then
|
||||
* reset it and compute the index.
|
||||
*/
|
||||
if (layout->binding[b].immutable_samplers == NULL)
|
||||
continue;
|
||||
const uint32_t info_idx =
|
||||
(uintptr_t)(void *)layout->binding[b].immutable_samplers - 1;
|
||||
layout->binding[b].immutable_samplers = NULL;
|
||||
|
||||
const VkDescriptorSetLayoutBinding *binding =
|
||||
&pCreateInfo->pBindings[info_idx];
|
||||
|
||||
if (binding->descriptorCount == 0)
|
||||
continue;
|
||||
|
||||
layout->binding[b].type = binding->descriptorType;
|
||||
layout->binding[b].mtl_resources_index = total_descriptor_count;
|
||||
layout->descriptor_count += binding->descriptorCount;
|
||||
|
||||
if (binding_flags_info && binding_flags_info->bindingCount > 0) {
|
||||
assert(binding_flags_info->bindingCount == pCreateInfo->bindingCount);
|
||||
layout->binding[b].flags = binding_flags_info->pBindingFlags[info_idx];
|
||||
}
|
||||
|
||||
layout->binding[b].array_size = binding->descriptorCount;
|
||||
|
||||
switch (binding->descriptorType) {
|
||||
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
|
||||
layout->binding[b].dynamic_buffer_index = dynamic_buffer_count;
|
||||
BITSET_SET_RANGE(layout->dynamic_ubos, dynamic_buffer_count,
|
||||
dynamic_buffer_count + binding->descriptorCount - 1);
|
||||
dynamic_buffer_count += binding->descriptorCount;
|
||||
break;
|
||||
|
||||
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
|
||||
layout->binding[b].dynamic_buffer_index = dynamic_buffer_count;
|
||||
dynamic_buffer_count += binding->descriptorCount;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
const VkMutableDescriptorTypeListEXT *type_list =
|
||||
kk_descriptor_get_type_list(binding->descriptorType, mutable_info,
|
||||
info_idx);
|
||||
|
||||
uint32_t stride, alignment;
|
||||
kk_descriptor_stride_align_for_type(binding->descriptorType, type_list,
|
||||
&stride, &alignment);
|
||||
|
||||
uint8_t max_plane_count = 1;
|
||||
|
||||
if (binding_has_immutable_samplers(binding)) {
|
||||
layout->binding[b].immutable_samplers = samplers;
|
||||
samplers += binding->descriptorCount;
|
||||
for (uint32_t i = 0; i < binding->descriptorCount; i++) {
|
||||
VK_FROM_HANDLE(kk_sampler, sampler, binding->pImmutableSamplers[i]);
|
||||
layout->binding[b].immutable_samplers[i] = sampler;
|
||||
const uint8_t sampler_plane_count =
|
||||
sampler->vk.ycbcr_conversion
|
||||
? vk_format_get_plane_count(
|
||||
sampler->vk.ycbcr_conversion->state.format)
|
||||
: 1;
|
||||
if (max_plane_count < sampler_plane_count)
|
||||
max_plane_count = sampler_plane_count;
|
||||
}
|
||||
}
|
||||
|
||||
stride *= max_plane_count;
|
||||
layout->binding[b].count_per_element = max_plane_count;
|
||||
total_descriptor_count += max_plane_count * binding->descriptorCount;
|
||||
|
||||
if (stride > 0) {
|
||||
assert(stride <= UINT8_MAX);
|
||||
assert(util_is_power_of_two_nonzero(alignment));
|
||||
|
||||
buffer_size = align64(buffer_size, alignment);
|
||||
layout->binding[b].offset = buffer_size;
|
||||
layout->binding[b].stride = stride;
|
||||
|
||||
if (layout->binding[b].flags &
|
||||
VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT) {
|
||||
/* From the Vulkan 1.3.256 spec:
|
||||
*
|
||||
* VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-pBindingFlags-03004
|
||||
* "If an element of pBindingFlags includes
|
||||
* VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT, then
|
||||
* all other elements of
|
||||
* VkDescriptorSetLayoutCreateInfo::pBindings must have a
|
||||
* smaller value of binding"
|
||||
*
|
||||
* In other words, it has to be the last binding.
|
||||
*/
|
||||
assert(b == num_bindings - 1);
|
||||
assert(max_variable_descriptor_size == 0);
|
||||
max_variable_descriptor_size = stride * binding->descriptorCount;
|
||||
} else {
|
||||
/* the allocation size will be computed at descriptor allocation,
|
||||
* but the buffer size will be already aligned as this binding will
|
||||
* be the last
|
||||
*/
|
||||
buffer_size += stride * binding->descriptorCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
layout->non_variable_descriptor_buffer_size = buffer_size;
|
||||
layout->max_buffer_size = buffer_size + max_variable_descriptor_size;
|
||||
layout->dynamic_buffer_count = dynamic_buffer_count;
|
||||
|
||||
struct mesa_blake3 blake3_ctx;
|
||||
_mesa_blake3_init(&blake3_ctx);
|
||||
|
||||
#define BLAKE3_UPDATE_VALUE(x) \
|
||||
_mesa_blake3_update(&blake3_ctx, &(x), sizeof(x));
|
||||
BLAKE3_UPDATE_VALUE(layout->non_variable_descriptor_buffer_size);
|
||||
BLAKE3_UPDATE_VALUE(layout->dynamic_buffer_count);
|
||||
BLAKE3_UPDATE_VALUE(layout->binding_count);
|
||||
|
||||
for (uint32_t b = 0; b < num_bindings; b++) {
|
||||
BLAKE3_UPDATE_VALUE(layout->binding[b].type);
|
||||
BLAKE3_UPDATE_VALUE(layout->binding[b].flags);
|
||||
BLAKE3_UPDATE_VALUE(layout->binding[b].array_size);
|
||||
BLAKE3_UPDATE_VALUE(layout->binding[b].offset);
|
||||
BLAKE3_UPDATE_VALUE(layout->binding[b].stride);
|
||||
BLAKE3_UPDATE_VALUE(layout->binding[b].dynamic_buffer_index);
|
||||
|
||||
if (layout->binding[b].immutable_samplers != NULL) {
|
||||
for (uint32_t i = 0; i < layout->binding[b].array_size; i++) {
|
||||
const struct kk_sampler *sampler =
|
||||
layout->binding[b].immutable_samplers[i];
|
||||
|
||||
/* We zalloc the object, so it's safe to hash the whole thing */
|
||||
if (sampler != NULL && sampler->vk.ycbcr_conversion != NULL)
|
||||
BLAKE3_UPDATE_VALUE(sampler->vk.ycbcr_conversion->state);
|
||||
}
|
||||
}
|
||||
}
|
||||
#undef BLAKE3_UPDATE_VALUE
|
||||
|
||||
_mesa_blake3_final(&blake3_ctx, layout->vk.blake3);
|
||||
|
||||
if (pCreateInfo->flags &
|
||||
VK_DESCRIPTOR_SET_LAYOUT_CREATE_EMBEDDED_IMMUTABLE_SAMPLERS_BIT_EXT) {
|
||||
void *sampler_desc_data =
|
||||
vk_alloc2(&dev->vk.alloc, pAllocator, buffer_size, 4,
|
||||
VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
|
||||
if (sampler_desc_data == NULL) {
|
||||
kk_descriptor_set_layout_destroy(&dev->vk, &layout->vk);
|
||||
return vk_error(dev, VK_ERROR_OUT_OF_HOST_MEMORY);
|
||||
}
|
||||
|
||||
for (uint32_t b = 0; b < num_bindings; b++) {
|
||||
assert(layout->binding[b].type == VK_DESCRIPTOR_TYPE_SAMPLER);
|
||||
assert(layout->binding[b].array_size == 1);
|
||||
assert(layout->binding[b].immutable_samplers != NULL);
|
||||
assert(!(layout->binding[b].flags &
|
||||
VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT));
|
||||
|
||||
/* I'm paranoid */
|
||||
if (layout->binding[b].immutable_samplers == NULL)
|
||||
continue;
|
||||
|
||||
struct kk_sampler *sampler = layout->binding[b].immutable_samplers[0];
|
||||
|
||||
/* YCbCr has to come in through a combined image/sampler */
|
||||
assert(sampler->plane_count == 1);
|
||||
|
||||
assert(sampler->planes[0].hw->handle);
|
||||
}
|
||||
|
||||
vk_free2(&dev->vk.alloc, pAllocator, sampler_desc_data);
|
||||
}
|
||||
|
||||
*pSetLayout = kk_descriptor_set_layout_to_handle(layout);
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
kk_GetDescriptorSetLayoutSupport(
|
||||
VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo,
|
||||
VkDescriptorSetLayoutSupport *pSupport)
|
||||
{
|
||||
const VkMutableDescriptorTypeCreateInfoEXT *mutable_info =
|
||||
vk_find_struct_const(pCreateInfo->pNext,
|
||||
MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_EXT);
|
||||
const VkDescriptorSetLayoutBindingFlagsCreateInfo *binding_flags =
|
||||
vk_find_struct_const(pCreateInfo->pNext,
|
||||
DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO);
|
||||
|
||||
/* Figure out the maximum alignment up-front. Otherwise, we need to sort
|
||||
* the list of descriptors by binding number in order to get the size
|
||||
* accumulation right.
|
||||
*/
|
||||
uint32_t max_align = 0;
|
||||
for (uint32_t i = 0; i < pCreateInfo->bindingCount; i++) {
|
||||
const VkDescriptorSetLayoutBinding *binding = &pCreateInfo->pBindings[i];
|
||||
const VkMutableDescriptorTypeListEXT *type_list =
|
||||
kk_descriptor_get_type_list(binding->descriptorType, mutable_info, i);
|
||||
|
||||
uint32_t stride, alignment;
|
||||
kk_descriptor_stride_align_for_type(binding->descriptorType, type_list,
|
||||
&stride, &alignment);
|
||||
max_align = MAX2(max_align, alignment);
|
||||
}
|
||||
|
||||
uint64_t non_variable_size = 0;
|
||||
uint32_t variable_stride = 0;
|
||||
uint32_t variable_count = 0;
|
||||
uint8_t dynamic_buffer_count = 0;
|
||||
|
||||
for (uint32_t i = 0; i < pCreateInfo->bindingCount; i++) {
|
||||
const VkDescriptorSetLayoutBinding *binding = &pCreateInfo->pBindings[i];
|
||||
|
||||
VkDescriptorBindingFlags flags = 0;
|
||||
if (binding_flags != NULL && binding_flags->bindingCount > 0)
|
||||
flags = binding_flags->pBindingFlags[i];
|
||||
|
||||
switch (binding->descriptorType) {
|
||||
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
|
||||
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
|
||||
dynamic_buffer_count += binding->descriptorCount;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
const VkMutableDescriptorTypeListEXT *type_list =
|
||||
kk_descriptor_get_type_list(binding->descriptorType, mutable_info, i);
|
||||
|
||||
uint32_t stride, alignment;
|
||||
kk_descriptor_stride_align_for_type(binding->descriptorType, type_list,
|
||||
&stride, &alignment);
|
||||
|
||||
if (stride > 0) {
|
||||
assert(stride <= UINT8_MAX);
|
||||
assert(util_is_power_of_two_nonzero(alignment));
|
||||
|
||||
if (flags & VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT) {
|
||||
/* From the Vulkan 1.3.256 spec:
|
||||
*
|
||||
* "For the purposes of this command, a variable-sized
|
||||
* descriptor binding with a descriptorCount of zero is treated
|
||||
* as if the descriptorCount is one"
|
||||
*/
|
||||
variable_count = MAX2(1, binding->descriptorCount);
|
||||
variable_stride = stride;
|
||||
} else {
|
||||
/* Since we're aligning to the maximum and since this is just a
|
||||
* check for whether or not the max buffer size is big enough, we
|
||||
* keep non_variable_size aligned to max_align.
|
||||
*/
|
||||
non_variable_size += stride * binding->descriptorCount;
|
||||
non_variable_size = align64(non_variable_size, max_align);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t buffer_size = non_variable_size;
|
||||
if (variable_stride > 0) {
|
||||
buffer_size += variable_stride * variable_count;
|
||||
buffer_size = align64(buffer_size, max_align);
|
||||
}
|
||||
|
||||
uint32_t max_buffer_size;
|
||||
if (pCreateInfo->flags &
|
||||
VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR)
|
||||
max_buffer_size = KK_PUSH_DESCRIPTOR_SET_SIZE;
|
||||
else
|
||||
max_buffer_size = KK_MAX_DESCRIPTOR_SET_SIZE;
|
||||
|
||||
pSupport->supported = dynamic_buffer_count <= KK_MAX_DYNAMIC_BUFFERS &&
|
||||
buffer_size <= max_buffer_size;
|
||||
|
||||
vk_foreach_struct(ext, pSupport->pNext) {
|
||||
switch (ext->sType) {
|
||||
case VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT: {
|
||||
VkDescriptorSetVariableDescriptorCountLayoutSupport *vs = (void *)ext;
|
||||
if (variable_stride > 0) {
|
||||
vs->maxVariableDescriptorCount =
|
||||
(max_buffer_size - non_variable_size) / variable_stride;
|
||||
} else {
|
||||
vs->maxVariableDescriptorCount = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
vk_debug_ignored_stype(ext->sType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
kk_GetDescriptorSetLayoutSizeEXT(VkDevice device, VkDescriptorSetLayout _layout,
|
||||
VkDeviceSize *pLayoutSizeInBytes)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_descriptor_set_layout, layout, _layout);
|
||||
|
||||
*pLayoutSizeInBytes = layout->max_buffer_size;
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
kk_GetDescriptorSetLayoutBindingOffsetEXT(VkDevice device,
|
||||
VkDescriptorSetLayout _layout,
|
||||
uint32_t binding,
|
||||
VkDeviceSize *pOffset)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_descriptor_set_layout, layout, _layout);
|
||||
|
||||
*pOffset = layout->binding[binding].offset;
|
||||
}
|
||||
103
src/kosmickrisp/vulkan/kk_descriptor_set_layout.h
Normal file
103
src/kosmickrisp/vulkan/kk_descriptor_set_layout.h
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* Copyright © 2022 Collabora Ltd. and Red Hat Inc.
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef KK_DESCRIPTOR_SET_LAYOUT
|
||||
#define KK_DESCRIPTOR_SET_LAYOUT 1
|
||||
|
||||
#include "kk_private.h"
|
||||
|
||||
#include "vk_descriptor_set_layout.h"
|
||||
#include "vk_object.h"
|
||||
|
||||
#include "util/bitset.h"
|
||||
|
||||
struct kk_device;
|
||||
struct kk_physical_device;
|
||||
struct kk_sampler;
|
||||
struct vk_pipeline_layout;
|
||||
|
||||
struct kk_descriptor_set_binding_layout {
|
||||
/* The type of the descriptors in this binding */
|
||||
VkDescriptorType type;
|
||||
|
||||
/* Flags provided when this binding was created */
|
||||
VkDescriptorBindingFlags flags;
|
||||
|
||||
/* Number of array elements in this binding (or size in bytes for inline
|
||||
* uniform data)
|
||||
*/
|
||||
uint32_t array_size;
|
||||
|
||||
/* Number of actual descriptors per element */
|
||||
uint32_t count_per_element;
|
||||
|
||||
/* Offset into the descriptor buffer where this descriptor lives */
|
||||
uint32_t offset;
|
||||
|
||||
/* Offset to the mtl_resource_ids array where this descriptor stores them */
|
||||
uint32_t mtl_resources_index;
|
||||
|
||||
/* Stride between array elements in the descriptor buffer */
|
||||
uint8_t stride;
|
||||
|
||||
/* Index into the dynamic buffer binding array */
|
||||
uint8_t dynamic_buffer_index;
|
||||
|
||||
/* Immutable samplers (or NULL if no immutable samplers) */
|
||||
struct kk_sampler **immutable_samplers;
|
||||
};
|
||||
|
||||
struct kk_descriptor_set_layout {
|
||||
struct vk_descriptor_set_layout vk;
|
||||
|
||||
VkDescriptorSetLayoutCreateFlagBits flags;
|
||||
|
||||
/* Size of the descriptor buffer for this descriptor set */
|
||||
/* Does not contain the size needed for variable count descriptors */
|
||||
uint32_t non_variable_descriptor_buffer_size;
|
||||
|
||||
/* Maximum possible buffer size for this descriptor set */
|
||||
uint32_t max_buffer_size;
|
||||
|
||||
/* Number of dynamic UBO bindings in this set */
|
||||
uint8_t dynamic_buffer_count;
|
||||
|
||||
/* Which dynamic buffers are UBOs */
|
||||
BITSET_DECLARE(dynamic_ubos, KK_MAX_DYNAMIC_BUFFERS);
|
||||
|
||||
/* Number of bindings in this descriptor set */
|
||||
uint32_t binding_count;
|
||||
|
||||
/* Number of descriptors in the layout */
|
||||
uint32_t descriptor_count;
|
||||
|
||||
/* Address to the embedded sampler descriptor buffer.
|
||||
*
|
||||
* This is allocated from nvk_device::heap and has the size
|
||||
* non_variable_descriptor_buffer_size.
|
||||
*/
|
||||
uint64_t embedded_samplers_addr;
|
||||
|
||||
/* Bindings in this descriptor set */
|
||||
struct kk_descriptor_set_binding_layout binding[0];
|
||||
};
|
||||
|
||||
VK_DEFINE_NONDISP_HANDLE_CASTS(kk_descriptor_set_layout, vk.base,
|
||||
VkDescriptorSetLayout,
|
||||
VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT)
|
||||
|
||||
void kk_descriptor_stride_align_for_type(
|
||||
VkDescriptorType type, const VkMutableDescriptorTypeListEXT *type_list,
|
||||
uint32_t *stride, uint32_t *alignment);
|
||||
|
||||
static inline struct kk_descriptor_set_layout *
|
||||
vk_to_kk_descriptor_set_layout(struct vk_descriptor_set_layout *layout)
|
||||
{
|
||||
return container_of(layout, struct kk_descriptor_set_layout, vk);
|
||||
}
|
||||
|
||||
#endif /* KK_DESCRIPTOR_SET_LAYOUT */
|
||||
45
src/kosmickrisp/vulkan/kk_descriptor_types.h
Normal file
45
src/kosmickrisp/vulkan/kk_descriptor_types.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright © 2024 Collabora Ltd. and Red Hat Inc.
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
#ifndef KK_DESCRIPTOR_TYPES
|
||||
#define KK_DESCRIPTOR_TYPES 1
|
||||
|
||||
#include "kk_private.h"
|
||||
|
||||
/* TODO_KOSMICKRISP Reduce size to 32 bytes by moving border to a heap. */
|
||||
struct kk_sampled_image_descriptor {
|
||||
uint64_t image_gpu_resource_id;
|
||||
uint16_t sampler_index;
|
||||
uint16_t lod_bias_fp16;
|
||||
uint16_t lod_min_fp16;
|
||||
uint16_t lod_max_fp16;
|
||||
uint32_t has_border;
|
||||
uint32_t pad_to_64_bits;
|
||||
uint32_t border[4];
|
||||
uint64_t pad_to_power_2[3];
|
||||
};
|
||||
|
||||
static_assert(sizeof(struct kk_sampled_image_descriptor) == 64,
|
||||
"kk_sampled_image_descriptor has no holes");
|
||||
|
||||
struct kk_storage_image_descriptor {
|
||||
uint64_t image_gpu_resource_id;
|
||||
};
|
||||
|
||||
static_assert(sizeof(struct kk_storage_image_descriptor) == 8,
|
||||
"kk_storage_image_descriptor has no holes");
|
||||
|
||||
/* This has to match nir_address_format_64bit_bounded_global */
|
||||
struct kk_buffer_address {
|
||||
uint64_t base_addr;
|
||||
uint32_t size;
|
||||
uint32_t zero; /* Must be zero! */
|
||||
};
|
||||
|
||||
static_assert(sizeof(struct kk_buffer_address) == 16,
|
||||
"kk_buffer_address has no holes");
|
||||
|
||||
#endif /* KK_DESCRIPTOR_TYPES */
|
||||
348
src/kosmickrisp/vulkan/kk_device.c
Normal file
348
src/kosmickrisp/vulkan/kk_device.c
Normal file
|
|
@ -0,0 +1,348 @@
|
|||
/*
|
||||
* Copyright © 2022 Collabora Ltd. and Red Hat Inc.
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "kk_device.h"
|
||||
|
||||
#include "kk_cmd_buffer.h"
|
||||
#include "kk_entrypoints.h"
|
||||
#include "kk_instance.h"
|
||||
#include "kk_physical_device.h"
|
||||
#include "kk_shader.h"
|
||||
|
||||
#include "kosmickrisp/bridge/mtl_bridge.h"
|
||||
|
||||
#include "vk_cmd_enqueue_entrypoints.h"
|
||||
#include "vk_common_entrypoints.h"
|
||||
|
||||
#include "vulkan/wsi/wsi_common.h"
|
||||
#include "vk_pipeline_cache.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
DERIVE_HASH_TABLE(mtl_sampler_packed);
|
||||
|
||||
static VkResult
|
||||
kk_init_sampler_heap(struct kk_device *dev, struct kk_sampler_heap *h)
|
||||
{
|
||||
h->ht = mtl_sampler_packed_table_create(NULL);
|
||||
if (!h->ht)
|
||||
return VK_ERROR_OUT_OF_HOST_MEMORY;
|
||||
|
||||
VkResult result = kk_query_table_init(dev, &h->table, 1024);
|
||||
|
||||
if (result != VK_SUCCESS) {
|
||||
ralloc_free(h->ht);
|
||||
return result;
|
||||
}
|
||||
|
||||
simple_mtx_init(&h->lock, mtx_plain);
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
kk_destroy_sampler_heap(struct kk_device *dev, struct kk_sampler_heap *h)
|
||||
{
|
||||
struct hash_entry *entry = _mesa_hash_table_next_entry(h->ht, NULL);
|
||||
while (entry) {
|
||||
struct kk_rc_sampler *sampler = (struct kk_rc_sampler *)entry->data;
|
||||
mtl_release(sampler->handle);
|
||||
entry = _mesa_hash_table_next_entry(h->ht, entry);
|
||||
}
|
||||
kk_query_table_finish(dev, &h->table);
|
||||
ralloc_free(h->ht);
|
||||
simple_mtx_destroy(&h->lock);
|
||||
}
|
||||
|
||||
static VkResult
|
||||
kk_sampler_heap_add_locked(struct kk_device *dev, struct kk_sampler_heap *h,
|
||||
struct mtl_sampler_packed desc,
|
||||
struct kk_rc_sampler **out)
|
||||
{
|
||||
struct hash_entry *ent = _mesa_hash_table_search(h->ht, &desc);
|
||||
if (ent != NULL) {
|
||||
*out = ent->data;
|
||||
|
||||
assert((*out)->refcount != 0);
|
||||
(*out)->refcount++;
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
struct kk_rc_sampler *rc = ralloc(h->ht, struct kk_rc_sampler);
|
||||
if (!rc)
|
||||
return VK_ERROR_OUT_OF_HOST_MEMORY;
|
||||
|
||||
mtl_sampler *handle = kk_sampler_create(dev, &desc);
|
||||
uint64_t gpu_id = mtl_sampler_get_gpu_resource_id(handle);
|
||||
|
||||
uint32_t index;
|
||||
VkResult result = kk_query_table_add(dev, &h->table, gpu_id, &index);
|
||||
if (result != VK_SUCCESS) {
|
||||
mtl_release(handle);
|
||||
ralloc_free(rc);
|
||||
return result;
|
||||
}
|
||||
|
||||
*rc = (struct kk_rc_sampler){
|
||||
.key = desc,
|
||||
.handle = handle,
|
||||
.refcount = 1,
|
||||
.index = index,
|
||||
};
|
||||
|
||||
_mesa_hash_table_insert(h->ht, &rc->key, rc);
|
||||
*out = rc;
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VkResult
|
||||
kk_sampler_heap_add(struct kk_device *dev, struct mtl_sampler_packed desc,
|
||||
struct kk_rc_sampler **out)
|
||||
{
|
||||
struct kk_sampler_heap *h = &dev->samplers;
|
||||
|
||||
simple_mtx_lock(&h->lock);
|
||||
VkResult result = kk_sampler_heap_add_locked(dev, h, desc, out);
|
||||
simple_mtx_unlock(&h->lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
kk_sampler_heap_remove_locked(struct kk_device *dev, struct kk_sampler_heap *h,
|
||||
struct kk_rc_sampler *rc)
|
||||
{
|
||||
assert(rc->refcount != 0);
|
||||
rc->refcount--;
|
||||
|
||||
if (rc->refcount == 0) {
|
||||
mtl_release(rc->handle);
|
||||
kk_query_table_remove(dev, &h->table, rc->index);
|
||||
_mesa_hash_table_remove_key(h->ht, &rc->key);
|
||||
ralloc_free(rc);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
kk_sampler_heap_remove(struct kk_device *dev, struct kk_rc_sampler *rc)
|
||||
{
|
||||
struct kk_sampler_heap *h = &dev->samplers;
|
||||
|
||||
simple_mtx_lock(&h->lock);
|
||||
kk_sampler_heap_remove_locked(dev, h, rc);
|
||||
simple_mtx_unlock(&h->lock);
|
||||
}
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL
|
||||
kk_CreateDevice(VkPhysicalDevice physicalDevice,
|
||||
const VkDeviceCreateInfo *pCreateInfo,
|
||||
const VkAllocationCallbacks *pAllocator, VkDevice *pDevice)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_physical_device, pdev, physicalDevice);
|
||||
VkResult result = VK_ERROR_OUT_OF_HOST_MEMORY;
|
||||
struct kk_device *dev;
|
||||
|
||||
dev = vk_zalloc2(&pdev->vk.instance->alloc, pAllocator, sizeof(*dev), 8,
|
||||
VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
|
||||
if (!dev)
|
||||
return vk_error(pdev, VK_ERROR_OUT_OF_HOST_MEMORY);
|
||||
|
||||
/* Fill the dispatch table we will expose to the users */
|
||||
vk_device_dispatch_table_from_entrypoints(
|
||||
&dev->exposed_dispatch_table, &vk_cmd_enqueue_device_entrypoints, true);
|
||||
vk_device_dispatch_table_from_entrypoints(&dev->exposed_dispatch_table,
|
||||
&kk_device_entrypoints, false);
|
||||
vk_device_dispatch_table_from_entrypoints(&dev->exposed_dispatch_table,
|
||||
&wsi_device_entrypoints, false);
|
||||
vk_device_dispatch_table_from_entrypoints(
|
||||
&dev->exposed_dispatch_table, &vk_common_device_entrypoints, false);
|
||||
|
||||
struct vk_device_dispatch_table dispatch_table;
|
||||
vk_device_dispatch_table_from_entrypoints(&dispatch_table,
|
||||
&kk_device_entrypoints, true);
|
||||
vk_device_dispatch_table_from_entrypoints(
|
||||
&dispatch_table, &vk_common_device_entrypoints, false);
|
||||
vk_device_dispatch_table_from_entrypoints(&dispatch_table,
|
||||
&wsi_device_entrypoints, false);
|
||||
|
||||
result = vk_device_init(&dev->vk, &pdev->vk, &dispatch_table, pCreateInfo,
|
||||
pAllocator);
|
||||
if (result != VK_SUCCESS)
|
||||
goto fail_alloc;
|
||||
|
||||
dev->vk.shader_ops = &kk_device_shader_ops;
|
||||
dev->mtl_handle = pdev->mtl_dev_handle;
|
||||
dev->vk.command_buffer_ops = &kk_cmd_buffer_ops;
|
||||
dev->vk.command_dispatch_table = &dev->vk.dispatch_table;
|
||||
|
||||
/* Buffer to use as null descriptor */
|
||||
result = kk_alloc_bo(dev, &dev->vk.base, sizeof(uint64_t) * 8, 8u,
|
||||
&dev->null_descriptor);
|
||||
if (result != VK_SUCCESS)
|
||||
goto fail_init;
|
||||
|
||||
result =
|
||||
kk_queue_init(dev, &dev->queue, &pCreateInfo->pQueueCreateInfos[0], 0);
|
||||
if (result != VK_SUCCESS)
|
||||
goto fail_vab_memory;
|
||||
|
||||
result = kk_device_init_meta(dev);
|
||||
if (result != VK_SUCCESS)
|
||||
goto fail_mem_cache;
|
||||
|
||||
result = kk_query_table_init(dev, &dev->occlusion_queries,
|
||||
KK_MAX_OCCLUSION_QUERIES);
|
||||
if (result != VK_SUCCESS)
|
||||
goto fail_meta;
|
||||
|
||||
result = kk_init_sampler_heap(dev, &dev->samplers);
|
||||
if (result != VK_SUCCESS)
|
||||
goto fail_query_table;
|
||||
|
||||
result = kk_device_init_lib(dev);
|
||||
if (result != VK_SUCCESS)
|
||||
goto fail_sampler_heap;
|
||||
|
||||
simple_mtx_init(&dev->user_heap_cache.mutex, mtx_plain);
|
||||
util_dynarray_init(&dev->user_heap_cache.handles, NULL);
|
||||
|
||||
*pDevice = kk_device_to_handle(dev);
|
||||
|
||||
dev->gpu_capture_enabled = kk_get_environment_boolean(KK_ENABLE_GPU_CAPTURE);
|
||||
mtl_start_gpu_capture(dev->mtl_handle);
|
||||
|
||||
return VK_SUCCESS;
|
||||
|
||||
fail_sampler_heap:
|
||||
kk_destroy_sampler_heap(dev, &dev->samplers);
|
||||
fail_query_table:
|
||||
kk_query_table_finish(dev, &dev->occlusion_queries);
|
||||
fail_meta:
|
||||
kk_device_finish_meta(dev);
|
||||
fail_mem_cache:
|
||||
kk_queue_finish(dev, &dev->queue);
|
||||
fail_vab_memory:
|
||||
kk_destroy_bo(dev, dev->null_descriptor);
|
||||
fail_init:
|
||||
vk_device_finish(&dev->vk);
|
||||
fail_alloc:
|
||||
vk_free(&dev->vk.alloc, dev);
|
||||
return result;
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
kk_DestroyDevice(VkDevice _device, const VkAllocationCallbacks *pAllocator)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_device, dev, _device);
|
||||
|
||||
if (!dev)
|
||||
return;
|
||||
|
||||
/* Meta first since it may destroy Vulkan objects */
|
||||
kk_device_finish_meta(dev);
|
||||
|
||||
util_dynarray_fini(&dev->user_heap_cache.handles);
|
||||
simple_mtx_destroy(&dev->user_heap_cache.mutex);
|
||||
kk_device_finish_lib(dev);
|
||||
kk_query_table_finish(dev, &dev->occlusion_queries);
|
||||
kk_destroy_sampler_heap(dev, &dev->samplers);
|
||||
|
||||
kk_queue_finish(dev, &dev->queue);
|
||||
kk_destroy_bo(dev, dev->null_descriptor);
|
||||
vk_device_finish(&dev->vk);
|
||||
|
||||
if (dev->gpu_capture_enabled) {
|
||||
mtl_stop_gpu_capture();
|
||||
}
|
||||
|
||||
vk_free(&dev->vk.alloc, dev);
|
||||
}
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL
|
||||
kk_GetCalibratedTimestampsKHR(
|
||||
VkDevice _device, uint32_t timestampCount,
|
||||
const VkCalibratedTimestampInfoKHR *pTimestampInfos, uint64_t *pTimestamps,
|
||||
uint64_t *pMaxDeviation)
|
||||
{
|
||||
uint64_t max_clock_period = 0;
|
||||
uint64_t begin, end;
|
||||
int d;
|
||||
|
||||
#ifdef CLOCK_MONOTONIC_RAW
|
||||
begin = vk_clock_gettime(CLOCK_MONOTONIC_RAW);
|
||||
#else
|
||||
begin = vk_clock_gettime(CLOCK_MONOTONIC);
|
||||
#endif
|
||||
|
||||
for (d = 0; d < timestampCount; d++) {
|
||||
switch (pTimestampInfos[d].timeDomain) {
|
||||
case VK_TIME_DOMAIN_CLOCK_MONOTONIC_KHR:
|
||||
pTimestamps[d] = vk_clock_gettime(CLOCK_MONOTONIC);
|
||||
max_clock_period = MAX2(max_clock_period, 1);
|
||||
break;
|
||||
|
||||
#ifdef CLOCK_MONOTONIC_RAW
|
||||
case VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_KHR:
|
||||
pTimestamps[d] = begin;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
pTimestamps[d] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CLOCK_MONOTONIC_RAW
|
||||
end = vk_clock_gettime(CLOCK_MONOTONIC_RAW);
|
||||
#else
|
||||
end = vk_clock_gettime(CLOCK_MONOTONIC);
|
||||
#endif
|
||||
|
||||
*pMaxDeviation = vk_time_max_deviation(begin, end, max_clock_period);
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
/* We need to implement this ourselves so we give the fake ones for vk_common_*
|
||||
* to work when executing actual commands */
|
||||
static PFN_vkVoidFunction
|
||||
kk_device_get_proc_addr(const struct kk_device *device, const char *name)
|
||||
{
|
||||
if (device == NULL || name == NULL)
|
||||
return NULL;
|
||||
|
||||
struct vk_instance *instance = device->vk.physical->instance;
|
||||
return vk_device_dispatch_table_get_if_supported(
|
||||
&device->exposed_dispatch_table, name, instance->app_info.api_version,
|
||||
&instance->enabled_extensions, &device->vk.enabled_extensions);
|
||||
}
|
||||
|
||||
VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
|
||||
kk_GetDeviceProcAddr(VkDevice _device, const char *pName)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_device, device, _device);
|
||||
return kk_device_get_proc_addr(device, pName);
|
||||
}
|
||||
|
||||
void
|
||||
kk_device_add_user_heap(struct kk_device *dev, mtl_heap *heap)
|
||||
{
|
||||
simple_mtx_lock(&dev->user_heap_cache.mutex);
|
||||
util_dynarray_append(&dev->user_heap_cache.handles, mtl_heap *, heap);
|
||||
dev->user_heap_cache.hash += 1u;
|
||||
simple_mtx_unlock(&dev->user_heap_cache.mutex);
|
||||
}
|
||||
|
||||
void
|
||||
kk_device_remove_user_heap(struct kk_device *dev, mtl_heap *heap)
|
||||
{
|
||||
simple_mtx_lock(&dev->user_heap_cache.mutex);
|
||||
util_dynarray_delete_unordered(&dev->user_heap_cache.handles, mtl_heap *,
|
||||
heap);
|
||||
simple_mtx_unlock(&dev->user_heap_cache.mutex);
|
||||
}
|
||||
137
src/kosmickrisp/vulkan/kk_device.h
Normal file
137
src/kosmickrisp/vulkan/kk_device.h
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* Copyright © 2022 Collabora Ltd. and Red Hat Inc.
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef KK_DEVICE_H
|
||||
#define KK_DEVICE_H 1
|
||||
|
||||
#include "kk_private.h"
|
||||
|
||||
#include "kk_query_table.h"
|
||||
#include "kk_queue.h"
|
||||
|
||||
#include "kosmickrisp/bridge/mtl_types.h"
|
||||
|
||||
#include "util/u_dynarray.h"
|
||||
|
||||
#include "vk_device.h"
|
||||
#include "vk_meta.h"
|
||||
#include "vk_queue.h"
|
||||
|
||||
struct kk_bo;
|
||||
struct kk_physical_device;
|
||||
struct vk_pipeline_cache;
|
||||
|
||||
enum kk_device_lib_pipeline {
|
||||
KK_LIB_IMM_WRITE = 0,
|
||||
KK_LIB_COPY_QUERY,
|
||||
KK_LIB_TRIANGLE_FAN,
|
||||
KK_LIB_COUNT,
|
||||
};
|
||||
|
||||
struct kk_user_heap_cache {
|
||||
simple_mtx_t mutex;
|
||||
uint32_t hash;
|
||||
struct util_dynarray handles;
|
||||
};
|
||||
|
||||
struct mtl_sampler_packed {
|
||||
enum mtl_sampler_address_mode mode_u;
|
||||
enum mtl_sampler_address_mode mode_v;
|
||||
enum mtl_sampler_address_mode mode_w;
|
||||
enum mtl_sampler_border_color border_color;
|
||||
|
||||
enum mtl_sampler_min_mag_filter min_filter;
|
||||
enum mtl_sampler_min_mag_filter mag_filter;
|
||||
enum mtl_sampler_mip_filter mip_filter;
|
||||
|
||||
enum mtl_compare_function compare_func;
|
||||
float min_lod;
|
||||
float max_lod;
|
||||
uint32_t max_anisotropy;
|
||||
bool normalized_coordinates;
|
||||
};
|
||||
|
||||
struct kk_rc_sampler {
|
||||
struct mtl_sampler_packed key;
|
||||
|
||||
mtl_sampler *handle;
|
||||
|
||||
/* Reference count for this hardware sampler, protected by the heap mutex */
|
||||
uint16_t refcount;
|
||||
|
||||
/* Index of this hardware sampler in the hardware sampler heap */
|
||||
uint16_t index;
|
||||
};
|
||||
|
||||
struct kk_sampler_heap {
|
||||
simple_mtx_t lock;
|
||||
|
||||
struct kk_query_table table;
|
||||
|
||||
/* Map of agx_sampler_packed to hk_rc_sampler */
|
||||
struct hash_table *ht;
|
||||
};
|
||||
|
||||
struct kk_device {
|
||||
struct vk_device vk;
|
||||
|
||||
mtl_device *mtl_handle;
|
||||
|
||||
/* Dispatch table exposed to the user. Required since we need to record all
|
||||
* commands due to Metal limitations */
|
||||
struct vk_device_dispatch_table exposed_dispatch_table;
|
||||
|
||||
struct kk_bo *null_descriptor;
|
||||
|
||||
struct kk_sampler_heap samplers;
|
||||
struct kk_query_table occlusion_queries;
|
||||
|
||||
/* Track all heaps the user allocated so we can set them all as resident when
|
||||
* recording as required by Metal. */
|
||||
struct kk_user_heap_cache user_heap_cache;
|
||||
|
||||
mtl_compute_pipeline_state *lib_pipelines[KK_LIB_COUNT];
|
||||
|
||||
struct kk_queue queue;
|
||||
|
||||
struct vk_meta_device meta;
|
||||
|
||||
bool gpu_capture_enabled;
|
||||
};
|
||||
|
||||
VK_DEFINE_HANDLE_CASTS(kk_device, vk.base, VkDevice, VK_OBJECT_TYPE_DEVICE)
|
||||
|
||||
static inline mtl_compute_pipeline_state *
|
||||
kk_device_lib_pipeline(const struct kk_device *dev,
|
||||
enum kk_device_lib_pipeline pipeline)
|
||||
{
|
||||
assert(pipeline < KK_LIB_COUNT);
|
||||
return dev->lib_pipelines[pipeline];
|
||||
}
|
||||
|
||||
static inline struct kk_physical_device *
|
||||
kk_device_physical(const struct kk_device *dev)
|
||||
{
|
||||
return (struct kk_physical_device *)dev->vk.physical;
|
||||
}
|
||||
|
||||
VkResult kk_device_init_meta(struct kk_device *dev);
|
||||
void kk_device_finish_meta(struct kk_device *dev);
|
||||
VkResult kk_device_init_lib(struct kk_device *dev);
|
||||
void kk_device_finish_lib(struct kk_device *dev);
|
||||
void kk_device_add_user_heap(struct kk_device *dev, mtl_heap *heap);
|
||||
void kk_device_remove_user_heap(struct kk_device *dev, mtl_heap *heap);
|
||||
|
||||
/* Required to create a sampler */
|
||||
mtl_sampler *kk_sampler_create(struct kk_device *dev,
|
||||
const struct mtl_sampler_packed *packed);
|
||||
VkResult kk_sampler_heap_add(struct kk_device *dev,
|
||||
struct mtl_sampler_packed desc,
|
||||
struct kk_rc_sampler **out);
|
||||
void kk_sampler_heap_remove(struct kk_device *dev, struct kk_rc_sampler *rc);
|
||||
|
||||
#endif // KK_DEVICE_H
|
||||
191
src/kosmickrisp/vulkan/kk_device_lib.c
Normal file
191
src/kosmickrisp/vulkan/kk_device_lib.c
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "kk_device.h"
|
||||
|
||||
#include "kk_shader.h"
|
||||
|
||||
#include "kkcl.h"
|
||||
|
||||
#include "kosmickrisp/bridge/mtl_bridge.h"
|
||||
|
||||
#include "nir/nir.h"
|
||||
#include "nir/nir_builder.h"
|
||||
|
||||
static nir_def *
|
||||
load_struct_var(nir_builder *b, nir_variable *var, uint32_t field)
|
||||
{
|
||||
nir_deref_instr *deref =
|
||||
nir_build_deref_struct(b, nir_build_deref_var(b, var), field);
|
||||
return nir_load_deref(b, deref);
|
||||
}
|
||||
|
||||
static nir_shader *
|
||||
create_imm_write_shader()
|
||||
{
|
||||
nir_builder build = nir_builder_init_simple_shader(MESA_SHADER_COMPUTE, NULL,
|
||||
"kk-meta-imm-write-u64");
|
||||
nir_builder *b = &build;
|
||||
|
||||
struct glsl_struct_field push_fields[] = {
|
||||
{.type = glsl_uint64_t_type(), .name = "buffer_address", .offset = 0},
|
||||
};
|
||||
const struct glsl_type *push_iface_type = glsl_interface_type(
|
||||
push_fields, ARRAY_SIZE(push_fields), GLSL_INTERFACE_PACKING_STD140,
|
||||
false /* row_major */, "push");
|
||||
nir_variable *push = nir_variable_create(b->shader, nir_var_mem_push_const,
|
||||
push_iface_type, "push");
|
||||
|
||||
b->shader->info.workgroup_size[0] = 1;
|
||||
b->shader->info.workgroup_size[1] = 1;
|
||||
b->shader->info.workgroup_size[2] = 1;
|
||||
|
||||
libkk_write_u64(b, load_struct_var(b, push, 0));
|
||||
|
||||
return build.shader;
|
||||
}
|
||||
|
||||
static nir_shader *
|
||||
create_copy_query_shader()
|
||||
{
|
||||
nir_builder build = nir_builder_init_simple_shader(MESA_SHADER_COMPUTE, NULL,
|
||||
"kk-meta-copy-queries");
|
||||
nir_builder *b = &build;
|
||||
|
||||
struct glsl_struct_field push_fields[] = {
|
||||
{.type = glsl_uint64_t_type(), .name = "availability", .offset = 0},
|
||||
{.type = glsl_uint64_t_type(), .name = "results", .offset = 8},
|
||||
{.type = glsl_uint64_t_type(), .name = "indices", .offset = 16},
|
||||
{.type = glsl_uint64_t_type(), .name = "dst_addr", .offset = 24},
|
||||
{.type = glsl_uint64_t_type(), .name = "dst_stride", .offset = 32},
|
||||
{.type = glsl_uint_type(), .name = "first_query", .offset = 40},
|
||||
{.type = glsl_uint_type(), .name = "flags", .offset = 44},
|
||||
{.type = glsl_uint16_t_type(), .name = "reports_per_query", .offset = 48},
|
||||
};
|
||||
/* TODO_KOSMICKRISP Don't use push constants and directly bind the buffer to
|
||||
* the binding index. This requires compiler work first to remove the
|
||||
* hard-coded buffer0 value. Same applies to other creation functions.
|
||||
*/
|
||||
const struct glsl_type *push_iface_type = glsl_interface_type(
|
||||
push_fields, ARRAY_SIZE(push_fields), GLSL_INTERFACE_PACKING_STD140,
|
||||
false /* row_major */, "push");
|
||||
nir_variable *push = nir_variable_create(b->shader, nir_var_mem_push_const,
|
||||
push_iface_type, "push");
|
||||
|
||||
b->shader->info.workgroup_size[0] = 1;
|
||||
b->shader->info.workgroup_size[1] = 1;
|
||||
b->shader->info.workgroup_size[2] = 1;
|
||||
|
||||
libkk_copy_queries(b, load_struct_var(b, push, 0),
|
||||
load_struct_var(b, push, 1), load_struct_var(b, push, 2),
|
||||
load_struct_var(b, push, 3), load_struct_var(b, push, 4),
|
||||
load_struct_var(b, push, 5), load_struct_var(b, push, 6),
|
||||
load_struct_var(b, push, 7));
|
||||
|
||||
return build.shader;
|
||||
}
|
||||
|
||||
static nir_shader *
|
||||
create_triangle_fan_shader()
|
||||
{
|
||||
nir_builder build = nir_builder_init_simple_shader(
|
||||
MESA_SHADER_COMPUTE, NULL, "kk-device-unroll-geomtry-and-restart");
|
||||
nir_builder *b = &build;
|
||||
|
||||
struct glsl_struct_field push_fields[] = {
|
||||
{.type = glsl_uint64_t_type(), .name = "index_buffer", .offset = 0},
|
||||
{.type = glsl_uint64_t_type(), .name = "out_ptr", .offset = 8},
|
||||
{.type = glsl_uint64_t_type(), .name = "indirect_in", .offset = 16},
|
||||
{.type = glsl_uint64_t_type(), .name = "indirect_out", .offset = 24},
|
||||
{.type = glsl_uint_type(), .name = "restart_index", .offset = 32},
|
||||
{.type = glsl_uint_type(), .name = "index_buffer_size_el", .offset = 36},
|
||||
{.type = glsl_uint_type(), .name = "in_el_size_B,", .offset = 40},
|
||||
{.type = glsl_uint_type(), .name = "out_el_size_B,", .offset = 44},
|
||||
{.type = glsl_uint_type(), .name = "flatshade_first", .offset = 48},
|
||||
{.type = glsl_uint_type(), .name = "mode", .offset = 52},
|
||||
};
|
||||
const struct glsl_type *push_iface_type = glsl_interface_type(
|
||||
push_fields, ARRAY_SIZE(push_fields), GLSL_INTERFACE_PACKING_STD140,
|
||||
false /* row_major */, "push");
|
||||
nir_variable *push = nir_variable_create(b->shader, nir_var_mem_push_const,
|
||||
push_iface_type, "push");
|
||||
|
||||
b->shader->info.workgroup_size[0] = 1;
|
||||
b->shader->info.workgroup_size[1] = 1;
|
||||
b->shader->info.workgroup_size[2] = 1;
|
||||
|
||||
libkk_unroll_geometry_and_restart(
|
||||
b, load_struct_var(b, push, 0), load_struct_var(b, push, 1),
|
||||
load_struct_var(b, push, 2), load_struct_var(b, push, 3),
|
||||
load_struct_var(b, push, 4), load_struct_var(b, push, 5),
|
||||
load_struct_var(b, push, 6), load_struct_var(b, push, 7),
|
||||
load_struct_var(b, push, 8), load_struct_var(b, push, 9));
|
||||
|
||||
return build.shader;
|
||||
}
|
||||
|
||||
static struct {
|
||||
enum kk_device_lib_pipeline ndx;
|
||||
nir_shader *(*create_shader_fn)();
|
||||
} lib_shaders[KK_LIB_COUNT] = {
|
||||
{KK_LIB_IMM_WRITE, create_imm_write_shader},
|
||||
{KK_LIB_COPY_QUERY, create_copy_query_shader},
|
||||
{KK_LIB_TRIANGLE_FAN, create_triangle_fan_shader},
|
||||
};
|
||||
static_assert(ARRAY_SIZE(lib_shaders) == KK_LIB_COUNT,
|
||||
"Device lib shader count and created shader count mismatch");
|
||||
|
||||
VkResult
|
||||
kk_device_init_lib(struct kk_device *dev)
|
||||
{
|
||||
VkResult result = VK_SUCCESS;
|
||||
uint32_t i = 0u;
|
||||
for (; i < KK_LIB_COUNT; ++i) {
|
||||
nir_shader *s = lib_shaders[i].create_shader_fn();
|
||||
if (!s)
|
||||
goto fail;
|
||||
|
||||
struct kk_shader *shader = NULL;
|
||||
result = kk_compile_nir_shader(dev, s, &dev->vk.alloc, &shader);
|
||||
if (result != VK_SUCCESS)
|
||||
goto fail;
|
||||
|
||||
mtl_library *library = mtl_new_library(dev->mtl_handle, shader->msl_code);
|
||||
if (library == NULL)
|
||||
goto fail;
|
||||
|
||||
uint32_t local_size_threads = shader->info.cs.local_size.x *
|
||||
shader->info.cs.local_size.y *
|
||||
shader->info.cs.local_size.z;
|
||||
mtl_function *function =
|
||||
mtl_new_function_with_name(library, shader->entrypoint_name);
|
||||
dev->lib_pipelines[i] = mtl_new_compute_pipeline_state(
|
||||
dev->mtl_handle, function, local_size_threads);
|
||||
mtl_release(function);
|
||||
mtl_release(library);
|
||||
|
||||
/* We no longer need the shader. Although it may be useful to keep it
|
||||
* alive for the info maybe? */
|
||||
shader->vk.ops->destroy(&dev->vk, &shader->vk, &dev->vk.alloc);
|
||||
|
||||
if (!dev->lib_pipelines[i])
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
fail:
|
||||
for (uint32_t j = 0u; j < i; ++j)
|
||||
mtl_release(dev->lib_pipelines[j]);
|
||||
return vk_error(dev, result);
|
||||
}
|
||||
|
||||
void
|
||||
kk_device_finish_lib(struct kk_device *dev)
|
||||
{
|
||||
for (uint32_t i = 0; i < KK_LIB_COUNT; ++i)
|
||||
mtl_release(dev->lib_pipelines[i]);
|
||||
}
|
||||
258
src/kosmickrisp/vulkan/kk_device_memory.c
Normal file
258
src/kosmickrisp/vulkan/kk_device_memory.c
Normal file
|
|
@ -0,0 +1,258 @@
|
|||
/*
|
||||
* Copyright © 2022 Collabora Ltd. and Red Hat Inc.
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "kk_device_memory.h"
|
||||
|
||||
#include "kk_device.h"
|
||||
#include "kk_entrypoints.h"
|
||||
#include "kk_physical_device.h"
|
||||
|
||||
#include "kosmickrisp/bridge/mtl_bridge.h"
|
||||
|
||||
#include "vulkan/vulkan_metal.h"
|
||||
|
||||
#include "util/u_atomic.h"
|
||||
#include "util/u_memory.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
/* Supports mtlheap only */
|
||||
const VkExternalMemoryProperties kk_mtlheap_mem_props = {
|
||||
.externalMemoryFeatures = VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT |
|
||||
VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT,
|
||||
.exportFromImportedHandleTypes =
|
||||
VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLHEAP_BIT_EXT,
|
||||
.compatibleHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLHEAP_BIT_EXT,
|
||||
};
|
||||
|
||||
#ifdef VK_USE_PLATFORM_METAL_EXT
|
||||
VKAPI_ATTR VkResult VKAPI_CALL
|
||||
kk_GetMemoryMetalHandlePropertiesEXT(
|
||||
VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType,
|
||||
const void *pHandle,
|
||||
VkMemoryMetalHandlePropertiesEXT *pMemoryMetalHandleProperties)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_device, dev, device);
|
||||
struct kk_physical_device *pdev = kk_device_physical(dev);
|
||||
|
||||
/* We only support heaps since that's the backing for all our memory and
|
||||
* simplifies implementation */
|
||||
switch (handleType) {
|
||||
case VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLHEAP_BIT_EXT:
|
||||
break;
|
||||
default:
|
||||
return vk_error(dev, VK_ERROR_INVALID_EXTERNAL_HANDLE);
|
||||
}
|
||||
pMemoryMetalHandleProperties->memoryTypeBits =
|
||||
BITFIELD_MASK(pdev->mem_type_count);
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
#endif /* VK_USE_PLATFORM_METAL_EXT */
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL
|
||||
kk_AllocateMemory(VkDevice device, const VkMemoryAllocateInfo *pAllocateInfo,
|
||||
const VkAllocationCallbacks *pAllocator, VkDeviceMemory *pMem)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_device, dev, device);
|
||||
struct kk_physical_device *pdev = kk_device_physical(dev);
|
||||
struct kk_device_memory *mem;
|
||||
VkResult result = VK_SUCCESS;
|
||||
const VkImportMemoryMetalHandleInfoEXT *metal_info = vk_find_struct_const(
|
||||
pAllocateInfo->pNext, IMPORT_MEMORY_METAL_HANDLE_INFO_EXT);
|
||||
const VkMemoryType *type = &pdev->mem_types[pAllocateInfo->memoryTypeIndex];
|
||||
|
||||
// TODO_KOSMICKRISP Do the actual memory allocation with alignment requirements
|
||||
uint32_t alignment = (1ULL << 12);
|
||||
|
||||
const uint64_t aligned_size =
|
||||
align64(pAllocateInfo->allocationSize, alignment);
|
||||
|
||||
mem = vk_device_memory_create(&dev->vk, pAllocateInfo, pAllocator,
|
||||
sizeof(*mem));
|
||||
if (!mem)
|
||||
return vk_error(dev, VK_ERROR_OUT_OF_HOST_MEMORY);
|
||||
|
||||
if (metal_info && metal_info->handleType) {
|
||||
/* We only support heaps since that's the backing for all our memory and
|
||||
* simplifies implementation */
|
||||
assert(metal_info->handleType ==
|
||||
VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLHEAP_BIT_EXT);
|
||||
mem->bo = CALLOC_STRUCT(kk_bo);
|
||||
if (!mem->bo) {
|
||||
result = vk_errorf(&dev->vk.base, VK_ERROR_OUT_OF_DEVICE_MEMORY, "%m");
|
||||
goto fail_alloc;
|
||||
}
|
||||
mem->bo->mtl_handle = mtl_retain(metal_info->handle);
|
||||
mem->bo->map =
|
||||
mtl_new_buffer_with_length(mem->bo->mtl_handle, mem->vk.size, 0u);
|
||||
mem->bo->gpu = mtl_buffer_get_gpu_address(mem->bo->map);
|
||||
mem->bo->cpu = mtl_get_contents(mem->bo->map);
|
||||
mem->bo->size_B = mtl_heap_get_size(mem->bo->mtl_handle);
|
||||
} else {
|
||||
result =
|
||||
kk_alloc_bo(dev, &dev->vk.base, aligned_size, alignment, &mem->bo);
|
||||
if (result != VK_SUCCESS)
|
||||
goto fail_alloc;
|
||||
}
|
||||
|
||||
struct kk_memory_heap *heap = &pdev->mem_heaps[type->heapIndex];
|
||||
p_atomic_add(&heap->used, mem->bo->size_B);
|
||||
|
||||
kk_device_add_user_heap(dev, mem->bo->mtl_handle);
|
||||
|
||||
*pMem = kk_device_memory_to_handle(mem);
|
||||
|
||||
return VK_SUCCESS;
|
||||
|
||||
fail_alloc:
|
||||
vk_device_memory_destroy(&dev->vk, pAllocator, &mem->vk);
|
||||
return result;
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
kk_FreeMemory(VkDevice device, VkDeviceMemory _mem,
|
||||
const VkAllocationCallbacks *pAllocator)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_device, dev, device);
|
||||
VK_FROM_HANDLE(kk_device_memory, mem, _mem);
|
||||
struct kk_physical_device *pdev = kk_device_physical(dev);
|
||||
|
||||
if (!mem)
|
||||
return;
|
||||
|
||||
kk_device_remove_user_heap(dev, mem->bo->mtl_handle);
|
||||
|
||||
const VkMemoryType *type = &pdev->mem_types[mem->vk.memory_type_index];
|
||||
struct kk_memory_heap *heap = &pdev->mem_heaps[type->heapIndex];
|
||||
p_atomic_add(&heap->used, -((int64_t)mem->bo->size_B));
|
||||
|
||||
kk_destroy_bo(dev, mem->bo);
|
||||
|
||||
vk_device_memory_destroy(&dev->vk, pAllocator, &mem->vk);
|
||||
}
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL
|
||||
kk_MapMemory2KHR(VkDevice device, const VkMemoryMapInfoKHR *pMemoryMapInfo,
|
||||
void **ppData)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_device, dev, device);
|
||||
VK_FROM_HANDLE(kk_device_memory, mem, pMemoryMapInfo->memory);
|
||||
VkResult result = VK_SUCCESS;
|
||||
|
||||
if (mem == NULL) {
|
||||
*ppData = NULL;
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
const VkDeviceSize offset = pMemoryMapInfo->offset;
|
||||
const VkDeviceSize size = vk_device_memory_range(
|
||||
&mem->vk, pMemoryMapInfo->offset, pMemoryMapInfo->size);
|
||||
|
||||
/* From the Vulkan spec version 1.0.32 docs for MapMemory:
|
||||
*
|
||||
* * If size is not equal to VK_WHOLE_SIZE, size must be greater than 0
|
||||
* assert(size != 0);
|
||||
* * If size is not equal to VK_WHOLE_SIZE, size must be less than or
|
||||
* equal to the size of the memory minus offset
|
||||
*/
|
||||
assert(size > 0);
|
||||
assert(offset + size <= mem->bo->size_B);
|
||||
|
||||
if (size != (size_t)size) {
|
||||
return vk_errorf(dev, VK_ERROR_MEMORY_MAP_FAILED,
|
||||
"requested size 0x%" PRIx64 " does not fit in %u bits",
|
||||
size, (unsigned)(sizeof(size_t) * 8));
|
||||
}
|
||||
|
||||
/* From the Vulkan 1.2.194 spec:
|
||||
*
|
||||
* "memory must not be currently host mapped"
|
||||
*/
|
||||
if (mem->map != NULL) {
|
||||
return vk_errorf(dev, VK_ERROR_MEMORY_MAP_FAILED,
|
||||
"Memory object already mapped.");
|
||||
}
|
||||
|
||||
// TODO_KOSMICKRISP Use mmap here to so we can support VK_EXT_map_memory_placed
|
||||
mem->map = mem->bo->cpu;
|
||||
|
||||
*ppData = mem->map + offset;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL
|
||||
kk_UnmapMemory2KHR(VkDevice device,
|
||||
const VkMemoryUnmapInfoKHR *pMemoryUnmapInfo)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_device_memory, mem, pMemoryUnmapInfo->memory);
|
||||
|
||||
if (mem == NULL)
|
||||
return VK_SUCCESS;
|
||||
|
||||
// TODO_KOSMICKRISP Use unmap here to so we can support
|
||||
// VK_EXT_map_memory_placed
|
||||
mem->map = NULL;
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL
|
||||
kk_FlushMappedMemoryRanges(VkDevice device, uint32_t memoryRangeCount,
|
||||
const VkMappedMemoryRange *pMemoryRanges)
|
||||
{
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL
|
||||
kk_InvalidateMappedMemoryRanges(VkDevice device, uint32_t memoryRangeCount,
|
||||
const VkMappedMemoryRange *pMemoryRanges)
|
||||
{
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
kk_GetDeviceMemoryCommitment(VkDevice device, VkDeviceMemory _mem,
|
||||
VkDeviceSize *pCommittedMemoryInBytes)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_device_memory, mem, _mem);
|
||||
|
||||
*pCommittedMemoryInBytes = mem->bo->size_B;
|
||||
}
|
||||
|
||||
#ifdef VK_USE_PLATFORM_METAL_EXT
|
||||
VKAPI_ATTR VkResult VKAPI_CALL
|
||||
kk_GetMemoryMetalHandleEXT(
|
||||
VkDevice device, const VkMemoryGetMetalHandleInfoEXT *pGetMetalHandleInfo,
|
||||
void **pHandle)
|
||||
{
|
||||
/* We only support heaps since that's the backing for all our memory and
|
||||
* simplifies implementation */
|
||||
assert(pGetMetalHandleInfo->handleType ==
|
||||
VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLHEAP_BIT_EXT);
|
||||
VK_FROM_HANDLE(kk_device_memory, mem, pGetMetalHandleInfo->memory);
|
||||
|
||||
/* From the Vulkan spec of vkGetMemoryMetalHandleEXT:
|
||||
*
|
||||
* "Unless the app retains the handle object returned by the call,
|
||||
* the lifespan will be the same as the associated VkDeviceMemory"
|
||||
*/
|
||||
*pHandle = mem->bo->mtl_handle;
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
#endif /* VK_USE_PLATFORM_METAL_EXT */
|
||||
|
||||
VKAPI_ATTR uint64_t VKAPI_CALL
|
||||
kk_GetDeviceMemoryOpaqueCaptureAddress(
|
||||
UNUSED VkDevice device, const VkDeviceMemoryOpaqueCaptureAddressInfo *pInfo)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_device_memory, mem, pInfo->memory);
|
||||
|
||||
return mem->bo->gpu;
|
||||
}
|
||||
30
src/kosmickrisp/vulkan/kk_device_memory.h
Normal file
30
src/kosmickrisp/vulkan/kk_device_memory.h
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright © 2022 Collabora Ltd. and Red Hat Inc.
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef KK_MEMORY_H
|
||||
#define KK_MEMORY_H 1
|
||||
|
||||
#include "kk_private.h"
|
||||
|
||||
#include "kk_bo.h"
|
||||
|
||||
#include "vk_device_memory.h"
|
||||
|
||||
#include "util/list.h"
|
||||
|
||||
struct kk_device_memory {
|
||||
struct vk_device_memory vk;
|
||||
struct kk_bo *bo;
|
||||
void *map;
|
||||
};
|
||||
|
||||
VK_DEFINE_NONDISP_HANDLE_CASTS(kk_device_memory, vk.base, VkDeviceMemory,
|
||||
VK_OBJECT_TYPE_DEVICE_MEMORY)
|
||||
|
||||
extern const VkExternalMemoryProperties kk_mtlheap_mem_props;
|
||||
|
||||
#endif // KK_MEMORY_H
|
||||
480
src/kosmickrisp/vulkan/kk_encoder.c
Normal file
480
src/kosmickrisp/vulkan/kk_encoder.c
Normal file
|
|
@ -0,0 +1,480 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "kk_encoder.h"
|
||||
|
||||
#include "kk_bo.h"
|
||||
#include "kk_cmd_buffer.h"
|
||||
#include "kk_queue.h"
|
||||
|
||||
#include "kosmickrisp/bridge/mtl_bridge.h"
|
||||
#include "kosmickrisp/bridge/vk_to_mtl_map.h"
|
||||
|
||||
#include "cl/kk_query.h"
|
||||
|
||||
static void
|
||||
kk_encoder_start_internal(struct kk_encoder_internal *encoder,
|
||||
mtl_device *device, mtl_command_queue *queue)
|
||||
{
|
||||
encoder->cmd_buffer = mtl_new_command_buffer(queue);
|
||||
encoder->last_used = KK_ENC_NONE;
|
||||
util_dynarray_init(&encoder->fences, NULL);
|
||||
}
|
||||
|
||||
VkResult
|
||||
kk_encoder_init(mtl_device *device, struct kk_queue *queue,
|
||||
struct kk_encoder **encoder)
|
||||
{
|
||||
assert(encoder && device && queue);
|
||||
struct kk_encoder *enc = (struct kk_encoder *)malloc(sizeof(*enc));
|
||||
if (!enc)
|
||||
return VK_ERROR_OUT_OF_HOST_MEMORY;
|
||||
|
||||
memset(enc, 0u, sizeof(*enc));
|
||||
enc->dev = device;
|
||||
kk_encoder_start_internal(&enc->main, device, queue->main.mtl_handle);
|
||||
kk_encoder_start_internal(&enc->pre_gfx, device, queue->pre_gfx.mtl_handle);
|
||||
enc->event = mtl_new_event(device);
|
||||
util_dynarray_init(&enc->imm_writes, NULL);
|
||||
util_dynarray_init(&enc->resident_buffers, NULL);
|
||||
util_dynarray_init(&enc->copy_query_pool_result_infos, NULL);
|
||||
|
||||
*encoder = enc;
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
mtl_render_encoder *
|
||||
kk_encoder_start_render(struct kk_cmd_buffer *cmd,
|
||||
mtl_render_pass_descriptor *descriptor,
|
||||
uint32_t view_mask)
|
||||
{
|
||||
struct kk_encoder *encoder = cmd->encoder;
|
||||
/* We must not already be in a render encoder */
|
||||
assert(encoder->main.last_used != KK_ENC_RENDER ||
|
||||
encoder->main.encoder == NULL);
|
||||
if (encoder->main.last_used != KK_ENC_RENDER) {
|
||||
kk_encoder_signal_fence_and_end(cmd);
|
||||
|
||||
/* Before we start any render operation we need to ensure we have the
|
||||
* requried signals to insert pre_gfx execution before the render encoder
|
||||
* in case we need to insert commands to massage input data for things
|
||||
* like triangle fans. For this, we signal the value pre_gfx will wait on,
|
||||
* and we wait on the value pre_gfx will signal once completed.
|
||||
*/
|
||||
encoder->signal_value_pre_gfx = encoder->event_value;
|
||||
mtl_encode_signal_event(encoder->main.cmd_buffer, encoder->event,
|
||||
++encoder->event_value);
|
||||
encoder->wait_value_pre_gfx = encoder->event_value;
|
||||
mtl_encode_wait_for_event(encoder->main.cmd_buffer, encoder->event,
|
||||
++encoder->event_value);
|
||||
|
||||
encoder->main.encoder = mtl_new_render_command_encoder_with_descriptor(
|
||||
encoder->main.cmd_buffer, descriptor);
|
||||
if (encoder->main.wait_fence) {
|
||||
mtl_render_wait_for_fence(
|
||||
encoder->main.encoder,
|
||||
util_dynarray_top(&encoder->main.fences, mtl_fence *));
|
||||
encoder->main.wait_fence = false;
|
||||
}
|
||||
|
||||
uint32_t layer_ids[KK_MAX_MULTIVIEW_VIEW_COUNT] = {};
|
||||
uint32_t count = 0u;
|
||||
u_foreach_bit(id, view_mask)
|
||||
layer_ids[count++] = id;
|
||||
if (view_mask == 0u) {
|
||||
layer_ids[count++] = 0;
|
||||
}
|
||||
mtl_set_vertex_amplification_count(encoder->main.encoder, layer_ids,
|
||||
count);
|
||||
encoder->main.user_heap_hash = UINT32_MAX;
|
||||
|
||||
/* Bind read only data aka samplers' argument buffer. */
|
||||
struct kk_device *dev = kk_cmd_buffer_device(cmd);
|
||||
mtl_set_vertex_buffer(encoder->main.encoder, dev->samplers.table.bo->map,
|
||||
0u, 1u);
|
||||
mtl_set_fragment_buffer(encoder->main.encoder,
|
||||
dev->samplers.table.bo->map, 0u, 1u);
|
||||
}
|
||||
encoder->main.last_used = KK_ENC_RENDER;
|
||||
return encoder->main.encoder;
|
||||
}
|
||||
|
||||
mtl_compute_encoder *
|
||||
kk_encoder_start_compute(struct kk_cmd_buffer *cmd)
|
||||
{
|
||||
struct kk_encoder *encoder = cmd->encoder;
|
||||
/* We must not already be in a render encoder */
|
||||
assert(encoder->main.last_used != KK_ENC_RENDER ||
|
||||
encoder->main.encoder == NULL);
|
||||
struct kk_encoder_internal *enc = &encoder->main;
|
||||
if (encoder->main.last_used != KK_ENC_COMPUTE) {
|
||||
kk_encoder_signal_fence_and_end(cmd);
|
||||
enc->encoder = mtl_new_compute_command_encoder(enc->cmd_buffer);
|
||||
if (enc->wait_fence) {
|
||||
mtl_compute_wait_for_fence(
|
||||
enc->encoder, util_dynarray_top(&enc->fences, mtl_fence *));
|
||||
enc->wait_fence = false;
|
||||
}
|
||||
enc->user_heap_hash = UINT32_MAX;
|
||||
|
||||
/* Bind read only data aka samplers' argument buffer. */
|
||||
struct kk_device *dev = kk_cmd_buffer_device(cmd);
|
||||
mtl_compute_set_buffer(enc->encoder, dev->samplers.table.bo->map, 0u, 1u);
|
||||
}
|
||||
encoder->main.last_used = KK_ENC_COMPUTE;
|
||||
return encoder->main.encoder;
|
||||
}
|
||||
|
||||
mtl_compute_encoder *
|
||||
kk_encoder_start_blit(struct kk_cmd_buffer *cmd)
|
||||
{
|
||||
struct kk_encoder *encoder = cmd->encoder;
|
||||
/* We must not already be in a render encoder */
|
||||
assert(encoder->main.last_used != KK_ENC_RENDER ||
|
||||
encoder->main.encoder == NULL);
|
||||
struct kk_encoder_internal *enc = &encoder->main;
|
||||
if (encoder->main.last_used != KK_ENC_BLIT) {
|
||||
kk_encoder_signal_fence_and_end(cmd);
|
||||
enc->encoder = mtl_new_blit_command_encoder(enc->cmd_buffer);
|
||||
if (enc->wait_fence) {
|
||||
mtl_compute_wait_for_fence(
|
||||
enc->encoder, util_dynarray_top(&enc->fences, mtl_fence *));
|
||||
enc->wait_fence = false;
|
||||
}
|
||||
}
|
||||
encoder->main.last_used = KK_ENC_BLIT;
|
||||
return encoder->main.encoder;
|
||||
}
|
||||
|
||||
void
|
||||
kk_encoder_end(struct kk_cmd_buffer *cmd)
|
||||
{
|
||||
assert(cmd);
|
||||
|
||||
kk_encoder_signal_fence_and_end(cmd);
|
||||
|
||||
/* Let remaining render encoders run without waiting since we are done */
|
||||
mtl_encode_signal_event(cmd->encoder->pre_gfx.cmd_buffer,
|
||||
cmd->encoder->event, cmd->encoder->event_value);
|
||||
}
|
||||
|
||||
struct kk_imm_write_push {
|
||||
uint64_t buffer_address;
|
||||
uint32_t count;
|
||||
};
|
||||
|
||||
void
|
||||
upload_queue_writes(struct kk_cmd_buffer *cmd)
|
||||
{
|
||||
struct kk_encoder *enc = cmd->encoder;
|
||||
|
||||
struct kk_device *dev = kk_cmd_buffer_device(cmd);
|
||||
uint32_t count = util_dynarray_num_elements(&enc->imm_writes, uint64_t) / 2u;
|
||||
if (count != 0) {
|
||||
mtl_compute_encoder *compute = kk_compute_encoder(cmd);
|
||||
struct kk_bo *bo = kk_cmd_allocate_buffer(cmd, enc->imm_writes.size, 8u);
|
||||
/* kk_cmd_allocate_buffer sets the cmd buffer error so we can just exit */
|
||||
if (!bo)
|
||||
return;
|
||||
memcpy(bo->cpu, enc->imm_writes.data, enc->imm_writes.size);
|
||||
uint32_t buffer_count =
|
||||
util_dynarray_num_elements(&enc->resident_buffers, mtl_buffer *);
|
||||
mtl_compute_use_resource(compute, bo->map, MTL_RESOURCE_USAGE_READ);
|
||||
mtl_compute_use_resources(
|
||||
compute, enc->resident_buffers.data, buffer_count,
|
||||
MTL_RESOURCE_USAGE_READ | MTL_RESOURCE_USAGE_WRITE);
|
||||
struct kk_imm_write_push push_data = {
|
||||
.buffer_address = bo->gpu,
|
||||
.count = count,
|
||||
};
|
||||
kk_cmd_dispatch_pipeline(cmd, compute,
|
||||
kk_device_lib_pipeline(dev, KK_LIB_IMM_WRITE),
|
||||
&push_data, sizeof(push_data), count, 1, 1);
|
||||
enc->resident_buffers.size = 0u;
|
||||
enc->imm_writes.size = 0u;
|
||||
}
|
||||
|
||||
count = util_dynarray_num_elements(&enc->copy_query_pool_result_infos,
|
||||
struct kk_copy_query_pool_results_info);
|
||||
if (count != 0u) {
|
||||
mtl_compute_encoder *compute = kk_compute_encoder(cmd);
|
||||
uint32_t buffer_count =
|
||||
util_dynarray_num_elements(&enc->resident_buffers, mtl_buffer *);
|
||||
mtl_compute_use_resources(
|
||||
compute, enc->resident_buffers.data, buffer_count,
|
||||
MTL_RESOURCE_USAGE_READ | MTL_RESOURCE_USAGE_WRITE);
|
||||
|
||||
for (uint32_t i = 0u; i < count; ++i) {
|
||||
struct kk_copy_query_pool_results_info *push_data =
|
||||
util_dynarray_element(&enc->copy_query_pool_result_infos,
|
||||
struct kk_copy_query_pool_results_info, i);
|
||||
|
||||
kk_cmd_dispatch_pipeline(
|
||||
cmd, compute, kk_device_lib_pipeline(dev, KK_LIB_COPY_QUERY),
|
||||
push_data, sizeof(*push_data), push_data->query_count, 1, 1);
|
||||
}
|
||||
enc->resident_buffers.size = 0u;
|
||||
enc->copy_query_pool_result_infos.size = 0u;
|
||||
}
|
||||
|
||||
/* All immediate write done, reset encoder */
|
||||
kk_encoder_signal_fence_and_end(cmd);
|
||||
}
|
||||
|
||||
void
|
||||
kk_encoder_signal_fence_and_end(struct kk_cmd_buffer *cmd)
|
||||
{
|
||||
struct kk_encoder *encoder = cmd->encoder;
|
||||
/* End pre_gfx */
|
||||
if (encoder->pre_gfx.encoder) {
|
||||
mtl_end_encoding(encoder->pre_gfx.encoder);
|
||||
mtl_release(encoder->pre_gfx.encoder);
|
||||
encoder->pre_gfx.encoder = NULL;
|
||||
|
||||
/* We can start rendering once all pre-graphics work is done */
|
||||
mtl_encode_signal_event(encoder->pre_gfx.cmd_buffer, encoder->event,
|
||||
encoder->event_value);
|
||||
}
|
||||
|
||||
assert(encoder);
|
||||
enum kk_encoder_type type = encoder->main.last_used;
|
||||
struct kk_encoder_internal *enc = kk_encoder_get_internal(encoder, type);
|
||||
if (!enc || !enc->encoder)
|
||||
return;
|
||||
|
||||
mtl_fence *fence = mtl_new_fence(encoder->dev);
|
||||
switch (type) {
|
||||
case KK_ENC_RENDER:
|
||||
mtl_render_update_fence(enc->encoder, fence);
|
||||
break;
|
||||
case KK_ENC_COMPUTE:
|
||||
mtl_compute_update_fence(enc->encoder, fence);
|
||||
break;
|
||||
case KK_ENC_BLIT:
|
||||
mtl_blit_update_fence(enc->encoder, fence);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
mtl_end_encoding(enc->encoder);
|
||||
mtl_release(enc->encoder);
|
||||
enc->encoder = NULL;
|
||||
enc->last_used = KK_ENC_NONE;
|
||||
enc->wait_fence = true;
|
||||
util_dynarray_append(&enc->fences, mtl_fence *, fence);
|
||||
|
||||
if (cmd->drawable) {
|
||||
mtl_present_drawable(enc->cmd_buffer, cmd->drawable);
|
||||
cmd->drawable = NULL;
|
||||
}
|
||||
upload_queue_writes(cmd);
|
||||
}
|
||||
|
||||
static void
|
||||
kk_post_execution_release_internal(struct kk_encoder_internal *encoder)
|
||||
{
|
||||
mtl_release(encoder->cmd_buffer);
|
||||
util_dynarray_foreach(&encoder->fences, mtl_fence *, fence)
|
||||
mtl_release(*fence);
|
||||
util_dynarray_fini(&encoder->fences);
|
||||
}
|
||||
|
||||
static void
|
||||
kk_post_execution_release(void *data)
|
||||
{
|
||||
struct kk_encoder *encoder = data;
|
||||
kk_post_execution_release_internal(&encoder->main);
|
||||
kk_post_execution_release_internal(&encoder->pre_gfx);
|
||||
mtl_release(encoder->event);
|
||||
util_dynarray_fini(&encoder->imm_writes);
|
||||
util_dynarray_fini(&encoder->resident_buffers);
|
||||
util_dynarray_fini(&encoder->copy_query_pool_result_infos);
|
||||
free(encoder);
|
||||
}
|
||||
|
||||
void
|
||||
kk_encoder_submit(struct kk_encoder *encoder)
|
||||
{
|
||||
assert(encoder);
|
||||
|
||||
mtl_add_completed_handler(encoder->main.cmd_buffer,
|
||||
kk_post_execution_release, encoder);
|
||||
|
||||
mtl_command_buffer_commit(encoder->pre_gfx.cmd_buffer);
|
||||
mtl_command_buffer_commit(encoder->main.cmd_buffer);
|
||||
}
|
||||
|
||||
mtl_render_encoder *
|
||||
kk_render_encoder(struct kk_cmd_buffer *cmd)
|
||||
{
|
||||
struct kk_encoder *encoder = cmd->encoder;
|
||||
/* Render encoders are created at vkBeginRendering only */
|
||||
assert(encoder->main.last_used == KK_ENC_RENDER && encoder->main.encoder);
|
||||
return (mtl_render_encoder *)encoder->main.encoder;
|
||||
}
|
||||
|
||||
mtl_compute_encoder *
|
||||
kk_compute_encoder(struct kk_cmd_buffer *cmd)
|
||||
{
|
||||
struct kk_encoder *encoder = cmd->encoder;
|
||||
return encoder->main.last_used == KK_ENC_COMPUTE
|
||||
? (mtl_blit_encoder *)encoder->main.encoder
|
||||
: kk_encoder_start_compute(cmd);
|
||||
}
|
||||
|
||||
mtl_blit_encoder *
|
||||
kk_blit_encoder(struct kk_cmd_buffer *cmd)
|
||||
{
|
||||
struct kk_encoder *encoder = cmd->encoder;
|
||||
return encoder->main.last_used == KK_ENC_BLIT
|
||||
? (mtl_blit_encoder *)encoder->main.encoder
|
||||
: kk_encoder_start_blit(cmd);
|
||||
}
|
||||
|
||||
struct kk_encoder_internal *
|
||||
kk_encoder_get_internal(struct kk_encoder *encoder, enum kk_encoder_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case KK_ENC_NONE:
|
||||
assert(encoder->main.last_used == KK_ENC_NONE);
|
||||
return NULL;
|
||||
case KK_ENC_RENDER:
|
||||
assert(encoder->main.last_used == KK_ENC_RENDER);
|
||||
return &encoder->main;
|
||||
case KK_ENC_COMPUTE:
|
||||
assert(encoder->main.last_used == KK_ENC_COMPUTE);
|
||||
return &encoder->main;
|
||||
case KK_ENC_BLIT:
|
||||
assert(encoder->main.last_used == KK_ENC_BLIT);
|
||||
return &encoder->main;
|
||||
default:
|
||||
assert(0);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static mtl_compute_encoder *
|
||||
kk_encoder_pre_gfx_encoder(struct kk_encoder *encoder)
|
||||
{
|
||||
if (!encoder->pre_gfx.encoder) {
|
||||
/* Fast-forward all previous render encoders and wait for the last one */
|
||||
mtl_encode_signal_event(encoder->pre_gfx.cmd_buffer, encoder->event,
|
||||
encoder->signal_value_pre_gfx);
|
||||
mtl_encode_wait_for_event(encoder->pre_gfx.cmd_buffer, encoder->event,
|
||||
encoder->wait_value_pre_gfx);
|
||||
encoder->pre_gfx.encoder =
|
||||
mtl_new_compute_command_encoder(encoder->pre_gfx.cmd_buffer);
|
||||
}
|
||||
|
||||
return encoder->pre_gfx.encoder;
|
||||
}
|
||||
|
||||
struct kk_triangle_fan_info {
|
||||
uint64_t index_buffer;
|
||||
uint64_t out_ptr;
|
||||
uint64_t in_draw;
|
||||
uint64_t out_draw;
|
||||
uint32_t restart_index;
|
||||
uint32_t index_buffer_size_el;
|
||||
uint32_t in_el_size_B;
|
||||
uint32_t out_el_size_B;
|
||||
uint32_t flatshade_first;
|
||||
uint32_t mode;
|
||||
};
|
||||
|
||||
static void
|
||||
kk_encoder_render_triangle_fan_common(struct kk_cmd_buffer *cmd,
|
||||
struct kk_triangle_fan_info *info,
|
||||
mtl_buffer *indirect, mtl_buffer *index,
|
||||
uint32_t index_count,
|
||||
uint32_t in_el_size_B,
|
||||
uint32_t out_el_size_B)
|
||||
{
|
||||
uint32_t index_buffer_size_B = index_count * out_el_size_B;
|
||||
uint32_t buffer_size_B =
|
||||
sizeof(VkDrawIndexedIndirectCommand) + index_buffer_size_B;
|
||||
struct kk_bo *index_buffer =
|
||||
kk_cmd_allocate_buffer(cmd, buffer_size_B, out_el_size_B);
|
||||
|
||||
if (!index_buffer)
|
||||
return;
|
||||
|
||||
info->out_ptr = index_buffer->gpu + sizeof(VkDrawIndexedIndirectCommand);
|
||||
info->out_draw = index_buffer->gpu;
|
||||
info->in_el_size_B = in_el_size_B;
|
||||
info->out_el_size_B = out_el_size_B;
|
||||
info->flatshade_first = true;
|
||||
mtl_compute_encoder *encoder = kk_encoder_pre_gfx_encoder(cmd->encoder);
|
||||
if (index)
|
||||
mtl_compute_use_resource(encoder, index, MTL_RESOURCE_USAGE_READ);
|
||||
mtl_compute_use_resource(encoder, indirect, MTL_RESOURCE_USAGE_READ);
|
||||
mtl_compute_use_resource(encoder, index_buffer->map,
|
||||
MTL_RESOURCE_USAGE_WRITE);
|
||||
|
||||
struct kk_device *dev = kk_cmd_buffer_device(cmd);
|
||||
kk_cmd_dispatch_pipeline(cmd, encoder,
|
||||
kk_device_lib_pipeline(dev, KK_LIB_TRIANGLE_FAN),
|
||||
info, sizeof(*info), 1u, 1u, 1u);
|
||||
|
||||
enum mtl_index_type index_type =
|
||||
index_size_in_bytes_to_mtl_index_type(out_el_size_B);
|
||||
mtl_render_encoder *enc = kk_render_encoder(cmd);
|
||||
mtl_draw_indexed_primitives_indirect(
|
||||
enc, cmd->state.gfx.primitive_type, index_type, index_buffer->map,
|
||||
sizeof(VkDrawIndexedIndirectCommand), index_buffer->map, 0u);
|
||||
}
|
||||
|
||||
void
|
||||
kk_encoder_render_triangle_fan_indirect(struct kk_cmd_buffer *cmd,
|
||||
mtl_buffer *indirect, uint64_t offset)
|
||||
{
|
||||
enum mesa_prim mode = cmd->state.gfx.prim;
|
||||
uint32_t decomposed_index_count =
|
||||
u_decomposed_prims_for_vertices(mode, cmd->state.gfx.vb.max_vertices) *
|
||||
mesa_vertices_per_prim(mode);
|
||||
uint32_t el_size_B = decomposed_index_count < UINT16_MAX ? 2u : 4u;
|
||||
struct kk_triangle_fan_info info = {
|
||||
.in_draw = mtl_buffer_get_gpu_address(indirect) + offset,
|
||||
.restart_index = UINT32_MAX, /* No restart */
|
||||
.mode = mode,
|
||||
};
|
||||
kk_encoder_render_triangle_fan_common(
|
||||
cmd, &info, indirect, NULL, decomposed_index_count, el_size_B, el_size_B);
|
||||
}
|
||||
|
||||
void
|
||||
kk_encoder_render_triangle_fan_indexed_indirect(struct kk_cmd_buffer *cmd,
|
||||
mtl_buffer *indirect,
|
||||
uint64_t offset,
|
||||
bool increase_el_size)
|
||||
{
|
||||
uint32_t el_size_B = cmd->state.gfx.index.bytes_per_index;
|
||||
|
||||
enum mesa_prim mode = cmd->state.gfx.prim;
|
||||
uint32_t max_index_count =
|
||||
(mtl_buffer_get_length(cmd->state.gfx.index.handle) -
|
||||
cmd->state.gfx.index.offset) /
|
||||
el_size_B;
|
||||
uint32_t decomposed_index_count =
|
||||
u_decomposed_prims_for_vertices(mode, max_index_count) *
|
||||
mesa_vertices_per_prim(mode);
|
||||
|
||||
struct kk_triangle_fan_info info = {
|
||||
.index_buffer = mtl_buffer_get_gpu_address(cmd->state.gfx.index.handle) +
|
||||
cmd->state.gfx.index.offset,
|
||||
.in_draw = mtl_buffer_get_gpu_address(indirect) + offset,
|
||||
.restart_index =
|
||||
increase_el_size ? UINT32_MAX : cmd->state.gfx.index.restart,
|
||||
.index_buffer_size_el = max_index_count,
|
||||
.mode = mode,
|
||||
};
|
||||
uint32_t out_el_size_B = increase_el_size ? sizeof(uint32_t) : el_size_B;
|
||||
kk_encoder_render_triangle_fan_common(
|
||||
cmd, &info, indirect, cmd->state.gfx.index.handle, decomposed_index_count,
|
||||
el_size_B, out_el_size_B);
|
||||
}
|
||||
125
src/kosmickrisp/vulkan/kk_encoder.h
Normal file
125
src/kosmickrisp/vulkan/kk_encoder.h
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef KK_ENCODER_H
|
||||
#define KK_ENCODER_H 1
|
||||
|
||||
#include "kosmickrisp/bridge/mtl_types.h"
|
||||
|
||||
#include "util/u_dynarray.h"
|
||||
|
||||
#include "vulkan/vulkan.h"
|
||||
|
||||
struct kk_queue;
|
||||
struct kk_cmd_buffer;
|
||||
|
||||
enum kk_encoder_type {
|
||||
KK_ENC_NONE = 0,
|
||||
KK_ENC_RENDER = BITFIELD_BIT(0),
|
||||
KK_ENC_COMPUTE = BITFIELD_BIT(1),
|
||||
KK_ENC_BLIT = BITFIELD_BIT(2),
|
||||
KK_ENC_ALL = (KK_ENC_RENDER | KK_ENC_COMPUTE | KK_ENC_BLIT),
|
||||
KK_ENC_COUNT = 3u,
|
||||
};
|
||||
|
||||
struct kk_encoder_internal {
|
||||
mtl_command_buffer *cmd_buffer;
|
||||
mtl_command_encoder *encoder;
|
||||
|
||||
/* Used to know if we need to make heaps resident again */
|
||||
uint32_t user_heap_hash;
|
||||
|
||||
/* Need to track last used to we can converge at submission */
|
||||
enum kk_encoder_type last_used;
|
||||
|
||||
/* Used to synchronize between passes inside the same command buffer */
|
||||
struct util_dynarray fences;
|
||||
/* Tracks if we need to wait on the last fence present in fences at the start
|
||||
* of the pass */
|
||||
bool wait_fence;
|
||||
};
|
||||
|
||||
struct kk_copy_query_pool_results_info {
|
||||
uint64_t availability;
|
||||
uint64_t results;
|
||||
uint64_t indices;
|
||||
uint64_t dst_addr;
|
||||
uint64_t dst_stride;
|
||||
uint32_t first_query;
|
||||
VkQueryResultFlagBits flags;
|
||||
uint16_t reports_per_query;
|
||||
uint32_t query_count;
|
||||
};
|
||||
|
||||
struct kk_encoder {
|
||||
mtl_device *dev;
|
||||
struct kk_encoder_internal main;
|
||||
/* Compute only for pre gfx required work */
|
||||
struct kk_encoder_internal pre_gfx;
|
||||
|
||||
/* Used to synchronize between main and pre_gfx encoders */
|
||||
mtl_event *event;
|
||||
uint64_t event_value;
|
||||
/* Track what values pre_gfx must wait/signal before starting the encoding */
|
||||
uint64_t wait_value_pre_gfx;
|
||||
uint64_t signal_value_pre_gfx;
|
||||
|
||||
/* uint64_t pairs with first being the address, second being the value to
|
||||
* write */
|
||||
struct util_dynarray imm_writes;
|
||||
/* mtl_buffers (destination buffers) so we can make them resident before the
|
||||
* dispatch */
|
||||
struct util_dynarray resident_buffers;
|
||||
/* Array of kk_copy_quer_pool_results_info structs */
|
||||
struct util_dynarray copy_query_pool_result_infos;
|
||||
};
|
||||
|
||||
/* Allocates encoder and initialises/creates all resources required to start
|
||||
* recording commands into the multiple encoders */
|
||||
VkResult kk_encoder_init(mtl_device *device, struct kk_queue *queue,
|
||||
struct kk_encoder **encoder);
|
||||
|
||||
/* Submits all command buffers and releases encoder memory. Requires all command
|
||||
* buffers in the encoder to be linked to the last one used so the post
|
||||
* execution callback is called once all are done */
|
||||
void kk_encoder_submit(struct kk_encoder *encoder);
|
||||
|
||||
mtl_render_encoder *
|
||||
kk_encoder_start_render(struct kk_cmd_buffer *cmd,
|
||||
mtl_render_pass_descriptor *descriptor,
|
||||
uint32_t view_mask);
|
||||
|
||||
mtl_compute_encoder *kk_encoder_start_compute(struct kk_cmd_buffer *cmd);
|
||||
|
||||
mtl_compute_encoder *kk_encoder_start_blit(struct kk_cmd_buffer *cmd);
|
||||
|
||||
/* Ends encoding on all command buffers */
|
||||
void kk_encoder_end(struct kk_cmd_buffer *cmd);
|
||||
|
||||
/* Creates a fence and signals it inside the encoder, then ends encoding */
|
||||
void kk_encoder_signal_fence_and_end(struct kk_cmd_buffer *cmd);
|
||||
|
||||
mtl_render_encoder *kk_render_encoder(struct kk_cmd_buffer *cmd);
|
||||
|
||||
mtl_compute_encoder *kk_compute_encoder(struct kk_cmd_buffer *cmd);
|
||||
|
||||
mtl_blit_encoder *kk_blit_encoder(struct kk_cmd_buffer *cmd);
|
||||
|
||||
struct kk_encoder_internal *kk_encoder_get_internal(struct kk_encoder *encoder,
|
||||
enum kk_encoder_type type);
|
||||
|
||||
void upload_queue_writes(struct kk_cmd_buffer *cmd);
|
||||
|
||||
void kk_encoder_render_triangle_fan_indirect(struct kk_cmd_buffer *cmd,
|
||||
mtl_buffer *indirect,
|
||||
uint64_t offset);
|
||||
|
||||
void kk_encoder_render_triangle_fan_indexed_indirect(struct kk_cmd_buffer *cmd,
|
||||
mtl_buffer *indirect,
|
||||
uint64_t offset,
|
||||
bool increase_el_size);
|
||||
|
||||
#endif /* KK_ENCODER_H */
|
||||
143
src/kosmickrisp/vulkan/kk_event.c
Normal file
143
src/kosmickrisp/vulkan/kk_event.c
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
* Copyright © 2022 Collabora Ltd. and Red Hat Inc.
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "kk_event.h"
|
||||
|
||||
#include "kk_bo.h"
|
||||
#include "kk_cmd_buffer.h"
|
||||
#include "kk_device.h"
|
||||
#include "kk_encoder.h"
|
||||
#include "kk_entrypoints.h"
|
||||
|
||||
#define KK_EVENT_MEM_SIZE sizeof(uint64_t)
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL
|
||||
kk_CreateEvent(VkDevice device, const VkEventCreateInfo *pCreateInfo,
|
||||
const VkAllocationCallbacks *pAllocator, VkEvent *pEvent)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_device, dev, device);
|
||||
struct kk_event *event;
|
||||
VkResult result = VK_SUCCESS;
|
||||
|
||||
event = vk_object_zalloc(&dev->vk, pAllocator, sizeof(*event),
|
||||
VK_OBJECT_TYPE_EVENT);
|
||||
if (!event)
|
||||
return vk_error(dev, VK_ERROR_OUT_OF_HOST_MEMORY);
|
||||
|
||||
/* TODO_KOSMICKRISP Bring back the heap. */
|
||||
result = kk_alloc_bo(dev, &dev->vk.base, KK_EVENT_MEM_SIZE,
|
||||
KK_EVENT_MEM_SIZE, &event->bo);
|
||||
if (result != VK_SUCCESS) {
|
||||
vk_object_free(&dev->vk, pAllocator, event);
|
||||
return result;
|
||||
}
|
||||
|
||||
event->status = event->bo->cpu;
|
||||
event->addr = event->bo->gpu;
|
||||
*event->status = VK_EVENT_RESET;
|
||||
|
||||
*pEvent = kk_event_to_handle(event);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
kk_DestroyEvent(VkDevice device, VkEvent _event,
|
||||
const VkAllocationCallbacks *pAllocator)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_device, dev, device);
|
||||
VK_FROM_HANDLE(kk_event, event, _event);
|
||||
|
||||
if (!event)
|
||||
return;
|
||||
|
||||
kk_destroy_bo(dev, event->bo);
|
||||
|
||||
vk_object_free(&dev->vk, pAllocator, event);
|
||||
}
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL
|
||||
kk_GetEventStatus(VkDevice device, VkEvent _event)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_event, event, _event);
|
||||
|
||||
return *event->status;
|
||||
}
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL
|
||||
kk_SetEvent(VkDevice device, VkEvent _event)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_event, event, _event);
|
||||
|
||||
*event->status = VK_EVENT_SET;
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL
|
||||
kk_ResetEvent(VkDevice device, VkEvent _event)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_event, event, _event);
|
||||
|
||||
*event->status = VK_EVENT_RESET;
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
kk_CmdSetEvent2(VkCommandBuffer commandBuffer, VkEvent _event,
|
||||
const VkDependencyInfo *pDependencyInfo)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_event, event, _event);
|
||||
VK_FROM_HANDLE(kk_cmd_buffer, cmd, commandBuffer);
|
||||
enum kk_encoder_type last_used = cmd->encoder->main.last_used;
|
||||
kk_cmd_write(cmd, event->bo->map, event->addr, VK_EVENT_SET);
|
||||
if (last_used != KK_ENC_NONE)
|
||||
kk_encoder_signal_fence_and_end(cmd);
|
||||
else
|
||||
upload_queue_writes(cmd);
|
||||
|
||||
/* If we were inside a render pass, restart it loading attachments */
|
||||
if (last_used == KK_ENC_RENDER) {
|
||||
struct kk_graphics_state *state = &cmd->state.gfx;
|
||||
assert(state->render_pass_descriptor);
|
||||
kk_encoder_start_render(cmd, state->render_pass_descriptor,
|
||||
state->render.view_mask);
|
||||
kk_cmd_buffer_dirty_all_gfx(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
kk_CmdResetEvent2(VkCommandBuffer commandBuffer, VkEvent _event,
|
||||
VkPipelineStageFlags2 stageMask)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_event, event, _event);
|
||||
VK_FROM_HANDLE(kk_cmd_buffer, cmd, commandBuffer);
|
||||
enum kk_encoder_type last_used = cmd->encoder->main.last_used;
|
||||
kk_cmd_write(cmd, event->bo->map, event->addr, VK_EVENT_RESET);
|
||||
if (last_used != KK_ENC_NONE)
|
||||
kk_encoder_signal_fence_and_end(cmd);
|
||||
else
|
||||
upload_queue_writes(cmd);
|
||||
|
||||
/* If we were inside a render pass, restart it loading attachments */
|
||||
if (last_used == KK_ENC_RENDER) {
|
||||
struct kk_graphics_state *state = &cmd->state.gfx;
|
||||
assert(state->render_pass_descriptor);
|
||||
kk_encoder_start_render(cmd, state->render_pass_descriptor,
|
||||
state->render.view_mask);
|
||||
kk_cmd_buffer_dirty_all_gfx(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
kk_CmdWaitEvents2(VkCommandBuffer commandBuffer, uint32_t eventCount,
|
||||
const VkEvent *pEvents,
|
||||
const VkDependencyInfo *pDependencyInfos)
|
||||
{
|
||||
/* We do nothing, event should already be set by the time we are here. */
|
||||
}
|
||||
27
src/kosmickrisp/vulkan/kk_event.h
Normal file
27
src/kosmickrisp/vulkan/kk_event.h
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright © 2022 Collabora Ltd. and Red Hat Inc.
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef KK_EVENT_H
|
||||
#define KK_EVENT_H 1
|
||||
|
||||
#include "kk_private.h"
|
||||
|
||||
#include "vk_object.h"
|
||||
|
||||
struct kk_bo;
|
||||
|
||||
struct kk_event {
|
||||
struct vk_object_base base;
|
||||
struct kk_bo *bo;
|
||||
|
||||
uint64_t addr;
|
||||
uint64_t *status;
|
||||
};
|
||||
|
||||
VK_DEFINE_NONDISP_HANDLE_CASTS(kk_event, base, VkEvent, VK_OBJECT_TYPE_EVENT)
|
||||
|
||||
#endif /* KK_EVENT_H */
|
||||
359
src/kosmickrisp/vulkan/kk_format.c
Normal file
359
src/kosmickrisp/vulkan/kk_format.c
Normal file
|
|
@ -0,0 +1,359 @@
|
|||
/*
|
||||
* Copyright © 2022 Collabora Ltd. and Red Hat Inc.
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "kk_format.h"
|
||||
|
||||
#include "kk_buffer_view.h"
|
||||
#include "kk_entrypoints.h"
|
||||
#include "kk_image.h"
|
||||
#include "kk_physical_device.h"
|
||||
|
||||
#include "kosmickrisp/bridge/mtl_format.h"
|
||||
|
||||
#include "vk_enum_defines.h"
|
||||
#include "vk_format.h"
|
||||
|
||||
#define MTL_FMT_ALL_NO_ATOMIC(width) \
|
||||
.bit_widths = width, .filter = 1u, .write = 1u, .color = 1u, .blend = 1u, \
|
||||
.msaa = 1u, .resolve = 1u, .sparse = 1u, .atomic = 0u
|
||||
|
||||
// Filter, Write, Color, Blend, MSAA, Sparse
|
||||
#define MTL_FMT_FWCBMS(width) \
|
||||
.bit_widths = width, .filter = 1u, .write = 1u, .color = 1u, .blend = 1u, \
|
||||
.msaa = 1u, .resolve = 0u, .sparse = 1u, .atomic = 0u
|
||||
|
||||
// Filter, Color, Blend, MSAA, Resolve, Sparse
|
||||
#define MTL_FMT_FCBMRS(width) \
|
||||
.bit_widths = width, .filter = 1u, .write = 0u, .color = 1u, .blend = 1u, \
|
||||
.msaa = 1u, .resolve = 1u, .sparse = 1u, .atomic = 0u
|
||||
|
||||
// Filter, Write, Color, Blend, MSAA
|
||||
#define MTL_FMT_FWCBM(width) \
|
||||
.bit_widths = width, .filter = 1u, .write = 1u, .color = 1u, .blend = 1u, \
|
||||
.msaa = 1u, .resolve = 0u, .sparse = 0u, .atomic = 0u
|
||||
|
||||
// Write, Color, Blend, MSAA, Sparse
|
||||
#define MTL_FMT_WCBMS(width) \
|
||||
.bit_widths = width, .filter = 0u, .write = 1u, .color = 1u, .blend = 1u, \
|
||||
.msaa = 1u, .resolve = 0u, .sparse = 0u, .atomic = 0u
|
||||
|
||||
// Write, Color, MSAA, Sparse
|
||||
#define MTL_FMT_WCMS(width) \
|
||||
.bit_widths = width, .filter = 0u, .write = 1u, .color = 1u, .blend = 0u, \
|
||||
.msaa = 1u, .resolve = 0u, .sparse = 1u, .atomic = 0u
|
||||
|
||||
// Write, Color, Sparse, Atomic
|
||||
#define MTL_FMT_WCSA(width) \
|
||||
.bit_widths = width, .filter = 0u, .write = 1u, .color = 1u, .blend = 0u, \
|
||||
.msaa = 0u, .resolve = 0u, .sparse = 1u, .atomic = 1u
|
||||
|
||||
// Write, Color, Sparse
|
||||
#define MTL_FMT_WCS(width) \
|
||||
.bit_widths = width, .filter = 0u, .write = 1u, .color = 1u, .blend = 0u, \
|
||||
.msaa = 0u, .resolve = 0u, .sparse = 1u, .atomic = 0u
|
||||
|
||||
// Filter, MSAA, Resolve
|
||||
#define MTL_FMT_FMR(width) \
|
||||
.bit_widths = width, .filter = 1u, .write = 0u, .color = 0u, .blend = 0u, \
|
||||
.msaa = 1u, .resolve = 1u, .sparse = 0u, .atomic = 0u
|
||||
|
||||
// Filter, Sparse
|
||||
#define MTL_FMT_FS(width) \
|
||||
.bit_widths = width, .filter = 1u, .write = 0u, .color = 0u, .blend = 0u, \
|
||||
.msaa = 0u, .resolve = 0u, .sparse = 1u, .atomic = 0u
|
||||
|
||||
// MSAA, Resolve
|
||||
#define MTL_FMT_MR(width) \
|
||||
.bit_widths = width, .filter = 0u, .write = 0u, .color = 0u, .blend = 0u, \
|
||||
.msaa = 1u, .resolve = 1u, .sparse = 0u, .atomic = 0u
|
||||
|
||||
// MSAA
|
||||
#define MTL_FMT_M(width) \
|
||||
.bit_widths = width, .filter = 0u, .write = 0u, .color = 0u, .blend = 0u, \
|
||||
.msaa = 1u, .resolve = 0u, .sparse = 0u, .atomic = 0u
|
||||
|
||||
#define MTL_FMT_TB_ALL \
|
||||
.texel_buffer = { \
|
||||
.write = 1u, \
|
||||
.read = 1u, \
|
||||
.read_write = 1u, \
|
||||
}
|
||||
|
||||
#define MTL_FMT_TB_WR \
|
||||
.texel_buffer = { \
|
||||
.write = 1u, \
|
||||
.read = 1u, \
|
||||
.read_write = 0u, \
|
||||
}
|
||||
|
||||
#define MTL_FMT_TB_R \
|
||||
.texel_buffer = { \
|
||||
.write = 0u, \
|
||||
.read = 1u, \
|
||||
.read_write = 0u, \
|
||||
}
|
||||
|
||||
#define MTL_FMT_TB_NONE \
|
||||
.texel_buffer = { \
|
||||
.write = 0u, \
|
||||
.read = 0u, \
|
||||
.read_write = 0u, \
|
||||
}
|
||||
|
||||
#define MTL_SWIZZLE_IDENTITY \
|
||||
.swizzle = { \
|
||||
.red = PIPE_SWIZZLE_X, \
|
||||
.green = PIPE_SWIZZLE_Y, \
|
||||
.blue = PIPE_SWIZZLE_Z, \
|
||||
.alpha = PIPE_SWIZZLE_W, \
|
||||
}
|
||||
|
||||
#define MTL_SWIZZLE_ABGR \
|
||||
.swizzle = { \
|
||||
.red = PIPE_SWIZZLE_W, \
|
||||
.green = PIPE_SWIZZLE_Z, \
|
||||
.blue = PIPE_SWIZZLE_Y, \
|
||||
.alpha = PIPE_SWIZZLE_X, \
|
||||
}
|
||||
|
||||
#define MTL_SWIZZLE_BGRA \
|
||||
.swizzle = { \
|
||||
.red = PIPE_SWIZZLE_Z, \
|
||||
.green = PIPE_SWIZZLE_Y, \
|
||||
.blue = PIPE_SWIZZLE_X, \
|
||||
.alpha = PIPE_SWIZZLE_W, \
|
||||
}
|
||||
|
||||
#define MTL_FMT(pipe_format, mtl_format, swizzle, capabilities, \
|
||||
texel_buffer_capabilities, native) \
|
||||
[PIPE_FORMAT_## \
|
||||
pipe_format] = {.mtl_pixel_format = MTL_PIXEL_FORMAT_##mtl_format, \
|
||||
swizzle, \
|
||||
capabilities, \
|
||||
texel_buffer_capabilities, \
|
||||
.is_native = native}
|
||||
|
||||
#define MTL_FMT_NATIVE(format, capabilities, texel_buffer_capabilities) \
|
||||
[PIPE_FORMAT_##format] = {.mtl_pixel_format = MTL_PIXEL_FORMAT_##format, \
|
||||
MTL_SWIZZLE_IDENTITY, \
|
||||
capabilities, \
|
||||
texel_buffer_capabilities, \
|
||||
.is_native = 1}
|
||||
|
||||
static const struct kk_va_format kk_vf_formats[] = {
|
||||
// 8-bit formats
|
||||
MTL_FMT_NATIVE(R8_UNORM, MTL_FMT_ALL_NO_ATOMIC(8), MTL_FMT_TB_ALL),
|
||||
MTL_FMT_NATIVE(A8_UNORM, MTL_FMT_ALL_NO_ATOMIC(8), MTL_FMT_TB_ALL),
|
||||
MTL_FMT_NATIVE(R8_SRGB, MTL_FMT_ALL_NO_ATOMIC(8), MTL_FMT_TB_NONE),
|
||||
MTL_FMT_NATIVE(R8_SNORM, MTL_FMT_ALL_NO_ATOMIC(8), MTL_FMT_TB_WR),
|
||||
MTL_FMT_NATIVE(R8_UINT, MTL_FMT_WCMS(8), MTL_FMT_TB_ALL),
|
||||
MTL_FMT_NATIVE(R8_SINT, MTL_FMT_WCMS(8), MTL_FMT_TB_ALL),
|
||||
|
||||
// 16-bit formats
|
||||
MTL_FMT_NATIVE(R16_UNORM, MTL_FMT_FWCBMS(16), MTL_FMT_TB_WR),
|
||||
MTL_FMT_NATIVE(R16_SNORM, MTL_FMT_FWCBMS(16), MTL_FMT_TB_WR),
|
||||
MTL_FMT_NATIVE(R16_UINT, MTL_FMT_WCMS(16), MTL_FMT_TB_ALL),
|
||||
MTL_FMT_NATIVE(R16_SINT, MTL_FMT_WCMS(16), MTL_FMT_TB_ALL),
|
||||
MTL_FMT_NATIVE(R16_FLOAT, MTL_FMT_ALL_NO_ATOMIC(16), MTL_FMT_TB_ALL),
|
||||
MTL_FMT_NATIVE(R8G8_UNORM, MTL_FMT_ALL_NO_ATOMIC(16), MTL_FMT_TB_WR),
|
||||
MTL_FMT_NATIVE(R8G8_SNORM, MTL_FMT_ALL_NO_ATOMIC(16), MTL_FMT_TB_WR),
|
||||
MTL_FMT_NATIVE(R8G8_SRGB, MTL_FMT_ALL_NO_ATOMIC(16), MTL_FMT_TB_NONE),
|
||||
MTL_FMT_NATIVE(R8G8_UINT, MTL_FMT_WCMS(16), MTL_FMT_TB_WR),
|
||||
MTL_FMT_NATIVE(R8G8_SINT, MTL_FMT_WCMS(16), MTL_FMT_TB_WR),
|
||||
|
||||
// 32-bit formats
|
||||
MTL_FMT_NATIVE(R32_UINT, MTL_FMT_WCSA(32), MTL_FMT_TB_ALL),
|
||||
MTL_FMT_NATIVE(R32_SINT, MTL_FMT_WCSA(32), MTL_FMT_TB_ALL),
|
||||
MTL_FMT_NATIVE(R32_FLOAT, MTL_FMT_WCBMS(32), MTL_FMT_TB_ALL),
|
||||
MTL_FMT_NATIVE(R16G16_UNORM, MTL_FMT_FWCBMS(32), MTL_FMT_TB_WR),
|
||||
MTL_FMT_NATIVE(R16G16_SNORM, MTL_FMT_FWCBMS(32), MTL_FMT_TB_WR),
|
||||
MTL_FMT_NATIVE(R16G16_UINT, MTL_FMT_WCMS(32), MTL_FMT_TB_WR),
|
||||
MTL_FMT_NATIVE(R16G16_SINT, MTL_FMT_WCMS(32), MTL_FMT_TB_WR),
|
||||
MTL_FMT_NATIVE(R16G16_FLOAT, MTL_FMT_ALL_NO_ATOMIC(32), MTL_FMT_TB_WR),
|
||||
MTL_FMT_NATIVE(R8G8B8A8_UNORM, MTL_FMT_ALL_NO_ATOMIC(32), MTL_FMT_TB_WR),
|
||||
MTL_FMT_NATIVE(R8G8B8A8_SNORM, MTL_FMT_ALL_NO_ATOMIC(32), MTL_FMT_TB_WR),
|
||||
MTL_FMT_NATIVE(R8G8B8A8_SRGB, MTL_FMT_ALL_NO_ATOMIC(32), MTL_FMT_TB_NONE),
|
||||
MTL_FMT_NATIVE(R8G8B8A8_UINT, MTL_FMT_WCMS(32), MTL_FMT_TB_ALL),
|
||||
MTL_FMT_NATIVE(R8G8B8A8_SINT, MTL_FMT_WCMS(32), MTL_FMT_TB_ALL),
|
||||
MTL_FMT_NATIVE(B8G8R8A8_UNORM, MTL_FMT_ALL_NO_ATOMIC(32), MTL_FMT_TB_R),
|
||||
MTL_FMT_NATIVE(B8G8R8A8_SRGB, MTL_FMT_ALL_NO_ATOMIC(32), MTL_FMT_TB_NONE),
|
||||
|
||||
// 64-bit formats
|
||||
MTL_FMT_NATIVE(R32G32_UINT, MTL_FMT_WCMS(64), MTL_FMT_TB_WR),
|
||||
MTL_FMT_NATIVE(R32G32_SINT, MTL_FMT_WCMS(64), MTL_FMT_TB_WR),
|
||||
MTL_FMT_NATIVE(R32G32_FLOAT, MTL_FMT_WCBMS(64), MTL_FMT_TB_WR),
|
||||
MTL_FMT_NATIVE(R16G16B16A16_UNORM, MTL_FMT_FWCBMS(64), MTL_FMT_TB_WR),
|
||||
MTL_FMT_NATIVE(R16G16B16A16_SNORM, MTL_FMT_FWCBMS(64), MTL_FMT_TB_WR),
|
||||
MTL_FMT_NATIVE(R16G16B16A16_UINT, MTL_FMT_WCMS(64), MTL_FMT_TB_ALL),
|
||||
MTL_FMT_NATIVE(R16G16B16A16_SINT, MTL_FMT_WCMS(64), MTL_FMT_TB_ALL),
|
||||
MTL_FMT_NATIVE(R16G16B16A16_FLOAT, MTL_FMT_ALL_NO_ATOMIC(64),
|
||||
MTL_FMT_TB_ALL),
|
||||
|
||||
// 128-bit formats
|
||||
MTL_FMT_NATIVE(R32G32B32A32_UINT, MTL_FMT_WCS(128), MTL_FMT_TB_ALL),
|
||||
MTL_FMT_NATIVE(R32G32B32A32_SINT, MTL_FMT_WCS(128), MTL_FMT_TB_ALL),
|
||||
MTL_FMT_NATIVE(R32G32B32A32_FLOAT, MTL_FMT_WCMS(128), MTL_FMT_TB_ALL),
|
||||
|
||||
// 16-bit packed formats
|
||||
MTL_FMT_NATIVE(B5G6R5_UNORM, MTL_FMT_FCBMRS(16), MTL_FMT_TB_NONE),
|
||||
/* Hardware has issues with border color opaque black, and since it's not
|
||||
* required by Vulkan, we can just disable it.
|
||||
*/
|
||||
/* MTL_FMT_NATIVE(A1B5G5R5_UNORM, MTL_FMT_FCBMRS(16), MTL_FMT_TB_NONE), */
|
||||
MTL_FMT_NATIVE(A4B4G4R4_UNORM, MTL_FMT_FCBMRS(16), MTL_FMT_TB_NONE),
|
||||
MTL_FMT(R4G4B4A4_UNORM, A4B4G4R4_UNORM, MTL_SWIZZLE_ABGR, MTL_FMT_FCBMRS(16),
|
||||
MTL_FMT_TB_NONE, false),
|
||||
MTL_FMT(A4R4G4B4_UNORM, A4B4G4R4_UNORM, MTL_SWIZZLE_BGRA, MTL_FMT_FCBMRS(16),
|
||||
MTL_FMT_TB_NONE, false),
|
||||
MTL_FMT_NATIVE(B5G5R5A1_UNORM, MTL_FMT_FCBMRS(16), MTL_FMT_TB_NONE),
|
||||
|
||||
// 32-bit packed formats
|
||||
MTL_FMT_NATIVE(R10G10B10A2_UNORM, MTL_FMT_ALL_NO_ATOMIC(32), MTL_FMT_TB_WR),
|
||||
MTL_FMT_NATIVE(B10G10R10A2_UNORM, MTL_FMT_ALL_NO_ATOMIC(32),
|
||||
MTL_FMT_TB_NONE),
|
||||
MTL_FMT_NATIVE(R10G10B10A2_UINT, MTL_FMT_WCMS(32), MTL_FMT_TB_WR),
|
||||
MTL_FMT_NATIVE(R11G11B10_FLOAT, MTL_FMT_ALL_NO_ATOMIC(32), MTL_FMT_TB_WR),
|
||||
MTL_FMT_NATIVE(R9G9B9E5_FLOAT, MTL_FMT_ALL_NO_ATOMIC(32), MTL_FMT_TB_NONE),
|
||||
|
||||
// ASTC formats
|
||||
MTL_FMT_NATIVE(ASTC_4x4, MTL_FMT_FS(128), MTL_FMT_TB_NONE),
|
||||
MTL_FMT_NATIVE(ASTC_5x4, MTL_FMT_FS(128), MTL_FMT_TB_NONE),
|
||||
MTL_FMT_NATIVE(ASTC_5x5, MTL_FMT_FS(128), MTL_FMT_TB_NONE),
|
||||
MTL_FMT_NATIVE(ASTC_6x5, MTL_FMT_FS(128), MTL_FMT_TB_NONE),
|
||||
MTL_FMT_NATIVE(ASTC_6x6, MTL_FMT_FS(128), MTL_FMT_TB_NONE),
|
||||
MTL_FMT_NATIVE(ASTC_8x5, MTL_FMT_FS(128), MTL_FMT_TB_NONE),
|
||||
MTL_FMT_NATIVE(ASTC_8x6, MTL_FMT_FS(128), MTL_FMT_TB_NONE),
|
||||
MTL_FMT_NATIVE(ASTC_8x8, MTL_FMT_FS(128), MTL_FMT_TB_NONE),
|
||||
MTL_FMT_NATIVE(ASTC_10x5, MTL_FMT_FS(128), MTL_FMT_TB_NONE),
|
||||
MTL_FMT_NATIVE(ASTC_10x6, MTL_FMT_FS(128), MTL_FMT_TB_NONE),
|
||||
MTL_FMT_NATIVE(ASTC_10x8, MTL_FMT_FS(128), MTL_FMT_TB_NONE),
|
||||
MTL_FMT_NATIVE(ASTC_10x10, MTL_FMT_FS(128), MTL_FMT_TB_NONE),
|
||||
MTL_FMT_NATIVE(ASTC_12x10, MTL_FMT_FS(128), MTL_FMT_TB_NONE),
|
||||
MTL_FMT_NATIVE(ASTC_12x12, MTL_FMT_FS(128), MTL_FMT_TB_NONE),
|
||||
|
||||
MTL_FMT_NATIVE(ASTC_4x4_SRGB, MTL_FMT_FS(128), MTL_FMT_TB_NONE),
|
||||
MTL_FMT_NATIVE(ASTC_5x4_SRGB, MTL_FMT_FS(128), MTL_FMT_TB_NONE),
|
||||
MTL_FMT_NATIVE(ASTC_5x5_SRGB, MTL_FMT_FS(128), MTL_FMT_TB_NONE),
|
||||
MTL_FMT_NATIVE(ASTC_6x5_SRGB, MTL_FMT_FS(128), MTL_FMT_TB_NONE),
|
||||
MTL_FMT_NATIVE(ASTC_6x6_SRGB, MTL_FMT_FS(128), MTL_FMT_TB_NONE),
|
||||
MTL_FMT_NATIVE(ASTC_8x5_SRGB, MTL_FMT_FS(128), MTL_FMT_TB_NONE),
|
||||
MTL_FMT_NATIVE(ASTC_8x6_SRGB, MTL_FMT_FS(128), MTL_FMT_TB_NONE),
|
||||
MTL_FMT_NATIVE(ASTC_8x8_SRGB, MTL_FMT_FS(128), MTL_FMT_TB_NONE),
|
||||
MTL_FMT_NATIVE(ASTC_10x5_SRGB, MTL_FMT_FS(128), MTL_FMT_TB_NONE),
|
||||
MTL_FMT_NATIVE(ASTC_10x6_SRGB, MTL_FMT_FS(128), MTL_FMT_TB_NONE),
|
||||
MTL_FMT_NATIVE(ASTC_10x8_SRGB, MTL_FMT_FS(128), MTL_FMT_TB_NONE),
|
||||
MTL_FMT_NATIVE(ASTC_10x10_SRGB, MTL_FMT_FS(128), MTL_FMT_TB_NONE),
|
||||
MTL_FMT_NATIVE(ASTC_12x10_SRGB, MTL_FMT_FS(128), MTL_FMT_TB_NONE),
|
||||
MTL_FMT_NATIVE(ASTC_12x12_SRGB, MTL_FMT_FS(128), MTL_FMT_TB_NONE),
|
||||
|
||||
// EAC/ETC formats
|
||||
MTL_FMT_NATIVE(ETC2_R11_UNORM, MTL_FMT_FS(64), MTL_FMT_TB_NONE),
|
||||
MTL_FMT_NATIVE(ETC2_R11_SNORM, MTL_FMT_FS(64), MTL_FMT_TB_NONE),
|
||||
MTL_FMT_NATIVE(ETC2_RG11_UNORM, MTL_FMT_FS(128), MTL_FMT_TB_NONE),
|
||||
MTL_FMT_NATIVE(ETC2_RG11_SNORM, MTL_FMT_FS(128), MTL_FMT_TB_NONE),
|
||||
MTL_FMT_NATIVE(ETC2_RGBA8, MTL_FMT_FS(128), MTL_FMT_TB_NONE),
|
||||
MTL_FMT_NATIVE(ETC2_SRGBA8, MTL_FMT_FS(128), MTL_FMT_TB_NONE),
|
||||
|
||||
MTL_FMT_NATIVE(ETC2_RGB8, MTL_FMT_FS(64), MTL_FMT_TB_NONE),
|
||||
MTL_FMT_NATIVE(ETC2_SRGB8, MTL_FMT_FS(64), MTL_FMT_TB_NONE),
|
||||
MTL_FMT_NATIVE(ETC2_RGB8A1, MTL_FMT_FS(64), MTL_FMT_TB_NONE),
|
||||
MTL_FMT_NATIVE(ETC2_SRGB8A1, MTL_FMT_FS(64), MTL_FMT_TB_NONE),
|
||||
|
||||
// Compressed PVRTC, HDR ASTC, BC TODO_KOSMICKRISP
|
||||
// YUV formats TODO_KOSMICKRISP
|
||||
// Extended range and wide color formats TODO_KOSMICKRISP
|
||||
|
||||
// Depth and stencil formats
|
||||
MTL_FMT_NATIVE(Z16_UNORM, MTL_FMT_FMR(16), MTL_FMT_TB_NONE),
|
||||
MTL_FMT_NATIVE(Z32_FLOAT, MTL_FMT_MR(32), MTL_FMT_TB_NONE),
|
||||
MTL_FMT_NATIVE(S8_UINT, MTL_FMT_M(8), MTL_FMT_TB_NONE),
|
||||
MTL_FMT_NATIVE(Z32_FLOAT_S8X24_UINT, MTL_FMT_MR(64), MTL_FMT_TB_NONE),
|
||||
MTL_FMT_NATIVE(X32_S8X24_UINT, MTL_FMT_MR(64), MTL_FMT_TB_NONE),
|
||||
};
|
||||
|
||||
#undef MTL_FMT_NATIVE
|
||||
#undef MTL_FMT
|
||||
|
||||
#undef MTL_SWIZZLE_BGRA
|
||||
#undef MTL_SWIZZLE_ABGR
|
||||
#undef MTL_SWIZZLE_IDENTITY
|
||||
|
||||
#undef MTL_FMT_ALL_NO_ATOMIC
|
||||
#undef MTL_FMT_FWCBMS
|
||||
#undef MTL_FMT_FCBMRS
|
||||
#undef MTL_FMT_FWCBM
|
||||
#undef MTL_FMT_WCBMS
|
||||
#undef MTL_FMT_WCMS
|
||||
#undef MTL_FMT_WCSA
|
||||
#undef MTL_FMT_WCS
|
||||
#undef MTL_FMT_FMR
|
||||
#undef MTL_FMT_FS
|
||||
#undef MTL_FMT_MR
|
||||
#undef MTL_FMT_M
|
||||
|
||||
#undef MTL_FMT_TB_ALL
|
||||
#undef MTL_FMT_TB_WR
|
||||
#undef MTL_FMT_TB_R
|
||||
#undef MTL_FMT_TB_NONE
|
||||
|
||||
const struct kk_va_format *
|
||||
kk_get_va_format(enum pipe_format format)
|
||||
{
|
||||
if (format >= ARRAY_SIZE(kk_vf_formats))
|
||||
return NULL;
|
||||
|
||||
if (kk_vf_formats[format].bit_widths == 0)
|
||||
return NULL;
|
||||
|
||||
return &kk_vf_formats[format];
|
||||
}
|
||||
|
||||
enum mtl_pixel_format
|
||||
vk_format_to_mtl_pixel_format(VkFormat vkformat)
|
||||
{
|
||||
enum pipe_format format = vk_format_to_pipe_format(vkformat);
|
||||
const struct kk_va_format *supported_format = kk_get_va_format(format);
|
||||
assert(supported_format);
|
||||
return supported_format->mtl_pixel_format;
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
kk_GetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice,
|
||||
VkFormat format,
|
||||
VkFormatProperties2 *pFormatProperties)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_physical_device, pdevice, physicalDevice);
|
||||
|
||||
VkFormatFeatureFlags2 linear2, optimal2, buffer2;
|
||||
linear2 =
|
||||
kk_get_image_format_features(pdevice, format, VK_IMAGE_TILING_LINEAR, 0);
|
||||
optimal2 =
|
||||
kk_get_image_format_features(pdevice, format, VK_IMAGE_TILING_OPTIMAL, 0);
|
||||
buffer2 = kk_get_buffer_format_features(pdevice, format);
|
||||
|
||||
pFormatProperties->formatProperties = (VkFormatProperties){
|
||||
.linearTilingFeatures = vk_format_features2_to_features(linear2),
|
||||
.optimalTilingFeatures = vk_format_features2_to_features(optimal2),
|
||||
.bufferFeatures = vk_format_features2_to_features(buffer2),
|
||||
};
|
||||
|
||||
vk_foreach_struct(ext, pFormatProperties->pNext) {
|
||||
switch (ext->sType) {
|
||||
case VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_3: {
|
||||
VkFormatProperties3 *p = (void *)ext;
|
||||
p->linearTilingFeatures = linear2;
|
||||
p->optimalTilingFeatures = optimal2;
|
||||
p->bufferFeatures = buffer2;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
vk_debug_ignored_stype(ext->sType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
55
src/kosmickrisp/vulkan/kk_format.h
Normal file
55
src/kosmickrisp/vulkan/kk_format.h
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright © 2022 Collabora Ltd. and Red Hat Inc.
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef KK_FORMAT_H
|
||||
#define KK_FORMAT_H 1
|
||||
|
||||
#include "kk_private.h"
|
||||
|
||||
#include "util/format/u_format.h"
|
||||
|
||||
struct kk_physical_device;
|
||||
enum pipe_format;
|
||||
enum mtl_pixel_format;
|
||||
|
||||
struct kk_va_format {
|
||||
/* Would love to use enum pipe_swizzle, but it's bigger than the required
|
||||
* type for util_format_compose_swizzles... */
|
||||
struct {
|
||||
union {
|
||||
struct {
|
||||
uint8_t red;
|
||||
uint8_t green;
|
||||
uint8_t blue;
|
||||
uint8_t alpha;
|
||||
};
|
||||
uint8_t channels[4];
|
||||
};
|
||||
} swizzle;
|
||||
uint32_t mtl_pixel_format;
|
||||
uint8_t bit_widths;
|
||||
uint8_t filter : 1;
|
||||
uint8_t write : 1;
|
||||
uint8_t color : 1;
|
||||
uint8_t blend : 1;
|
||||
uint8_t msaa : 1;
|
||||
uint8_t resolve : 1;
|
||||
uint8_t sparse : 1;
|
||||
uint8_t atomic : 1;
|
||||
struct {
|
||||
uint8_t write : 1;
|
||||
uint8_t read : 1;
|
||||
uint8_t read_write : 1;
|
||||
} texel_buffer;
|
||||
uint8_t is_native : 1;
|
||||
};
|
||||
|
||||
const struct kk_va_format *kk_get_va_format(enum pipe_format format);
|
||||
|
||||
enum mtl_pixel_format vk_format_to_mtl_pixel_format(enum VkFormat vkformat);
|
||||
|
||||
#endif /* KK_FORMAT_H */
|
||||
967
src/kosmickrisp/vulkan/kk_image.c
Normal file
967
src/kosmickrisp/vulkan/kk_image.c
Normal file
|
|
@ -0,0 +1,967 @@
|
|||
/*
|
||||
* Copyright © 2022 Collabora Ltd. and Red Hat Inc.
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "kk_image.h"
|
||||
|
||||
#include "kk_device.h"
|
||||
#include "kk_device_memory.h"
|
||||
#include "kk_entrypoints.h"
|
||||
#include "kk_format.h"
|
||||
#include "kk_physical_device.h"
|
||||
|
||||
#include "kosmickrisp/bridge/mtl_bridge.h"
|
||||
|
||||
#include "vk_enum_defines.h"
|
||||
#include "vk_enum_to_str.h"
|
||||
#include "vk_format.h"
|
||||
#include "wsi_common_private.h"
|
||||
|
||||
static VkFormatFeatureFlags2
|
||||
kk_get_image_plane_format_features(struct kk_physical_device *pdev,
|
||||
VkFormat vk_format, VkImageTiling tiling,
|
||||
uint64_t drm_format_mod)
|
||||
{
|
||||
VkFormatFeatureFlags2 features = 0;
|
||||
|
||||
/* Metal does not support linear tiling for compressed formats */
|
||||
if (tiling == VK_IMAGE_TILING_LINEAR && vk_format_is_compressed(vk_format))
|
||||
return 0;
|
||||
|
||||
enum pipe_format p_format = vk_format_to_pipe_format(vk_format);
|
||||
if (p_format == PIPE_FORMAT_NONE)
|
||||
return 0;
|
||||
|
||||
/* You can't tile a non-power-of-two */
|
||||
if (!util_is_power_of_two_nonzero(util_format_get_blocksize(p_format)))
|
||||
return 0;
|
||||
|
||||
const struct kk_va_format *va_format = kk_get_va_format(p_format);
|
||||
if (va_format == NULL)
|
||||
return 0;
|
||||
|
||||
// Textures can at least be sampled
|
||||
features |= VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_BIT;
|
||||
features |= VK_FORMAT_FEATURE_2_BLIT_SRC_BIT;
|
||||
|
||||
if (va_format->filter) {
|
||||
features |= VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_LINEAR_BIT;
|
||||
features |=
|
||||
VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_MINMAX_BIT; // TODO_KOSMICKRISP
|
||||
// Understand if
|
||||
// we want to
|
||||
// expose this
|
||||
}
|
||||
|
||||
/* TODO: VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_DEPTH_COMPARISON_BIT */
|
||||
if (vk_format_has_depth(vk_format)) {
|
||||
features |= VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_DEPTH_COMPARISON_BIT;
|
||||
}
|
||||
|
||||
/* We disable A8 format due to lower blend pass issues */
|
||||
if (va_format->color && tiling != VK_IMAGE_TILING_LINEAR &&
|
||||
vk_format != VK_FORMAT_A8_UNORM) {
|
||||
features |= VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BIT;
|
||||
features |= VK_FORMAT_FEATURE_2_BLIT_DST_BIT;
|
||||
// TODO_KOSMICKRISP Support snorm formats once the following spec issue is
|
||||
// resolved: https://gitlab.khronos.org/vulkan/vulkan/-/issues/4293
|
||||
if (!vk_format_is_snorm(vk_format))
|
||||
features |= VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BLEND_BIT;
|
||||
}
|
||||
|
||||
if (vk_format_is_depth_or_stencil(vk_format)) {
|
||||
if (tiling == VK_IMAGE_TILING_LINEAR)
|
||||
return 0;
|
||||
|
||||
features |= VK_FORMAT_FEATURE_2_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
}
|
||||
|
||||
if (va_format->write) {
|
||||
features |= VK_FORMAT_FEATURE_2_STORAGE_IMAGE_BIT;
|
||||
}
|
||||
|
||||
if (va_format->atomic)
|
||||
features |= VK_FORMAT_FEATURE_2_STORAGE_IMAGE_ATOMIC_BIT;
|
||||
|
||||
if (features != 0) {
|
||||
features |= VK_FORMAT_FEATURE_2_TRANSFER_SRC_BIT;
|
||||
features |= VK_FORMAT_FEATURE_2_TRANSFER_DST_BIT;
|
||||
}
|
||||
|
||||
return features;
|
||||
}
|
||||
|
||||
VkFormatFeatureFlags2
|
||||
kk_get_image_format_features(struct kk_physical_device *pdev,
|
||||
VkFormat vk_format, VkImageTiling tiling,
|
||||
uint64_t drm_format_mod)
|
||||
{
|
||||
const struct vk_format_ycbcr_info *ycbcr_info =
|
||||
vk_format_get_ycbcr_info(vk_format);
|
||||
if (ycbcr_info == NULL) {
|
||||
return kk_get_image_plane_format_features(pdev, vk_format, tiling,
|
||||
drm_format_mod);
|
||||
}
|
||||
|
||||
/* For multi-plane, we get the feature flags of each plane separately,
|
||||
* then take their intersection as the overall format feature flags
|
||||
*/
|
||||
VkFormatFeatureFlags2 features = ~0ull;
|
||||
bool cosited_chroma = false;
|
||||
for (uint8_t plane = 0; plane < ycbcr_info->n_planes; plane++) {
|
||||
const struct vk_format_ycbcr_plane *plane_info =
|
||||
&ycbcr_info->planes[plane];
|
||||
features &= kk_get_image_plane_format_features(pdev, plane_info->format,
|
||||
tiling, drm_format_mod);
|
||||
if (plane_info->denominator_scales[0] > 1 ||
|
||||
plane_info->denominator_scales[1] > 1)
|
||||
cosited_chroma = true;
|
||||
}
|
||||
if (features == 0)
|
||||
return 0;
|
||||
|
||||
/* Uh... We really should be able to sample from YCbCr */
|
||||
assert(features & VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_BIT);
|
||||
assert(features & VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_LINEAR_BIT);
|
||||
|
||||
/* These aren't allowed for YCbCr formats */
|
||||
features &=
|
||||
~(VK_FORMAT_FEATURE_2_BLIT_SRC_BIT | VK_FORMAT_FEATURE_2_BLIT_DST_BIT |
|
||||
VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BIT |
|
||||
VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BLEND_BIT |
|
||||
VK_FORMAT_FEATURE_2_STORAGE_IMAGE_BIT);
|
||||
|
||||
/* This is supported on all YCbCr formats */
|
||||
features |=
|
||||
VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT;
|
||||
|
||||
if (ycbcr_info->n_planes > 1) {
|
||||
/* DISJOINT_BIT implies that each plane has its own separate binding,
|
||||
* while SEPARATE_RECONSTRUCTION_FILTER_BIT implies that luma and chroma
|
||||
* each have their own, separate filters, so these two bits make sense
|
||||
* for multi-planar formats only.
|
||||
*
|
||||
* For MIDPOINT_CHROMA_SAMPLES_BIT, NVIDIA HW on single-plane interleaved
|
||||
* YCbCr defaults to COSITED_EVEN, which is inaccurate and fails tests.
|
||||
* This can be fixed with a NIR tweak but for now, we only enable this bit
|
||||
* for multi-plane formats. See Issue #9525 on the mesa/main tracker.
|
||||
*/
|
||||
features |=
|
||||
VK_FORMAT_FEATURE_DISJOINT_BIT |
|
||||
VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT |
|
||||
VK_FORMAT_FEATURE_2_MIDPOINT_CHROMA_SAMPLES_BIT;
|
||||
}
|
||||
|
||||
if (cosited_chroma)
|
||||
features |= VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT;
|
||||
|
||||
return features;
|
||||
}
|
||||
|
||||
static VkFormatFeatureFlags2
|
||||
vk_image_usage_to_format_features(VkImageUsageFlagBits usage_flag)
|
||||
{
|
||||
assert(util_bitcount(usage_flag) == 1);
|
||||
switch (usage_flag) {
|
||||
case VK_IMAGE_USAGE_TRANSFER_SRC_BIT:
|
||||
return VK_FORMAT_FEATURE_2_TRANSFER_SRC_BIT |
|
||||
VK_FORMAT_FEATURE_BLIT_SRC_BIT;
|
||||
case VK_IMAGE_USAGE_TRANSFER_DST_BIT:
|
||||
return VK_FORMAT_FEATURE_2_TRANSFER_DST_BIT |
|
||||
VK_FORMAT_FEATURE_BLIT_DST_BIT;
|
||||
case VK_IMAGE_USAGE_SAMPLED_BIT:
|
||||
return VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_BIT;
|
||||
case VK_IMAGE_USAGE_STORAGE_BIT:
|
||||
return VK_FORMAT_FEATURE_2_STORAGE_IMAGE_BIT;
|
||||
case VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT:
|
||||
return VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BIT;
|
||||
case VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT:
|
||||
return VK_FORMAT_FEATURE_2_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
case VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT:
|
||||
return VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BIT |
|
||||
VK_FORMAT_FEATURE_2_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
case VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR:
|
||||
return VK_FORMAT_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
kk_image_max_dimension(VkImageType image_type)
|
||||
{
|
||||
/* Values taken from Apple7
|
||||
* https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf */
|
||||
switch (image_type) {
|
||||
case VK_IMAGE_TYPE_1D:
|
||||
case VK_IMAGE_TYPE_2D:
|
||||
return 16384;
|
||||
case VK_IMAGE_TYPE_3D:
|
||||
return 2048;
|
||||
default:
|
||||
UNREACHABLE("Invalid image type");
|
||||
}
|
||||
}
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL
|
||||
kk_GetPhysicalDeviceImageFormatProperties2(
|
||||
VkPhysicalDevice physicalDevice,
|
||||
const VkPhysicalDeviceImageFormatInfo2 *pImageFormatInfo,
|
||||
VkImageFormatProperties2 *pImageFormatProperties)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_physical_device, pdev, physicalDevice);
|
||||
|
||||
const VkPhysicalDeviceExternalImageFormatInfo *external_info =
|
||||
vk_find_struct_const(pImageFormatInfo->pNext,
|
||||
PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO);
|
||||
|
||||
/* Initialize to zero in case we return VK_ERROR_FORMAT_NOT_SUPPORTED */
|
||||
memset(&pImageFormatProperties->imageFormatProperties, 0,
|
||||
sizeof(pImageFormatProperties->imageFormatProperties));
|
||||
|
||||
/* Metal does not support depth/stencil textures that are not 2D (we make 1D
|
||||
* textures 2D) */
|
||||
if (vk_format_is_depth_or_stencil(pImageFormatInfo->format) &&
|
||||
pImageFormatInfo->type == VK_IMAGE_TYPE_3D)
|
||||
return VK_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
/* Metal does not support EAC/ETC formats for 3D textures. */
|
||||
if (util_format_is_etc(vk_format_to_pipe_format(pImageFormatInfo->format)) &&
|
||||
pImageFormatInfo->type == VK_IMAGE_TYPE_3D)
|
||||
return VK_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
/* Metal disallows reading compressed formats as uncompressed format.
|
||||
* VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT is only used with
|
||||
* compressed formats.
|
||||
*/
|
||||
if (pImageFormatInfo->flags &
|
||||
VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT)
|
||||
return VK_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
const struct vk_format_ycbcr_info *ycbcr_info =
|
||||
vk_format_get_ycbcr_info(pImageFormatInfo->format);
|
||||
|
||||
/* For the purposes of these checks, we don't care about all the extra
|
||||
* YCbCr features and we just want the accumulation of features available
|
||||
* to all planes of the given format.
|
||||
*/
|
||||
VkFormatFeatureFlags2 features;
|
||||
if (ycbcr_info == NULL) {
|
||||
features = kk_get_image_plane_format_features(
|
||||
pdev, pImageFormatInfo->format, pImageFormatInfo->tiling, 0u);
|
||||
} else {
|
||||
features = ~0ull;
|
||||
assert(ycbcr_info->n_planes > 0);
|
||||
for (uint8_t plane = 0; plane < ycbcr_info->n_planes; plane++) {
|
||||
const VkFormat plane_format = ycbcr_info->planes[plane].format;
|
||||
features &= kk_get_image_plane_format_features(
|
||||
pdev, plane_format, pImageFormatInfo->tiling, 0u);
|
||||
}
|
||||
}
|
||||
|
||||
if (features == 0)
|
||||
return VK_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
if (pImageFormatInfo->tiling == VK_IMAGE_TILING_LINEAR &&
|
||||
pImageFormatInfo->type == VK_IMAGE_TYPE_3D)
|
||||
return VK_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
/* TODO_KOSMICKRISP We could allow linear images that are used as render
|
||||
* target as long as they are not used as input attachments. Main reason for
|
||||
* this is that we expect arrays when rendering and reading from input
|
||||
* attachments and Metal disallows arrays for linear textures.
|
||||
*/
|
||||
if (pImageFormatInfo->tiling == VK_IMAGE_TILING_LINEAR &&
|
||||
(pImageFormatInfo->usage &
|
||||
(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
|
||||
VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)))
|
||||
return VK_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
if (ycbcr_info && pImageFormatInfo->type != VK_IMAGE_TYPE_2D)
|
||||
return VK_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
/* Don't support sparse residency */
|
||||
if ((pImageFormatInfo->flags & VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT))
|
||||
return VK_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
/* From the Vulkan 1.3.279 spec:
|
||||
*
|
||||
* VUID-VkImageCreateInfo-tiling-04121
|
||||
*
|
||||
* "If tiling is VK_IMAGE_TILING_LINEAR, flags must not contain
|
||||
* VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT"
|
||||
*
|
||||
* VUID-VkImageCreateInfo-imageType-00970
|
||||
*
|
||||
* "If imageType is VK_IMAGE_TYPE_1D, flags must not contain
|
||||
* VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT"
|
||||
*/
|
||||
if ((pImageFormatInfo->flags & VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT) &&
|
||||
(pImageFormatInfo->type == VK_IMAGE_TYPE_1D ||
|
||||
pImageFormatInfo->tiling == VK_IMAGE_TILING_LINEAR))
|
||||
return VK_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
/* From the Vulkan 1.3.279 spec:
|
||||
*
|
||||
* VUID-VkImageCreateInfo-flags-09403
|
||||
*
|
||||
* "If flags contains VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT, flags
|
||||
* must not include VK_IMAGE_CREATE_SPARSE_ALIASED_BIT,
|
||||
* VK_IMAGE_CREATE_SPARSE_BINDING_BIT, or
|
||||
* VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT"
|
||||
*/
|
||||
if ((pImageFormatInfo->flags & VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT) &&
|
||||
(pImageFormatInfo->flags & (VK_IMAGE_CREATE_SPARSE_ALIASED_BIT |
|
||||
VK_IMAGE_CREATE_SPARSE_BINDING_BIT |
|
||||
VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT)))
|
||||
return VK_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
if (pImageFormatInfo->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT &&
|
||||
pImageFormatInfo->type != VK_IMAGE_TYPE_2D)
|
||||
return VK_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
const uint32_t max_dim = kk_image_max_dimension(pImageFormatInfo->type);
|
||||
assert(util_is_power_of_two_nonzero(max_dim));
|
||||
uint32_t maxMipLevels = util_logbase2(max_dim) + 1;
|
||||
VkExtent3D maxExtent;
|
||||
uint32_t maxArraySize;
|
||||
switch (pImageFormatInfo->type) {
|
||||
case VK_IMAGE_TYPE_1D:
|
||||
maxExtent = (VkExtent3D){max_dim, 1, 1};
|
||||
maxArraySize = 2048u;
|
||||
break;
|
||||
case VK_IMAGE_TYPE_2D:
|
||||
maxExtent = (VkExtent3D){max_dim, max_dim, 1};
|
||||
maxArraySize = 2048u;
|
||||
break;
|
||||
case VK_IMAGE_TYPE_3D:
|
||||
maxExtent = (VkExtent3D){max_dim, max_dim, max_dim};
|
||||
maxArraySize = 1u;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE("Invalid image type");
|
||||
}
|
||||
if (pImageFormatInfo->tiling == VK_IMAGE_TILING_LINEAR)
|
||||
maxArraySize = 1;
|
||||
|
||||
if (ycbcr_info != NULL || pImageFormatInfo->tiling == VK_IMAGE_TILING_LINEAR)
|
||||
maxMipLevels = 1;
|
||||
|
||||
if (pImageFormatInfo->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT) {
|
||||
maxArraySize = 1;
|
||||
maxMipLevels = 1;
|
||||
}
|
||||
|
||||
VkSampleCountFlags sampleCounts = VK_SAMPLE_COUNT_1_BIT;
|
||||
if (pImageFormatInfo->tiling == VK_IMAGE_TILING_OPTIMAL &&
|
||||
pImageFormatInfo->type == VK_IMAGE_TYPE_2D && ycbcr_info == NULL &&
|
||||
(features & (VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BIT |
|
||||
VK_FORMAT_FEATURE_2_DEPTH_STENCIL_ATTACHMENT_BIT)) &&
|
||||
!(pImageFormatInfo->flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT)) {
|
||||
sampleCounts =
|
||||
VK_SAMPLE_COUNT_1_BIT | VK_SAMPLE_COUNT_2_BIT |
|
||||
// TODO_KOSMICKRISP Modify sample count based on what pdev supports
|
||||
VK_SAMPLE_COUNT_4_BIT /* |
|
||||
VK_SAMPLE_COUNT_8_BIT */
|
||||
;
|
||||
}
|
||||
|
||||
/* From the Vulkan 1.2.199 spec:
|
||||
*
|
||||
* "VK_IMAGE_CREATE_EXTENDED_USAGE_BIT specifies that the image can be
|
||||
* created with usage flags that are not supported for the format the
|
||||
* image is created with but are supported for at least one format a
|
||||
* VkImageView created from the image can have."
|
||||
*
|
||||
* If VK_IMAGE_CREATE_EXTENDED_USAGE_BIT is set, views can be created with
|
||||
* different usage than the image so we can't always filter on usage.
|
||||
* There is one exception to this below for storage.
|
||||
*/
|
||||
const VkImageUsageFlags image_usage = pImageFormatInfo->usage;
|
||||
VkImageUsageFlags view_usage = image_usage;
|
||||
if (pImageFormatInfo->flags & VK_IMAGE_CREATE_EXTENDED_USAGE_BIT)
|
||||
view_usage = 0;
|
||||
|
||||
u_foreach_bit(b, view_usage) {
|
||||
VkFormatFeatureFlags2 usage_features =
|
||||
vk_image_usage_to_format_features(1 << b);
|
||||
if (usage_features && !(features & usage_features))
|
||||
return VK_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
const VkExternalMemoryProperties *ext_mem_props = NULL;
|
||||
if (external_info != NULL && external_info->handleType != 0) {
|
||||
/* We only support heaps since that's the backing for all our memory and
|
||||
* simplifies implementation */
|
||||
switch (external_info->handleType) {
|
||||
case VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLHEAP_BIT_EXT:
|
||||
ext_mem_props = &kk_mtlheap_mem_props;
|
||||
break;
|
||||
default:
|
||||
/* From the Vulkan 1.3.256 spec:
|
||||
*
|
||||
* "If handleType is not compatible with the [parameters] in
|
||||
* VkPhysicalDeviceImageFormatInfo2, then
|
||||
* vkGetPhysicalDeviceImageFormatProperties2 returns
|
||||
* VK_ERROR_FORMAT_NOT_SUPPORTED."
|
||||
*/
|
||||
return vk_errorf(pdev, VK_ERROR_FORMAT_NOT_SUPPORTED,
|
||||
"unsupported VkExternalMemoryHandleTypeFlagBits: %s ",
|
||||
vk_ExternalMemoryHandleTypeFlagBits_to_str(
|
||||
external_info->handleType));
|
||||
}
|
||||
}
|
||||
|
||||
const unsigned plane_count =
|
||||
vk_format_get_plane_count(pImageFormatInfo->format);
|
||||
|
||||
/* From the Vulkan 1.3.259 spec, VkImageCreateInfo:
|
||||
*
|
||||
* VUID-VkImageCreateInfo-imageCreateFormatFeatures-02260
|
||||
*
|
||||
* "If format is a multi-planar format, and if imageCreateFormatFeatures
|
||||
* (as defined in Image Creation Limits) does not contain
|
||||
* VK_FORMAT_FEATURE_DISJOINT_BIT, then flags must not contain
|
||||
* VK_IMAGE_CREATE_DISJOINT_BIT"
|
||||
*
|
||||
* This is satisfied trivially because we support DISJOINT on all
|
||||
* multi-plane formats. Also,
|
||||
*
|
||||
* VUID-VkImageCreateInfo-format-01577
|
||||
*
|
||||
* "If format is not a multi-planar format, and flags does not include
|
||||
* VK_IMAGE_CREATE_ALIAS_BIT, flags must not contain
|
||||
* VK_IMAGE_CREATE_DISJOINT_BIT"
|
||||
*/
|
||||
if (plane_count == 1 &&
|
||||
!(pImageFormatInfo->flags & VK_IMAGE_CREATE_ALIAS_BIT) &&
|
||||
(pImageFormatInfo->flags & VK_IMAGE_CREATE_DISJOINT_BIT))
|
||||
return VK_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
if (ycbcr_info &&
|
||||
((pImageFormatInfo->flags & VK_IMAGE_CREATE_SPARSE_BINDING_BIT) ||
|
||||
(pImageFormatInfo->flags & VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT)))
|
||||
return VK_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
if ((pImageFormatInfo->flags & VK_IMAGE_CREATE_SPARSE_BINDING_BIT) &&
|
||||
(pImageFormatInfo->usage & VK_IMAGE_USAGE_HOST_TRANSFER_BIT_EXT))
|
||||
return VK_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
|
||||
pImageFormatProperties->imageFormatProperties = (VkImageFormatProperties){
|
||||
.maxExtent = maxExtent,
|
||||
.maxMipLevels = maxMipLevels,
|
||||
.maxArrayLayers = maxArraySize,
|
||||
.sampleCounts = sampleCounts,
|
||||
.maxResourceSize = UINT32_MAX, /* TODO */
|
||||
};
|
||||
|
||||
vk_foreach_struct(s, pImageFormatProperties->pNext) {
|
||||
switch (s->sType) {
|
||||
case VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES: {
|
||||
VkExternalImageFormatProperties *p = (void *)s;
|
||||
/* From the Vulkan 1.3.256 spec:
|
||||
*
|
||||
* "If handleType is 0, vkGetPhysicalDeviceImageFormatProperties2
|
||||
* will behave as if VkPhysicalDeviceExternalImageFormatInfo was
|
||||
* not present, and VkExternalImageFormatProperties will be
|
||||
* ignored."
|
||||
*
|
||||
* This is true if and only if ext_mem_props == NULL
|
||||
*/
|
||||
if (ext_mem_props != NULL)
|
||||
p->externalMemoryProperties = *ext_mem_props;
|
||||
break;
|
||||
}
|
||||
case VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES: {
|
||||
VkSamplerYcbcrConversionImageFormatProperties *ycbcr_props = (void *)s;
|
||||
ycbcr_props->combinedImageSamplerDescriptorCount = plane_count;
|
||||
break;
|
||||
}
|
||||
case VK_STRUCTURE_TYPE_HOST_IMAGE_COPY_DEVICE_PERFORMANCE_QUERY_EXT: {
|
||||
VkHostImageCopyDevicePerformanceQueryEXT *host_props = (void *)s;
|
||||
host_props->optimalDeviceAccess = true;
|
||||
host_props->identicalMemoryLayout = true;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
vk_debug_ignored_stype(s->sType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
kk_GetPhysicalDeviceSparseImageFormatProperties2(
|
||||
VkPhysicalDevice physicalDevice,
|
||||
const VkPhysicalDeviceSparseImageFormatInfo2 *pFormatInfo,
|
||||
uint32_t *pPropertyCount, VkSparseImageFormatProperties2 *pProperties)
|
||||
{
|
||||
*pPropertyCount = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
static VkResult
|
||||
kk_image_init(struct kk_device *dev, struct kk_image *image,
|
||||
const VkImageCreateInfo *pCreateInfo)
|
||||
{
|
||||
vk_image_init(&dev->vk, &image->vk, pCreateInfo);
|
||||
|
||||
if ((image->vk.usage & (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
|
||||
VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) &&
|
||||
image->vk.samples > 1) {
|
||||
image->vk.usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
image->vk.stencil_usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
}
|
||||
|
||||
if (image->vk.usage & VK_IMAGE_USAGE_TRANSFER_SRC_BIT)
|
||||
image->vk.usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
if (image->vk.usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT) {
|
||||
if (util_format_is_depth_or_stencil(
|
||||
vk_format_to_pipe_format(image->vk.format))) {
|
||||
image->vk.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
image->vk.stencil_usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
} else {
|
||||
image->vk.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
}
|
||||
}
|
||||
|
||||
image->plane_count = vk_format_get_plane_count(pCreateInfo->format);
|
||||
image->disjoint = image->plane_count > 1 &&
|
||||
(pCreateInfo->flags & VK_IMAGE_CREATE_DISJOINT_BIT);
|
||||
|
||||
const struct vk_format_ycbcr_info *ycbcr_info =
|
||||
vk_format_get_ycbcr_info(pCreateInfo->format);
|
||||
for (uint8_t plane = 0; plane < image->plane_count; plane++) {
|
||||
VkFormat format =
|
||||
ycbcr_info ? ycbcr_info->planes[plane].format : pCreateInfo->format;
|
||||
const uint8_t width_scale =
|
||||
ycbcr_info ? ycbcr_info->planes[plane].denominator_scales[0] : 1;
|
||||
const uint8_t height_scale =
|
||||
ycbcr_info ? ycbcr_info->planes[plane].denominator_scales[1] : 1;
|
||||
kk_image_layout_init(dev, pCreateInfo, vk_format_to_pipe_format(format),
|
||||
width_scale, height_scale,
|
||||
&image->planes[plane].layout);
|
||||
}
|
||||
|
||||
if (image->vk.format == VK_FORMAT_D32_SFLOAT_S8_UINT) {
|
||||
kk_image_layout_init(dev, pCreateInfo, PIPE_FORMAT_R32_UINT, 1, 1,
|
||||
&image->stencil_copy_temp.layout);
|
||||
}
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
kk_image_plane_size_align_B(struct kk_device *dev, const struct kk_image *image,
|
||||
const struct kk_image_plane *plane,
|
||||
uint64_t *size_B_out, uint64_t *align_B_out)
|
||||
{
|
||||
*size_B_out = plane->layout.size_B;
|
||||
*align_B_out = plane->layout.align_B;
|
||||
}
|
||||
|
||||
static void
|
||||
kk_image_plane_finish(struct kk_device *dev, struct kk_image_plane *plane,
|
||||
VkImageCreateFlags create_flags,
|
||||
const VkAllocationCallbacks *pAllocator)
|
||||
{
|
||||
if (plane->mtl_handle != NULL)
|
||||
mtl_release(plane->mtl_handle);
|
||||
if (plane->mtl_handle_array != NULL)
|
||||
mtl_release(plane->mtl_handle_array);
|
||||
}
|
||||
|
||||
static void
|
||||
kk_image_finish(struct kk_device *dev, struct kk_image *image,
|
||||
const VkAllocationCallbacks *pAllocator)
|
||||
{
|
||||
for (uint8_t plane = 0; plane < image->plane_count; plane++) {
|
||||
kk_image_plane_finish(dev, &image->planes[plane], image->vk.create_flags,
|
||||
pAllocator);
|
||||
}
|
||||
|
||||
if (image->stencil_copy_temp.layout.size_B > 0) {
|
||||
kk_image_plane_finish(dev, &image->stencil_copy_temp,
|
||||
image->vk.create_flags, pAllocator);
|
||||
}
|
||||
|
||||
vk_image_finish(&image->vk);
|
||||
}
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL
|
||||
kk_CreateImage(VkDevice _device, const VkImageCreateInfo *pCreateInfo,
|
||||
const VkAllocationCallbacks *pAllocator, VkImage *pImage)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_device, dev, _device);
|
||||
struct kk_physical_device *pdev = kk_device_physical(dev);
|
||||
struct kk_image *image;
|
||||
VkResult result;
|
||||
|
||||
#ifdef KK_USE_WSI_PLATFORM
|
||||
/* Ignore swapchain creation info on Android. Since we don't have an
|
||||
* implementation in Mesa, we're guaranteed to access an Android object
|
||||
* incorrectly.
|
||||
*/
|
||||
const VkImageSwapchainCreateInfoKHR *swapchain_info =
|
||||
vk_find_struct_const(pCreateInfo->pNext, IMAGE_SWAPCHAIN_CREATE_INFO_KHR);
|
||||
if (swapchain_info && swapchain_info->swapchain != VK_NULL_HANDLE) {
|
||||
return wsi_common_create_swapchain_image(
|
||||
&pdev->wsi_device, pCreateInfo, swapchain_info->swapchain, pImage);
|
||||
}
|
||||
#endif
|
||||
|
||||
image = vk_zalloc2(&dev->vk.alloc, pAllocator, sizeof(*image), 8,
|
||||
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
|
||||
if (!image)
|
||||
return vk_error(dev, VK_ERROR_OUT_OF_HOST_MEMORY);
|
||||
|
||||
result = kk_image_init(dev, image, pCreateInfo);
|
||||
if (result != VK_SUCCESS) {
|
||||
vk_free2(&dev->vk.alloc, pAllocator, image);
|
||||
return result;
|
||||
}
|
||||
|
||||
*pImage = kk_image_to_handle(image);
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
kk_DestroyImage(VkDevice device, VkImage _image,
|
||||
const VkAllocationCallbacks *pAllocator)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_device, dev, device);
|
||||
VK_FROM_HANDLE(kk_image, image, _image);
|
||||
|
||||
if (!image)
|
||||
return;
|
||||
|
||||
kk_image_finish(dev, image, pAllocator);
|
||||
vk_free2(&dev->vk.alloc, pAllocator, image);
|
||||
}
|
||||
|
||||
static void
|
||||
kk_image_plane_add_req(struct kk_device *dev, const struct kk_image *image,
|
||||
const struct kk_image_plane *plane, uint64_t *size_B,
|
||||
uint32_t *align_B)
|
||||
{
|
||||
assert(util_is_power_of_two_or_zero64(*align_B));
|
||||
uint64_t plane_size_B, plane_align_B;
|
||||
kk_image_plane_size_align_B(dev, image, plane, &plane_size_B,
|
||||
&plane_align_B);
|
||||
|
||||
*align_B = MAX2(*align_B, plane_align_B);
|
||||
*size_B = align64(*size_B, plane_align_B);
|
||||
*size_B += plane_size_B;
|
||||
}
|
||||
|
||||
static void
|
||||
kk_get_image_memory_requirements(struct kk_device *dev, struct kk_image *image,
|
||||
VkImageAspectFlags aspects,
|
||||
VkMemoryRequirements2 *pMemoryRequirements)
|
||||
{
|
||||
struct kk_physical_device *pdev = kk_device_physical(dev);
|
||||
uint32_t memory_types = (1 << pdev->mem_type_count) - 1;
|
||||
|
||||
/* Remove non host visible heaps from the types for host image copy in case
|
||||
* of potential issues. This should be removed when we get ReBAR.
|
||||
*/
|
||||
if (image->vk.usage & VK_IMAGE_USAGE_HOST_TRANSFER_BIT_EXT) {
|
||||
for (uint32_t i = 0; i < pdev->mem_type_count; i++) {
|
||||
if (!(pdev->mem_types[i].propertyFlags &
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT))
|
||||
memory_types &= ~BITFIELD_BIT(i);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO hope for the best?
|
||||
|
||||
uint64_t size_B = 0;
|
||||
uint32_t align_B = 0;
|
||||
if (image->disjoint) {
|
||||
uint8_t plane = kk_image_memory_aspects_to_plane(image, aspects);
|
||||
kk_image_plane_add_req(dev, image, &image->planes[plane], &size_B,
|
||||
&align_B);
|
||||
} else {
|
||||
for (unsigned plane = 0; plane < image->plane_count; plane++) {
|
||||
kk_image_plane_add_req(dev, image, &image->planes[plane], &size_B,
|
||||
&align_B);
|
||||
}
|
||||
}
|
||||
|
||||
if (image->stencil_copy_temp.layout.size_B > 0) {
|
||||
kk_image_plane_add_req(dev, image, &image->stencil_copy_temp, &size_B,
|
||||
&align_B);
|
||||
}
|
||||
|
||||
pMemoryRequirements->memoryRequirements.memoryTypeBits = memory_types;
|
||||
pMemoryRequirements->memoryRequirements.alignment = align_B;
|
||||
pMemoryRequirements->memoryRequirements.size = size_B;
|
||||
|
||||
vk_foreach_struct_const(ext, pMemoryRequirements->pNext) {
|
||||
switch (ext->sType) {
|
||||
case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS: {
|
||||
VkMemoryDedicatedRequirements *dedicated = (void *)ext;
|
||||
dedicated->prefersDedicatedAllocation =
|
||||
image->vk.tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
|
||||
dedicated->requiresDedicatedAllocation =
|
||||
image->vk.tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
vk_debug_ignored_stype(ext->sType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
kk_GetImageMemoryRequirements2(VkDevice device,
|
||||
const VkImageMemoryRequirementsInfo2 *pInfo,
|
||||
VkMemoryRequirements2 *pMemoryRequirements)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_device, dev, device);
|
||||
VK_FROM_HANDLE(kk_image, image, pInfo->image);
|
||||
|
||||
const VkImagePlaneMemoryRequirementsInfo *plane_info =
|
||||
vk_find_struct_const(pInfo->pNext, IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO);
|
||||
const VkImageAspectFlags aspects =
|
||||
image->disjoint ? plane_info->planeAspect : image->vk.aspects;
|
||||
|
||||
kk_get_image_memory_requirements(dev, image, aspects, pMemoryRequirements);
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
kk_GetDeviceImageMemoryRequirements(VkDevice device,
|
||||
const VkDeviceImageMemoryRequirements *pInfo,
|
||||
VkMemoryRequirements2 *pMemoryRequirements)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_device, dev, device);
|
||||
ASSERTED VkResult result;
|
||||
struct kk_image image = {0};
|
||||
|
||||
result = kk_image_init(dev, &image, pInfo->pCreateInfo);
|
||||
assert(result == VK_SUCCESS);
|
||||
|
||||
const VkImageAspectFlags aspects =
|
||||
image.disjoint ? pInfo->planeAspect : image.vk.aspects;
|
||||
|
||||
kk_get_image_memory_requirements(dev, &image, aspects, pMemoryRequirements);
|
||||
|
||||
kk_image_finish(dev, &image, NULL);
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
kk_GetImageSparseMemoryRequirements2(
|
||||
VkDevice device, const VkImageSparseMemoryRequirementsInfo2 *pInfo,
|
||||
uint32_t *pSparseMemoryRequirementCount,
|
||||
VkSparseImageMemoryRequirements2 *pSparseMemoryRequirements)
|
||||
{
|
||||
*pSparseMemoryRequirementCount = 0u;
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
kk_GetDeviceImageSparseMemoryRequirements(
|
||||
VkDevice device, const VkDeviceImageMemoryRequirements *pInfo,
|
||||
uint32_t *pSparseMemoryRequirementCount,
|
||||
VkSparseImageMemoryRequirements2 *pSparseMemoryRequirements)
|
||||
{
|
||||
*pSparseMemoryRequirementCount = 0u;
|
||||
}
|
||||
|
||||
static void
|
||||
kk_get_image_subresource_layout(struct kk_device *dev, struct kk_image *image,
|
||||
const VkImageSubresource2KHR *pSubresource,
|
||||
VkSubresourceLayout2KHR *pLayout)
|
||||
{
|
||||
const VkImageSubresource *isr = &pSubresource->imageSubresource;
|
||||
|
||||
const uint8_t p = kk_image_memory_aspects_to_plane(image, isr->aspectMask);
|
||||
const struct kk_image_plane *plane = &image->planes[p];
|
||||
|
||||
uint64_t offset_B = 0;
|
||||
if (!image->disjoint) {
|
||||
uint32_t align_B = 0;
|
||||
for (unsigned i = 0; i < p; i++) {
|
||||
kk_image_plane_add_req(dev, image, &image->planes[i], &offset_B,
|
||||
&align_B);
|
||||
}
|
||||
}
|
||||
|
||||
pLayout->subresourceLayout = (VkSubresourceLayout){
|
||||
.offset = offset_B,
|
||||
.size = plane->layout.size_B,
|
||||
.rowPitch = plane->layout.linear_stride_B,
|
||||
.arrayPitch = plane->layout.layer_stride_B,
|
||||
.depthPitch = 1u,
|
||||
};
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
kk_GetImageSubresourceLayout2KHR(VkDevice device, VkImage _image,
|
||||
const VkImageSubresource2KHR *pSubresource,
|
||||
VkSubresourceLayout2KHR *pLayout)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_device, dev, device);
|
||||
VK_FROM_HANDLE(kk_image, image, _image);
|
||||
|
||||
kk_get_image_subresource_layout(dev, image, pSubresource, pLayout);
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
kk_GetDeviceImageSubresourceLayoutKHR(
|
||||
VkDevice device, const VkDeviceImageSubresourceInfoKHR *pInfo,
|
||||
VkSubresourceLayout2KHR *pLayout)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_device, dev, device);
|
||||
ASSERTED VkResult result;
|
||||
struct kk_image image = {0};
|
||||
|
||||
result = kk_image_init(dev, &image, pInfo->pCreateInfo);
|
||||
assert(result == VK_SUCCESS);
|
||||
|
||||
kk_get_image_subresource_layout(dev, &image, pInfo->pSubresource, pLayout);
|
||||
|
||||
kk_image_finish(dev, &image, NULL);
|
||||
}
|
||||
|
||||
static VkResult
|
||||
kk_image_plane_bind(struct kk_device *dev, struct kk_image *image,
|
||||
struct kk_image_plane *plane, struct kk_device_memory *mem,
|
||||
uint64_t *offset_B)
|
||||
{
|
||||
uint64_t plane_size_B, plane_align_B;
|
||||
kk_image_plane_size_align_B(dev, image, plane, &plane_size_B,
|
||||
&plane_align_B);
|
||||
*offset_B = align64(*offset_B, plane_align_B);
|
||||
|
||||
/* Linear textures in Metal need to be allocated through a buffer... */
|
||||
if (plane->layout.optimized_layout)
|
||||
plane->mtl_handle = mtl_new_texture_with_descriptor(
|
||||
mem->bo->mtl_handle, &plane->layout, *offset_B);
|
||||
else
|
||||
plane->mtl_handle = mtl_new_texture_with_descriptor_linear(
|
||||
mem->bo->map, &plane->layout, *offset_B);
|
||||
plane->addr = mem->bo->gpu + *offset_B;
|
||||
|
||||
/* Create auxiliary 2D array texture for 3D images so we can use 2D views of
|
||||
* it */
|
||||
if (plane->layout.type == MTL_TEXTURE_TYPE_3D &&
|
||||
(image->vk.create_flags & VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT)) {
|
||||
struct kk_image_layout array_layout = plane->layout;
|
||||
array_layout.type = MTL_TEXTURE_TYPE_2D_ARRAY;
|
||||
// TODO_KOSMICKRISP We need to make sure that this doesn't go over Metal's
|
||||
// layer maximum which is 2048. Probably by limiting the dimensions and
|
||||
// layers for 3D images
|
||||
array_layout.layers = array_layout.layers * array_layout.depth_px;
|
||||
array_layout.depth_px = 1u;
|
||||
plane->mtl_handle_array = mtl_new_texture_with_descriptor(
|
||||
mem->bo->mtl_handle, &array_layout, *offset_B);
|
||||
}
|
||||
|
||||
*offset_B += plane_size_B;
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
static VkResult
|
||||
kk_bind_image_memory(struct kk_device *dev, const VkBindImageMemoryInfo *info)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_device_memory, mem, info->memory);
|
||||
VK_FROM_HANDLE(kk_image, image, info->image);
|
||||
VkResult result;
|
||||
|
||||
/* Ignore this struct on Android, we cannot access swapchain structures
|
||||
* there. */
|
||||
#ifdef KK_USE_WSI_PLATFORM
|
||||
const VkBindImageMemorySwapchainInfoKHR *swapchain_info =
|
||||
vk_find_struct_const(info->pNext, BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR);
|
||||
|
||||
if (swapchain_info && swapchain_info->swapchain != VK_NULL_HANDLE) {
|
||||
VK_FROM_HANDLE(wsi_swapchain, swapchain, swapchain_info->swapchain);
|
||||
VkImage _wsi_image =
|
||||
swapchain->get_wsi_image(swapchain, swapchain_info->imageIndex)->image;
|
||||
VK_FROM_HANDLE(kk_image, wsi_img, _wsi_image);
|
||||
|
||||
assert(image->plane_count == 1);
|
||||
assert(wsi_img->plane_count == 1);
|
||||
|
||||
struct kk_image_plane *plane = &image->planes[0];
|
||||
struct kk_image_plane *swapchain_plane = &wsi_img->planes[0];
|
||||
|
||||
/* Copy swapchain plane data retaining relevant resources. */
|
||||
plane->layout = swapchain_plane->layout;
|
||||
plane->mtl_handle = mtl_retain(swapchain_plane->mtl_handle);
|
||||
plane->mtl_handle_array =
|
||||
swapchain_plane->mtl_handle_array
|
||||
? mtl_retain(swapchain_plane->mtl_handle_array)
|
||||
: NULL;
|
||||
plane->addr = swapchain_plane->addr;
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint64_t offset_B = info->memoryOffset;
|
||||
if (image->disjoint) {
|
||||
const VkBindImagePlaneMemoryInfo *plane_info =
|
||||
vk_find_struct_const(info->pNext, BIND_IMAGE_PLANE_MEMORY_INFO);
|
||||
const uint8_t plane =
|
||||
kk_image_memory_aspects_to_plane(image, plane_info->planeAspect);
|
||||
result =
|
||||
kk_image_plane_bind(dev, image, &image->planes[plane], mem, &offset_B);
|
||||
if (result != VK_SUCCESS)
|
||||
return result;
|
||||
} else {
|
||||
for (unsigned plane = 0; plane < image->plane_count; plane++) {
|
||||
result = kk_image_plane_bind(dev, image, &image->planes[plane], mem,
|
||||
&offset_B);
|
||||
if (result != VK_SUCCESS)
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (image->stencil_copy_temp.layout.size_B > 0) {
|
||||
result = kk_image_plane_bind(dev, image, &image->stencil_copy_temp, mem,
|
||||
&offset_B);
|
||||
if (result != VK_SUCCESS)
|
||||
return result;
|
||||
}
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL
|
||||
kk_BindImageMemory2(VkDevice device, uint32_t bindInfoCount,
|
||||
const VkBindImageMemoryInfo *pBindInfos)
|
||||
{
|
||||
VK_FROM_HANDLE(kk_device, dev, device);
|
||||
VkResult first_error_or_success = VK_SUCCESS;
|
||||
|
||||
for (uint32_t i = 0; i < bindInfoCount; ++i) {
|
||||
VkResult result = kk_bind_image_memory(dev, &pBindInfos[i]);
|
||||
|
||||
const VkBindMemoryStatusKHR *status =
|
||||
vk_find_struct_const(pBindInfos[i].pNext, BIND_MEMORY_STATUS_KHR);
|
||||
if (status != NULL && status->pResult != NULL)
|
||||
*status->pResult = VK_SUCCESS;
|
||||
|
||||
if (first_error_or_success == VK_SUCCESS)
|
||||
first_error_or_success = result;
|
||||
}
|
||||
|
||||
return first_error_or_success;
|
||||
}
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL
|
||||
kk_GetImageOpaqueCaptureDescriptorDataEXT(
|
||||
VkDevice _device, const VkImageCaptureDescriptorDataInfoEXT *pInfo,
|
||||
void *pData)
|
||||
{
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
155
src/kosmickrisp/vulkan/kk_image.h
Normal file
155
src/kosmickrisp/vulkan/kk_image.h
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
* Copyright © 2022 Collabora Ltd. and Red Hat Inc.
|
||||
* Copyright 2025 LunarG, Inc.
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef KK_IMAGE_H
|
||||
#define KK_IMAGE_H 1
|
||||
|
||||
#include "kk_private.h"
|
||||
|
||||
#include "kk_device_memory.h"
|
||||
#include "kk_image_layout.h"
|
||||
|
||||
#include "kosmickrisp/bridge/mtl_types.h"
|
||||
|
||||
#include "vk_image.h"
|
||||
|
||||
/* Because small images can end up with an array_stride_B that is less than
|
||||
* the sparse block size (in bytes), we have to set SINGLE_MIPTAIL_BIT when
|
||||
* advertising sparse properties to the client. This means that we get one
|
||||
* single memory range for the miptail of the image. For large images with
|
||||
* mipTailStartLod > 0, we have to deal with the array stride ourselves.
|
||||
*
|
||||
* We do this by returning NVK_MIP_TAIL_START_OFFSET as the image's
|
||||
* imageMipTailOffset. We can then detect anything with that address as
|
||||
* being part of the miptail and re-map it accordingly. The Vulkan spec
|
||||
* explicitly allows for this.
|
||||
*
|
||||
* From the Vulkan 1.3.279 spec:
|
||||
*
|
||||
* "When VK_SPARSE_MEMORY_BIND_METADATA_BIT is present, the resourceOffset
|
||||
* must have been derived explicitly from the imageMipTailOffset in the
|
||||
* sparse resource properties returned for the metadata aspect. By
|
||||
* manipulating the value returned for imageMipTailOffset, the
|
||||
* resourceOffset does not have to correlate directly to a device virtual
|
||||
* address offset, and may instead be whatever value makes it easiest for
|
||||
* the implementation to derive the correct device virtual address."
|
||||
*/
|
||||
#define NVK_MIP_TAIL_START_OFFSET 0x6d74000000000000UL
|
||||
|
||||
struct kk_device_memory;
|
||||
struct kk_physical_device;
|
||||
struct kk_queue;
|
||||
|
||||
VkFormatFeatureFlags2
|
||||
kk_get_image_format_features(struct kk_physical_device *pdevice,
|
||||
VkFormat format, VkImageTiling tiling,
|
||||
uint64_t drm_format_mod);
|
||||
|
||||
uint32_t kk_image_max_dimension(VkImageType image_type);
|
||||
|
||||
struct kk_image_plane {
|
||||
struct kk_image_layout layout;
|
||||
// TODO_KOSMICKRISP Only have one handle since we will only create 2D arrays
|
||||
// anyway
|
||||
/* Metal handle with original handle type */
|
||||
mtl_texture *mtl_handle;
|
||||
/* Metal handle with 2D array type for 3D images */
|
||||
mtl_texture *mtl_handle_array;
|
||||
uint64_t addr;
|
||||
};
|
||||
|
||||
struct kk_image {
|
||||
struct vk_image vk;
|
||||
|
||||
/** True if the planes are bound separately
|
||||
* * This is set based on VK_IMAGE_CREATE_DISJOINT_BIT
|
||||
*/
|
||||
bool disjoint;
|
||||
|
||||
uint8_t plane_count;
|
||||
struct kk_image_plane planes[3];
|
||||
|
||||
/* In order to support D32_SFLOAT_S8_UINT, a temp area is
|
||||
* needed. The stencil plane can't be a copied using the DMA
|
||||
* engine in a single pass since it would need 8 components support.
|
||||
* Instead we allocate a 16-bit temp, that gets copied into, then
|
||||
* copied again down to the 8-bit result.
|
||||
*/
|
||||
struct kk_image_plane stencil_copy_temp;
|
||||
};
|
||||
|
||||
static inline mtl_resource *
|
||||
kk_image_to_mtl_resource(const struct kk_image *image, int plane)
|
||||
{
|
||||
if (image != NULL) {
|
||||
assert(plane < ARRAY_SIZE(image->planes));
|
||||
return (mtl_resource *)image->planes[plane].mtl_handle;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
VK_DEFINE_NONDISP_HANDLE_CASTS(kk_image, vk.base, VkImage, VK_OBJECT_TYPE_IMAGE)
|
||||
|
||||
static inline uint64_t
|
||||
kk_image_plane_base_address(const struct kk_image_plane *plane)
|
||||
{
|
||||
return plane->addr;
|
||||
}
|
||||
|
||||
static inline uint64_t
|
||||
kk_image_base_address(const struct kk_image *image, uint8_t plane)
|
||||
{
|
||||
return kk_image_plane_base_address(&image->planes[plane]);
|
||||
}
|
||||
|
||||
static inline uint8_t
|
||||
kk_image_aspects_to_plane(ASSERTED const struct kk_image *image,
|
||||
VkImageAspectFlags aspectMask)
|
||||
{
|
||||
/* Memory planes are only allowed for memory operations */
|
||||
assert(!(aspectMask & (VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT |
|
||||
VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT |
|
||||
VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT |
|
||||
VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT)));
|
||||
|
||||
/* Verify that the aspects are actually in the image */
|
||||
assert(!(aspectMask & ~image->vk.aspects));
|
||||
|
||||
/* Must only be one aspect unless it's depth/stencil */
|
||||
assert(aspectMask ==
|
||||
(VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT) ||
|
||||
util_bitcount(aspectMask) == 1);
|
||||
|
||||
switch (aspectMask) {
|
||||
case VK_IMAGE_ASPECT_PLANE_1_BIT:
|
||||
return 1;
|
||||
case VK_IMAGE_ASPECT_PLANE_2_BIT:
|
||||
return 2;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint8_t
|
||||
kk_image_memory_aspects_to_plane(ASSERTED const struct kk_image *image,
|
||||
VkImageAspectFlags aspectMask)
|
||||
{
|
||||
if (aspectMask & (VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT |
|
||||
VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT |
|
||||
VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT |
|
||||
VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT)) {
|
||||
/* We don't support DRM format modifiers on anything but single-plane
|
||||
* color at the moment.
|
||||
*/
|
||||
assert(aspectMask == VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT);
|
||||
return 0;
|
||||
} else {
|
||||
return kk_image_aspects_to_plane(image, aspectMask);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue