From 07addb41835a556361515261ee27a095118fa63a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Pi=C3=B1eiro?= Date: Wed, 25 Mar 2020 11:50:16 +0100 Subject: [PATCH] v3dv/cmd_buffer: update shader variants at CmdBindDescriptorSets/CmdBindPipeline Specially after CmdBindDescriptorSets, it is likely that we would need a new shader variant, like for example if sampler descriptor sets are bound. At that moment a new v3d key is populated, using as base the one used at pipeline creation, so only cmd_buffer depending values are changed. Then a new variant is requested. Note that internally it is handled with a cache, so no new compilation will be done if not needed. Part-of: --- src/broadcom/vulkan/v3dv_cmd_buffer.c | 126 ++++++++++++++++++++++ src/broadcom/vulkan/v3dv_descriptor_set.c | 49 +++++++++ src/broadcom/vulkan/v3dv_formats.c | 10 ++ src/broadcom/vulkan/v3dv_pipeline.c | 14 +-- src/broadcom/vulkan/v3dv_private.h | 15 +++ src/broadcom/vulkan/v3dv_uniforms.c | 64 ++--------- 6 files changed, 214 insertions(+), 64 deletions(-) diff --git a/src/broadcom/vulkan/v3dv_cmd_buffer.c b/src/broadcom/vulkan/v3dv_cmd_buffer.c index ee9eee9d000..2425709136a 100644 --- a/src/broadcom/vulkan/v3dv_cmd_buffer.c +++ b/src/broadcom/vulkan/v3dv_cmd_buffer.c @@ -1736,6 +1736,120 @@ cmd_buffer_update_ez_state(struct v3dv_cmd_buffer *cmd_buffer, } } +/* Note that the following poopulate methods doesn't do a detailed fill-up of + * the v3d_fs_key. Here we just fill-up cmd_buffer specific info. All info + * coming from the pipeline create info was alredy filled up when the pipeline + * was created + */ +static void +cmd_buffer_populate_v3d_key(struct v3d_key *key, + struct v3dv_cmd_buffer *cmd_buffer) +{ + struct v3dv_descriptor_map *map = &cmd_buffer->state.pipeline->texture_map; + struct v3dv_descriptor_state *descriptor_state = + &cmd_buffer->state.descriptor_state; + + for (uint32_t i = 0; i < map->num_desc; i++) { + struct v3dv_descriptor *descriptor = + v3dv_descriptor_map_get_descriptor(descriptor_state, + map, + cmd_buffer->state.pipeline->layout, + i, NULL); + + assert(descriptor->type == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE || + descriptor->type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER); + assert(descriptor); + assert(descriptor->image_view); + assert(descriptor->image_view->image); + + key->tex[i].return_size = + v3dv_get_tex_return_size(descriptor->image_view->format, + 0); /* FIXME: how to get the sampler compare mode? */ + + if (key->tex[i].return_size == 16) { + key->tex[i].return_channels = 2; + } else { + key->tex[i].return_channels = 4; + } + + /* Note: we don't need to do anything for the swizzle, as that is + * handled with the swizzle info at the Texture State, and the + * default values for key->tex[].swizzle were already filled up on + * the pipeline populate. + */ + } +} + +static void +update_fs_variant(struct v3dv_cmd_buffer *cmd_buffer) +{ + struct v3dv_shader_variant *variant; + struct v3dv_pipeline_stage *p_stage = cmd_buffer->state.pipeline->fs; + struct v3d_fs_key local_key; + + /* We start with a copy of the original pipeline key */ + memcpy(&local_key, &p_stage->key.fs, sizeof(struct v3d_fs_key)); + + cmd_buffer_populate_v3d_key(&local_key.base, cmd_buffer); + + variant = v3dv_get_shader_variant(p_stage, &local_key.base, + sizeof(struct v3d_fs_key)); + + if (p_stage->current_variant != variant) { + p_stage->current_variant = variant; + /* FIXME: we need to set any dirty flag here? */ + } +} + +static void +update_vs_variant(struct v3dv_cmd_buffer *cmd_buffer) +{ + struct v3dv_shader_variant *variant; + struct v3dv_pipeline_stage *p_stage = cmd_buffer->state.pipeline->vs; + struct v3d_vs_key local_key; + + /* We start with a copy of the original pipeline key */ + memcpy(&local_key, &p_stage->key.vs, sizeof(struct v3d_vs_key)); + + cmd_buffer_populate_v3d_key(&local_key.base, cmd_buffer); + + variant = v3dv_get_shader_variant(p_stage, &local_key.base, + sizeof(struct v3d_vs_key)); + + if (p_stage->current_variant != variant) { + p_stage->current_variant = variant; + /* FIXME: we need to set any dirty flag here? */ + } + + p_stage = cmd_buffer->state.pipeline->vs_bin; + memcpy(&local_key, &p_stage->key.vs, sizeof(struct v3d_vs_key)); + + cmd_buffer_populate_v3d_key(&local_key.base, cmd_buffer); + variant = v3dv_get_shader_variant(p_stage, &local_key.base, + sizeof(struct v3d_vs_key)); + + if (p_stage->current_variant != variant) { + p_stage->current_variant = variant; + /* FIXME: we need to set any dirty flag here? */ + } +} + +/* + * Some updates on the cmd buffer requires also updates on the shader being + * compiled at the pipeline. The poster boy here are textures, as the compiler + * needs to do certain things depending on the texture format. So here we + * re-create the v3d_keys and update the variant. Note that internally the + * pipeline has a variant cache (hash table) to avoid unneeded compilations + */ +static void +update_pipeline_variants(struct v3dv_cmd_buffer *cmd_buffer) +{ + assert(cmd_buffer->state.pipeline); + + update_fs_variant(cmd_buffer); + update_vs_variant(cmd_buffer); +} + static void bind_graphics_pipeline(struct v3dv_cmd_buffer *cmd_buffer, struct v3dv_pipeline *pipeline) @@ -1768,6 +1882,12 @@ bind_graphics_pipeline(struct v3dv_cmd_buffer *cmd_buffer, cmd_buffer_bind_pipeline_static_state(cmd_buffer, &pipeline->dynamic_state); cmd_buffer_update_ez_state(cmd_buffer, pipeline); + if (cmd_buffer->state.dirty & V3DV_CMD_DIRTY_SHADER_VARIANTS) { + update_pipeline_variants(cmd_buffer); + + cmd_buffer->state.dirty &= ~V3DV_CMD_DIRTY_SHADER_VARIANTS; + } + cmd_buffer->state.dirty |= V3DV_CMD_DIRTY_PIPELINE; } @@ -2787,6 +2907,12 @@ v3dv_CmdBindDescriptorSets(VkCommandBuffer commandBuffer, } } + if (cmd_buffer->state.pipeline) { + update_pipeline_variants(cmd_buffer); + } else { + cmd_buffer->state.dirty |= V3DV_CMD_DIRTY_SHADER_VARIANTS; + } + cmd_buffer->state.dirty |= V3DV_CMD_DIRTY_DESCRIPTOR_SETS; } diff --git a/src/broadcom/vulkan/v3dv_descriptor_set.c b/src/broadcom/vulkan/v3dv_descriptor_set.c index 2c8d2c9e75b..a5f63f6548d 100644 --- a/src/broadcom/vulkan/v3dv_descriptor_set.c +++ b/src/broadcom/vulkan/v3dv_descriptor_set.c @@ -25,6 +25,55 @@ #include "v3dv_private.h" +static bool +descriptor_type_is_dynamic(VkDescriptorType type) +{ + switch (type) { + case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: + case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: + return true; + break; + default: + return false; + } +} + +struct v3dv_descriptor * +v3dv_descriptor_map_get_descriptor(struct v3dv_descriptor_state *descriptor_state, + struct v3dv_descriptor_map *map, + struct v3dv_pipeline_layout *pipeline_layout, + uint32_t index, + uint32_t *dynamic_offset) +{ + assert(index >= 0 && index < map->num_desc); + + uint32_t set_number = map->set[index]; + assert(descriptor_state->valid & 1 << set_number); + + struct v3dv_descriptor_set *set = + descriptor_state->descriptor_sets[set_number]; + assert(set); + + uint32_t binding_number = map->binding[index]; + assert(binding_number < set->layout->binding_count); + + const struct v3dv_descriptor_set_binding_layout *binding_layout = + &set->layout->binding[binding_number]; + + uint32_t array_index = map->array_index[index]; + assert(array_index < binding_layout->array_size); + + if (descriptor_type_is_dynamic(binding_layout->type)) { + uint32_t dynamic_offset_index = + pipeline_layout->set[set_number].dynamic_offset_start + + binding_layout->dynamic_offset_index + array_index; + + *dynamic_offset = descriptor_state->dynamic_offsets[dynamic_offset_index]; + } + + return &set->descriptors[binding_layout->descriptor_index + array_index]; +} + /* * As anv and tu already points: * diff --git a/src/broadcom/vulkan/v3dv_formats.c b/src/broadcom/vulkan/v3dv_formats.c index 4ec743fec66..db75598ebe6 100644 --- a/src/broadcom/vulkan/v3dv_formats.c +++ b/src/broadcom/vulkan/v3dv_formats.c @@ -308,6 +308,16 @@ v3dv_get_format_swizzle(VkFormat f) return vf->swizzle; } +uint8_t +v3dv_get_tex_return_size(const struct v3dv_format *vf, + enum pipe_tex_compare compare) +{ + if (compare == PIPE_TEX_COMPARE_R_TO_TEXTURE) + return 16; + + return vf->return_size; +} + static bool format_supports_blending(const struct v3dv_format *format) { diff --git a/src/broadcom/vulkan/v3dv_pipeline.c b/src/broadcom/vulkan/v3dv_pipeline.c index 270b5a9ad80..4e8dcea3fc5 100644 --- a/src/broadcom/vulkan/v3dv_pipeline.c +++ b/src/broadcom/vulkan/v3dv_pipeline.c @@ -1056,10 +1056,10 @@ upload_assembly(struct v3dv_pipeline_stage *p_stage, * already compiled, it gets it from the p_stage cache, if not it compiles is * through the v3d compiler */ -static struct v3dv_shader_variant* -get_shader_variant(struct v3dv_pipeline_stage *p_stage, - struct v3d_key *key, - size_t key_size) +struct v3dv_shader_variant* +v3dv_get_shader_variant(struct v3dv_pipeline_stage *p_stage, + struct v3d_key *key, + size_t key_size) { struct hash_table *ht = p_stage->cache; struct hash_entry *entry = _mesa_hash_table_search(ht, key); @@ -1359,12 +1359,12 @@ pipeline_compile_graphics(struct v3dv_pipeline *pipeline, struct v3d_vs_key *key = &pipeline->vs->key.vs; pipeline_populate_v3d_vs_key(key, pCreateInfo, pipeline->vs); pipeline->vs->current_variant = - get_shader_variant(pipeline->vs, &key->base, sizeof(*key)); + v3dv_get_shader_variant(pipeline->vs, &key->base, sizeof(*key)); key = &pipeline->vs_bin->key.vs; pipeline_populate_v3d_vs_key(key, pCreateInfo, pipeline->vs_bin); pipeline->vs_bin->current_variant = - get_shader_variant(pipeline->vs_bin, &key->base, sizeof(*key)); + v3dv_get_shader_variant(pipeline->vs_bin, &key->base, sizeof(*key)); break; } case MESA_SHADER_FRAGMENT: { @@ -1377,7 +1377,7 @@ pipeline_compile_graphics(struct v3dv_pipeline *pipeline, lower_fs_io(p_stage->nir); p_stage->current_variant = - get_shader_variant(p_stage, &key->base, sizeof(*key)); + v3dv_get_shader_variant(p_stage, &key->base, sizeof(*key)); break; } diff --git a/src/broadcom/vulkan/v3dv_private.h b/src/broadcom/vulkan/v3dv_private.h index 61778d7fc7f..209a619eb3b 100644 --- a/src/broadcom/vulkan/v3dv_private.h +++ b/src/broadcom/vulkan/v3dv_private.h @@ -526,6 +526,7 @@ enum v3dv_cmd_dirty_bits { V3DV_CMD_DIRTY_DESCRIPTOR_SETS = 1 << 7, V3DV_CMD_DIRTY_PUSH_CONSTANTS = 1 << 8, V3DV_CMD_DIRTY_BLEND_CONSTANTS = 1 << 9, + V3DV_CMD_DIRTY_SHADER_VARIANTS = 1 << 10, }; @@ -1126,6 +1127,8 @@ void v3dv_loge_v(const char *format, va_list va); const struct v3dv_format *v3dv_get_format(VkFormat); const uint8_t *v3dv_get_format_swizzle(VkFormat f); void v3dv_get_internal_type_bpp_for_output_format(uint32_t format, uint32_t *type, uint32_t *bpp); +uint8_t v3dv_get_tex_return_size(const struct v3dv_format *vf, enum pipe_tex_compare compare); + uint32_t v3d_utile_width(int cpp); uint32_t v3d_utile_height(int cpp); @@ -1145,6 +1148,18 @@ void v3d_store_tiled_image(void *dst, uint32_t dst_stride, struct v3dv_cl_reloc v3dv_write_uniforms(struct v3dv_cmd_buffer *cmd_buffer, struct v3dv_pipeline_stage *p_stage); +struct v3dv_shader_variant * +v3dv_get_shader_variant(struct v3dv_pipeline_stage *p_stage, + struct v3d_key *key, + size_t key_size); + +struct v3dv_descriptor * +v3dv_descriptor_map_get_descriptor(struct v3dv_descriptor_state *descriptor_state, + struct v3dv_descriptor_map *map, + struct v3dv_pipeline_layout *pipeline_layout, + uint32_t index, + uint32_t *dynamic_offset); + #define V3DV_DEFINE_HANDLE_CASTS(__v3dv_type, __VkType) \ \ static inline struct __v3dv_type * \ diff --git a/src/broadcom/vulkan/v3dv_uniforms.c b/src/broadcom/vulkan/v3dv_uniforms.c index 7b4dad84e9f..7493afea306 100644 --- a/src/broadcom/vulkan/v3dv_uniforms.c +++ b/src/broadcom/vulkan/v3dv_uniforms.c @@ -28,56 +28,6 @@ #include "v3dv_private.h" #include "vk_format_info.h" -static bool -descriptor_type_is_dynamic(VkDescriptorType type) -{ - switch (type) { - case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: - case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: - return true; - break; - default: - return false; - } - return false; -} - -static struct v3dv_descriptor * -get_descriptor(struct v3dv_descriptor_state *descriptor_state, - struct v3dv_descriptor_map *map, - struct v3dv_pipeline_layout *pipeline_layout, - uint32_t index, - uint32_t *dynamic_offset) -{ - assert(index >= 0 && index < map->num_desc); - - uint32_t set_number = map->set[index]; - assert(descriptor_state->valid & 1 << set_number); - - struct v3dv_descriptor_set *set = - descriptor_state->descriptor_sets[set_number]; - assert(set); - - uint32_t binding_number = map->binding[index]; - assert(binding_number < set->layout->binding_count); - - const struct v3dv_descriptor_set_binding_layout *binding_layout = - &set->layout->binding[binding_number]; - - uint32_t array_index = map->array_index[index]; - assert(array_index < binding_layout->array_size); - - if (descriptor_type_is_dynamic(binding_layout->type)) { - uint32_t dynamic_offset_index = - pipeline_layout->set[set_number].dynamic_offset_start + - binding_layout->dynamic_offset_index + array_index; - - *dynamic_offset = descriptor_state->dynamic_offsets[dynamic_offset_index]; - } - - return &set->descriptors[binding_layout->descriptor_index + array_index]; -} - /* * This method checks if the ubo used for push constants is needed to be * updated or not. @@ -145,8 +95,8 @@ write_tmu_p0(struct v3dv_cmd_buffer *cmd_buffer, &cmd_buffer->state.descriptor_state; struct v3dv_descriptor *descriptor = - get_descriptor(descriptor_state, &pipeline->texture_map, - pipeline->layout, unit, NULL); + v3dv_descriptor_map_get_descriptor(descriptor_state, &pipeline->texture_map, + pipeline->layout, unit, NULL); assert(descriptor); assert(descriptor->image_view); @@ -172,8 +122,8 @@ write_tmu_p1(struct v3dv_cmd_buffer *cmd_buffer, &cmd_buffer->state.descriptor_state; struct v3dv_descriptor *descriptor = - get_descriptor(descriptor_state, &pipeline->sampler_map, - pipeline->layout, unit, NULL); + v3dv_descriptor_map_get_descriptor(descriptor_state, &pipeline->sampler_map, + pipeline->layout, unit, NULL); assert(descriptor); assert(descriptor->sampler); @@ -230,9 +180,9 @@ write_ubo_ssbo_uniforms(struct v3dv_cmd_buffer *cmd_buffer, data; struct v3dv_descriptor *descriptor = - get_descriptor(descriptor_state, map, - pipeline->layout, - index, &dynamic_offset); + v3dv_descriptor_map_get_descriptor(descriptor_state, map, + pipeline->layout, + index, &dynamic_offset); assert(descriptor); assert(descriptor->buffer);