diff --git a/include/Refresh.h b/include/Refresh.h index 3d03ddf..04eb270 100644 --- a/include/Refresh.h +++ b/include/Refresh.h @@ -64,6 +64,7 @@ typedef struct REFRESH_DepthStencilTarget REFRESH_DepthStencilTarget; typedef struct REFRESH_Framebuffer REFRESH_Framebuffer; typedef struct REFRESH_ShaderModule REFRESH_ShaderModule; typedef struct REFRESH_RenderPass REFRESH_RenderPass; +typedef struct REFRESH_ComputePipeline REFRESH_ComputePipeline; typedef struct REFRESH_GraphicsPipeline REFRESH_GraphicsPipeline; typedef enum REFRESH_PresentMode @@ -454,11 +455,17 @@ typedef struct REFRESH_ColorTargetBlendState REFRESH_ColorComponentFlags colorWriteMask; } REFRESH_ColorTargetBlendState; -typedef struct REFRESH_PipelineLayoutCreateInfo +typedef struct REFRESH_ComputePipelineLayoutCreateInfo +{ + uint32_t bufferBindingCount; + uint32_t imageBindingCount; +} REFRESH_ComputePipelineLayoutCreateInfo; + +typedef struct REFRESH_GraphicsPipelineLayoutCreateInfo { uint32_t vertexSamplerBindingCount; uint32_t fragmentSamplerBindingCount; -} REFRESH_PipelineLayoutCreateInfo; +} REFRESH_GraphicsPipelineLayoutCreateInfo; typedef struct REFRESH_ColorTargetDescription { @@ -492,12 +499,18 @@ typedef struct REFRESH_ShaderModuleCreateInfo /* Pipeline state structures */ -typedef struct REFRESH_ShaderStageState +typedef struct REFRESH_ComputeShaderStageState +{ + REFRESH_ShaderModule *shaderModule; + const char* entryPointName; +} REFRESH_ComputeShaderStageState; + +typedef struct REFRESH_GraphicsShaderStageState { REFRESH_ShaderModule *shaderModule; const char* entryPointName; uint64_t uniformBufferSize; -} REFRESH_ShaderStageState; +} REFRESH_GraphicsShaderStageState; typedef struct REFRESH_TopologyState { @@ -553,10 +566,16 @@ typedef struct REFRESH_ColorBlendState float blendConstants[4]; } REFRESH_ColorBlendState; +typedef struct REFRESH_ComputePipelineCreateInfo +{ + REFRESH_ComputeShaderStageState computeShaderState; + REFRESH_ComputePipelineLayoutCreateInfo pipelineLayoutCreateInfo; +} REFRESH_ComputePipelineCreateInfo; + typedef struct REFRESH_GraphicsPipelineCreateInfo { - REFRESH_ShaderStageState vertexShaderState; - REFRESH_ShaderStageState fragmentShaderState; + REFRESH_GraphicsShaderStageState vertexShaderState; + REFRESH_GraphicsShaderStageState fragmentShaderState; REFRESH_VertexInputState vertexInputState; REFRESH_TopologyState topologyState; REFRESH_ViewportState viewportState; @@ -564,7 +583,7 @@ typedef struct REFRESH_GraphicsPipelineCreateInfo REFRESH_MultisampleState multisampleState; REFRESH_DepthStencilState depthStencilState; REFRESH_ColorBlendState colorBlendState; - REFRESH_PipelineLayoutCreateInfo pipelineLayoutCreateInfo; + REFRESH_GraphicsPipelineLayoutCreateInfo pipelineLayoutCreateInfo; REFRESH_RenderPass *renderPass; } REFRESH_GraphicsPipelineCreateInfo; @@ -718,7 +737,13 @@ REFRESHAPI REFRESH_RenderPass* REFRESH_CreateRenderPass( REFRESH_RenderPassCreateInfo *renderPassCreateInfo ); -/* Returns an allocated Pipeline* object. */ +/* Returns an allocated ComputePipeline* object. */ +REFRESHAPI REFRESH_ComputePipeline* REFRESH_CreateComputePipeline( + REFRESH_Device *device, + REFRESH_ComputePipelineCreateInfo *pipelineCreateInfo +); + +/* Returns an allocated GraphicsPipeline* object. */ REFRESHAPI REFRESH_GraphicsPipeline* REFRESH_CreateGraphicsPipeline( REFRESH_Device *device, REFRESH_GraphicsPipelineCreateInfo *pipelineCreateInfo @@ -1211,6 +1236,18 @@ REFRESHAPI void REFRESH_AddDisposeRenderPass( REFRESH_RenderPass *renderPass ); +/* Sends a compute pipeline to be destroyed by the renderer. Note that we call it + * "AddDispose" because it may not be immediately destroyed by the renderer if + * this is not called from the main thread (for example, if a garbage collector + * deletes the resource instead of the programmer). + * + * computePipeline: The REFRESH_ComputePipeline to be destroyed. + */ +REFRESHAPI void REFRESH_AddDisposeComputePipeline( + REFRESH_Device *device, + REFRESH_ComputePipeline *computePipeline +); + /* Sends a graphics pipeline to be destroyed by the renderer. Note that we call it * "AddDispose" because it may not be immediately destroyed by the renderer if * this is not called from the main thread (for example, if a garbage collector diff --git a/src/Refresh.c b/src/Refresh.c index 1cb830e..8f9c209 100644 --- a/src/Refresh.c +++ b/src/Refresh.c @@ -252,6 +252,17 @@ REFRESH_RenderPass* REFRESH_CreateRenderPass( ); } +REFRESH_ComputePipeline* REFRESH_CreateComputePipeline( + REFRESH_Device *device, + REFRESH_ComputePipelineCreateInfo *pipelineCreateInfo +) { + NULL_RETURN_NULL(device); + return device->CreateComputePipeline( + device->driverData, + pipelineCreateInfo + ); +} + REFRESH_GraphicsPipeline* REFRESH_CreateGraphicsPipeline( REFRESH_Device *device, REFRESH_GraphicsPipelineCreateInfo *pipelineCreateInfo @@ -746,6 +757,17 @@ void REFRESH_AddDisposeRenderPass( ); } +void REFRESH_AddDisposeComputePipeline( + REFRESH_Device *device, + REFRESH_ComputePipeline *computePipeline +) { + NULL_RETURN(device); + device->AddDisposeComputePipeline( + device->driverData, + computePipeline + ); +} + void REFRESH_AddDisposeGraphicsPipeline( REFRESH_Device *device, REFRESH_GraphicsPipeline *graphicsPipeline diff --git a/src/Refresh_Driver.h b/src/Refresh_Driver.h index dc3558a..5e7847c 100644 --- a/src/Refresh_Driver.h +++ b/src/Refresh_Driver.h @@ -220,6 +220,11 @@ struct REFRESH_Device REFRESH_RenderPassCreateInfo *renderPassCreateInfo ); + REFRESH_ComputePipeline* (*CreateComputePipeline)( + REFRESH_Renderer *driverData, + REFRESH_ComputePipelineCreateInfo *pipelineCreateInfo + ); + REFRESH_GraphicsPipeline* (*CreateGraphicsPipeline)( REFRESH_Renderer *driverData, REFRESH_GraphicsPipelineCreateInfo *pipelineCreateInfo @@ -457,6 +462,11 @@ struct REFRESH_Device REFRESH_RenderPass *renderPass ); + void(*AddDisposeComputePipeline)( + REFRESH_Renderer *driverData, + REFRESH_ComputePipeline *computePipeline + ); + void(*AddDisposeGraphicsPipeline)( REFRESH_Renderer *driverData, REFRESH_GraphicsPipeline *graphicsPipeline @@ -522,6 +532,7 @@ struct REFRESH_Device ASSIGN_DRIVER_FUNC(DrawInstancedPrimitives, name) \ ASSIGN_DRIVER_FUNC(DrawPrimitives, name) \ ASSIGN_DRIVER_FUNC(CreateRenderPass, name) \ + ASSIGN_DRIVER_FUNC(CreateComputePipeline, name) \ ASSIGN_DRIVER_FUNC(CreateGraphicsPipeline, name) \ ASSIGN_DRIVER_FUNC(CreateSampler, name) \ ASSIGN_DRIVER_FUNC(CreateFramebuffer, name) \ @@ -554,6 +565,7 @@ struct REFRESH_Device ASSIGN_DRIVER_FUNC(AddDisposeFramebuffer, name) \ ASSIGN_DRIVER_FUNC(AddDisposeShaderModule, name) \ ASSIGN_DRIVER_FUNC(AddDisposeRenderPass, name) \ + ASSIGN_DRIVER_FUNC(AddDisposeComputePipeline, name) \ ASSIGN_DRIVER_FUNC(AddDisposeGraphicsPipeline, name) \ ASSIGN_DRIVER_FUNC(BeginRenderPass, name) \ ASSIGN_DRIVER_FUNC(EndRenderPass, name) \ diff --git a/src/Refresh_Driver_Vulkan.c b/src/Refresh_Driver_Vulkan.c index 575db81..7f0cda4 100644 --- a/src/Refresh_Driver_Vulkan.c +++ b/src/Refresh_Driver_Vulkan.c @@ -678,6 +678,8 @@ typedef struct SwapChainSupportDetails } SwapChainSupportDetails; typedef struct SamplerDescriptorSetCache SamplerDescriptorSetCache; +typedef struct ComputeBufferDescriptorSetCache ComputeBufferDescriptorSetCache; +typedef struct ComputeImageDescriptorSetCache ComputeImageDescriptorSetCache; typedef struct VulkanGraphicsPipelineLayout { @@ -700,6 +702,19 @@ typedef struct VulkanGraphicsPipeline VkDeviceSize fragmentUBOBlockSize; /* permantenly set in Create function */ } VulkanGraphicsPipeline; +typedef struct VulkanComputePipelineLayout +{ + VkPipelineLayout pipelineLayout; + ComputeBufferDescriptorSetCache *bufferDescriptorSetCache; + ComputeImageDescriptorSetCache *imageDescriptorSetCache; +} VulkanComputePipelineLayout; + +typedef struct VulkanComputePipeline +{ + VkPipeline pipeline; + VulkanComputePipelineLayout *pipelineLayout; +} VulkanComputePipeline; + typedef struct VulkanTexture { VulkanMemoryAllocation *allocation; @@ -750,9 +765,13 @@ typedef struct VulkanFramebuffer /* Cache structures */ +/* Descriptor Set Layout Caches*/ + +#define NUM_DESCRIPTOR_SET_LAYOUT_BUCKETS 1031 + typedef struct SamplerDescriptorSetLayoutHash { - VkDescriptorType descriptorType; + VkDescriptorType descriptorType; // FIXME: unnecessary uint32_t samplerBindingCount; VkShaderStageFlagBits stageFlag; } SamplerDescriptorSetLayoutHash; @@ -770,8 +789,6 @@ typedef struct SamplerDescriptorSetLayoutHashArray int32_t capacity; } SamplerDescriptorSetLayoutHashArray; -#define NUM_DESCRIPTOR_SET_LAYOUT_BUCKETS 1031 - typedef struct SamplerDescriptorSetLayoutHashTable { SamplerDescriptorSetLayoutHashArray buckets[NUM_DESCRIPTOR_SET_LAYOUT_BUCKETS]; @@ -827,86 +844,78 @@ static inline void SamplerDescriptorSetLayoutHashTable_Insert( arr->count += 1; } -typedef struct PipelineLayoutHash +/* FIXME: we can probably just index this by count */ +typedef struct ComputeBufferDescriptorSetLayoutHash { - VkDescriptorSetLayout vertexSamplerLayout; - VkDescriptorSetLayout fragmentSamplerLayout; - VkDescriptorSetLayout vertexUniformLayout; - VkDescriptorSetLayout fragmentUniformLayout; -} PipelineLayoutHash; + uint32_t bindingCount; +} ComputeBufferDescriptorSetLayoutHash; -typedef struct PipelineLayoutHashMap +typedef struct ComputeBufferDescriptorSetLayoutHashMap { - PipelineLayoutHash key; - VulkanGraphicsPipelineLayout *value; -} PipelineLayoutHashMap; + ComputeBufferDescriptorSetLayoutHash key; + VkDescriptorSetLayout value; +} ComputeBufferDescriptorSetLayoutHashMap; -typedef struct PipelineLayoutHashArray +typedef struct ComputeBufferDescriptorSetLayoutHashArray { - PipelineLayoutHashMap *elements; + ComputeBufferDescriptorSetLayoutHashMap *elements; int32_t count; int32_t capacity; -} PipelineLayoutHashArray; +} ComputeBufferDescriptorSetLayoutHashArray; -#define NUM_PIPELINE_LAYOUT_BUCKETS 1031 - -typedef struct PipelineLayoutHashTable +typedef struct ComputeBufferDescriptorSetLayoutHashTable { - PipelineLayoutHashArray buckets[NUM_PIPELINE_LAYOUT_BUCKETS]; -} PipelineLayoutHashTable; + ComputeBufferDescriptorSetLayoutHashArray buckets[NUM_DESCRIPTOR_SET_LAYOUT_BUCKETS]; +} ComputeBufferDescriptorSetLayoutHashTable; -static inline uint64_t PipelineLayoutHashTable_GetHashCode(PipelineLayoutHash key) +static inline uint64_t ComputeBufferDescriptorSetLayoutHashTable_GetHashCode(ComputeBufferDescriptorSetLayoutHash key) { const uint64_t HASH_FACTOR = 97; uint64_t result = 1; - result = result * HASH_FACTOR + (uint64_t) key.vertexSamplerLayout; - result = result * HASH_FACTOR + (uint64_t) key.fragmentSamplerLayout; - result = result * HASH_FACTOR + (uint64_t) key.vertexUniformLayout; - result = result * HASH_FACTOR + (uint64_t) key.fragmentUniformLayout; + result = result * HASH_FACTOR + key.bindingCount; return result; } -static inline VulkanGraphicsPipelineLayout* PipelineLayoutHashArray_Fetch( - PipelineLayoutHashTable *table, - PipelineLayoutHash key +static inline VkDescriptorSetLayout ComputeBufferDescriptorSetLayoutHashTable_Fetch( + ComputeBufferDescriptorSetLayoutHashTable *table, + ComputeBufferDescriptorSetLayoutHash key ) { int32_t i; - uint64_t hashcode = PipelineLayoutHashTable_GetHashCode(key); - PipelineLayoutHashArray *arr = &table->buckets[hashcode % NUM_PIPELINE_LAYOUT_BUCKETS]; + uint64_t hashcode = ComputeBufferDescriptorSetLayoutHashTable_GetHashCode(key); + ComputeBufferDescriptorSetLayoutHashArray *arr = &table->buckets[hashcode % NUM_DESCRIPTOR_SET_LAYOUT_BUCKETS]; for (i = 0; i < arr->count; i += 1) { - const PipelineLayoutHash *e = &arr->elements[i].key; - if ( key.vertexSamplerLayout == e->vertexSamplerLayout && - key.fragmentSamplerLayout == e->fragmentSamplerLayout && - key.vertexUniformLayout == e->vertexUniformLayout && - key.fragmentUniformLayout == e->fragmentUniformLayout ) + const ComputeBufferDescriptorSetLayoutHash *e = &arr->elements[i].key; + if (key.bindingCount == e->bindingCount) { return arr->elements[i].value; } } - return NULL; + return VK_NULL_HANDLE; } -static inline void PipelineLayoutHashArray_Insert( - PipelineLayoutHashTable *table, - PipelineLayoutHash key, - VulkanGraphicsPipelineLayout *value +static inline void ComputeBufferDescriptorSetLayoutHashTable_Insert( + ComputeBufferDescriptorSetLayoutHashTable *table, + ComputeBufferDescriptorSetLayoutHash key, + VkDescriptorSetLayout value ) { - uint64_t hashcode = PipelineLayoutHashTable_GetHashCode(key); - PipelineLayoutHashArray *arr = &table->buckets[hashcode % NUM_PIPELINE_LAYOUT_BUCKETS]; + uint64_t hashcode = ComputeBufferDescriptorSetLayoutHashTable_GetHashCode(key); + ComputeBufferDescriptorSetLayoutHashArray *arr = &table->buckets[hashcode % NUM_DESCRIPTOR_SET_LAYOUT_BUCKETS]; - PipelineLayoutHashMap map; + ComputeBufferDescriptorSetLayoutHashMap map; map.key = key; map.value = value; - EXPAND_ELEMENTS_IF_NEEDED(arr, 4, PipelineLayoutHashMap) + EXPAND_ELEMENTS_IF_NEEDED(arr, 4, ComputeBufferDescriptorSetLayoutHashMap) arr->elements[arr->count] = map; arr->count += 1; } +/* Descriptor Set Caches */ + typedef struct SamplerDescriptorSetData { VkDescriptorImageInfo descriptorImageInfo[MAX_TEXTURE_SAMPLERS]; /* used for vertex samplers as well */ @@ -965,6 +974,160 @@ struct SamplerDescriptorSetCache uint32_t inactiveDescriptorSetCapacity; }; +/* Pipeline Caches */ + +typedef struct GraphicsPipelineLayoutHash +{ + VkDescriptorSetLayout vertexSamplerLayout; + VkDescriptorSetLayout fragmentSamplerLayout; + VkDescriptorSetLayout vertexUniformLayout; + VkDescriptorSetLayout fragmentUniformLayout; +} GraphicsPipelineLayoutHash; + +typedef struct GraphicsPipelineLayoutHashMap +{ + GraphicsPipelineLayoutHash key; + VulkanGraphicsPipelineLayout *value; +} GraphicsPipelineLayoutHashMap; + +typedef struct GraphicsPipelineLayoutHashArray +{ + GraphicsPipelineLayoutHashMap *elements; + int32_t count; + int32_t capacity; +} GraphicsPipelineLayoutHashArray; + +#define NUM_PIPELINE_LAYOUT_BUCKETS 1031 + +typedef struct GraphicsPipelineLayoutHashTable +{ + GraphicsPipelineLayoutHashArray buckets[NUM_PIPELINE_LAYOUT_BUCKETS]; +} GraphicsPipelineLayoutHashTable; + +static inline uint64_t GraphicsPipelineLayoutHashTable_GetHashCode(GraphicsPipelineLayoutHash key) +{ + const uint64_t HASH_FACTOR = 97; + uint64_t result = 1; + result = result * HASH_FACTOR + (uint64_t) key.vertexSamplerLayout; + result = result * HASH_FACTOR + (uint64_t) key.fragmentSamplerLayout; + result = result * HASH_FACTOR + (uint64_t) key.vertexUniformLayout; + result = result * HASH_FACTOR + (uint64_t) key.fragmentUniformLayout; + return result; +} + +static inline VulkanGraphicsPipelineLayout* GraphicsPipelineLayoutHashArray_Fetch( + GraphicsPipelineLayoutHashTable *table, + GraphicsPipelineLayoutHash key +) { + int32_t i; + uint64_t hashcode = GraphicsPipelineLayoutHashTable_GetHashCode(key); + GraphicsPipelineLayoutHashArray *arr = &table->buckets[hashcode % NUM_PIPELINE_LAYOUT_BUCKETS]; + + for (i = 0; i < arr->count; i += 1) + { + const GraphicsPipelineLayoutHash *e = &arr->elements[i].key; + if ( key.vertexSamplerLayout == e->vertexSamplerLayout && + key.fragmentSamplerLayout == e->fragmentSamplerLayout && + key.vertexUniformLayout == e->vertexUniformLayout && + key.fragmentUniformLayout == e->fragmentUniformLayout ) + { + return arr->elements[i].value; + } + } + + return NULL; +} + +static inline void GraphicsPipelineLayoutHashArray_Insert( + GraphicsPipelineLayoutHashTable *table, + GraphicsPipelineLayoutHash key, + VulkanGraphicsPipelineLayout *value +) { + uint64_t hashcode = GraphicsPipelineLayoutHashTable_GetHashCode(key); + GraphicsPipelineLayoutHashArray *arr = &table->buckets[hashcode % NUM_PIPELINE_LAYOUT_BUCKETS]; + + GraphicsPipelineLayoutHashMap map; + map.key = key; + map.value = value; + + EXPAND_ELEMENTS_IF_NEEDED(arr, 4, GraphicsPipelineLayoutHashMap) + + arr->elements[arr->count] = map; + arr->count += 1; +} + +typedef struct ComputePipelineLayoutHash +{ + VkDescriptorSetLayout bufferLayout; + VkDescriptorSetLayout imageLayout; +} ComputePipelineLayoutHash; + +typedef struct ComputePipelineLayoutHashMap +{ + ComputePipelineLayoutHash key; + VulkanComputePipelineLayout *value; +} ComputePipelineLayoutHashMap; + +typedef struct ComputePipelineLayoutHashArray +{ + ComputePipelineLayoutHashMap *elements; + int32_t count; + int32_t capacity; +} ComputePipelineLayoutHashArray; + +typedef struct ComputePipelineLayoutHashTable +{ + ComputePipelineLayoutHashArray buckets[NUM_PIPELINE_LAYOUT_BUCKETS]; +} ComputePipelineLayoutHashTable; + +static inline uint64_t ComputePipelineLayoutHashTable_GetHashCode(ComputePipelineLayoutHash key) +{ + const uint64_t HASH_FACTOR = 97; + uint64_t result = 1; + result = result * HASH_FACTOR + (uint64_t) key.bufferLayout; + result = result * HASH_FACTOR + (uint64_t) key.imageLayout; + return result; +} + +static inline VulkanComputePipelineLayout* ComputePipelineLayoutHashArray_Fetch( + ComputePipelineLayoutHashTable *table, + ComputePipelineLayoutHash key +) { + int32_t i; + uint64_t hashcode = ComputePipelineLayoutHashTable_GetHashCode(key); + ComputePipelineLayoutHashArray *arr = &table->buckets[hashcode % NUM_PIPELINE_LAYOUT_BUCKETS]; + + for (i = 0; i < arr->count; i += 1) + { + const ComputePipelineLayoutHash *e = &arr->elements[i].key; + if ( key.bufferLayout == e->bufferLayout && + key.imageLayout == e->imageLayout ) + { + return arr->elements[i].value; + } + } + + return NULL; +} + +static inline void ComputePipelineLayoutHashArray_Insert( + ComputePipelineLayoutHashTable *table, + ComputePipelineLayoutHash key, + VulkanComputePipelineLayout *value +) { + uint64_t hashcode = ComputePipelineLayoutHashTable_GetHashCode(key); + ComputePipelineLayoutHashArray *arr = &table->buckets[hashcode % NUM_PIPELINE_LAYOUT_BUCKETS]; + + ComputePipelineLayoutHashMap map; + map.key = key; + map.value = value; + + EXPAND_ELEMENTS_IF_NEEDED(arr, 4, ComputePipelineLayoutHashMap) + + arr->elements[arr->count] = map; + arr->count += 1; +} + /* Context */ typedef struct VulkanRenderer @@ -1023,8 +1186,10 @@ typedef struct VulkanRenderer VulkanFramebuffer *currentFramebuffer; SamplerDescriptorSetLayoutHashTable samplerDescriptorSetLayoutHashTable; - PipelineLayoutHashTable pipelineLayoutHashTable; + ComputeBufferDescriptorSetLayoutHashTable computeBufferDescriptorSetLayoutHashTable; + GraphicsPipelineLayoutHashTable graphicsPipelineLayoutHashTable; + ComputePipelineLayoutHashTable computePipelineLayoutHashTable; /* * TODO: we can get rid of this reference when we * come up with a clever descriptor set reuse system @@ -1034,10 +1199,14 @@ typedef struct VulkanRenderer /* initialize baseline descriptor info */ VkDescriptorPool defaultDescriptorPool; + VkDescriptorSetLayout emptyVertexSamplerLayout; VkDescriptorSetLayout emptyFragmentSamplerLayout; + VkDescriptorSetLayout emptyComputeBufferDescriptorSetLayout; + VkDescriptorSet emptyVertexSamplerDescriptorSet; VkDescriptorSet emptyFragmentSamplerDescriptorSet; + VkDescriptorSet emptyComputeBufferDescriptorSet; VkDescriptorSetLayout vertexParamLayout; VkDescriptorSetLayout fragmentParamLayout; @@ -3083,7 +3252,7 @@ static void VULKAN_DestroyDevice( ) { VulkanRenderer* renderer = (VulkanRenderer*) device->driverData; VkResult waitResult; - PipelineLayoutHashArray pipelineLayoutHashArray; + GraphicsPipelineLayoutHashArray pipelineLayoutHashArray; VulkanMemorySubAllocator *allocator; uint32_t i, j, k; @@ -3133,7 +3302,7 @@ static void VULKAN_DestroyDevice( for (i = 0; i < NUM_PIPELINE_LAYOUT_BUCKETS; i += 1) { - pipelineLayoutHashArray = renderer->pipelineLayoutHashTable.buckets[i]; + pipelineLayoutHashArray = renderer->graphicsPipelineLayoutHashTable.buckets[i]; for (j = 0; j < pipelineLayoutHashArray.count; j += 1) { VULKAN_INTERNAL_DestroySamplerDescriptorSetCache( @@ -3912,7 +4081,7 @@ static VulkanGraphicsPipelineLayout* VULKAN_INTERNAL_FetchGraphicsPipelineLayout ) { VkDescriptorSetLayout setLayouts[4]; - PipelineLayoutHash pipelineLayoutHash; + GraphicsPipelineLayoutHash pipelineLayoutHash; VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo; VkResult vulkanResult; @@ -3933,12 +4102,12 @@ static VulkanGraphicsPipelineLayout* VULKAN_INTERNAL_FetchGraphicsPipelineLayout pipelineLayoutHash.vertexUniformLayout = renderer->vertexParamLayout; pipelineLayoutHash.fragmentUniformLayout = renderer->fragmentParamLayout; - vulkanGraphicsPipelineLayout = PipelineLayoutHashArray_Fetch( - &renderer->pipelineLayoutHashTable, + vulkanGraphicsPipelineLayout = GraphicsPipelineLayoutHashArray_Fetch( + &renderer->graphicsPipelineLayoutHashTable, pipelineLayoutHash ); - if (vulkanGraphicsPipelineLayout != VK_NULL_HANDLE) + if (vulkanGraphicsPipelineLayout != NULL) { return vulkanGraphicsPipelineLayout; } @@ -3971,8 +4140,8 @@ static VulkanGraphicsPipelineLayout* VULKAN_INTERNAL_FetchGraphicsPipelineLayout return NULL; } - PipelineLayoutHashArray_Insert( - &renderer->pipelineLayoutHashTable, + GraphicsPipelineLayoutHashArray_Insert( + &renderer->graphicsPipelineLayoutHashTable, pipelineLayoutHash, vulkanGraphicsPipelineLayout ); @@ -4454,6 +4623,221 @@ static REFRESH_GraphicsPipeline* VULKAN_CreateGraphicsPipeline( return (REFRESH_GraphicsPipeline*) graphicsPipeline; } +static VkDescriptorSetLayout VULKAN_INTERNAL_FetchComputeBufferDescriptorSetLayout( + VulkanRenderer *renderer, + uint32_t bindingCount +) { + ComputeBufferDescriptorSetLayoutHash descriptorSetLayoutHash; + VkDescriptorSetLayout descriptorSetLayout; + + VkDescriptorSetLayoutBinding *setLayoutBindings; + VkDescriptorSetLayoutCreateInfo setLayoutCreateInfo; + + VkResult vulkanResult; + uint32_t i; + + if (bindingCount == 0) + { + return renderer->emptyComputeBufferDescriptorSetLayout; + } + + descriptorSetLayoutHash.bindingCount = bindingCount; + + descriptorSetLayout = ComputeBufferDescriptorSetLayoutHashTable_Fetch( + &renderer->computeBufferDescriptorSetLayoutHashTable, + descriptorSetLayoutHash + ); + + if (descriptorSetLayout != VK_NULL_HANDLE) + { + return descriptorSetLayout; + } + + setLayoutBindings = SDL_stack_alloc(VkDescriptorSetLayoutBinding, bindingCount); + + for (i = 0; i < bindingCount; i += 1) + { + setLayoutBindings[i].binding = i; + setLayoutBindings[i].descriptorCount = 1; + setLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + setLayoutBindings[i].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; + setLayoutBindings[i].pImmutableSamplers = NULL; + } + + setLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + setLayoutCreateInfo.pNext = NULL; + setLayoutCreateInfo.flags = 0; + setLayoutCreateInfo.bindingCount = bindingCount; + setLayoutCreateInfo.pBindings = setLayoutBindings; + + vulkanResult = renderer->vkCreateDescriptorSetLayout( + renderer->logicalDevice, + &setLayoutCreateInfo, + NULL, + &descriptorSetLayout + ); + + if (vulkanResult != VK_SUCCESS) + { + LogVulkanResult("vkCreateDescriptorSetLayout", vulkanResult); + SDL_stack_free(setLayoutBindings); + return NULL_DESC_LAYOUT; + } + + ComputeBufferDescriptorSetLayoutHashTable_Insert( + &renderer->computeBufferDescriptorSetLayoutHashTable, + descriptorSetLayoutHash, + descriptorSetLayout + ); + + SDL_stack_free(setLayoutBindings); + return descriptorSetLayout; +} + +static VulkanComputePipelineLayout* VULKAN_INTERNAL_FetchComputePipelineLayout( + VulkanRenderer *renderer, + uint32_t bufferBindingCount, + uint32_t imageBindingCount +) { + VkResult vulkanResult; + VkDescriptorSetLayout setLayouts[2]; + VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo; + ComputePipelineLayoutHash pipelineLayoutHash; + VulkanComputePipelineLayout *vulkanComputePipelineLayout; + + pipelineLayoutHash.bufferLayout = VULKAN_INTERNAL_FetchComputeBufferDescriptorSetLayout( + renderer, + bufferBindingCount + ); + + pipelineLayoutHash.imageLayout = VULKAN_INTERNAL_FetchComputeImageDescriptorSetLayout( + renderer, + imageBindingCount + ); + + vulkanComputePipelineLayout = ComputePipelineLayoutHashArray_Fetch( + &renderer->computePipelineLayoutHashTable, + pipelineLayoutHash + ); + + if (vulkanComputePipelineLayout != NULL) + { + return vulkanComputePipelineLayout; + } + + vulkanComputePipelineLayout = SDL_malloc(sizeof(VulkanComputePipelineLayout)); + + setLayouts[0] = pipelineLayoutHash.bufferLayout; + setLayouts[1] = pipelineLayoutHash.imageLayout; + + pipelineLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipelineLayoutCreateInfo.pNext = NULL; + pipelineLayoutCreateInfo.flags = 0; + pipelineLayoutCreateInfo.setLayoutCount = 2; + pipelineLayoutCreateInfo.pSetLayouts = setLayouts; + pipelineLayoutCreateInfo.pushConstantRangeCount = 0; + pipelineLayoutCreateInfo.pPushConstantRanges = NULL; + + vulkanResult = renderer->vkCreatePipelineLayout( + renderer->logicalDevice, + &pipelineLayoutCreateInfo, + NULL, + &vulkanComputePipelineLayout->pipelineLayout + ); + + if (vulkanResult != VK_SUCCESS) + { + LogVulkanResult("vkCreatePipelineLayout", vulkanResult); + return NULL; + } + + ComputePipelineLayoutHashArray_Insert( + &renderer->computePipelineLayoutHashTable, + pipelineLayoutHash, + vulkanComputePipelineLayout + ); + + /* If the binding count is 0 + * we can just bind the same descriptor set + * so no cache is needed + */ + + if (bufferBindingCount == 0) + { + vulkanComputePipelineLayout->bufferDescriptorSetCache = NULL; + } + else + { + vulkanComputePipelineLayout->bufferDescriptorSetCache = + VULKAN_INTERNAL_CreateComputeBufferDescriptorSetCache( + renderer, + pipelineLayoutHash.bufferLayout, + bufferBindingCount + ); + } + + if (imageBindingCount == 0) + { + vulkanComputePipelineLayout->imageDescriptorSetCache = NULL; + } + else + { + vulkanComputePipelineLayout->imageDescriptorSetCache = + VULKAN_INTERNAL_CreateComputeImageDescriptorSetSetCache( + renderer, + pipelineLayoutHash.imageLayout, + imageBindingCount + ); + } + + return vulkanComputePipelineLayout; +} + +static REFRESH_ComputePipeline* VULKAN_CreateComputePipeline( + REFRESH_Renderer *driverData, + REFRESH_ComputePipelineCreateInfo *pipelineCreateInfo +) { + VkComputePipelineCreateInfo computePipelineCreateInfo; + VkPipelineShaderStageCreateInfo pipelineShaderStageCreateInfo; + VulkanComputePipelineLayout *computePipelineLayout; + + VulkanRenderer *renderer = (VulkanRenderer*) driverData; + VulkanComputePipeline *vulkanComputePipeline = SDL_malloc(sizeof(VulkanComputePipeline)); + + pipelineShaderStageCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + pipelineShaderStageCreateInfo.pNext = NULL; + pipelineShaderStageCreateInfo.flags = 0; + pipelineShaderStageCreateInfo.stage = VK_SHADER_STAGE_COMPUTE_BIT; + pipelineShaderStageCreateInfo.module = (VkShaderModule) pipelineCreateInfo->computeShaderState.shaderModule; + pipelineShaderStageCreateInfo.pName = pipelineCreateInfo->computeShaderState.entryPointName; + pipelineShaderStageCreateInfo.pSpecializationInfo = NULL; + + computePipelineLayout = VULKAN_INTERNAL_FetchComputePipelineLayout( + renderer, + pipelineCreateInfo->pipelineLayoutCreateInfo.bufferBindingCount, + pipelineCreateInfo->pipelineLayoutCreateInfo.imageBindingCount + ); + + computePipelineCreateInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; + computePipelineCreateInfo.pNext = NULL; + computePipelineCreateInfo.flags = 0; + computePipelineCreateInfo.stage = pipelineShaderStageCreateInfo; + computePipelineCreateInfo.layout = computePipelineLayout->pipelineLayout; + computePipelineCreateInfo.basePipelineHandle = NULL; + computePipelineCreateInfo.basePipelineIndex = 0; + + renderer->vkCreateComputePipelines( + renderer->logicalDevice, + NULL, + 1, + &computePipelineCreateInfo, + NULL, + &vulkanComputePipeline->pipeline + ); + + return (REFRESH_ComputePipeline*) vulkanComputePipeline; +} + static REFRESH_Sampler* VULKAN_CreateSampler( REFRESH_Renderer *driverData, REFRESH_SamplerStateCreateInfo *samplerStateCreateInfo @@ -6311,6 +6695,13 @@ static void VULKAN_AddDisposeRenderPass( SDL_UnlockMutex(renderer->disposeLock); } +static void VULKAN_AddDisposeComputePipeline( + REFRESH_Renderer *driverData, + REFRESH_ComputePipeline *computePipeline +) { + SDL_assert(0 && "Function not implemented!"); +} + static void VULKAN_AddDisposeGraphicsPipeline( REFRESH_Renderer *driverData, REFRESH_GraphicsPipeline *graphicsPipeline @@ -6792,9 +7183,9 @@ static void VULKAN_INTERNAL_ResetDescriptorSetData(VulkanRenderer *renderer) for (i = 0; i < NUM_PIPELINE_LAYOUT_BUCKETS; i += 1) { - for (j = 0; j < renderer->pipelineLayoutHashTable.buckets[i].count; j += 1) + for (j = 0; j < renderer->graphicsPipelineLayoutHashTable.buckets[i].count; j += 1) { - pipelineLayout = renderer->pipelineLayoutHashTable.buckets[i].elements[j].value; + pipelineLayout = renderer->graphicsPipelineLayoutHashTable.buckets[i].elements[j].value; if (pipelineLayout->vertexSamplerDescriptorSetCache != NULL) { @@ -7573,16 +7964,18 @@ static REFRESH_Device* VULKAN_CreateDevice( VkCommandPoolCreateInfo commandPoolCreateInfo; VkCommandBufferAllocateInfo commandBufferAllocateInfo; - /* Variables: Shader param layouts */ + /* Variables: Descriptor set layouts */ VkDescriptorSetLayoutCreateInfo setLayoutCreateInfo; VkDescriptorSetLayoutBinding emptyVertexSamplerLayoutBinding; VkDescriptorSetLayoutBinding emptyFragmentSamplerLayoutBinding; VkDescriptorSetLayoutBinding vertexParamLayoutBinding; VkDescriptorSetLayoutBinding fragmentParamLayoutBinding; + VkDescriptorSetLayoutBinding emptyComputeBufferDescriptorSetLayoutBinding; + /* Variables: UBO Creation */ VkDescriptorPoolCreateInfo defaultDescriptorPoolInfo; - VkDescriptorPoolSize poolSizes[2]; + VkDescriptorPoolSize poolSizes[3]; VkDescriptorSetAllocateInfo descriptorAllocateInfo; result = (REFRESH_Device*) SDL_malloc(sizeof(REFRESH_Device)); @@ -7908,10 +8301,6 @@ static REFRESH_Device* VULKAN_CreateDevice( emptyFragmentSamplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; emptyFragmentSamplerLayoutBinding.pImmutableSamplers = NULL; - setLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - setLayoutCreateInfo.pNext = NULL; - setLayoutCreateInfo.flags = 0; - setLayoutCreateInfo.bindingCount = 1; setLayoutCreateInfo.pBindings = &emptyFragmentSamplerLayoutBinding; vulkanResult = renderer->vkCreateDescriptorSetLayout( @@ -7921,6 +8310,21 @@ static REFRESH_Device* VULKAN_CreateDevice( &renderer->emptyFragmentSamplerLayout ); + emptyComputeBufferDescriptorSetLayoutBinding.binding = 0; + emptyComputeBufferDescriptorSetLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + emptyComputeBufferDescriptorSetLayoutBinding.descriptorCount = 0; + emptyComputeBufferDescriptorSetLayoutBinding.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; + emptyComputeBufferDescriptorSetLayoutBinding.pImmutableSamplers = NULL; + + setLayoutCreateInfo.pBindings = &emptyComputeBufferDescriptorSetLayoutBinding; + + vulkanResult = renderer->vkCreateDescriptorSetLayout( + renderer->logicalDevice, + &setLayoutCreateInfo, + NULL, + &renderer->emptyComputeBufferDescriptorSetLayout + ); + vertexParamLayoutBinding.binding = 0; vertexParamLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; vertexParamLayoutBinding.descriptorCount = 1; @@ -7978,11 +8382,14 @@ static REFRESH_Device* VULKAN_CreateDevice( poolSizes[1].descriptorCount = UBO_POOL_SIZE; poolSizes[1].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; + poolSizes[2].descriptorCount = 1; + poolSizes[2].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + defaultDescriptorPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; defaultDescriptorPoolInfo.pNext = NULL; defaultDescriptorPoolInfo.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; - defaultDescriptorPoolInfo.maxSets = UBO_POOL_SIZE + 2; - defaultDescriptorPoolInfo.poolSizeCount = 2; + defaultDescriptorPoolInfo.maxSets = UBO_POOL_SIZE + 2 + 1; + defaultDescriptorPoolInfo.poolSizeCount = 3; defaultDescriptorPoolInfo.pPoolSizes = poolSizes; renderer->vkCreateDescriptorPool( @@ -8012,6 +8419,14 @@ static REFRESH_Device* VULKAN_CreateDevice( &renderer->emptyFragmentSamplerDescriptorSet ); + descriptorAllocateInfo.pSetLayouts = &renderer->emptyComputeBufferDescriptorSetLayout; + + renderer->vkAllocateDescriptorSets( + renderer->logicalDevice, + &descriptorAllocateInfo, + &renderer->emptyComputeBufferDescriptorSet + ); + /* Initialize buffer space */ renderer->buffersInUseCapacity = 32; @@ -8076,9 +8491,16 @@ static REFRESH_Device* VULKAN_CreateDevice( for (i = 0; i < NUM_PIPELINE_LAYOUT_BUCKETS; i += 1) { - renderer->pipelineLayoutHashTable.buckets[i].elements = NULL; - renderer->pipelineLayoutHashTable.buckets[i].count = 0; - renderer->pipelineLayoutHashTable.buckets[i].capacity = 0; + renderer->graphicsPipelineLayoutHashTable.buckets[i].elements = NULL; + renderer->graphicsPipelineLayoutHashTable.buckets[i].count = 0; + renderer->graphicsPipelineLayoutHashTable.buckets[i].capacity = 0; + } + + for (i = 0; i < NUM_PIPELINE_LAYOUT_BUCKETS; i += 1) + { + renderer->computePipelineLayoutHashTable.buckets[i].elements = NULL; + renderer->computePipelineLayoutHashTable.buckets[i].count = 0; + renderer->computePipelineLayoutHashTable.buckets[i].capacity = 0; } for (i = 0; i < NUM_DESCRIPTOR_SET_LAYOUT_BUCKETS; i += 1) @@ -8088,6 +8510,13 @@ static REFRESH_Device* VULKAN_CreateDevice( renderer->samplerDescriptorSetLayoutHashTable.buckets[i].capacity = 0; } + for (i = 0; i < NUM_DESCRIPTOR_SET_LAYOUT_BUCKETS; i += 1) + { + renderer->computeBufferDescriptorSetLayoutHashTable.buckets[i].elements = NULL; + renderer->computeBufferDescriptorSetLayoutHashTable.buckets[i].count = 0; + renderer->computeBufferDescriptorSetLayoutHashTable.buckets[i].capacity = 0; + } + /* Descriptor Pools */ renderer->descriptorPools = NULL; diff --git a/src/Refresh_Driver_Vulkan_vkfuncs.h b/src/Refresh_Driver_Vulkan_vkfuncs.h index 5e858f4..1e85cb7 100644 --- a/src/Refresh_Driver_Vulkan_vkfuncs.h +++ b/src/Refresh_Driver_Vulkan_vkfuncs.h @@ -24,7 +24,6 @@ * */ - /* * Global functions from the Vulkan Loader */ @@ -105,6 +104,7 @@ VULKAN_DEVICE_FUNCTION(BaseVK, VkResult, vkCreateDescriptorPool, (VkDevice devic VULKAN_DEVICE_FUNCTION(BaseVK, VkResult, vkCreateDescriptorSetLayout, (VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDescriptorSetLayout *pSetLayout)) VULKAN_DEVICE_FUNCTION(BaseVK, VkResult, vkCreateFence, (VkDevice device, const VkFenceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkFence *pFence)) VULKAN_DEVICE_FUNCTION(BaseVK, VkResult, vkCreateFramebuffer, (VkDevice device, const VkFramebufferCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkFramebuffer *pFramebuffer)) +VULKAN_DEVICE_FUNCTION(BaseVK, VkResult, vkCreateComputePipelines, (VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkComputePipelineCreateInfo *pCreateInfos, const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines)) VULKAN_DEVICE_FUNCTION(BaseVK, VkResult, vkCreateGraphicsPipelines, (VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkGraphicsPipelineCreateInfo *pCreateInfos, const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines)) VULKAN_DEVICE_FUNCTION(BaseVK, VkResult, vkCreateImage, (VkDevice device, const VkImageCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkImage *pImage)) VULKAN_DEVICE_FUNCTION(BaseVK, VkResult, vkCreateImageView, (VkDevice device, const VkImageViewCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkImageView *pView)) @@ -131,17 +131,17 @@ VULKAN_DEVICE_FUNCTION(BaseVK, void, vkDestroyPipelineLayout, (VkDevice device, VULKAN_DEVICE_FUNCTION(BaseVK, void, vkDestroyRenderPass, (VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks *pAllocator)) VULKAN_DEVICE_FUNCTION(BaseVK, void, vkDestroySampler, (VkDevice device, VkSampler sampler, const VkAllocationCallbacks *pAllocator)) VULKAN_DEVICE_FUNCTION(BaseVK, void, vkDestroySemaphore, (VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks *pAllocator)) -VULKAN_DEVICE_FUNCTION(BaseVK, void, vkDestroyShaderModule, (VkDevice device, VkShaderModule shaderModule, const VkAllocationCallbacks* pAllocator)) +VULKAN_DEVICE_FUNCTION(BaseVK, void, vkDestroyShaderModule, (VkDevice device, VkShaderModule shaderModule, const VkAllocationCallbacks *pAllocator)) VULKAN_DEVICE_FUNCTION(BaseVK, void, vkDestroySwapchainKHR, (VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks *pAllocator)) VULKAN_DEVICE_FUNCTION(BaseVK, void, vkDestroyQueryPool, (VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks *pAllocator)) VULKAN_DEVICE_FUNCTION(BaseVK, VkResult, vkDeviceWaitIdle, (VkDevice device)) VULKAN_DEVICE_FUNCTION(BaseVK, VkResult, vkEndCommandBuffer, (VkCommandBuffer commandBuffer)) VULKAN_DEVICE_FUNCTION(BaseVK, void, vkFreeCommandBuffers, (VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount, const VkCommandBuffer *pCommandBuffers)) -VULKAN_DEVICE_FUNCTION(BaseVK, VkResult, vkFreeDescriptorSets, (VkDevice device, VkDescriptorPool descriptorPool, uint32_t descriptorSetCount, const VkDescriptorSet* pDescriptorSets)) +VULKAN_DEVICE_FUNCTION(BaseVK, VkResult, vkFreeDescriptorSets, (VkDevice device, VkDescriptorPool descriptorPool, uint32_t descriptorSetCount, const VkDescriptorSet *pDescriptorSets)) VULKAN_DEVICE_FUNCTION(BaseVK, void, vkFreeMemory, (VkDevice device, VkDeviceMemory memory, const VkAllocationCallbacks *pAllocator)) -VULKAN_DEVICE_FUNCTION(BaseVK, void, vkGetBufferMemoryRequirements2KHR, (VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements)) +VULKAN_DEVICE_FUNCTION(BaseVK, void, vkGetBufferMemoryRequirements2KHR, (VkDevice device, const VkBufferMemoryRequirementsInfo2 *pInfo, VkMemoryRequirements2 *pMemoryRequirements)) VULKAN_DEVICE_FUNCTION(BaseVK, void, vkGetDeviceQueue, (VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue *pQueue)) -VULKAN_DEVICE_FUNCTION(BaseVK, void, vkGetImageMemoryRequirements2KHR, (VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements)) +VULKAN_DEVICE_FUNCTION(BaseVK, void, vkGetImageMemoryRequirements2KHR, (VkDevice device, const VkImageMemoryRequirementsInfo2 *pInfo, VkMemoryRequirements2 *pMemoryRequirements)) VULKAN_DEVICE_FUNCTION(BaseVK, VkResult, vkGetFenceStatus, (VkDevice device, VkFence fence)) VULKAN_DEVICE_FUNCTION(BaseVK, VkResult, vkGetSwapchainImagesKHR, (VkDevice device, VkSwapchainKHR swapchain, uint32_t *pSwapchainImageCount, VkImage *pSwapchainImages)) VULKAN_DEVICE_FUNCTION(BaseVK, VkResult, vkMapMemory, (VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, void **ppData))