tu: Create singleton "empty" shaders

The most important of these is the empty FS, which should cut down on
time spent in the compiler when we fast-link a pipeline where there is
only a library with the VS and no library with the empty FS. Source
engine is known to do this.

This is also necessary for shader objects where the "empty" shaders are
never created up-front. We will use these when a NULL shader is bound.

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/25276>
This commit is contained in:
Connor Abbott 2023-09-04 17:54:35 +02:00 committed by Marge Bot
parent 1020cf8a82
commit 0f022c3076
5 changed files with 106 additions and 27 deletions

View file

@ -2184,6 +2184,12 @@ tu_CreateDevice(VkPhysicalDevice physicalDevice,
device->global_bo_map = global;
tu_init_clear_blit_shaders(device);
result = tu_init_empty_shaders(device);
if (result != VK_SUCCESS) {
vk_startup_errorf(device->instance, result, "empty shaders");
goto fail_empty_shaders;
}
global->predicate = 0;
global->vtx_stats_query_not_running = 1;
global->dbg_one = (uint32_t)-1;
@ -2327,6 +2333,8 @@ fail_perfcntrs_pass_alloc:
fail_pipeline_cache:
tu_destroy_dynamic_rendering(device);
fail_dynamic_rendering:
tu_destroy_empty_shaders(device);
fail_empty_shaders:
tu_destroy_clear_blit_shaders(device);
fail_global_bo_map:
tu_bo_finish(device, device->global_bo);
@ -2377,6 +2385,8 @@ tu_DestroyDevice(VkDevice _device, const VkAllocationCallbacks *pAllocator)
tu_destroy_clear_blit_shaders(device);
tu_destroy_empty_shaders(device);
tu_destroy_dynamic_rendering(device);
ir3_compiler_destroy(device->compiler);

View file

@ -287,6 +287,8 @@ struct tu_device
struct ir3_shader *global_shaders[GLOBAL_SH_COUNT];
uint64_t global_shader_va[GLOBAL_SH_COUNT];
struct tu_shader *empty_tcs, *empty_tes, *empty_gs, *empty_fs;
uint32_t vsc_draw_strm_pitch;
uint32_t vsc_prim_strm_pitch;
BITSET_DECLARE(custom_border_color, TU_BORDER_COLOR_COUNT);

View file

@ -1766,8 +1766,7 @@ tu_pipeline_builder_compile_shaders(struct tu_pipeline_builder *builder,
const VkPipelineCreationFeedbackCreateInfo *creation_feedback =
vk_find_struct_const(builder->create_info->pNext, PIPELINE_CREATION_FEEDBACK_CREATE_INFO);
bool must_compile =
builder->state & VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT;
bool must_compile = false;
for (uint32_t i = 0; i < builder->create_info->stageCount; i++) {
if (!(builder->active_stages & builder->create_info->pStages[i].stage))
continue;
@ -1854,9 +1853,7 @@ tu_pipeline_builder_compile_shaders(struct tu_pipeline_builder *builder,
for (gl_shader_stage stage = MESA_SHADER_VERTEX; stage < ARRAY_SIZE(nir);
stage = (gl_shader_stage) (stage + 1)) {
if (stage_infos[stage] || nir[stage] ||
(stage == MESA_SHADER_FRAGMENT &&
(builder->state & VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT))) {
if (stage_infos[stage] || nir[stage]) {
bool shader_application_cache_hit;
shader_sha1[20] = (unsigned char) stage;
shaders[stage] =
@ -1920,16 +1917,6 @@ tu_pipeline_builder_compile_shaders(struct tu_pipeline_builder *builder,
stage_feedbacks[stage].duration += os_time_get_nano() - stage_start;
}
if (!nir[MESA_SHADER_FRAGMENT] &&
(builder->state & VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT)) {
const nir_shader_compiler_options *nir_options =
ir3_get_compiler_options(builder->device->compiler);
nir_builder fs_b = nir_builder_init_simple_shader(MESA_SHADER_FRAGMENT,
nir_options,
"noop_fs");
nir[MESA_SHADER_FRAGMENT] = fs_b.shader;
}
if (executable_info) {
for (gl_shader_stage stage = MESA_SHADER_VERTEX;
stage < ARRAY_SIZE(nir);
@ -2020,14 +2007,25 @@ done:
*/
if (builder->state &
VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT) {
for (gl_shader_stage stage = MESA_SHADER_TESS_CTRL; stage <= MESA_SHADER_GEOMETRY;
stage = (gl_shader_stage) (stage + 1)) {
if (!shaders[stage]) {
result = tu_empty_shader_create(builder->device, &shaders[stage],
stage);
if (result != VK_SUCCESS)
goto fail;
}
if (!shaders[MESA_SHADER_TESS_CTRL]) {
shaders[MESA_SHADER_TESS_CTRL] = builder->device->empty_tcs;
vk_pipeline_cache_object_ref(&shaders[MESA_SHADER_TESS_CTRL]->base);
}
if (!shaders[MESA_SHADER_TESS_EVAL]) {
shaders[MESA_SHADER_TESS_EVAL] = builder->device->empty_tes;
vk_pipeline_cache_object_ref(&shaders[MESA_SHADER_TESS_EVAL]->base);
}
if (!shaders[MESA_SHADER_GEOMETRY]) {
shaders[MESA_SHADER_GEOMETRY] = builder->device->empty_gs;
vk_pipeline_cache_object_ref(&shaders[MESA_SHADER_GEOMETRY]->base);
}
}
if (builder->state &
VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT) {
if (!shaders[MESA_SHADER_FRAGMENT]) {
shaders[MESA_SHADER_FRAGMENT] = builder->device->empty_fs;
vk_pipeline_cache_object_ref(&shaders[MESA_SHADER_FRAGMENT]->base);
}
}

View file

@ -2289,7 +2289,7 @@ tu_shader_create(struct tu_device *dev,
return VK_SUCCESS;
}
VkResult
static VkResult
tu_empty_shader_create(struct tu_device *dev,
struct tu_shader **shader_out,
gl_shader_stage stage)
@ -2322,6 +2322,74 @@ tu_empty_shader_create(struct tu_device *dev,
return VK_SUCCESS;
}
static VkResult
tu_empty_fs_create(struct tu_device *dev, struct tu_shader **shader)
{
struct ir3_shader_key key = {};
const struct ir3_shader_options options = {};
struct ir3_stream_output_info so_info = {};
const nir_shader_compiler_options *nir_options =
ir3_get_compiler_options(dev->compiler);
nir_builder fs_b;
fs_b = nir_builder_init_simple_shader(MESA_SHADER_FRAGMENT, nir_options,
"noop_fs");
*shader = tu_shader_init(dev, NULL, 0);
if (!*shader)
return VK_ERROR_OUT_OF_HOST_MEMORY;
struct ir3_shader *ir3_shader =
ir3_shader_from_nir(dev->compiler, fs_b.shader, &options, &so_info);
(*shader)->variant = ir3_shader_create_variant(ir3_shader, &key, false);
return tu_upload_shader(dev, *shader);
}
VkResult
tu_init_empty_shaders(struct tu_device *dev)
{
VkResult result;
result = tu_empty_shader_create(dev, &dev->empty_tcs, MESA_SHADER_TESS_CTRL);
if (result != VK_SUCCESS)
goto out;
result = tu_empty_shader_create(dev, &dev->empty_tes, MESA_SHADER_TESS_EVAL);
if (result != VK_SUCCESS)
goto out;
result = tu_empty_shader_create(dev, &dev->empty_gs, MESA_SHADER_GEOMETRY);
if (result != VK_SUCCESS)
goto out;
result = tu_empty_fs_create(dev, &dev->empty_fs);
if (result != VK_SUCCESS)
goto out;
return VK_SUCCESS;
out:
if (dev->empty_tcs)
vk_pipeline_cache_object_unref(&dev->vk, &dev->empty_tcs->base);
if (dev->empty_tes)
vk_pipeline_cache_object_unref(&dev->vk, &dev->empty_tes->base);
if (dev->empty_gs)
vk_pipeline_cache_object_unref(&dev->vk, &dev->empty_gs->base);
if (dev->empty_fs)
vk_pipeline_cache_object_unref(&dev->vk, &dev->empty_fs->base);
return result;
}
void
tu_destroy_empty_shaders(struct tu_device *dev)
{
vk_pipeline_cache_object_unref(&dev->vk, &dev->empty_tcs->base);
vk_pipeline_cache_object_unref(&dev->vk, &dev->empty_tes->base);
vk_pipeline_cache_object_unref(&dev->vk, &dev->empty_gs->base);
vk_pipeline_cache_object_unref(&dev->vk, &dev->empty_fs->base);
}
void
tu_shader_destroy(struct tu_device *dev,
struct tu_shader *shader)

View file

@ -122,9 +122,10 @@ tu_shader_create(struct tu_device *dev,
bool executable_info);
VkResult
tu_empty_shader_create(struct tu_device *device,
struct tu_shader **shader_out,
gl_shader_stage stage);
tu_init_empty_shaders(struct tu_device *device);
void
tu_destroy_empty_shaders(struct tu_device *device);
void
tu_shader_destroy(struct tu_device *dev,