diff options
author | Niklas Haas <git@haasn.xyz> | 2017-09-13 03:09:48 +0200 |
---|---|---|
committer | Niklas Haas <git@haasn.xyz> | 2017-09-26 17:25:35 +0200 |
commit | 258487370fd840b018a404225277d74f74899c59 (patch) | |
tree | 83a9a112d141f08a87d290ddf0aa57ea04fbf60a /video/out/vulkan | |
parent | 91f23c7067af248846420854a0dc78c26ea6e300 (diff) | |
download | mpv-258487370fd840b018a404225277d74f74899c59.tar.bz2 mpv-258487370fd840b018a404225277d74f74899c59.tar.xz |
vo_gpu: vulkan: generalize SPIR-V compiler
In addition to the built-in nvidia compiler, we now also support a
backend based on libshaderc. shaderc is sort of like glslang except it
has a C API and is available as a dynamic library.
The generated SPIR-V is now cached alongside the VkPipeline in the
cached_program. We use a special cache header to ensure validity of this
cache before passing it blindly to the vulkan implementation, since
passing invalid SPIR-V can cause all sorts of nasty things. It's also
designed to self-invalidate if the compiler gets better, by offering a
catch-all `int compiler_version` that implementations can use as a cache
invalidation marker.
Diffstat (limited to 'video/out/vulkan')
-rw-r--r-- | video/out/vulkan/common.h | 1 | ||||
-rw-r--r-- | video/out/vulkan/context.c | 16 | ||||
-rw-r--r-- | video/out/vulkan/context.h | 3 | ||||
-rw-r--r-- | video/out/vulkan/ra_vk.c | 275 | ||||
-rw-r--r-- | video/out/vulkan/spirv_nvidia.c | 54 | ||||
-rw-r--r-- | video/out/vulkan/utils.c | 28 |
6 files changed, 288 insertions, 89 deletions
diff --git a/video/out/vulkan/common.h b/video/out/vulkan/common.h index 4c0e783f0e..d0d14e28c2 100644 --- a/video/out/vulkan/common.h +++ b/video/out/vulkan/common.h @@ -45,6 +45,7 @@ struct mpvk_ctx { struct vk_malloc *alloc; // memory allocator for this device struct vk_cmdpool *pool; // primary command pool for this device struct vk_cmd *last_cmd; // most recently submitted command + struct spirv_compiler *spirv; // GLSL -> SPIR-V compiler // Cached capabilities VkPhysicalDeviceLimits limits; diff --git a/video/out/vulkan/context.c b/video/out/vulkan/context.c index bd456d214c..d2445fbda7 100644 --- a/video/out/vulkan/context.c +++ b/video/out/vulkan/context.c @@ -16,6 +16,8 @@ */ #include "options/m_config.h" +#include "video/out/gpu/spirv.h" + #include "context.h" #include "ra_vk.h" #include "utils.h" @@ -125,6 +127,17 @@ struct priv { int last_imgidx; // the image index last acquired (for submit) }; +static const struct ra_swapchain_fns vulkan_swapchain; + +struct mpvk_ctx *ra_vk_ctx_get(struct ra_ctx *ctx) +{ + if (ctx->swapchain->fns != &vulkan_swapchain) + return NULL; + + struct priv *p = ctx->swapchain->priv; + return p->vk; +} + static bool update_swapchain_info(struct priv *p, VkSwapchainCreateInfoKHR *info) { @@ -265,6 +278,9 @@ bool ra_vk_ctx_init(struct ra_ctx *ctx, struct mpvk_ctx *vk, if (!mpvk_find_phys_device(vk, p->opts->device, ctx->opts.allow_sw)) goto error; + if (!spirv_compiler_init(ctx)) + goto error; + vk->spirv = ctx->spirv; if (!mpvk_pick_surface_format(vk)) goto error; if (!mpvk_device_init(vk, p->opts->dev_opts)) diff --git a/video/out/vulkan/context.h b/video/out/vulkan/context.h index 3f630bc10e..a64d39f125 100644 --- a/video/out/vulkan/context.h +++ b/video/out/vulkan/context.h @@ -8,3 +8,6 @@ void ra_vk_ctx_uninit(struct ra_ctx *ctx); bool ra_vk_ctx_init(struct ra_ctx *ctx, struct mpvk_ctx *vk, VkPresentModeKHR preferred_mode); bool ra_vk_ctx_resize(struct ra_swapchain *sw, int w, int h); + +// May be called on a ra_ctx of any type. +struct mpvk_ctx *ra_vk_ctx_get(struct ra_ctx *ctx); diff --git a/video/out/vulkan/ra_vk.c b/video/out/vulkan/ra_vk.c index ce0cbc66e9..897b2e1ff1 100644 --- a/video/out/vulkan/ra_vk.c +++ b/video/out/vulkan/ra_vk.c @@ -1,6 +1,8 @@ +#include "video/out/gpu/utils.h" +#include "video/out/gpu/spirv.h" + #include "ra_vk.h" #include "malloc.h" -#include "video/out/opengl/utils.h" static struct ra_fns ra_fns_vk; @@ -185,13 +187,10 @@ struct ra *ra_create_vk(struct mpvk_ctx *vk, struct mp_log *log) struct ra_vk *p = ra->priv = talloc_zero(ra, struct ra_vk); p->vk = vk; - // There's no way to query the supported GLSL version from VK_NV_glsl_shader - // (thanks nvidia), so just pick the GL version that modern nvidia devices - // support.. - ra->glsl_version = 450; + ra->caps |= vk->spirv->ra_caps; + ra->glsl_version = vk->spirv->glsl_version; ra->glsl_vulkan = true; ra->max_shmem = vk->limits.maxComputeSharedMemorySize; - ra->caps = RA_CAP_NESTED_ARRAY; if (vk->pool->props.queueFlags & VK_QUEUE_COMPUTE_BIT) ra->caps |= RA_CAP_COMPUTE; @@ -821,14 +820,9 @@ error: // For ra_renderpass.priv struct ra_renderpass_vk { - // Compiled shaders - VkShaderModule vert; - VkShaderModule frag; - VkShaderModule comp; // Pipeline / render pass VkPipeline pipe; VkPipelineLayout pipeLayout; - VkPipelineCache pipeCache; VkRenderPass renderPass; // Descriptor set (bindings) VkDescriptorSetLayout dsLayout; @@ -854,14 +848,10 @@ static void vk_renderpass_destroy(struct ra *ra, struct ra_renderpass *pass) ra_buf_pool_uninit(ra, &pass_vk->vbo); vkDestroyPipeline(vk->dev, pass_vk->pipe, MPVK_ALLOCATOR); - vkDestroyPipelineCache(vk->dev, pass_vk->pipeCache, MPVK_ALLOCATOR); vkDestroyRenderPass(vk->dev, pass_vk->renderPass, MPVK_ALLOCATOR); vkDestroyPipelineLayout(vk->dev, pass_vk->pipeLayout, MPVK_ALLOCATOR); vkDestroyDescriptorPool(vk->dev, pass_vk->dsPool, MPVK_ALLOCATOR); vkDestroyDescriptorSetLayout(vk->dev, pass_vk->dsLayout, MPVK_ALLOCATOR); - vkDestroyShaderModule(vk->dev, pass_vk->vert, MPVK_ALLOCATOR); - vkDestroyShaderModule(vk->dev, pass_vk->frag, MPVK_ALLOCATOR); - vkDestroyShaderModule(vk->dev, pass_vk->comp, MPVK_ALLOCATOR); talloc_free(pass); } @@ -909,6 +899,82 @@ static bool vk_get_input_format(struct ra *ra, struct ra_renderpass_input *inp, return false; } +static const char vk_cache_magic[4] = {'R','A','V','K'}; +static const int vk_cache_version = 2; + +struct vk_cache_header { + char magic[sizeof(vk_cache_magic)]; + int cache_version; + char compiler[SPIRV_NAME_MAX_LEN]; + int compiler_version; + size_t vert_spirv_len; + size_t frag_spirv_len; + size_t comp_spirv_len; + size_t pipecache_len; +}; + +static bool vk_use_cached_program(const struct ra_renderpass_params *params, + const struct spirv_compiler *spirv, + struct bstr *vert_spirv, + struct bstr *frag_spirv, + struct bstr *comp_spirv, + struct bstr *pipecache) +{ + struct bstr cache = params->cached_program; + if (cache.len < sizeof(struct vk_cache_header)) + return false; + + struct vk_cache_header *header = (struct vk_cache_header *)cache.start; + cache = bstr_cut(cache, sizeof(*header)); + + if (strncmp(header->magic, vk_cache_magic, sizeof(vk_cache_magic)) != 0) + return false; + if (header->cache_version != vk_cache_version) + return false; + if (strncmp(header->compiler, spirv->name, sizeof(header->compiler)) != 0) + return false; + if (header->compiler_version != spirv->compiler_version) + return false; + +#define GET(ptr) \ + if (cache.len < header->ptr##_len) \ + return false; \ + *ptr = bstr_splice(cache, 0, header->ptr##_len); \ + cache = bstr_cut(cache, ptr->len); + + GET(vert_spirv); + GET(frag_spirv); + GET(comp_spirv); + GET(pipecache); + return true; +} + +static VkResult vk_compile_glsl(struct ra *ra, void *tactx, + enum glsl_shader type, const char *glsl, + struct bstr *spirv) +{ + struct mpvk_ctx *vk = ra_vk_get(ra); + VkResult ret = VK_SUCCESS; + int msgl = MSGL_DEBUG; + + if (!vk->spirv->fns->compile_glsl(vk->spirv, tactx, type, glsl, spirv)) { + ret = VK_ERROR_INVALID_SHADER_NV; + msgl = MSGL_ERR; + } + + static const char *shader_names[] = { + [GLSL_SHADER_VERTEX] = "vertex", + [GLSL_SHADER_FRAGMENT] = "fragment", + [GLSL_SHADER_COMPUTE] = "compute", + }; + + if (mp_msg_test(ra->log, msgl)) { + MP_MSG(ra, msgl, "%s shader source:\n", shader_names[type]); + mp_log_source(ra->log, msgl, glsl); + } + return ret; +} + static const VkPipelineStageFlagBits stageFlags[] = { [RA_RENDERPASS_TYPE_RASTER] = VK_SHADER_STAGE_FRAGMENT_BIT, [RA_RENDERPASS_TYPE_COMPUTE] = VK_SHADER_STAGE_COMPUTE_BIT, @@ -918,6 +984,8 @@ static struct ra_renderpass *vk_renderpass_create(struct ra *ra, const struct ra_renderpass_params *params) { struct mpvk_ctx *vk = ra_vk_get(ra); + bool success = false; + assert(vk->spirv); struct ra_renderpass *pass = talloc_zero(NULL, struct ra_renderpass); pass->params = *ra_renderpass_params_copy(pass, params); @@ -925,6 +993,13 @@ static struct ra_renderpass *vk_renderpass_create(struct ra *ra, struct ra_renderpass_vk *pass_vk = pass->priv = talloc_zero(pass, struct ra_renderpass_vk); + // temporary allocations/objects + void *tmp = talloc_new(NULL); + VkPipelineCache pipeCache = NULL; + VkShaderModule vert_shader = NULL; + VkShaderModule frag_shader = NULL; + VkShaderModule comp_shader = NULL; + static int dsCount[RA_VARTYPE_COUNT] = {0}; VkDescriptorSetLayoutBinding *bindings = NULL; int num_bindings = 0; @@ -943,7 +1018,7 @@ static struct ra_renderpass *vk_renderpass_create(struct ra *ra, .stageFlags = stageFlags[params->type], }; - MP_TARRAY_APPEND(pass, bindings, num_bindings, desc); + MP_TARRAY_APPEND(tmp, bindings, num_bindings, desc); dsCount[inp->type]++; break; } @@ -953,6 +1028,7 @@ static struct ra_renderpass *vk_renderpass_create(struct ra *ra, VkDescriptorPoolSize *dsPoolSizes = NULL; int poolSizeCount = 0; + for (enum ra_vartype t = 0; t < RA_VARTYPE_COUNT; t++) { if (dsCount[t] > 0) { VkDescriptorPoolSize dssize = { @@ -960,7 +1036,7 @@ static struct ra_renderpass *vk_renderpass_create(struct ra *ra, .descriptorCount = dsCount[t] * MPVK_NUM_DS, }; - MP_TARRAY_APPEND(pass, dsPoolSizes, poolSizeCount, dssize); + MP_TARRAY_APPEND(tmp, dsPoolSizes, poolSizeCount, dssize); } } @@ -972,7 +1048,6 @@ static struct ra_renderpass *vk_renderpass_create(struct ra *ra, }; VK(vkCreateDescriptorPool(vk->dev, &pinfo, MPVK_ALLOCATOR, &pass_vk->dsPool)); - talloc_free(dsPoolSizes); pass_vk->dswrite = talloc_array(pass, VkWriteDescriptorSet, num_bindings); pass_vk->dsiinfo = talloc_array(pass, VkDescriptorImageInfo, num_bindings); @@ -1009,13 +1084,35 @@ static struct ra_renderpass *vk_renderpass_create(struct ra *ra, VK(vkCreatePipelineLayout(vk->dev, &linfo, MPVK_ALLOCATOR, &pass_vk->pipeLayout)); + struct bstr vert = {0}, frag = {0}, comp = {0}, pipecache = {0}; + if (vk_use_cached_program(params, vk->spirv, &vert, &frag, &comp, &pipecache)) { + MP_VERBOSE(ra, "Using cached SPIR-V and VkPipeline.\n"); + } else { + pipecache.len = 0; + switch (params->type) { + case RA_RENDERPASS_TYPE_RASTER: + VK(vk_compile_glsl(ra, tmp, GLSL_SHADER_VERTEX, + params->vertex_shader, &vert)); + VK(vk_compile_glsl(ra, tmp, GLSL_SHADER_FRAGMENT, + params->frag_shader, &frag)); + comp.len = 0; + break; + case RA_RENDERPASS_TYPE_COMPUTE: + VK(vk_compile_glsl(ra, tmp, GLSL_SHADER_COMPUTE, + params->compute_shader, &comp)); + frag.len = 0; + vert.len = 0; + break; + } + } + VkPipelineCacheCreateInfo pcinfo = { .sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, - .pInitialData = params->cached_program.start, - .initialDataSize = params->cached_program.len, + .pInitialData = pipecache.start, + .initialDataSize = pipecache.len, }; - VK(vkCreatePipelineCache(vk->dev, &pcinfo, MPVK_ALLOCATOR, &pass_vk->pipeCache)); + VK(vkCreatePipelineCache(vk->dev, &pcinfo, MPVK_ALLOCATOR, &pipeCache)); VkShaderModuleCreateInfo sinfo = { .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, @@ -1023,33 +1120,15 @@ static struct ra_renderpass *vk_renderpass_create(struct ra *ra, switch (params->type) { case RA_RENDERPASS_TYPE_RASTER: { - sinfo.pCode = (uint32_t *)params->vertex_shader; - sinfo.codeSize = strlen(params->vertex_shader); - VK(vkCreateShaderModule(vk->dev, &sinfo, MPVK_ALLOCATOR, &pass_vk->vert)); + sinfo.pCode = (uint32_t *)vert.start; + sinfo.codeSize = vert.len; + VK(vkCreateShaderModule(vk->dev, &sinfo, MPVK_ALLOCATOR, &vert_shader)); - sinfo.pCode = (uint32_t *)params->frag_shader; - sinfo.codeSize = strlen(params->frag_shader); - VK(vkCreateShaderModule(vk->dev, &sinfo, MPVK_ALLOCATOR, &pass_vk->frag)); + sinfo.pCode = (uint32_t *)frag.start; + sinfo.codeSize = frag.len; + VK(vkCreateShaderModule(vk->dev, &sinfo, MPVK_ALLOCATOR, &frag_shader)); - VK(vk_create_render_pass(vk->dev, params->target_format, - params->enable_blend, &pass_vk->renderPass)); - - VkPipelineShaderStageCreateInfo stages[] = { - { - .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, - .stage = VK_SHADER_STAGE_VERTEX_BIT, - .module = pass_vk->vert, - .pName = "main", - }, - { - .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, - .stage = VK_SHADER_STAGE_FRAGMENT_BIT, - .module = pass_vk->frag, - .pName = "main", - } - }; - - VkVertexInputAttributeDescription *attrs = talloc_array(pass, + VkVertexInputAttributeDescription *attrs = talloc_array(tmp, VkVertexInputAttributeDescription, params->num_vertex_attribs); for (int i = 0; i < params->num_vertex_attribs; i++) { @@ -1066,6 +1145,8 @@ static struct ra_renderpass *vk_renderpass_create(struct ra *ra, goto error; } } + VK(vk_create_render_pass(vk->dev, params->target_format, + params->enable_blend, &pass_vk->renderPass)); static const VkBlendFactor blendFactors[] = { [RA_BLEND_ZERO] = VK_BLEND_FACTOR_ZERO, @@ -1074,24 +1155,22 @@ static struct ra_renderpass *vk_renderpass_create(struct ra *ra, [RA_BLEND_ONE_MINUS_SRC_ALPHA] = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, }; - VkPipelineColorBlendAttachmentState binfo = { - .blendEnable = params->enable_blend, - .colorBlendOp = VK_BLEND_OP_ADD, - .srcColorBlendFactor = blendFactors[params->blend_src_rgb], - .dstColorBlendFactor = blendFactors[params->blend_dst_rgb], - .alphaBlendOp = VK_BLEND_OP_ADD, - .srcAlphaBlendFactor = blendFactors[params->blend_src_alpha], - .dstAlphaBlendFactor = blendFactors[params->blend_dst_alpha], - .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | - VK_COLOR_COMPONENT_G_BIT | - VK_COLOR_COMPONENT_B_BIT | - VK_COLOR_COMPONENT_A_BIT, - }; - VkGraphicsPipelineCreateInfo cinfo = { .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, - .stageCount = MP_ARRAY_SIZE(stages), - .pStages = &stages[0], + .stageCount = 2, + .pStages = (VkPipelineShaderStageCreateInfo[]) { + { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .stage = VK_SHADER_STAGE_VERTEX_BIT, + .module = vert_shader, + .pName = "main", + }, { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .stage = VK_SHADER_STAGE_FRAGMENT_BIT, + .module = frag_shader, + .pName = "main", + } + }, .pVertexInputState = &(VkPipelineVertexInputStateCreateInfo) { .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, .vertexBindingDescriptionCount = 1, @@ -1125,7 +1204,19 @@ static struct ra_renderpass *vk_renderpass_create(struct ra *ra, .pColorBlendState = &(VkPipelineColorBlendStateCreateInfo) { .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, .attachmentCount = 1, - .pAttachments = &binfo, + .pAttachments = &(VkPipelineColorBlendAttachmentState) { + .blendEnable = params->enable_blend, + .colorBlendOp = VK_BLEND_OP_ADD, + .srcColorBlendFactor = blendFactors[params->blend_src_rgb], + .dstColorBlendFactor = blendFactors[params->blend_dst_rgb], + .alphaBlendOp = VK_BLEND_OP_ADD, + .srcAlphaBlendFactor = blendFactors[params->blend_src_alpha], + .dstAlphaBlendFactor = blendFactors[params->blend_dst_alpha], + .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | + VK_COLOR_COMPONENT_G_BIT | + VK_COLOR_COMPONENT_B_BIT | + VK_COLOR_COMPONENT_A_BIT, + }, }, .pDynamicState = &(VkPipelineDynamicStateCreateInfo) { .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, @@ -1139,43 +1230,73 @@ static struct ra_renderpass *vk_renderpass_create(struct ra *ra, .renderPass = pass_vk->renderPass, }; - VK(vkCreateGraphicsPipelines(vk->dev, pass_vk->pipeCache, 1, &cinfo, + VK(vkCreateGraphicsPipelines(vk->dev, pipeCache, 1, &cinfo, MPVK_ALLOCATOR, &pass_vk->pipe)); break; } case RA_RENDERPASS_TYPE_COMPUTE: { - sinfo.pCode = (uint32_t *)params->compute_shader; - sinfo.codeSize = strlen(params->compute_shader); - VK(vkCreateShaderModule(vk->dev, &sinfo, MPVK_ALLOCATOR, &pass_vk->comp)); + sinfo.pCode = (uint32_t *)comp.start; + sinfo.codeSize = comp.len; + VK(vkCreateShaderModule(vk->dev, &sinfo, MPVK_ALLOCATOR, &comp_shader)); VkComputePipelineCreateInfo cinfo = { .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, .stage = { .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, .stage = VK_SHADER_STAGE_COMPUTE_BIT, - .module = pass_vk->comp, + .module = comp_shader, .pName = "main", }, .layout = pass_vk->pipeLayout, }; - VK(vkCreateComputePipelines(vk->dev, pass_vk->pipeCache, 1, &cinfo, + VK(vkCreateComputePipelines(vk->dev, pipeCache, 1, &cinfo, MPVK_ALLOCATOR, &pass_vk->pipe)); break; } } - // Update cached program - bstr *prog = &pass->params.cached_program; - VK(vkGetPipelineCacheData(vk->dev, pass_vk->pipeCache, &prog->len, NULL)); - prog->start = talloc_size(pass, prog->len); - VK(vkGetPipelineCacheData(vk->dev, pass_vk->pipeCache, &prog->len, prog->start)); + // Update params->cached_program + struct bstr cache = {0}; + VK(vkGetPipelineCacheData(vk->dev, pipeCache, &cache.len, NULL)); + cache.start = talloc_size(tmp, cache.len); + VK(vkGetPipelineCacheData(vk->dev, pipeCache, &cache.len, cache.start)); + + struct vk_cache_header header = { + .cache_version = vk_cache_version, + .compiler_version = vk->spirv->compiler_version, + .vert_spirv_len = vert.len, + .frag_spirv_len = frag.len, + .comp_spirv_len = comp.len, + .pipecache_len = cache.len, + }; - return pass; + for (int i = 0; i < MP_ARRAY_SIZE(header.magic); i++) + header.magic[i] = vk_cache_magic[i]; + for (int i = 0; i < sizeof(vk->spirv->name); i++) + header.compiler[i] = vk->spirv->name[i]; + + struct bstr *prog = &pass->params.cached_program; + bstr_xappend(pass, prog, (struct bstr){ (char *) &header, sizeof(header) }); + bstr_xappend(pass, prog, vert); + bstr_xappend(pass, prog, frag); + bstr_xappend(pass, prog, comp); + bstr_xappend(pass, prog, cache); + + success = true; error: - vk_renderpass_destroy(ra, pass); - return NULL; + if (!success) { + vk_renderpass_destroy(ra, pass); + pass = NULL; + } + + vkDestroyShaderModule(vk->dev, vert_shader, MPVK_ALLOCATOR); + vkDestroyShaderModule(vk->dev, frag_shader, MPVK_ALLOCATOR); + vkDestroyShaderModule(vk->dev, comp_shader, MPVK_ALLOCATOR); + vkDestroyPipelineCache(vk->dev, pipeCache, MPVK_ALLOCATOR); + talloc_free(tmp); + return pass; } static void vk_update_descriptor(struct ra *ra, struct vk_cmd *cmd, diff --git a/video/out/vulkan/spirv_nvidia.c b/video/out/vulkan/spirv_nvidia.c new file mode 100644 index 0000000000..6cc43a5619 --- /dev/null +++ b/video/out/vulkan/spirv_nvidia.c @@ -0,0 +1,54 @@ +#include "video/out/gpu/spirv.h" + +#include "common.h" +#include "context.h" +#include "utils.h" + +static bool nv_glsl_compile(struct spirv_compiler *spirv, void *tactx, + enum glsl_shader type, const char *glsl, + struct bstr *out_spirv) +{ + // The nvidia extension literally assumes your SPIRV is in fact valid GLSL + *out_spirv = bstr0(glsl); + return true; +} + +static bool nv_glsl_init(struct ra_ctx *ctx) +{ + struct mpvk_ctx *vk = ra_vk_ctx_get(ctx); + if (!vk) + return false; + + struct spirv_compiler *spv = ctx->spirv; + spv->required_ext = VK_NV_GLSL_SHADER_EXTENSION_NAME; + spv->glsl_version = 450; // impossible to query, so hard-code it.. + spv->ra_caps = RA_CAP_NESTED_ARRAY; + + // Make sure the extension is actually available, and fail gracefully + // if it isn't + VkExtensionProperties *props = NULL; + uint32_t extnum = 0; + VK(vkEnumerateDeviceExtensionProperties(vk->physd, NULL, &extnum, NULL)); + props = talloc_array(NULL, VkExtensionProperties, extnum); + VK(vkEnumerateDeviceExtensionProperties(vk->physd, NULL, &extnum, props)); + + bool ret = true; + for (int e = 0; e < extnum; e++) { + if (strncmp(props[e].extensionName, spv->required_ext, + VK_MAX_EXTENSION_NAME_SIZE) == 0) + goto done; + } + +error: + MP_VERBOSE(ctx, "Device doesn't support VK_NV_glsl_shader, skipping..\n"); + ret = false; + +done: + talloc_free(props); + return ret; +} + +const struct spirv_compiler_fns spirv_nvidia_builtin = { + .compile_glsl = nv_glsl_compile, + .init = nv_glsl_init, +}; diff --git a/video/out/vulkan/utils.c b/video/out/vulkan/utils.c index 43e446bc36..659da9159a 100644 --- a/video/out/vulkan/utils.c +++ b/video/out/vulkan/utils.c @@ -1,5 +1,6 @@ #include <libavutil/macros.h> +#include "video/out/gpu/spirv.h" #include "utils.h" #include "malloc.h" @@ -445,13 +446,12 @@ error: bool mpvk_device_init(struct mpvk_ctx *vk, struct mpvk_device_opts opts) { assert(vk->physd); - - VkQueueFamilyProperties *qfs = NULL; - int qfnum; + void *tmp = talloc_new(NULL); // Enumerate the queue families and find suitable families for each task + int qfnum; vkGetPhysicalDeviceQueueFamilyProperties(vk->physd, &qfnum, NULL); - qfs = talloc_array(NULL, VkQueueFamilyProperties, qfnum); + VkQueueFamilyProperties *qfs = talloc_array(tmp, VkQueueFamilyProperties, qfnum); vkGetPhysicalDeviceQueueFamilyProperties(vk->physd, &qfnum, qfs); MP_VERBOSE(vk, "Queue families supported by device:\n"); @@ -503,20 +503,24 @@ bool mpvk_device_init(struct mpvk_ctx *vk, struct mpvk_device_opts opts) .pQueuePriorities = priorities, }; - static const char *exts[] = { - VK_KHR_SWAPCHAIN_EXTENSION_NAME, - VK_NV_GLSL_SHADER_EXTENSION_NAME, - }; + const char **exts = NULL; + int num_exts = 0; + MP_TARRAY_APPEND(tmp, exts, num_exts, VK_KHR_SWAPCHAIN_EXTENSION_NAME); + if (vk->spirv->required_ext) + MP_TARRAY_APPEND(tmp, exts, num_exts, vk->spirv->required_ext); VkDeviceCreateInfo dinfo = { .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, .queueCreateInfoCount = 1, .pQueueCreateInfos = &qinfo, .ppEnabledExtensionNames = exts, - .enabledExtensionCount = MP_ARRAY_SIZE(exts), + .enabledExtensionCount = num_exts, }; - MP_VERBOSE(vk, "Creating vulkan device...\n"); + MP_VERBOSE(vk, "Creating vulkan device with extensions:\n"); + for (int i = 0; i < num_exts; i++) + MP_VERBOSE(vk, " %s\n", exts[i]); + VK(vkCreateDevice(vk->physd, &dinfo, MPVK_ALLOCATOR, &vk->dev)); vk_malloc_init(vk); @@ -525,12 +529,12 @@ bool mpvk_device_init(struct mpvk_ctx *vk, struct mpvk_device_opts opts) if (!vk_cmdpool_init(vk, qinfo, qfs[idx], &vk->pool)) goto error; - talloc_free(qfs); + talloc_free(tmp); return true; error: MP_ERR(vk, "Failed creating logical device!\n"); - talloc_free(qfs); + talloc_free(tmp); return false; } |