diff --git a/include/SDL3/SDL_gpu.h b/include/SDL3/SDL_gpu.h index cee0b731bc6b7..6611f4366d05f 100644 --- a/include/SDL3/SDL_gpu.h +++ b/include/SDL3/SDL_gpu.h @@ -298,6 +298,19 @@ typedef struct SDL_GPUComputePipeline SDL_GPUComputePipeline; */ typedef struct SDL_GPUGraphicsPipeline SDL_GPUGraphicsPipeline; +/** + * An opaque handle representing a pipeline cache. + * + * Used during pipeline creation. + * + * \since This struct is available since SDL 3.1.3 + * + * \sa SDL_CreateGPUPipelineCache + * \sa SDL_ReleaseGPUPipelineCache + * \sa SDL_FetchGPUPipelineCacheData + */ +typedef struct SDL_GPUPipelineCache SDL_GPUPipelineCache; + /** * An opaque handle representing a command buffer. * @@ -1700,6 +1713,22 @@ typedef struct SDL_GPUComputePipelineCreateInfo SDL_PropertiesID props; /**< A properties ID for extensions. Should be 0 if no extensions are needed. */ } SDL_GPUComputePipelineCreateInfo; +/** + * A structure specifying the parameters of a pipeline cache. + * + * \since This struct is available since SDL 3.1.3 + * + * \sa SDL_CreateGPUPipelineCache + * \sa SDL_FetchGPUPipelineCacheData + */ +typedef struct SDL_GPUPipelineCacheCreateInfo +{ + size_t checksum_size; /**< The size in bytes of the cache checksum. */ + void* checksum_data; /**< A pointer to the checksum data. */ + size_t cache_size; /**< The size in bytes of the pipeline cache. */ + void* cache_data; /**< A pointer to the cache data. */ +} SDL_GPUPipelineCacheCreateInfo; + /** * A structure specifying the parameters of a color target used by a render * pass. @@ -2009,6 +2038,7 @@ extern SDL_DECLSPEC SDL_GPUDevice *SDLCALL SDL_CreateGPUDeviceWithProperties( #define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_MSL_BOOLEAN "SDL.gpu.device.create.shaders.msl" #define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_METALLIB_BOOLEAN "SDL.gpu.device.create.shaders.metallib" #define SDL_PROP_GPU_DEVICE_CREATE_D3D12_SEMANTIC_NAME_STRING "SDL.gpu.device.create.d3d12.semantic" +#define SDL_PROP_GPU_PIPELINE_USE_CACHE "SDL.gpu.pipeline.use.cache" /** * Destroys a GPU context previously returned by SDL_CreateGPUDevice. @@ -2136,6 +2166,43 @@ extern SDL_DECLSPEC SDL_GPUGraphicsPipeline *SDLCALL SDL_CreateGPUGraphicsPipeli SDL_GPUDevice *device, const SDL_GPUGraphicsPipelineCreateInfo *createinfo); +/** + * Creates a pipeline cache object to be used during pipeline builds. + * + * \param device a GPU Context. + * \param createinfo a struct containing the pipeline cache data. Set everything to NULL/0 in order to force a cache rebuild + * \returns a pipeline cache object on success, or NULL on failure; call + * SDL_GetError() for more information. + * + * \since This function is available since SDL 3.1.3. + * + * \sa SDL_CreatePipelineCache + * \sa SDL_ReleasePipelineCache + * \sa SDL_RetrievePipelineCacheData + */ +extern SDL_DECLSPEC SDL_GPUPipelineCache* SDLCALL SDL_CreateGPUPipelineCache( + SDL_GPUDevice* device, + const SDL_GPUPipelineCacheCreateInfo* createinfo); + +/** + * Fetches a pipeline cache object data. This can then be stored to disk and loaded on the next application run + * + * \param device a GPU Context. + * \param pipeline_cache pipeline cache object to fetch data from + * \param createinfo a struct that will contain the cache's serializable data + * \returns true on success, or false on failure; call + * SDL_GetError() for more information. + * + * \since This function is available since SDL 3.1.3. + * + * \sa SDL_CreatePipelineCache + * \sa SDL_ReleasePipelineCache + */ +extern SDL_DECLSPEC bool SDLCALL SDL_FetchGPUPipelineCacheData( + SDL_GPUDevice* device, + SDL_GPUPipelineCache* pipeline_cache, + SDL_GPUPipelineCacheCreateInfo* createinfo); + /** * Creates a sampler object to be used when binding textures in a graphics * workflow. @@ -2496,6 +2563,20 @@ extern SDL_DECLSPEC void SDLCALL SDL_ReleaseGPUGraphicsPipeline( SDL_GPUDevice *device, SDL_GPUGraphicsPipeline *graphics_pipeline); +/** + * Frees the given pipeline cache as soon as it is safe to do so. + * + * You must not reference the pipeline cache after calling this function. + * + * \param device a GPU context. + * \param pipeline_cache a pipeline cache to be destroyed. + * + * \since This function is available since SDL 3.1.3. + */ +extern SDL_DECLSPEC void SDLCALL SDL_ReleaseGPUPipelineCache( + SDL_GPUDevice* device, + SDL_GPUPipelineCache* pipeline_cache); + /** * Acquire a command buffer. * diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym index cba2c637298b0..7c0f7d868721c 100644 --- a/src/dynapi/SDL_dynapi.sym +++ b/src/dynapi/SDL_dynapi.sym @@ -1205,6 +1205,9 @@ SDL3_0.0.0 { SDL_RunOnMainThread; SDL_SetGPUAllowedFramesInFlight; SDL_RenderTextureAffine; + SDL_CreateGPUPipelineCache; + SDL_FetchGPUPipelineCacheData; + SDL_ReleaseGPUPipelineCache; # extra symbols go here (don't modify this line) local: *; }; diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index 7dd37385ad352..a7aece4f828f3 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -1230,3 +1230,6 @@ #define SDL_RunOnMainThread SDL_RunOnMainThread_REAL #define SDL_SetGPUAllowedFramesInFlight SDL_SetGPUAllowedFramesInFlight_REAL #define SDL_RenderTextureAffine SDL_RenderTextureAffine_REAL +#define SDL_CreateGPUPipelineCache SDL_CreateGPUPipelineCache_REAL +#define SDL_FetchGPUPipelineCacheData SDL_FetchGPUPipelineCacheData_REAL +#define SDL_ReleaseGPUPipelineCache SDL_ReleaseGPUPipelineCache_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index 1a9acd50010f4..d17ad912b1597 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -1236,3 +1236,6 @@ SDL_DYNAPI_PROC(bool,SDL_IsMainThread,(void),(),return) SDL_DYNAPI_PROC(bool,SDL_RunOnMainThread,(SDL_MainThreadCallback a,void *b,bool c),(a,b,c),return) SDL_DYNAPI_PROC(bool,SDL_SetGPUAllowedFramesInFlight,(SDL_GPUDevice *a,Uint32 b),(a,b),return) SDL_DYNAPI_PROC(bool,SDL_RenderTextureAffine,(SDL_Renderer *a,SDL_Texture *b,const SDL_FRect *c,const SDL_FPoint *d,const SDL_FPoint *e,const SDL_FPoint *f),(a,b,c,d,e,f),return) +SDL_DYNAPI_PROC(SDL_GPUPipelineCache*,SDL_CreateGPUPipelineCache,(SDL_GPUDevice *a,const SDL_GPUPipelineCacheCreateInfo *b),(a,b),return) +SDL_DYNAPI_PROC(bool,SDL_FetchGPUPipelineCacheData,(SDL_GPUDevice *a,SDL_GPUPipelineCache *b,SDL_GPUPipelineCacheCreateInfo *c),(a,b,c),return) +SDL_DYNAPI_PROC(void,SDL_ReleaseGPUPipelineCache,(SDL_GPUDevice *a,SDL_GPUPipelineCache *b),(a,b),) diff --git a/src/gpu/SDL_gpu.c b/src/gpu/SDL_gpu.c index 5763e793dd729..68b1bca66667a 100644 --- a/src/gpu/SDL_gpu.c +++ b/src/gpu/SDL_gpu.c @@ -862,6 +862,37 @@ SDL_GPUGraphicsPipeline *SDL_CreateGPUGraphicsPipeline( graphicsPipelineCreateInfo); } +SDL_GPUPipelineCache* SDL_CreateGPUPipelineCache( + SDL_GPUDevice* device, + const SDL_GPUPipelineCacheCreateInfo* createinfo) +{ + CHECK_DEVICE_MAGIC(device, NULL); + if (createinfo == NULL) { + SDL_InvalidParamError("createinfo"); + return NULL; + } + + return device->CreatePipelineCache(device->driverData, createinfo); +} + +bool SDL_FetchGPUPipelineCacheData( + SDL_GPUDevice* device, + SDL_GPUPipelineCache* pipeline_cache, + SDL_GPUPipelineCacheCreateInfo* createinfo) +{ + CHECK_DEVICE_MAGIC(device, false); + if (pipeline_cache == NULL) { + SDL_InvalidParamError("pipeline_cache"); + return false; + } + if (createinfo == NULL) { + SDL_InvalidParamError("createinfo"); + return false; + } + + return device->FetchPipelineCacheData(device->driverData, pipeline_cache, createinfo); +} + SDL_GPUSampler *SDL_CreateGPUSampler( SDL_GPUDevice *device, const SDL_GPUSamplerCreateInfo *createinfo) @@ -1279,6 +1310,20 @@ void SDL_ReleaseGPUGraphicsPipeline( graphics_pipeline); } +void SDL_ReleaseGPUPipelineCache( + SDL_GPUDevice* device, + SDL_GPUPipelineCache* pipeline_cache) +{ + CHECK_DEVICE_MAGIC(device, ); + if (pipeline_cache == NULL) { + return; + } + + device->ReleasePipelineCache( + device->driverData, + pipeline_cache); +} + // Command Buffer SDL_GPUCommandBuffer *SDL_AcquireGPUCommandBuffer( diff --git a/src/gpu/SDL_sysgpu.h b/src/gpu/SDL_sysgpu.h index 2cf8f6459b74a..451ca9ab32a8f 100644 --- a/src/gpu/SDL_sysgpu.h +++ b/src/gpu/SDL_sysgpu.h @@ -459,6 +459,15 @@ struct SDL_GPUDevice SDL_GPURenderer *driverData, const SDL_GPUGraphicsPipelineCreateInfo *createinfo); + SDL_GPUPipelineCache* (*CreatePipelineCache)( + SDL_GPURenderer* driverData, + const SDL_GPUPipelineCacheCreateInfo* createinfo); + + bool (*FetchPipelineCacheData)( + SDL_GPURenderer* driverData, + SDL_GPUPipelineCache* pipelineCache, + SDL_GPUPipelineCacheCreateInfo* createinfo); + SDL_GPUSampler *(*CreateSampler)( SDL_GPURenderer *driverData, const SDL_GPUSamplerCreateInfo *createinfo); @@ -534,6 +543,10 @@ struct SDL_GPUDevice SDL_GPURenderer *driverData, SDL_GPUGraphicsPipeline *graphicsPipeline); + void (*ReleasePipelineCache)( + SDL_GPURenderer* driverData, + SDL_GPUPipelineCache* pipelineCache); + // Render Pass void (*BeginRenderPass)( @@ -869,6 +882,8 @@ struct SDL_GPUDevice ASSIGN_DRIVER_FUNC(DestroyDevice, name) \ ASSIGN_DRIVER_FUNC(CreateComputePipeline, name) \ ASSIGN_DRIVER_FUNC(CreateGraphicsPipeline, name) \ + ASSIGN_DRIVER_FUNC(CreatePipelineCache, name) \ + ASSIGN_DRIVER_FUNC(FetchPipelineCacheData, name) \ ASSIGN_DRIVER_FUNC(CreateSampler, name) \ ASSIGN_DRIVER_FUNC(CreateShader, name) \ ASSIGN_DRIVER_FUNC(CreateTexture, name) \ @@ -886,6 +901,7 @@ struct SDL_GPUDevice ASSIGN_DRIVER_FUNC(ReleaseShader, name) \ ASSIGN_DRIVER_FUNC(ReleaseComputePipeline, name) \ ASSIGN_DRIVER_FUNC(ReleaseGraphicsPipeline, name) \ + ASSIGN_DRIVER_FUNC(ReleasePipelineCache, name) \ ASSIGN_DRIVER_FUNC(BeginRenderPass, name) \ ASSIGN_DRIVER_FUNC(BindGraphicsPipeline, name) \ ASSIGN_DRIVER_FUNC(SetViewport, name) \ diff --git a/src/gpu/d3d12/SDL_gpu_d3d12.c b/src/gpu/d3d12/SDL_gpu_d3d12.c index 7b024f0b024b6..45708ad593953 100644 --- a/src/gpu/d3d12/SDL_gpu_d3d12.c +++ b/src/gpu/d3d12/SDL_gpu_d3d12.c @@ -2875,6 +2875,23 @@ static SDL_GPUGraphicsPipeline *D3D12_CreateGraphicsPipeline( return (SDL_GPUGraphicsPipeline *)pipeline; } +static SDL_GPUPipelineCache* D3D12_CreatePipelineCache( + SDL_GPURenderer* driverData, + const SDL_GPUPipelineCacheCreateInfo* createinfo) +{ + // Not yet implemented + return NULL; +} + +static bool D3D12_FetchPipelineCacheData( + SDL_GPURenderer* driverData, + SDL_GPUPipelineCache* pipelineCache, + SDL_GPUPipelineCacheCreateInfo* createinfo) +{ + // Not yet implemented + return false; +} + static SDL_GPUSampler *D3D12_CreateSampler( SDL_GPURenderer *driverData, const SDL_GPUSamplerCreateInfo *createinfo) @@ -3854,6 +3871,13 @@ static void D3D12_INTERNAL_ReleaseBlitPipelines(SDL_GPURenderer *driverData) SDL_free(renderer->blitPipelines); } +static void D3D12_ReleasePipelineCache( + SDL_GPURenderer* driverData, + SDL_GPUPipelineCache* pipelineCache) +{ + // Not yet implemented +} + // Render Pass static void D3D12_SetViewport( diff --git a/src/gpu/metal/SDL_gpu_metal.m b/src/gpu/metal/SDL_gpu_metal.m index 981355a3ad88b..2dc3cdb5ac5a1 100644 --- a/src/gpu/metal/SDL_gpu_metal.m +++ b/src/gpu/metal/SDL_gpu_metal.m @@ -513,6 +513,17 @@ static MTLDepthClipMode SDLToMetal_DepthClipMode( Uint32 threadcountZ; } MetalComputePipeline; +/* +typedef struct MetalPipelineCache +{ + id pipelineCache; + size_t checksumSize; + void* checksumData; + size_t cacheBlobSize; + void* cacheBlob; +} MetalPipelineCache; +*/ + typedef struct MetalBuffer { id handle; @@ -1018,6 +1029,26 @@ static void METAL_ReleaseGraphicsPipeline( } } +static void METAL_ReleasePipelineCache( + SDL_GPURenderer* driverData, + SDL_GPUPipelineCache* pipelineCache) +{ + /* + @autoreleasepool { + MetalRenderer* renderer = (MetalRenderer*)driverData; + MetalPipelineCache* metalPipelineCache = (MetalPipelineCache*)pipelineCache; + + if (metalPipelineCache->checksumData != NULL) + { + SDL_free(metalPipelineCache->checksumData); + metalPipelineCache->checksumSize = 0; + } + metalPipelineCache->pipelineCache = nil; + SDL_free(metalPipelineCache); + } + */ +} + // Pipeline Creation static SDL_GPUComputePipeline *METAL_CreateComputePipeline( @@ -1071,6 +1102,11 @@ static void METAL_ReleaseGraphicsPipeline( MetalRenderer *renderer = (MetalRenderer *)driverData; MetalShader *vertexShader = (MetalShader *)createinfo->vertex_shader; MetalShader *fragmentShader = (MetalShader *)createinfo->fragment_shader; + + /* + MetalPipelineCache* pipelineCache = SDL_GetPointerProperty_REAL(createinfo->props,SDL_PROP_GPU_PIPELINE_USE_CACHE,NULL); + */ + MTLRenderPipelineDescriptor *pipelineDescriptor; const SDL_GPUColorTargetBlendState *blendState; MTLVertexDescriptor *vertexDescriptor; @@ -1084,7 +1120,17 @@ static void METAL_ReleaseGraphicsPipeline( MetalGraphicsPipeline *result = NULL; pipelineDescriptor = [MTLRenderPipelineDescriptor new]; - + + /* + if(@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) + { + if(pipelineCache->pipelineCache != nil) + { + pipelineDescriptor.binaryArchives = @[pipelineCache->pipelineCache]; + } + } + */ + // Blend for (Uint32 i = 0; i < createinfo->target_info.num_color_targets; i += 1) { @@ -1171,7 +1217,16 @@ static void METAL_ReleaseGraphicsPipeline( pipelineDescriptor.vertexDescriptor = vertexDescriptor; } - + + /* + if(@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) + { + if(pipelineCache != NULL){ + [pipelineCache->pipelineCache addRenderPipelineFunctionsWithDescriptor:pipelineDescriptor error:&error]; + } + } + */ + // Create the graphics pipeline pipelineState = [renderer->device newRenderPipelineStateWithDescriptor:pipelineDescriptor error:&error]; @@ -1201,6 +1256,60 @@ static void METAL_ReleaseGraphicsPipeline( } } +static SDL_GPUPipelineCache* METAL_CreatePipelineCache( + SDL_GPURenderer* driverData, + const SDL_GPUPipelineCacheCreateInfo* createinfo) +{ + // Implementing it is easy, but there's not way to get the binary data out of MTLBinaryArchive without bouncing it to a file first + /* + if(@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)){ + @autoreleasepool { + MetalRenderer* renderer = (MetalRenderer*)driverData; + MetalPipelineCache* pipelineCache = (MetalPipelineCache*)SDL_malloc(sizeof(MetalPipelineCache)); + + MTLBinaryArchiveDescriptor* archiveDescriptor = [[MTLBinaryArchiveDescriptor alloc] init]; + NSError* error; + pipelineCache->pipelineCache = [renderer->device newBinaryArchiveWithDescriptor:archiveDescriptor error:&error]; + + if (error != NULL) { + SET_ERROR_AND_RETURN("Creating pipeline cache failed: %s", [[error description] UTF8String], NULL); + } + if (createinfo->checksum_size != 0 && createinfo->checksum_data != NULL) + { + pipelineCache->checksumSize = createinfo->checksum_size; + pipelineCache->checksumData = SDL_malloc(createinfo->checksum_size); + SDL_memcpy(pipelineCache->checksumData, createinfo->checksum_data, createinfo->checksum_size); + } + else + { + pipelineCache->checksumSize = 0; + pipelineCache->checksumData = NULL; + } + return (SDL_GPUPipelineCache*)pipelineCache; + } + } + else{ + return NULL; + } + */ + return NULL; +} + +static bool METAL_FetchPipelineCacheData( + SDL_GPURenderer* driverData, + SDL_GPUPipelineCache* pipelineCache, + SDL_GPUPipelineCacheCreateInfo* createinfo) +{ + /* + MetalRenderer* renderer = (MetalRenderer*)driverData; + MetalPipelineCache* metalPipelineCache = (MetalPipelineCache*)pipelineCache; + createinfo->checksum_size = metalPipelineCache->checksumSize; + createinfo->checksum_data = metalPipelineCache->checksumData; + return true; + */ + return false; +} + // Debug Naming static void METAL_SetBufferName( diff --git a/src/gpu/vulkan/SDL_gpu_vulkan.c b/src/gpu/vulkan/SDL_gpu_vulkan.c index 359aecdfeb0f8..7c7a7f3a018e6 100644 --- a/src/gpu/vulkan/SDL_gpu_vulkan.c +++ b/src/gpu/vulkan/SDL_gpu_vulkan.c @@ -906,6 +906,15 @@ typedef struct VulkanComputePipeline SDL_AtomicInt referenceCount; } VulkanComputePipeline; +typedef struct VulkanPipelineCache +{ + VkPipelineCache pipelineCache; + size_t checksumSize; + void* checksumData; + size_t cacheBlobSize; + void* cacheBlob; +} VulkanPipelineCache; + typedef struct RenderPassColorTargetDescription { VkFormat format; @@ -6153,6 +6162,8 @@ static SDL_GPUGraphicsPipeline *VULKAN_CreateGraphicsPipeline( VulkanGraphicsPipeline *graphicsPipeline = (VulkanGraphicsPipeline *)SDL_malloc(sizeof(VulkanGraphicsPipeline)); VkGraphicsPipelineCreateInfo vkPipelineCreateInfo; + VulkanPipelineCache* pipelineCache = SDL_GetPointerProperty(createinfo->props, SDL_PROP_GPU_PIPELINE_USE_CACHE, NULL); + VkPipelineShaderStageCreateInfo shaderStageCreateInfos[2]; VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo; @@ -6448,15 +6459,21 @@ static SDL_GPUGraphicsPipeline *VULKAN_CreateGraphicsPipeline( vkPipelineCreateInfo.basePipelineHandle = VK_NULL_HANDLE; vkPipelineCreateInfo.basePipelineIndex = 0; - // TODO: enable pipeline caching vulkanResult = renderer->vkCreateGraphicsPipelines( renderer->logicalDevice, - VK_NULL_HANDLE, + (pipelineCache != NULL) ? pipelineCache->pipelineCache : VK_NULL_HANDLE, 1, &vkPipelineCreateInfo, NULL, &graphicsPipeline->pipeline); + if (pipelineCache != NULL) + { + renderer->vkGetPipelineCacheData(renderer->logicalDevice, pipelineCache->pipelineCache, &pipelineCache->cacheBlobSize, NULL); + pipelineCache->cacheBlob = SDL_realloc(pipelineCache->cacheBlob, pipelineCache->cacheBlobSize); + renderer->vkGetPipelineCacheData(renderer->logicalDevice, pipelineCache->pipelineCache, &pipelineCache->cacheBlobSize, pipelineCache->cacheBlob); + } + SDL_stack_free(vertexInputBindingDescriptions); SDL_stack_free(vertexInputAttributeDescriptions); SDL_stack_free(colorBlendAttachmentStates); @@ -6488,6 +6505,8 @@ static SDL_GPUComputePipeline *VULKAN_CreateComputePipeline( VulkanRenderer *renderer = (VulkanRenderer *)driverData; VulkanComputePipeline *vulkanComputePipeline; + VulkanPipelineCache* pipelineCache = SDL_GetPointerProperty(createinfo->props, SDL_PROP_GPU_PIPELINE_USE_CACHE, NULL); + if (createinfo->format != SDL_GPU_SHADERFORMAT_SPIRV) { SET_STRING_ERROR_AND_RETURN("Incompatible shader format for Vulkan!", NULL); } @@ -6541,12 +6560,19 @@ static SDL_GPUComputePipeline *VULKAN_CreateComputePipeline( vulkanResult = renderer->vkCreateComputePipelines( renderer->logicalDevice, - (VkPipelineCache)VK_NULL_HANDLE, + (pipelineCache != NULL) ? pipelineCache->pipelineCache : VK_NULL_HANDLE, 1, &vkShaderCreateInfo, NULL, &vulkanComputePipeline->pipeline); + if (pipelineCache != NULL) + { + renderer->vkGetPipelineCacheData(renderer->logicalDevice, pipelineCache->pipelineCache, &pipelineCache->cacheBlobSize, NULL); + SDL_realloc(pipelineCache->cacheBlob, pipelineCache->cacheBlobSize); + renderer->vkGetPipelineCacheData(renderer->logicalDevice, pipelineCache->pipelineCache, &pipelineCache->cacheBlobSize, &pipelineCache->cacheBlobSize); + } + if (vulkanResult != VK_SUCCESS) { VULKAN_INTERNAL_DestroyComputePipeline(renderer, vulkanComputePipeline); CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateComputePipeline, NULL); @@ -6558,6 +6584,78 @@ static SDL_GPUComputePipeline *VULKAN_CreateComputePipeline( return (SDL_GPUComputePipeline *)vulkanComputePipeline; } +static SDL_GPUPipelineCache* VULKAN_CreatePipelineCache( + SDL_GPURenderer* driverData, + const SDL_GPUPipelineCacheCreateInfo* createinfo) +{ + VulkanRenderer* renderer = (VulkanRenderer*)driverData; + VulkanPipelineCache* pipelineCache = (VulkanPipelineCache*)SDL_malloc(sizeof(VulkanPipelineCache)); + VkPipelineCache vkPipelineCache; + VkResult vulkanResult; + + // Here I'll eventually need to implement the checksum control + VkPipelineCacheCreateInfo vkPipelineCacheInfo; + vkPipelineCacheInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO; + vkPipelineCacheInfo.pNext = NULL; + vkPipelineCacheInfo.flags = 0; + vkPipelineCacheInfo.initialDataSize = createinfo->cache_size; + vkPipelineCacheInfo.pInitialData = createinfo->cache_data; + + vulkanResult = renderer->vkCreatePipelineCache( + renderer->logicalDevice, + &vkPipelineCacheInfo, + NULL, + &vkPipelineCache); + + if (vulkanResult != VK_SUCCESS) + { + SDL_free(pipelineCache); + CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreatePipelineCache, NULL); + return NULL; + } + + pipelineCache->pipelineCache = vkPipelineCache; + + if (createinfo->cache_size != 0 && createinfo->cache_data != NULL) + { + pipelineCache->cacheBlobSize = createinfo->cache_size; + pipelineCache->cacheBlob = SDL_malloc(createinfo->cache_size); + SDL_memcpy(pipelineCache->cacheBlob, createinfo->cache_data, createinfo->cache_size); + } + else + { + pipelineCache->cacheBlobSize = 0; + pipelineCache->cacheBlob = NULL; + } + if (createinfo->checksum_size != 0 && createinfo->checksum_data != NULL) + { + pipelineCache->checksumSize = createinfo->checksum_size; + pipelineCache->checksumData = SDL_malloc(createinfo->checksum_size); + SDL_memcpy(pipelineCache->checksumData, createinfo->checksum_data, createinfo->checksum_size); + } + else + { + pipelineCache->checksumSize = 0; + pipelineCache->checksumData = NULL; + } + + return (SDL_GPUPipelineCache*)pipelineCache; +} + +static bool VULKAN_FetchPipelineCacheData( + SDL_GPURenderer* driverData, + SDL_GPUPipelineCache* pipelineCache, + SDL_GPUPipelineCacheCreateInfo* createinfo) +{ + VulkanPipelineCache* vulkanPipelineCache = (VulkanPipelineCache*)pipelineCache; + createinfo->checksum_size = vulkanPipelineCache->checksumSize; + createinfo->checksum_data = vulkanPipelineCache->checksumData; + createinfo->cache_size = vulkanPipelineCache->cacheBlobSize; + createinfo->cache_data = vulkanPipelineCache->cacheBlob; + + return true; +} + static SDL_GPUSampler *VULKAN_CreateSampler( SDL_GPURenderer *driverData, const SDL_GPUSamplerCreateInfo *createinfo) @@ -6945,6 +7043,27 @@ static void VULKAN_ReleaseGraphicsPipeline( SDL_UnlockMutex(renderer->disposeLock); } +static void VULKAN_ReleasePipelineCache( + SDL_GPURenderer* driverData, + SDL_GPUPipelineCache* pipelineCache) +{ + VulkanRenderer* renderer = (VulkanRenderer*)driverData; + VulkanPipelineCache* vulkanPipelineCache = (VulkanPipelineCache*)pipelineCache; + + if (vulkanPipelineCache->cacheBlob != NULL) + { + SDL_free(vulkanPipelineCache->cacheBlob); + vulkanPipelineCache->cacheBlobSize = 0; + } + if (vulkanPipelineCache->checksumData != NULL) + { + SDL_free(vulkanPipelineCache->checksumData); + vulkanPipelineCache->checksumSize = 0; + } + renderer->vkDestroyPipelineCache(renderer->logicalDevice, vulkanPipelineCache->pipelineCache, NULL); + SDL_free(vulkanPipelineCache); +} + // Command Buffer render state static VkRenderPass VULKAN_INTERNAL_FetchRenderPass(