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: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6766>
This commit is contained in:
Alejandro Piñeiro 2020-03-25 11:50:16 +01:00 committed by Marge Bot
parent f76dad8f89
commit 07addb4183
6 changed files with 214 additions and 64 deletions

View File

@ -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;
}

View File

@ -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:
*

View File

@ -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)
{

View File

@ -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;
}

View File

@ -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 * \

View File

@ -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);