lavapipe: implement EXT_graphics_pipeline_library

Reviewed-by: Dave Airlie <airlied@redhat.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/15636>
This commit is contained in:
Mike Blumenkrantz
2022-03-29 08:02:30 -04:00
committed by Marge Bot
parent 22fd70ca81
commit d4d5a7abba
5 changed files with 474 additions and 200 deletions

View File

@@ -267,10 +267,16 @@ VKAPI_ATTR VkResult VKAPI_CALL lvp_CreatePipelineLayout(
VK_OBJECT_TYPE_PIPELINE_LAYOUT);
layout->ref_cnt = 1;
layout->num_sets = pCreateInfo->setLayoutCount;
if (pCreateInfo->flags & VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT)
layout->independent_sets = true;
for (uint32_t set = 0; set < pCreateInfo->setLayoutCount; set++) {
LVP_FROM_HANDLE(lvp_descriptor_set_layout, set_layout,
pCreateInfo->pSetLayouts[set]);
if (layout->independent_sets && (!layout->num_sets || !set_layout)) {
layout->set[set].layout = NULL;
continue;
}
layout->set[set].layout = set_layout;
for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
layout->stage[i].uniform_block_size += set_layout->stage[i].uniform_block_size;
@@ -300,7 +306,7 @@ VKAPI_ATTR VkResult VKAPI_CALL lvp_CreatePipelineLayout(
uint16_t sampler_view_count = 0;
uint16_t image_count = 0;
for (unsigned j = 0; j < layout->num_sets; j++) {
if (layout->set[j].layout->shader_stages & array[i]) {
if (layout->set[j].layout && layout->set[j].layout->shader_stages & array[i]) {
const_buffer_count += layout->set[j].layout->stage[i].const_buffer_count;
shader_buffer_count += layout->set[j].layout->stage[i].shader_buffer_count;
sampler_count += layout->set[j].layout->stage[i].sampler_count;

View File

@@ -1420,7 +1420,11 @@ static void handle_descriptor_sets(struct vk_cmd_queue_entry *cmd,
}
for (i = 0; i < bds->descriptor_set_count; i++) {
if (!layout->set[bds->first_set + i].layout)
continue;
const struct lvp_descriptor_set *set = lvp_descriptor_set_from_handle(bds->descriptor_sets[i]);
if (!set)
continue;
/* verify that there's enough total offsets */
assert(set->layout->dynamic_offset_count <= dyn_info.dynamic_offset_count);
/* verify there's either no offsets... */

View File

@@ -106,6 +106,8 @@ static nir_ssa_def *lower_vri_intrin_vri(struct nir_builder *b,
return nir_imm_ivec2(b, 0, 0);
for (unsigned s = 0; s < desc_set_idx; s++) {
if (!layout->set[s].layout)
continue;
if (is_ubo)
value += layout->set[s].layout->stage[b->shader->info.stage].const_buffer_count;
else
@@ -165,6 +167,8 @@ lower_vri_instr_tex_deref(nir_tex_instr *tex,
struct lvp_descriptor_set_binding_layout *binding = &layout->set[desc_set_idx].layout->binding[binding_idx];
nir_tex_instr_remove_src(tex, deref_src_idx);
for (unsigned s = 0; s < desc_set_idx; s++) {
if (!layout->set[s].layout)
continue;
if (deref_src_type == nir_tex_src_sampler_deref)
value += layout->set[s].layout->stage[stage].sampler_count;
else
@@ -269,20 +273,29 @@ void lvp_lower_pipeline_layout(const struct lvp_device *device,
var->data.descriptor_set = 0;
if (base_type == GLSL_TYPE_SAMPLER || base_type == GLSL_TYPE_TEXTURE) {
if (binding->type == VK_DESCRIPTOR_TYPE_SAMPLER) {
for (unsigned s = 0; s < desc_set_idx; s++)
for (unsigned s = 0; s < desc_set_idx; s++) {
if (!layout->set[s].layout)
continue;
value += layout->set[s].layout->stage[shader->info.stage].sampler_count;
}
value += binding->stage[shader->info.stage].sampler_index;
} else {
for (unsigned s = 0; s < desc_set_idx; s++)
for (unsigned s = 0; s < desc_set_idx; s++) {
if (!layout->set[s].layout)
continue;
value += layout->set[s].layout->stage[shader->info.stage].sampler_view_count;
}
value += binding->stage[shader->info.stage].sampler_view_index;
}
var->data.binding = value;
}
if (base_type == GLSL_TYPE_IMAGE) {
var->data.descriptor_set = 0;
for (unsigned s = 0; s < desc_set_idx; s++)
for (unsigned s = 0; s < desc_set_idx; s++) {
if (!layout->set[s].layout)
continue;
value += layout->set[s].layout->stage[shader->info.stage].image_count;
}
value += binding->stage[shader->info.stage].image_index;
var->data.binding = value;
}

View File

@@ -69,7 +69,8 @@ VKAPI_ATTR void VKAPI_CALL lvp_DestroyPipeline(
for (unsigned i = 0; i < MESA_SHADER_STAGES; i++)
ralloc_free(pipeline->pipeline_nir[i]);
lvp_pipeline_layout_unref(device, pipeline->layout);
if (pipeline->layout)
lvp_pipeline_layout_unref(device, pipeline->layout);
ralloc_free(pipeline->mem_ctx);
vk_object_base_finish(&pipeline->base);
@@ -232,17 +233,64 @@ deep_copy_color_blend_state(void *mem_ctx,
static VkResult
deep_copy_dynamic_state(void *mem_ctx,
VkPipelineDynamicStateCreateInfo *dst,
const VkPipelineDynamicStateCreateInfo *src)
const VkPipelineDynamicStateCreateInfo *src,
VkGraphicsPipelineLibraryFlagsEXT stages)
{
dst->sType = src->sType;
dst->pNext = NULL;
dst->flags = src->flags;
VkDynamicState *states = (void*)dst->pDynamicStates;
for (unsigned i = 0; i < src->dynamicStateCount; i++) {
switch (src->pDynamicStates[i]) {
case VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT:
case VK_DYNAMIC_STATE_VERTEX_INPUT_EXT:
if (stages & VK_GRAPHICS_PIPELINE_LIBRARY_VERTEX_INPUT_INTERFACE_BIT_EXT)
states[dst->dynamicStateCount++] = src->pDynamicStates[i];
break;
LVP_PIPELINE_DUP(dst->pDynamicStates,
src->pDynamicStates,
VkDynamicState,
src->dynamicStateCount);
dst->dynamicStateCount = src->dynamicStateCount;
case VK_DYNAMIC_STATE_VIEWPORT:
case VK_DYNAMIC_STATE_SCISSOR:
case VK_DYNAMIC_STATE_LINE_WIDTH:
case VK_DYNAMIC_STATE_LINE_STIPPLE_EXT:
case VK_DYNAMIC_STATE_CULL_MODE_EXT:
case VK_DYNAMIC_STATE_FRONT_FACE_EXT:
case VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT:
case VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT:
case VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT_EXT:
case VK_DYNAMIC_STATE_PATCH_CONTROL_POINTS_EXT:
case VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE_EXT:
case VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE_EXT:
if (stages & VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT)
states[dst->dynamicStateCount++] = src->pDynamicStates[i];
break;
case VK_DYNAMIC_STATE_DEPTH_BIAS:
case VK_DYNAMIC_STATE_DEPTH_BOUNDS:
case VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK:
case VK_DYNAMIC_STATE_STENCIL_WRITE_MASK:
case VK_DYNAMIC_STATE_STENCIL_REFERENCE:
case VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT:
case VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT:
case VK_DYNAMIC_STATE_DEPTH_COMPARE_OP_EXT:
case VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE_EXT:
case VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE_EXT:
case VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE_EXT:
case VK_DYNAMIC_STATE_STENCIL_OP_EXT:
if (stages & VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT)
states[dst->dynamicStateCount++] = src->pDynamicStates[i];
break;
case VK_DYNAMIC_STATE_LOGIC_OP_EXT:
case VK_DYNAMIC_STATE_BLEND_CONSTANTS:
case VK_DYNAMIC_STATE_COLOR_WRITE_ENABLE_EXT:
if (stages & VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_OUTPUT_INTERFACE_BIT_EXT)
states[dst->dynamicStateCount++] = src->pDynamicStates[i];
break;
default:
unreachable("unknown dynamic state!");
}
}
assert(dst->dynamicStateCount <= 37);
return VK_SUCCESS;
}
@@ -278,139 +326,190 @@ deep_copy_rasterization_state(void *mem_ctx,
static VkResult
deep_copy_graphics_create_info(void *mem_ctx,
VkGraphicsPipelineCreateInfo *dst,
const VkGraphicsPipelineCreateInfo *src)
const VkGraphicsPipelineCreateInfo *src,
VkGraphicsPipelineLibraryFlagsEXT shaders)
{
int i;
VkResult result;
VkPipelineShaderStageCreateInfo *stages;
VkPipelineVertexInputStateCreateInfo *vertex_input;
VkPipelineRasterizationStateCreateInfo *rasterization_state;
const VkPipelineRenderingCreateInfoKHR *rp_info =
vk_get_pipeline_rendering_create_info(src);
const VkPipelineRenderingCreateInfoKHR *rp_info = NULL;
dst->sType = src->sType;
dst->pNext = NULL;
dst->flags = src->flags;
dst->layout = src->layout;
if (shaders & (VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT | VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_OUTPUT_INTERFACE_BIT_EXT)) {
assert(!dst->renderPass || !src->renderPass || dst->renderPass == src->renderPass);
assert(!dst->subpass || !src->subpass || dst->subpass == src->subpass);
dst->subpass = src->subpass;
dst->renderPass = src->renderPass;
rp_info = vk_get_pipeline_rendering_create_info(src);
}
dst->basePipelineHandle = src->basePipelineHandle;
dst->basePipelineIndex = src->basePipelineIndex;
/* pStages */
VkShaderStageFlags stages_present = 0;
dst->stageCount = src->stageCount;
stages = ralloc_array(mem_ctx, VkPipelineShaderStageCreateInfo, dst->stageCount);
for (i = 0 ; i < dst->stageCount; i++) {
result = deep_copy_shader_stage(mem_ctx, &stages[i], &src->pStages[i]);
stages = (void*)dst->pStages;
if (!stages)
stages = ralloc_array(mem_ctx, VkPipelineShaderStageCreateInfo, 5 /* max number of gfx stages */);
for (i = 0 ; i < src->stageCount; i++) {
if (shaders & VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT) {
/* only vertex stages allowed */
if (!(src->pStages[i].stage & BITFIELD_MASK(VK_SHADER_STAGE_FRAGMENT_BIT)))
continue;
} else if (shaders & VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT) {
/* only fragment stages allowed */
if (src->pStages[i].stage != VK_SHADER_STAGE_FRAGMENT_BIT)
continue;
} else {
/* other partials don't consume shaders */
continue;
}
result = deep_copy_shader_stage(mem_ctx, &stages[dst->stageCount++], &src->pStages[i]);
if (result != VK_SUCCESS)
return result;
stages_present |= src->pStages[i].stage;
}
dst->pStages = stages;
/* pVertexInputState */
if (!dynamic_state_contains(src->pDynamicState, VK_DYNAMIC_STATE_VERTEX_INPUT_EXT)) {
vertex_input = ralloc(mem_ctx, VkPipelineVertexInputStateCreateInfo);
result = deep_copy_vertex_input_state(mem_ctx, vertex_input,
src->pVertexInputState);
if (result != VK_SUCCESS)
return result;
dst->pVertexInputState = vertex_input;
} else
dst->pVertexInputState = NULL;
if (shaders & VK_GRAPHICS_PIPELINE_LIBRARY_VERTEX_INPUT_INTERFACE_BIT_EXT) {
/* pVertexInputState */
if (!dynamic_state_contains(src->pDynamicState, VK_DYNAMIC_STATE_VERTEX_INPUT_EXT)) {
vertex_input = ralloc(mem_ctx, VkPipelineVertexInputStateCreateInfo);
result = deep_copy_vertex_input_state(mem_ctx, vertex_input,
src->pVertexInputState);
if (result != VK_SUCCESS)
return result;
dst->pVertexInputState = vertex_input;
} else
dst->pVertexInputState = NULL;
/* pInputAssemblyState */
LVP_PIPELINE_DUP(dst->pInputAssemblyState,
src->pInputAssemblyState,
VkPipelineInputAssemblyStateCreateInfo,
1);
/* pTessellationState */
if (src->pTessellationState &&
(stages_present & (VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)) ==
(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)) {
LVP_PIPELINE_DUP(dst->pTessellationState,
src->pTessellationState,
VkPipelineTessellationStateCreateInfo,
/* pInputAssemblyState */
LVP_PIPELINE_DUP(dst->pInputAssemblyState,
src->pInputAssemblyState,
VkPipelineInputAssemblyStateCreateInfo,
1);
}
/* pViewportState */
bool rasterization_disabled = !dynamic_state_contains(src->pDynamicState, VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE_EXT) &&
src->pRasterizationState->rasterizerDiscardEnable;
if (src->pViewportState && !rasterization_disabled) {
VkPipelineViewportStateCreateInfo *viewport_state;
viewport_state = ralloc(mem_ctx, VkPipelineViewportStateCreateInfo);
if (!viewport_state)
return VK_ERROR_OUT_OF_HOST_MEMORY;
deep_copy_viewport_state(mem_ctx, src->pDynamicState,
viewport_state, src->pViewportState);
dst->pViewportState = viewport_state;
} else
dst->pViewportState = NULL;
/* pRasterizationState */
rasterization_state = ralloc(mem_ctx, VkPipelineRasterizationStateCreateInfo);
if (!rasterization_state)
return VK_ERROR_OUT_OF_HOST_MEMORY;
deep_copy_rasterization_state(mem_ctx, rasterization_state, src->pRasterizationState);
dst->pRasterizationState = rasterization_state;
/* pMultisampleState */
if (src->pMultisampleState && !rasterization_disabled) {
VkPipelineMultisampleStateCreateInfo* ms_state;
ms_state = ralloc_size(mem_ctx, sizeof(VkPipelineMultisampleStateCreateInfo) + sizeof(VkSampleMask));
if (!ms_state)
return VK_ERROR_OUT_OF_HOST_MEMORY;
/* does samplemask need deep copy? */
memcpy(ms_state, src->pMultisampleState, sizeof(VkPipelineMultisampleStateCreateInfo));
if (src->pMultisampleState->pSampleMask) {
VkSampleMask *sample_mask = (VkSampleMask *)(ms_state + 1);
sample_mask[0] = src->pMultisampleState->pSampleMask[0];
ms_state->pSampleMask = sample_mask;
bool rasterization_disabled = false;
if (shaders & VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT) {
/* pTessellationState */
if (src->pTessellationState &&
(stages_present & (VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)) ==
(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)) {
LVP_PIPELINE_DUP(dst->pTessellationState,
src->pTessellationState,
VkPipelineTessellationStateCreateInfo,
1);
}
dst->pMultisampleState = ms_state;
} else
dst->pMultisampleState = NULL;
/* pDepthStencilState */
if (src->pDepthStencilState && !rasterization_disabled &&
(rp_info->depthAttachmentFormat != VK_FORMAT_UNDEFINED ||
rp_info->stencilAttachmentFormat != VK_FORMAT_UNDEFINED)) {
LVP_PIPELINE_DUP(dst->pDepthStencilState,
src->pDepthStencilState,
VkPipelineDepthStencilStateCreateInfo,
1);
} else
dst->pDepthStencilState = NULL;
/* pViewportState */
rasterization_disabled = !dynamic_state_contains(src->pDynamicState, VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE_EXT) &&
src->pRasterizationState->rasterizerDiscardEnable;
if (src->pViewportState && !rasterization_disabled) {
VkPipelineViewportStateCreateInfo *viewport_state;
viewport_state = ralloc(mem_ctx, VkPipelineViewportStateCreateInfo);
if (!viewport_state)
return VK_ERROR_OUT_OF_HOST_MEMORY;
deep_copy_viewport_state(mem_ctx, src->pDynamicState,
viewport_state, src->pViewportState);
dst->pViewportState = viewport_state;
} else
dst->pViewportState = NULL;
bool uses_color_att = false;
for (unsigned i = 0; i < rp_info->colorAttachmentCount; i++) {
if (rp_info->pColorAttachmentFormats[i] != VK_FORMAT_UNDEFINED) {
uses_color_att = true;
break;
}
/* pRasterizationState */
rasterization_state = ralloc(mem_ctx, VkPipelineRasterizationStateCreateInfo);
if (!rasterization_state)
return VK_ERROR_OUT_OF_HOST_MEMORY;
deep_copy_rasterization_state(mem_ctx, rasterization_state, src->pRasterizationState);
dst->pRasterizationState = rasterization_state;
}
/* pColorBlendState */
if (src->pColorBlendState && !rasterization_disabled && uses_color_att) {
VkPipelineColorBlendStateCreateInfo* cb_state;
if (shaders & VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT) {
assert(rp_info);
/* pDepthStencilState */
if (src->pDepthStencilState && !rasterization_disabled &&
(rp_info->depthAttachmentFormat != VK_FORMAT_UNDEFINED ||
rp_info->stencilAttachmentFormat != VK_FORMAT_UNDEFINED)) {
LVP_PIPELINE_DUP(dst->pDepthStencilState,
src->pDepthStencilState,
VkPipelineDepthStencilStateCreateInfo,
1);
} else
dst->pDepthStencilState = NULL;
}
cb_state = ralloc(mem_ctx, VkPipelineColorBlendStateCreateInfo);
if (!cb_state)
return VK_ERROR_OUT_OF_HOST_MEMORY;
deep_copy_color_blend_state(mem_ctx, cb_state, src->pColorBlendState);
dst->pColorBlendState = cb_state;
} else
dst->pColorBlendState = NULL;
if (shaders & VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_OUTPUT_INTERFACE_BIT_EXT) {
assert(rp_info);
/* pMultisampleState */
if (src->pMultisampleState && !rasterization_disabled) {
VkPipelineMultisampleStateCreateInfo* ms_state;
ms_state = ralloc_size(mem_ctx, sizeof(VkPipelineMultisampleStateCreateInfo) + sizeof(VkSampleMask));
if (!ms_state)
return VK_ERROR_OUT_OF_HOST_MEMORY;
/* does samplemask need deep copy? */
memcpy(ms_state, src->pMultisampleState, sizeof(VkPipelineMultisampleStateCreateInfo));
if (src->pMultisampleState->pSampleMask) {
VkSampleMask *sample_mask = (VkSampleMask *)(ms_state + 1);
sample_mask[0] = src->pMultisampleState->pSampleMask[0];
ms_state->pSampleMask = sample_mask;
}
dst->pMultisampleState = ms_state;
} else
dst->pMultisampleState = NULL;
bool uses_color_att = false;
for (unsigned i = 0; i < rp_info->colorAttachmentCount; i++) {
if (rp_info->pColorAttachmentFormats[i] != VK_FORMAT_UNDEFINED) {
uses_color_att = true;
break;
}
}
/* pColorBlendState */
if (src->pColorBlendState && !rasterization_disabled && uses_color_att) {
VkPipelineColorBlendStateCreateInfo* cb_state;
cb_state = ralloc(mem_ctx, VkPipelineColorBlendStateCreateInfo);
if (!cb_state)
return VK_ERROR_OUT_OF_HOST_MEMORY;
deep_copy_color_blend_state(mem_ctx, cb_state, src->pColorBlendState);
dst->pColorBlendState = cb_state;
if (!dynamic_state_contains(src->pDynamicState, VK_DYNAMIC_STATE_COLOR_WRITE_ENABLE_EXT)) {
const VkPipelineColorWriteCreateInfoEXT *cw_state =
vk_find_struct_const(src->pColorBlendState, PIPELINE_COLOR_WRITE_CREATE_INFO_EXT);
if (cw_state) {
assert(cw_state->attachmentCount <= src->pColorBlendState->attachmentCount);
for (unsigned i = 0; i < cw_state->attachmentCount; i++)
if (!cw_state->pColorWriteEnables[i]) {
VkPipelineColorBlendAttachmentState *att = (void*)&cb_state->pAttachments[i];
att->colorWriteMask = 0;
}
}
}
} else
dst->pColorBlendState = NULL;
}
if (src->pDynamicState) {
VkPipelineDynamicStateCreateInfo* dyn_state;
/* pDynamicState */
dyn_state = ralloc(mem_ctx, VkPipelineDynamicStateCreateInfo);
if (!dyn_state)
if (dst->pDynamicState) {
dyn_state = (void*)dst->pDynamicState;
} else {
dyn_state = ralloc(mem_ctx, VkPipelineDynamicStateCreateInfo);
VkDynamicState *states = ralloc_array(mem_ctx, VkDynamicState, 37 /* current (1.3) number of dynamic states */);
dyn_state->pDynamicStates = states;
dyn_state->dynamicStateCount = 0;
}
if (!dyn_state || !dyn_state->pDynamicStates)
return VK_ERROR_OUT_OF_HOST_MEMORY;
deep_copy_dynamic_state(mem_ctx, dyn_state, src->pDynamicState);
deep_copy_dynamic_state(mem_ctx, dyn_state, src->pDynamicState, shaders);
dst->pDynamicState = dyn_state;
} else
dst->pDynamicState = NULL;
@@ -669,16 +768,17 @@ optimize(nir_shader *nir)
static void
lvp_shader_compile_to_ir(struct lvp_pipeline *pipeline,
struct vk_shader_module *module,
uint32_t size,
const void *module,
const char *entrypoint_name,
gl_shader_stage stage,
const VkSpecializationInfo *spec_info)
{
nir_shader *nir;
const nir_shader_compiler_options *drv_options = pipeline->device->pscreen->get_compiler_options(pipeline->device->pscreen, PIPE_SHADER_IR_NIR, st_shader_stage_to_ptarget(stage));
uint32_t *spirv = (uint32_t *) module->data;
const uint32_t *spirv = module;
assert(spirv[0] == SPIR_V_MAGIC_NUMBER);
assert(module->size % 4 == 0);
assert(size % 4 == 0);
uint32_t num_spec_entries = 0;
struct nir_spirv_specialization *spec_entries =
@@ -728,7 +828,7 @@ lvp_shader_compile_to_ir(struct lvp_pipeline *pipeline,
.shared_addr_format = nir_address_format_32bit_offset,
};
nir = spirv_to_nir(spirv, module->size / 4,
nir = spirv_to_nir(spirv, size / 4,
spec_entries, num_spec_entries,
stage, entrypoint_name, &spirv_options, drv_options);
@@ -977,6 +1077,79 @@ lvp_pipeline_compile(struct lvp_pipeline *pipeline,
return VK_SUCCESS;
}
#ifndef NDEBUG
static bool
layouts_equal(const struct lvp_descriptor_set_layout *a, const struct lvp_descriptor_set_layout *b)
{
const uint8_t *pa = (const uint8_t*)a, *pb = (const uint8_t*)b;
uint32_t hash_start_offset = offsetof(struct lvp_descriptor_set_layout, ref_cnt) + sizeof(uint32_t);
uint32_t binding_offset = offsetof(struct lvp_descriptor_set_layout, binding);
/* base equal */
if (memcmp(pa + hash_start_offset, pb + hash_start_offset, binding_offset - hash_start_offset))
return false;
/* bindings equal */
if (a->binding_count != b->binding_count)
return false;
size_t binding_size = a->binding_count * sizeof(struct lvp_descriptor_set_binding_layout);
const struct lvp_descriptor_set_binding_layout *la = a->binding;
const struct lvp_descriptor_set_binding_layout *lb = b->binding;
if (memcmp(la, lb, binding_size)) {
for (unsigned i = 0; i < a->binding_count; i++) {
if (memcmp(&la[i], &lb[i], offsetof(struct lvp_descriptor_set_binding_layout, immutable_samplers)))
return false;
}
}
/* immutable sampler equal */
if (a->immutable_sampler_count != b->immutable_sampler_count)
return false;
if (a->immutable_sampler_count) {
size_t sampler_size = a->immutable_sampler_count * sizeof(struct lvp_sampler *);
if (memcmp(pa + binding_offset + binding_size, pb + binding_offset + binding_size, sampler_size)) {
struct lvp_sampler **sa = (struct lvp_sampler **)(pa + binding_offset);
struct lvp_sampler **sb = (struct lvp_sampler **)(pb + binding_offset);
for (unsigned i = 0; i < a->immutable_sampler_count; i++) {
if (memcmp(sa[i], sb[i], sizeof(struct lvp_sampler)))
return false;
}
}
}
return true;
}
#endif
static void
merge_layouts(struct lvp_pipeline *dst, struct lvp_pipeline_layout *src)
{
if (!src)
return;
if (!dst->layout) {
/* no layout created yet: copy onto ralloc ctx allocation for auto-free */
dst->layout = ralloc(dst->mem_ctx, struct lvp_pipeline_layout);
memcpy(dst->layout, src, sizeof(struct lvp_pipeline_layout));
return;
}
#ifndef NDEBUG
/* verify that layouts match */
const struct lvp_pipeline_layout *smaller = dst->layout->num_sets < src->num_sets ? dst->layout : src;
const struct lvp_pipeline_layout *bigger = smaller == dst->layout ? src : dst->layout;
for (unsigned i = 0; i < smaller->num_sets; i++) {
assert(!smaller->set[i].layout || !bigger->set[i].layout ||
!smaller->set[i].layout->binding_count || !bigger->set[i].layout->binding_count ||
smaller->set[i].layout == bigger->set[i].layout ||
layouts_equal(smaller->set[i].layout, bigger->set[i].layout));
}
#endif
for (unsigned i = 0; i < src->num_sets; i++) {
if (!dst->layout->set[i].layout)
dst->layout->set[i].layout = src->set[i].layout;
}
dst->layout->num_sets = MAX2(dst->layout->num_sets, src->num_sets);
dst->layout->push_constant_size += src->push_constant_size;
dst->layout->push_constant_stages |= src->push_constant_stages;
}
static VkResult
lvp_graphics_pipeline_init(struct lvp_pipeline *pipeline,
struct lvp_device *device,
@@ -984,93 +1157,114 @@ lvp_graphics_pipeline_init(struct lvp_pipeline *pipeline,
const VkGraphicsPipelineCreateInfo *pCreateInfo,
const VkAllocationCallbacks *alloc)
{
if (alloc == NULL)
alloc = &device->vk.alloc;
pipeline->device = device;
pipeline->layout = lvp_pipeline_layout_from_handle(pCreateInfo->layout);
lvp_pipeline_layout_ref(pipeline->layout);
pipeline->force_min_sample = false;
const VkGraphicsPipelineLibraryCreateInfoEXT *libinfo = vk_find_struct_const(pCreateInfo,
GRAPHICS_PIPELINE_LIBRARY_CREATE_INFO_EXT);
const VkPipelineLibraryCreateInfoKHR *libstate = vk_find_struct_const(pCreateInfo,
PIPELINE_LIBRARY_CREATE_INFO_KHR);
const VkGraphicsPipelineLibraryFlagsEXT layout_stages = VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT |
VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT;
if (libinfo)
pipeline->stages = libinfo->flags;
else if (!libstate)
pipeline->stages = VK_GRAPHICS_PIPELINE_LIBRARY_VERTEX_INPUT_INTERFACE_BIT_EXT |
VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT |
VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT |
VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_OUTPUT_INTERFACE_BIT_EXT;
pipeline->mem_ctx = ralloc_context(NULL);
/* recreate createinfo */
deep_copy_graphics_create_info(pipeline->mem_ctx, &pipeline->graphics_create_info, pCreateInfo);
pipeline->is_compute_pipeline = false;
if (pCreateInfo->flags & VK_PIPELINE_CREATE_LIBRARY_BIT_KHR)
pipeline->library = true;
if (pipeline->graphics_create_info.pViewportState) {
/* if pViewportState is null, it means rasterization is discarded,
* so this is ignored
*/
const VkPipelineViewportDepthClipControlCreateInfoEXT *ccontrol = vk_find_struct_const(pCreateInfo->pViewportState,
PIPELINE_VIEWPORT_DEPTH_CLIP_CONTROL_CREATE_INFO_EXT);
if (ccontrol)
pipeline->negative_one_to_one = !!ccontrol->negativeOneToOne;
struct lvp_pipeline_layout *layout = lvp_pipeline_layout_from_handle(pCreateInfo->layout);
if (layout)
lvp_pipeline_layout_ref(layout);
if (!layout || !layout->independent_sets)
/* this is a regular pipeline with no partials: directly reuse */
pipeline->layout = layout;
else if (pipeline->stages & layout_stages) {
if ((pipeline->stages & layout_stages) == layout_stages)
/* this has all the layout stages: directly reuse */
pipeline->layout = layout;
else {
/* this is a partial: copy for later merging to avoid modifying another layout */
merge_layouts(pipeline, layout);
}
}
const VkPipelineRasterizationProvokingVertexStateCreateInfoEXT *pv_state =
vk_find_struct_const(pCreateInfo->pRasterizationState,
PIPELINE_RASTERIZATION_PROVOKING_VERTEX_STATE_CREATE_INFO_EXT);
pipeline->provoking_vertex_last = pv_state && pv_state->provokingVertexMode == VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT;
const VkPipelineRasterizationLineStateCreateInfoEXT *line_state =
vk_find_struct_const(pCreateInfo->pRasterizationState,
PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT);
if (line_state) {
/* always draw bresenham if !smooth */
pipeline->line_stipple_enable = line_state->stippledLineEnable;
pipeline->line_smooth = line_state->lineRasterizationMode == VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT;
pipeline->disable_multisample = line_state->lineRasterizationMode == VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT ||
line_state->lineRasterizationMode == VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT;
pipeline->line_rectangular = line_state->lineRasterizationMode != VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT;
if (pipeline->line_stipple_enable) {
if (!dynamic_state_contains(pipeline->graphics_create_info.pDynamicState, VK_DYNAMIC_STATE_LINE_STIPPLE_EXT)) {
pipeline->line_stipple_factor = line_state->lineStippleFactor - 1;
pipeline->line_stipple_pattern = line_state->lineStipplePattern;
} else {
pipeline->line_stipple_factor = 0;
pipeline->line_stipple_pattern = UINT16_MAX;
/* recreate createinfo */
if (!libstate || libinfo)
deep_copy_graphics_create_info(pipeline->mem_ctx, &pipeline->graphics_create_info, pCreateInfo, pipeline->stages);
if (libstate) {
for (unsigned i = 0; i < libstate->libraryCount; i++) {
LVP_FROM_HANDLE(lvp_pipeline, p, libstate->pLibraries[i]);
deep_copy_graphics_create_info(pipeline->mem_ctx, &pipeline->graphics_create_info, &p->graphics_create_info, p->stages);
if (p->stages & VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT) {
pipeline->provoking_vertex_last = p->provoking_vertex_last;
pipeline->line_stipple_enable = p->line_stipple_enable;
pipeline->line_smooth = p->line_smooth;
pipeline->disable_multisample = p->disable_multisample;
pipeline->line_rectangular = p->line_rectangular;
pipeline->line_stipple_factor = p->line_stipple_factor;
pipeline->line_stipple_pattern = p->line_stipple_pattern;
pipeline->negative_one_to_one = p->negative_one_to_one;
}
}
} else
pipeline->line_rectangular = true;
bool rasterization_disabled = !dynamic_state_contains(pipeline->graphics_create_info.pDynamicState, VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE_EXT) &&
pipeline->graphics_create_info.pRasterizationState->rasterizerDiscardEnable;
if (!dynamic_state_contains(pipeline->graphics_create_info.pDynamicState, VK_DYNAMIC_STATE_COLOR_WRITE_ENABLE_EXT) &&
!rasterization_disabled) {
const VkPipelineColorWriteCreateInfoEXT *cw_state =
vk_find_struct_const(pCreateInfo->pColorBlendState, PIPELINE_COLOR_WRITE_CREATE_INFO_EXT);
if (cw_state) {
assert(cw_state->attachmentCount <= pipeline->graphics_create_info.pColorBlendState->attachmentCount);
for (unsigned i = 0; i < cw_state->attachmentCount; i++)
if (!cw_state->pColorWriteEnables[i]) {
VkPipelineColorBlendAttachmentState *att = (void*)&pipeline->graphics_create_info.pColorBlendState->pAttachments[i];
att->colorWriteMask = 0;
}
if (p->stages & VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT)
pipeline->force_min_sample = p->force_min_sample;
if (p->stages & layout_stages) {
if (!layout || layout->independent_sets)
merge_layouts(pipeline, p->layout);
}
pipeline->stages |= p->stages;
}
}
if (alloc == NULL)
alloc = &device->vk.alloc;
pipeline->device = device;
for (uint32_t i = 0; i < pCreateInfo->stageCount; i++) {
VK_FROM_HANDLE(vk_shader_module, module,
pCreateInfo->pStages[i].module);
gl_shader_stage stage = lvp_shader_stage(pCreateInfo->pStages[i].stage);
lvp_shader_compile_to_ir(pipeline, module,
pCreateInfo->pStages[i].pName,
stage,
pCreateInfo->pStages[i].pSpecializationInfo);
if (stage == MESA_SHADER_FRAGMENT) {
if (!(pipeline->stages & VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT))
continue;
} else {
if (!(pipeline->stages & VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT))
continue;
}
if (module) {
lvp_shader_compile_to_ir(pipeline, module->size, module->data,
pCreateInfo->pStages[i].pName,
stage,
pCreateInfo->pStages[i].pSpecializationInfo);
} else {
const VkShaderModuleCreateInfo *info = vk_find_struct_const(pCreateInfo->pStages[i].pNext, SHADER_MODULE_CREATE_INFO);
assert(info);
lvp_shader_compile_to_ir(pipeline, info->codeSize, info->pCode,
pCreateInfo->pStages[i].pName,
stage,
pCreateInfo->pStages[i].pSpecializationInfo);
}
if (!pipeline->pipeline_nir[stage])
return VK_ERROR_FEATURE_NOT_PRESENT;
}
if (pipeline->pipeline_nir[MESA_SHADER_FRAGMENT]) {
if (pipeline->pipeline_nir[MESA_SHADER_FRAGMENT]->info.fs.uses_sample_qualifier ||
BITSET_TEST(pipeline->pipeline_nir[MESA_SHADER_FRAGMENT]->info.system_values_read, SYSTEM_VALUE_SAMPLE_ID) ||
BITSET_TEST(pipeline->pipeline_nir[MESA_SHADER_FRAGMENT]->info.system_values_read, SYSTEM_VALUE_SAMPLE_POS))
pipeline->force_min_sample = true;
switch (stage) {
case MESA_SHADER_GEOMETRY:
pipeline->gs_output_lines = pipeline->pipeline_nir[MESA_SHADER_GEOMETRY] &&
pipeline->pipeline_nir[MESA_SHADER_GEOMETRY]->info.gs.output_primitive == SHADER_PRIM_LINES;
break;
case MESA_SHADER_FRAGMENT:
if (pipeline->pipeline_nir[MESA_SHADER_FRAGMENT]->info.fs.uses_sample_qualifier ||
BITSET_TEST(pipeline->pipeline_nir[MESA_SHADER_FRAGMENT]->info.system_values_read, SYSTEM_VALUE_SAMPLE_ID) ||
BITSET_TEST(pipeline->pipeline_nir[MESA_SHADER_FRAGMENT]->info.system_values_read, SYSTEM_VALUE_SAMPLE_POS))
pipeline->force_min_sample = true;
break;
default: break;
}
}
if (pipeline->pipeline_nir[MESA_SHADER_TESS_CTRL]) {
if (pCreateInfo->stageCount && pipeline->pipeline_nir[MESA_SHADER_TESS_EVAL]) {
nir_lower_patch_vertices(pipeline->pipeline_nir[MESA_SHADER_TESS_EVAL], pipeline->pipeline_nir[MESA_SHADER_TESS_CTRL]->info.tess.tcs_vertices_out, NULL);
merge_tess_info(&pipeline->pipeline_nir[MESA_SHADER_TESS_EVAL]->info, &pipeline->pipeline_nir[MESA_SHADER_TESS_CTRL]->info);
const VkPipelineTessellationDomainOriginStateCreateInfo *domain_origin_state =
@@ -1079,29 +1273,81 @@ lvp_graphics_pipeline_init(struct lvp_pipeline *pipeline,
if (!domain_origin_state || domain_origin_state->domainOrigin == VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT)
pipeline->pipeline_nir[MESA_SHADER_TESS_EVAL]->info.tess.ccw = !pipeline->pipeline_nir[MESA_SHADER_TESS_EVAL]->info.tess.ccw;
}
pipeline->gs_output_lines = pipeline->pipeline_nir[MESA_SHADER_GEOMETRY] &&
pipeline->pipeline_nir[MESA_SHADER_GEOMETRY]->info.gs.output_primitive == SHADER_PRIM_LINES;
bool has_fragment_shader = false;
for (uint32_t i = 0; i < pCreateInfo->stageCount; i++) {
gl_shader_stage stage = lvp_shader_stage(pCreateInfo->pStages[i].stage);
lvp_pipeline_compile(pipeline, stage);
if (stage == MESA_SHADER_FRAGMENT)
has_fragment_shader = true;
if (libstate) {
for (unsigned i = 0; i < libstate->libraryCount; i++) {
LVP_FROM_HANDLE(lvp_pipeline, p, libstate->pLibraries[i]);
if (p->stages & VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT) {
if (p->pipeline_nir[MESA_SHADER_FRAGMENT])
pipeline->pipeline_nir[MESA_SHADER_FRAGMENT] = nir_shader_clone(pipeline->mem_ctx, p->pipeline_nir[MESA_SHADER_FRAGMENT]);
}
if (p->stages & VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT) {
for (unsigned j = MESA_SHADER_VERTEX; j < MESA_SHADER_FRAGMENT; j++) {
if (p->pipeline_nir[j])
pipeline->pipeline_nir[j] = nir_shader_clone(pipeline->mem_ctx, p->pipeline_nir[j]);
}
}
}
}
if (has_fragment_shader == false) {
/* create a dummy fragment shader for this pipeline. */
nir_builder b = nir_builder_init_simple_shader(MESA_SHADER_FRAGMENT, NULL,
"dummy_frag");
if (pipeline->stages & VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT) {
if (pipeline->graphics_create_info.pViewportState) {
/* if pViewportState is null, it means rasterization is discarded,
* so this is ignored
*/
const VkPipelineViewportDepthClipControlCreateInfoEXT *ccontrol = vk_find_struct_const(pCreateInfo->pViewportState,
PIPELINE_VIEWPORT_DEPTH_CLIP_CONTROL_CREATE_INFO_EXT);
if (ccontrol)
pipeline->negative_one_to_one = !!ccontrol->negativeOneToOne;
}
pipeline->pipeline_nir[MESA_SHADER_FRAGMENT] = b.shader;
struct pipe_shader_state shstate = {0};
shstate.type = PIPE_SHADER_IR_NIR;
shstate.ir.nir = nir_shader_clone(NULL, pipeline->pipeline_nir[MESA_SHADER_FRAGMENT]);
pipeline->shader_cso[PIPE_SHADER_FRAGMENT] = device->queue.ctx->create_fs_state(device->queue.ctx, &shstate);
const VkPipelineRasterizationProvokingVertexStateCreateInfoEXT *pv_state =
vk_find_struct_const(pCreateInfo->pRasterizationState,
PIPELINE_RASTERIZATION_PROVOKING_VERTEX_STATE_CREATE_INFO_EXT);
pipeline->provoking_vertex_last = pv_state && pv_state->provokingVertexMode == VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT;
const VkPipelineRasterizationLineStateCreateInfoEXT *line_state =
vk_find_struct_const(pCreateInfo->pRasterizationState,
PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT);
if (line_state) {
/* always draw bresenham if !smooth */
pipeline->line_stipple_enable = line_state->stippledLineEnable;
pipeline->line_smooth = line_state->lineRasterizationMode == VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT;
pipeline->disable_multisample = line_state->lineRasterizationMode == VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT ||
line_state->lineRasterizationMode == VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT;
pipeline->line_rectangular = line_state->lineRasterizationMode != VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT;
if (pipeline->line_stipple_enable) {
if (!dynamic_state_contains(pipeline->graphics_create_info.pDynamicState, VK_DYNAMIC_STATE_LINE_STIPPLE_EXT)) {
pipeline->line_stipple_factor = line_state->lineStippleFactor - 1;
pipeline->line_stipple_pattern = line_state->lineStipplePattern;
} else {
pipeline->line_stipple_factor = 0;
pipeline->line_stipple_pattern = UINT16_MAX;
}
}
} else
pipeline->line_rectangular = true;
}
if (!pipeline->library) {
bool has_fragment_shader = false;
for (uint32_t i = 0; i < pipeline->graphics_create_info.stageCount; i++) {
gl_shader_stage stage = lvp_shader_stage(pipeline->graphics_create_info.pStages[i].stage);
lvp_pipeline_compile(pipeline, stage);
if (stage == MESA_SHADER_FRAGMENT)
has_fragment_shader = true;
}
if (has_fragment_shader == false) {
/* create a dummy fragment shader for this pipeline. */
nir_builder b = nir_builder_init_simple_shader(MESA_SHADER_FRAGMENT, NULL,
"dummy_frag");
pipeline->pipeline_nir[MESA_SHADER_FRAGMENT] = b.shader;
struct pipe_shader_state shstate = {0};
shstate.type = PIPE_SHADER_IR_NIR;
shstate.ir.nir = nir_shader_clone(NULL, pipeline->pipeline_nir[MESA_SHADER_FRAGMENT]);
pipeline->shader_cso[PIPE_SHADER_FRAGMENT] = device->queue.ctx->create_fs_state(device->queue.ctx, &shstate);
}
}
return VK_SUCCESS;
}
@@ -1202,7 +1448,7 @@ lvp_compute_pipeline_init(struct lvp_pipeline *pipeline,
&pipeline->compute_create_info, pCreateInfo);
pipeline->is_compute_pipeline = true;
lvp_shader_compile_to_ir(pipeline, module,
lvp_shader_compile_to_ir(pipeline, module->size, module->data,
pCreateInfo->stage.pName,
MESA_SHADER_COMPUTE,
pCreateInfo->stage.pSpecializationInfo);

View File

@@ -284,6 +284,7 @@ struct lvp_descriptor_set_layout {
/* Descriptor set layouts can be destroyed at almost any time */
uint32_t ref_cnt;
/* add new members after this */
uint32_t immutable_sampler_count;
@@ -328,7 +329,9 @@ static inline void
lvp_descriptor_set_layout_unref(struct lvp_device *device,
struct lvp_descriptor_set_layout *layout)
{
assert(layout && layout->ref_cnt >= 1);
if (!layout)
return;
assert(layout->ref_cnt >= 1);
if (p_atomic_dec_zero(&layout->ref_cnt))
lvp_descriptor_set_layout_destroy(device, layout);
}
@@ -406,6 +409,7 @@ struct lvp_pipeline_layout {
uint16_t uniform_block_count;
uint16_t uniform_block_sizes[MAX_PER_STAGE_DESCRIPTOR_UNIFORM_BLOCKS * MAX_SETS];
} stage[MESA_SHADER_STAGES];
bool independent_sets;
};
void lvp_pipeline_layout_destroy(struct lvp_device *device,
@@ -447,6 +451,7 @@ struct lvp_pipeline {
void *shader_cso[PIPE_SHADER_TYPES];
VkGraphicsPipelineCreateInfo graphics_create_info;
VkComputePipelineCreateInfo compute_create_info;
VkGraphicsPipelineLibraryFlagsEXT stages;
uint32_t line_stipple_factor;
uint16_t line_stipple_pattern;
bool line_stipple_enable;