lavapipe: implement EXT_shader_object

Reviewed-by: Dave Airlie <airlied@redhat.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/22233>
This commit is contained in:
Mike Blumenkrantz
2023-03-07 12:44:53 -05:00
committed by Marge Bot
parent 469a1d8c11
commit 8b3022c918
4 changed files with 263 additions and 0 deletions

View File

@@ -29,6 +29,7 @@
#include "util/os_time.h"
#include "spirv/nir_spirv.h"
#include "nir/nir_builder.h"
#include "nir/nir_serialize.h"
#include "lvp_lower_vulkan_resource.h"
#include "pipe/p_state.h"
#include "pipe/p_context.h"
@@ -1122,3 +1123,165 @@ VKAPI_ATTR VkResult VKAPI_CALL lvp_CreateComputePipelines(
return result;
}
VKAPI_ATTR void VKAPI_CALL lvp_DestroyShaderEXT(
VkDevice _device,
VkShaderEXT _shader,
const VkAllocationCallbacks* pAllocator)
{
LVP_FROM_HANDLE(lvp_device, device, _device);
LVP_FROM_HANDLE(lvp_shader, shader, _shader);
if (!shader)
return;
shader_destroy(device, shader);
vk_pipeline_layout_unref(&device->vk, &shader->layout->vk);
blob_finish(&shader->blob);
vk_object_base_finish(&shader->base);
vk_free2(&device->vk.alloc, pAllocator, shader);
}
static VkShaderEXT
create_shader_object(struct lvp_device *device, const VkShaderCreateInfoEXT *pCreateInfo, const VkAllocationCallbacks *pAllocator)
{
nir_shader *nir = NULL;
gl_shader_stage stage = vk_to_mesa_shader_stage(pCreateInfo->stage);
assert(stage <= MESA_SHADER_COMPUTE && stage != MESA_SHADER_NONE);
if (pCreateInfo->codeType == VK_SHADER_CODE_TYPE_SPIRV_EXT) {
VkShaderModuleCreateInfo minfo = {
VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
NULL,
0,
pCreateInfo->codeSize,
pCreateInfo->pCode,
};
VkPipelineShaderStageCreateFlagBits flags = 0;
if (pCreateInfo->flags & VK_SHADER_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT_EXT)
flags |= VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT;
if (pCreateInfo->flags & VK_SHADER_CREATE_REQUIRE_FULL_SUBGROUPS_BIT_EXT)
flags |= VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT;
VkPipelineShaderStageCreateInfo sinfo = {
VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
&minfo,
flags,
pCreateInfo->stage,
VK_NULL_HANDLE,
pCreateInfo->pName,
pCreateInfo->pSpecializationInfo,
};
VkResult result = compile_spirv(device, &sinfo, &nir);
if (result != VK_SUCCESS)
goto fail;
} else {
assert(pCreateInfo->codeType == VK_SHADER_CODE_TYPE_BINARY_EXT);
if (pCreateInfo->codeSize < SHA1_DIGEST_LENGTH + 1)
return VK_NULL_HANDLE;
struct blob_reader blob;
const uint8_t *data = pCreateInfo->pCode;
size_t size = pCreateInfo->codeSize - SHA1_DIGEST_LENGTH;
unsigned char sha1[20];
struct mesa_sha1 sctx;
_mesa_sha1_init(&sctx);
_mesa_sha1_update(&sctx, data + SHA1_DIGEST_LENGTH, size);
_mesa_sha1_final(&sctx, sha1);
if (memcmp(sha1, data, SHA1_DIGEST_LENGTH))
return VK_NULL_HANDLE;
blob_reader_init(&blob, data + SHA1_DIGEST_LENGTH, size);
nir = nir_deserialize(NULL, device->pscreen->get_compiler_options(device->pscreen, PIPE_SHADER_IR_NIR, stage), &blob);
if (!nir)
goto fail;
}
if (!nir_shader_get_entrypoint(nir))
goto fail;
struct lvp_shader *shader = vk_object_zalloc(&device->vk, pAllocator, sizeof(struct lvp_shader), VK_OBJECT_TYPE_SHADER_EXT);
if (!shader)
goto fail;
blob_init(&shader->blob);
VkPipelineLayoutCreateInfo pci = {
VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
NULL,
0,
pCreateInfo->setLayoutCount,
pCreateInfo->pSetLayouts,
pCreateInfo->pushConstantRangeCount,
pCreateInfo->pPushConstantRanges,
};
shader->layout = lvp_pipeline_layout_create(device, &pci, pAllocator);
lvp_shader_lower(device, nir, shader, shader->layout);
lvp_shader_xfb_init(shader);
if (stage == MESA_SHADER_TESS_EVAL) {
/* spec requires that all tess modes are set in both shaders */
nir_lower_patch_vertices(shader->pipeline_nir->nir, shader->pipeline_nir->nir->info.tess.tcs_vertices_out, NULL);
shader->tess_ccw = create_pipeline_nir(nir_shader_clone(NULL, shader->pipeline_nir->nir));
shader->tess_ccw->nir->info.tess.ccw = !shader->pipeline_nir->nir->info.tess.ccw;
shader->tess_ccw_cso = lvp_shader_compile(device, shader, nir_shader_clone(NULL, shader->tess_ccw->nir));
} else if (stage == MESA_SHADER_FRAGMENT && nir->info.fs.uses_fbfetch_output) {
/* this is (currently) illegal */
assert(!nir->info.fs.uses_fbfetch_output);
shader_destroy(device, shader);
vk_object_base_finish(&shader->base);
vk_free2(&device->vk.alloc, pAllocator, shader);
return VK_NULL_HANDLE;
}
nir_serialize(&shader->blob, nir, true);
shader->shader_cso = lvp_shader_compile(device, shader, nir_shader_clone(NULL, nir));
return lvp_shader_to_handle(shader);
fail:
ralloc_free(nir);
return VK_NULL_HANDLE;
}
VKAPI_ATTR VkResult VKAPI_CALL lvp_CreateShadersEXT(
VkDevice _device,
uint32_t createInfoCount,
const VkShaderCreateInfoEXT* pCreateInfos,
const VkAllocationCallbacks* pAllocator,
VkShaderEXT* pShaders)
{
LVP_FROM_HANDLE(lvp_device, device, _device);
unsigned i;
for (i = 0; i < createInfoCount; i++) {
pShaders[i] = create_shader_object(device, &pCreateInfos[i], pAllocator);
if (!pShaders[i]) {
if (pCreateInfos[i].codeType == VK_SHADER_CODE_TYPE_BINARY_EXT) {
if (i < createInfoCount - 1)
memset(&pShaders[i + 1], 0, (createInfoCount - i - 1) * sizeof(VkShaderEXT));
return vk_error(device, VK_ERROR_INCOMPATIBLE_SHADER_BINARY_EXT);
}
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
}
}
return VK_SUCCESS;
}
VKAPI_ATTR VkResult VKAPI_CALL lvp_GetShaderBinaryDataEXT(
VkDevice device,
VkShaderEXT _shader,
size_t* pDataSize,
void* pData)
{
LVP_FROM_HANDLE(lvp_shader, shader, _shader);
VkResult ret = VK_SUCCESS;
if (pData) {
if (*pDataSize < shader->blob.size + SHA1_DIGEST_LENGTH) {
ret = VK_INCOMPLETE;
*pDataSize = 0;
} else {
*pDataSize = MIN2(*pDataSize, shader->blob.size + SHA1_DIGEST_LENGTH);
struct mesa_sha1 sctx;
_mesa_sha1_init(&sctx);
_mesa_sha1_update(&sctx, shader->blob.data, shader->blob.size);
_mesa_sha1_final(&sctx, pData);
uint8_t *data = pData;
memcpy(data + SHA1_DIGEST_LENGTH, shader->blob.data, shader->blob.size);
}
} else {
*pDataSize = shader->blob.size + SHA1_DIGEST_LENGTH;
}
return ret;
}