2019-05-26 09:43:12 +01:00
|
|
|
|
/*
|
|
|
|
|
* Copyright © Microsoft Corporation
|
|
|
|
|
*
|
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
|
|
|
* to deal in the Software without restriction, including without limitation
|
|
|
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
|
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
|
|
|
*
|
|
|
|
|
* The above copyright notice and this permission notice (including the next
|
|
|
|
|
* paragraph) shall be included in all copies or substantial portions of the
|
|
|
|
|
* Software.
|
|
|
|
|
*
|
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
|
|
|
* IN THE SOFTWARE.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "d3d12_compiler.h"
|
|
|
|
|
#include "d3d12_context.h"
|
|
|
|
|
#include "d3d12_debug.h"
|
|
|
|
|
#include "d3d12_screen.h"
|
|
|
|
|
#include "d3d12_nir_passes.h"
|
|
|
|
|
#include "nir_to_dxil.h"
|
2021-03-26 01:21:37 +00:00
|
|
|
|
#include "dxil_nir.h"
|
2022-06-08 14:53:44 +01:00
|
|
|
|
#include "dxil_nir_lower_int_cubemaps.h"
|
2019-05-26 09:43:12 +01:00
|
|
|
|
|
|
|
|
|
#include "pipe/p_state.h"
|
|
|
|
|
|
|
|
|
|
#include "nir.h"
|
|
|
|
|
#include "nir/nir_draw_helpers.h"
|
|
|
|
|
#include "nir/tgsi_to_nir.h"
|
|
|
|
|
#include "compiler/nir/nir_builder.h"
|
|
|
|
|
#include "tgsi/tgsi_from_mesa.h"
|
|
|
|
|
#include "tgsi/tgsi_ureg.h"
|
|
|
|
|
|
2022-05-08 02:48:22 +01:00
|
|
|
|
#include "util/hash_table.h"
|
2019-05-26 09:43:12 +01:00
|
|
|
|
#include "util/u_memory.h"
|
|
|
|
|
#include "util/u_prim.h"
|
|
|
|
|
#include "util/u_simple_shaders.h"
|
2020-12-08 18:56:03 +00:00
|
|
|
|
#include "util/u_dl.h"
|
2019-05-26 09:43:12 +01:00
|
|
|
|
|
2020-12-08 18:02:35 +00:00
|
|
|
|
#include <dxguids/dxguids.h>
|
|
|
|
|
|
2019-05-26 09:43:12 +01:00
|
|
|
|
extern "C" {
|
|
|
|
|
#include "tgsi/tgsi_parse.h"
|
|
|
|
|
#include "tgsi/tgsi_point_sprite.h"
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-05 10:11:54 +01:00
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
#include "dxil_validator.h"
|
|
|
|
|
#endif
|
2019-05-26 09:43:12 +01:00
|
|
|
|
|
|
|
|
|
const void *
|
|
|
|
|
d3d12_get_compiler_options(struct pipe_screen *screen,
|
|
|
|
|
enum pipe_shader_ir ir,
|
|
|
|
|
enum pipe_shader_type shader)
|
|
|
|
|
{
|
|
|
|
|
assert(ir == PIPE_SHADER_IR_NIR);
|
2022-01-28 20:37:23 +00:00
|
|
|
|
return &d3d12_screen(screen)->nir_options;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static uint32_t
|
|
|
|
|
resource_dimension(enum glsl_sampler_dim dim)
|
|
|
|
|
{
|
|
|
|
|
switch (dim) {
|
|
|
|
|
case GLSL_SAMPLER_DIM_1D:
|
|
|
|
|
return RESOURCE_DIMENSION_TEXTURE1D;
|
|
|
|
|
case GLSL_SAMPLER_DIM_2D:
|
|
|
|
|
return RESOURCE_DIMENSION_TEXTURE2D;
|
|
|
|
|
case GLSL_SAMPLER_DIM_3D:
|
|
|
|
|
return RESOURCE_DIMENSION_TEXTURE3D;
|
|
|
|
|
case GLSL_SAMPLER_DIM_CUBE:
|
|
|
|
|
return RESOURCE_DIMENSION_TEXTURECUBE;
|
|
|
|
|
default:
|
|
|
|
|
return RESOURCE_DIMENSION_UNKNOWN;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-15 22:56:03 +01:00
|
|
|
|
static bool
|
|
|
|
|
can_remove_dead_sampler(nir_variable *var, void *data)
|
|
|
|
|
{
|
|
|
|
|
const struct glsl_type *base_type = glsl_without_array(var->type);
|
|
|
|
|
return glsl_type_is_sampler(base_type) && !glsl_type_is_bare_sampler(base_type);
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-26 09:43:12 +01:00
|
|
|
|
static struct d3d12_shader *
|
|
|
|
|
compile_nir(struct d3d12_context *ctx, struct d3d12_shader_selector *sel,
|
|
|
|
|
struct d3d12_shader_key *key, struct nir_shader *nir)
|
|
|
|
|
{
|
|
|
|
|
struct d3d12_screen *screen = d3d12_screen(ctx->base.screen);
|
|
|
|
|
struct d3d12_shader *shader = rzalloc(sel, d3d12_shader);
|
|
|
|
|
shader->key = *key;
|
|
|
|
|
shader->nir = nir;
|
|
|
|
|
sel->current = shader;
|
|
|
|
|
|
|
|
|
|
NIR_PASS_V(nir, nir_lower_samplers);
|
2021-10-15 22:56:03 +01:00
|
|
|
|
NIR_PASS_V(nir, dxil_nir_split_typed_samplers);
|
|
|
|
|
|
|
|
|
|
NIR_PASS_V(nir, nir_opt_dce);
|
2021-11-22 13:41:35 +00:00
|
|
|
|
struct nir_remove_dead_variables_options dead_var_opts = {};
|
|
|
|
|
dead_var_opts.can_remove_var = can_remove_dead_sampler;
|
2021-10-15 22:56:03 +01:00
|
|
|
|
NIR_PASS_V(nir, nir_remove_dead_variables, nir_var_uniform, &dead_var_opts);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
|
|
|
|
|
if (key->samples_int_textures)
|
|
|
|
|
NIR_PASS_V(nir, dxil_lower_sample_to_txf_for_integer_tex,
|
|
|
|
|
key->tex_wrap_states, key->swizzle_state,
|
|
|
|
|
screen->base.get_paramf(&screen->base, PIPE_CAPF_MAX_TEXTURE_LOD_BIAS));
|
|
|
|
|
|
|
|
|
|
if (key->vs.needs_format_emulation)
|
2022-06-14 11:09:51 +01:00
|
|
|
|
dxil_nir_lower_vs_vertex_conversion(nir, key->vs.format_conversion);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
|
|
|
|
|
uint32_t num_ubos_before_lower_to_ubo = nir->info.num_ubos;
|
|
|
|
|
uint32_t num_uniforms_before_lower_to_ubo = nir->num_uniforms;
|
2021-04-10 00:10:30 +01:00
|
|
|
|
NIR_PASS_V(nir, nir_lower_uniforms_to_ubo, false, false);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
shader->has_default_ubo0 = num_uniforms_before_lower_to_ubo > 0 &&
|
|
|
|
|
nir->info.num_ubos > num_ubos_before_lower_to_ubo;
|
|
|
|
|
|
|
|
|
|
if (key->last_vertex_processing_stage) {
|
|
|
|
|
if (key->invert_depth)
|
2022-02-07 17:49:33 +00:00
|
|
|
|
NIR_PASS_V(nir, d3d12_nir_invert_depth, key->invert_depth, key->halfz);
|
|
|
|
|
if (!key->halfz)
|
|
|
|
|
NIR_PASS_V(nir, nir_lower_clip_halfz);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
NIR_PASS_V(nir, d3d12_lower_yflip);
|
|
|
|
|
}
|
|
|
|
|
NIR_PASS_V(nir, nir_lower_packed_ubo_loads);
|
2022-01-10 22:09:30 +00:00
|
|
|
|
NIR_PASS_V(nir, d3d12_lower_load_draw_params);
|
2022-01-06 00:07:51 +00:00
|
|
|
|
NIR_PASS_V(nir, d3d12_lower_load_patch_vertices_in);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
NIR_PASS_V(nir, d3d12_lower_state_vars, shader);
|
2021-10-08 00:19:33 +01:00
|
|
|
|
NIR_PASS_V(nir, dxil_nir_lower_bool_input);
|
2021-12-22 19:54:40 +00:00
|
|
|
|
NIR_PASS_V(nir, dxil_nir_lower_loads_stores_to_dxil);
|
2022-01-01 16:09:05 +00:00
|
|
|
|
NIR_PASS_V(nir, dxil_nir_lower_atomics_to_dxil);
|
2022-01-28 20:55:10 +00:00
|
|
|
|
NIR_PASS_V(nir, dxil_nir_lower_double_math);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
|
2022-01-14 00:44:32 +00:00
|
|
|
|
if (key->fs.multisample_disabled)
|
|
|
|
|
NIR_PASS_V(nir, d3d12_disable_multisampling);
|
|
|
|
|
|
2019-05-26 09:43:12 +01:00
|
|
|
|
struct nir_to_dxil_options opts = {};
|
|
|
|
|
opts.interpolate_at_vertex = screen->have_load_at_vertex;
|
|
|
|
|
opts.lower_int16 = !screen->opts4.Native16BitShaderOpsSupported;
|
2022-01-17 15:31:53 +00:00
|
|
|
|
opts.no_ubo0 = !shader->has_default_ubo0;
|
|
|
|
|
opts.last_ubo_is_not_arrayed = shader->num_state_vars > 0;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
opts.provoking_vertex = key->fs.provoking_vertex;
|
2022-01-06 15:42:22 +00:00
|
|
|
|
opts.input_clip_size = key->input_clip_size;
|
2021-12-28 21:13:03 +00:00
|
|
|
|
opts.environment = DXIL_ENVIRONMENT_GL;
|
2021-12-20 16:55:55 +00:00
|
|
|
|
opts.shader_model_max = SHADER_MODEL_6_2;
|
2022-02-13 21:05:12 +00:00
|
|
|
|
opts.validator_version_max = DXIL_VALIDATOR_1_4;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
|
|
|
|
|
struct blob tmp;
|
|
|
|
|
if (!nir_to_dxil(nir, &opts, &tmp)) {
|
|
|
|
|
debug_printf("D3D12: nir_to_dxil failed\n");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Non-ubo variables
|
2021-04-16 19:40:35 +01:00
|
|
|
|
shader->begin_srv_binding = (UINT_MAX);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
nir_foreach_variable_with_modes(var, nir, nir_var_uniform) {
|
2021-12-29 00:29:13 +00:00
|
|
|
|
auto type_no_array = glsl_without_array(var->type);
|
|
|
|
|
if (glsl_type_is_texture(type_no_array)) {
|
2019-05-26 09:43:12 +01:00
|
|
|
|
unsigned count = glsl_type_is_array(var->type) ? glsl_get_aoa_size(var->type) : 1;
|
|
|
|
|
for (unsigned i = 0; i < count; ++i) {
|
2021-12-29 00:29:13 +00:00
|
|
|
|
shader->srv_bindings[var->data.binding + i].dimension = resource_dimension(glsl_get_sampler_dim(type_no_array));
|
2019-05-26 09:43:12 +01:00
|
|
|
|
}
|
2021-04-16 19:40:35 +01:00
|
|
|
|
shader->begin_srv_binding = MIN2(var->data.binding, shader->begin_srv_binding);
|
|
|
|
|
shader->end_srv_binding = MAX2(var->data.binding + count, shader->end_srv_binding);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-29 00:29:13 +00:00
|
|
|
|
nir_foreach_image_variable(var, nir) {
|
|
|
|
|
auto type_no_array = glsl_without_array(var->type);
|
|
|
|
|
unsigned count = glsl_type_is_array(var->type) ? glsl_get_aoa_size(var->type) : 1;
|
|
|
|
|
for (unsigned i = 0; i < count; ++i) {
|
|
|
|
|
shader->uav_bindings[var->data.driver_location + i].format = var->data.image.format;
|
|
|
|
|
shader->uav_bindings[var->data.driver_location + i].dimension = resource_dimension(glsl_get_sampler_dim(type_no_array));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-26 09:43:12 +01:00
|
|
|
|
// Ubo variables
|
|
|
|
|
if(nir->info.num_ubos) {
|
|
|
|
|
// Ignore state_vars ubo as it is bound as root constants
|
|
|
|
|
unsigned num_ubo_bindings = nir->info.num_ubos - (shader->state_vars_used ? 1 : 0);
|
2022-01-17 15:31:53 +00:00
|
|
|
|
for(unsigned i = shader->has_default_ubo0 ? 0 : 1; i < num_ubo_bindings; ++i) {
|
2019-05-26 09:43:12 +01:00
|
|
|
|
shader->cb_bindings[shader->num_cb_bindings++].binding = i;
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-04-05 10:11:54 +01:00
|
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
if (ctx->dxil_validator) {
|
|
|
|
|
if (!(d3d12_debug & D3D12_DEBUG_EXPERIMENTAL)) {
|
|
|
|
|
char *err;
|
|
|
|
|
if (!dxil_validate_module(ctx->dxil_validator, tmp.data,
|
|
|
|
|
tmp.size, &err) && err) {
|
|
|
|
|
debug_printf(
|
|
|
|
|
"== VALIDATION ERROR =============================================\n"
|
|
|
|
|
"%s\n"
|
|
|
|
|
"== END ==========================================================\n",
|
|
|
|
|
err);
|
|
|
|
|
ralloc_free(err);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-05-26 09:43:12 +01:00
|
|
|
|
|
2021-02-04 16:30:02 +00:00
|
|
|
|
if (d3d12_debug & D3D12_DEBUG_DISASS) {
|
2022-04-05 10:11:54 +01:00
|
|
|
|
char *str = dxil_disasm_module(ctx->dxil_validator, tmp.data,
|
|
|
|
|
tmp.size);
|
|
|
|
|
fprintf(stderr,
|
|
|
|
|
"== BEGIN SHADER ============================================\n"
|
|
|
|
|
"%s\n"
|
|
|
|
|
"== END SHADER ==============================================\n",
|
|
|
|
|
str);
|
|
|
|
|
ralloc_free(str);
|
2021-02-04 16:30:02 +00:00
|
|
|
|
}
|
2019-05-26 09:43:12 +01:00
|
|
|
|
}
|
2022-04-05 10:11:54 +01:00
|
|
|
|
#endif
|
2019-05-26 09:43:12 +01:00
|
|
|
|
|
|
|
|
|
blob_finish_get_buffer(&tmp, &shader->bytecode, &shader->bytecode_length);
|
|
|
|
|
|
|
|
|
|
if (d3d12_debug & D3D12_DEBUG_DXIL) {
|
|
|
|
|
char buf[256];
|
|
|
|
|
static int i;
|
|
|
|
|
snprintf(buf, sizeof(buf), "dump%02d.dxil", i++);
|
|
|
|
|
FILE *fp = fopen(buf, "wb");
|
|
|
|
|
fwrite(shader->bytecode, sizeof(char), shader->bytecode_length, fp);
|
|
|
|
|
fclose(fp);
|
|
|
|
|
fprintf(stderr, "wrote '%s'...\n", buf);
|
|
|
|
|
}
|
|
|
|
|
return shader;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct d3d12_selection_context {
|
|
|
|
|
struct d3d12_context *ctx;
|
|
|
|
|
bool needs_point_sprite_lowering;
|
|
|
|
|
bool needs_vertex_reordering;
|
|
|
|
|
unsigned provoking_vertex;
|
|
|
|
|
bool alternate_tri;
|
|
|
|
|
unsigned fill_mode_lowered;
|
|
|
|
|
unsigned cull_mode_lowered;
|
|
|
|
|
bool manual_depth_range;
|
|
|
|
|
unsigned missing_dual_src_outputs;
|
|
|
|
|
unsigned frag_result_color_lowering;
|
2021-12-31 20:54:04 +00:00
|
|
|
|
const unsigned *variable_workgroup_size;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static unsigned
|
|
|
|
|
missing_dual_src_outputs(struct d3d12_context *ctx)
|
|
|
|
|
{
|
|
|
|
|
if (!ctx->gfx_pipeline_state.blend->is_dual_src)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
struct d3d12_shader_selector *fs = ctx->gfx_stages[PIPE_SHADER_FRAGMENT];
|
|
|
|
|
nir_shader *s = fs->initial;
|
|
|
|
|
|
|
|
|
|
unsigned indices_seen = 0;
|
|
|
|
|
nir_foreach_function(function, s) {
|
|
|
|
|
if (function->impl) {
|
|
|
|
|
nir_foreach_block(block, function->impl) {
|
|
|
|
|
nir_foreach_instr(instr, block) {
|
|
|
|
|
if (instr->type != nir_instr_type_intrinsic)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
|
|
|
|
|
if (intr->intrinsic != nir_intrinsic_store_deref)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
nir_variable *var = nir_intrinsic_get_var(intr, 0);
|
2022-02-09 23:22:40 +00:00
|
|
|
|
if (var->data.mode != nir_var_shader_out)
|
2019-05-26 09:43:12 +01:00
|
|
|
|
continue;
|
|
|
|
|
|
2022-02-09 23:22:40 +00:00
|
|
|
|
unsigned index = var->data.index;
|
|
|
|
|
if (var->data.location > FRAG_RESULT_DATA0)
|
|
|
|
|
index = var->data.location - FRAG_RESULT_DATA0;
|
|
|
|
|
else if (var->data.location != FRAG_RESULT_COLOR &&
|
|
|
|
|
var->data.location != FRAG_RESULT_DATA0)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
indices_seen |= 1u << index;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
if ((indices_seen & 3) == 3)
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 3 & ~indices_seen;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static unsigned
|
|
|
|
|
frag_result_color_lowering(struct d3d12_context *ctx)
|
|
|
|
|
{
|
|
|
|
|
struct d3d12_shader_selector *fs = ctx->gfx_stages[PIPE_SHADER_FRAGMENT];
|
|
|
|
|
assert(fs);
|
|
|
|
|
|
|
|
|
|
if (fs->initial->info.outputs_written & BITFIELD64_BIT(FRAG_RESULT_COLOR))
|
|
|
|
|
return ctx->fb.nr_cbufs > 1 ? ctx->fb.nr_cbufs : 0;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
manual_depth_range(struct d3d12_context *ctx)
|
|
|
|
|
{
|
|
|
|
|
if (!d3d12_need_zero_one_depth_range(ctx))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* If we can't use the D3D12 zero-one depth-range, we might have to apply
|
|
|
|
|
* depth-range ourselves.
|
|
|
|
|
*
|
|
|
|
|
* Because we only need to override the depth-range to zero-one range in
|
|
|
|
|
* the case where we write frag-depth, we only need to apply manual
|
|
|
|
|
* depth-range to gl_FragCoord.z.
|
|
|
|
|
*
|
|
|
|
|
* No extra care is needed to be taken in the case where gl_FragDepth is
|
|
|
|
|
* written conditionally, because the GLSL 4.60 spec states:
|
|
|
|
|
*
|
|
|
|
|
* If a shader statically assigns a value to gl_FragDepth, and there
|
|
|
|
|
* is an execution path through the shader that does not set
|
|
|
|
|
* gl_FragDepth, then the value of the fragment’s depth may be
|
|
|
|
|
* undefined for executions of the shader that take that path. That
|
|
|
|
|
* is, if the set of linked fragment shaders statically contain a
|
|
|
|
|
* write to gl_FragDepth, then it is responsible for always writing
|
|
|
|
|
* it.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
struct d3d12_shader_selector *fs = ctx->gfx_stages[PIPE_SHADER_FRAGMENT];
|
|
|
|
|
return fs && fs->initial->info.inputs_read & VARYING_BIT_POS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
needs_edge_flag_fix(enum pipe_prim_type mode)
|
|
|
|
|
{
|
|
|
|
|
return (mode == PIPE_PRIM_QUADS ||
|
|
|
|
|
mode == PIPE_PRIM_QUAD_STRIP ||
|
|
|
|
|
mode == PIPE_PRIM_POLYGON);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static unsigned
|
|
|
|
|
fill_mode_lowered(struct d3d12_context *ctx, const struct pipe_draw_info *dinfo)
|
|
|
|
|
{
|
|
|
|
|
struct d3d12_shader_selector *vs = ctx->gfx_stages[PIPE_SHADER_VERTEX];
|
|
|
|
|
|
|
|
|
|
if ((ctx->gfx_stages[PIPE_SHADER_GEOMETRY] != NULL &&
|
2022-01-03 20:49:28 +00:00
|
|
|
|
!ctx->gfx_stages[PIPE_SHADER_GEOMETRY]->is_variant) ||
|
2019-05-26 09:43:12 +01:00
|
|
|
|
ctx->gfx_pipeline_state.rast == NULL ||
|
|
|
|
|
(dinfo->mode != PIPE_PRIM_TRIANGLES &&
|
|
|
|
|
dinfo->mode != PIPE_PRIM_TRIANGLE_STRIP))
|
|
|
|
|
return PIPE_POLYGON_MODE_FILL;
|
|
|
|
|
|
|
|
|
|
/* D3D12 supports line mode (wireframe) but doesn't support edge flags */
|
|
|
|
|
if (((ctx->gfx_pipeline_state.rast->base.fill_front == PIPE_POLYGON_MODE_LINE &&
|
|
|
|
|
ctx->gfx_pipeline_state.rast->base.cull_face != PIPE_FACE_FRONT) ||
|
|
|
|
|
(ctx->gfx_pipeline_state.rast->base.fill_back == PIPE_POLYGON_MODE_LINE &&
|
|
|
|
|
ctx->gfx_pipeline_state.rast->base.cull_face == PIPE_FACE_FRONT)) &&
|
|
|
|
|
(vs->initial->info.outputs_written & VARYING_BIT_EDGE ||
|
|
|
|
|
needs_edge_flag_fix(ctx->initial_api_prim)))
|
|
|
|
|
return PIPE_POLYGON_MODE_LINE;
|
|
|
|
|
|
|
|
|
|
if (ctx->gfx_pipeline_state.rast->base.fill_front == PIPE_POLYGON_MODE_POINT)
|
|
|
|
|
return PIPE_POLYGON_MODE_POINT;
|
|
|
|
|
|
|
|
|
|
return PIPE_POLYGON_MODE_FILL;
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-14 21:43:15 +00:00
|
|
|
|
static bool
|
|
|
|
|
has_stream_out_for_streams(struct d3d12_context *ctx)
|
|
|
|
|
{
|
|
|
|
|
unsigned mask = ctx->gfx_stages[PIPE_SHADER_GEOMETRY]->initial->info.gs.active_stream_mask & ~1;
|
|
|
|
|
for (unsigned i = 0; i < ctx->gfx_pipeline_state.so_info.num_outputs; ++i) {
|
|
|
|
|
unsigned stream = ctx->gfx_pipeline_state.so_info.output[i].stream;
|
|
|
|
|
if (((1 << stream) & mask) &&
|
|
|
|
|
ctx->so_buffer_views[stream].SizeInBytes)
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-26 09:43:12 +01:00
|
|
|
|
static bool
|
|
|
|
|
needs_point_sprite_lowering(struct d3d12_context *ctx, const struct pipe_draw_info *dinfo)
|
|
|
|
|
{
|
|
|
|
|
struct d3d12_shader_selector *vs = ctx->gfx_stages[PIPE_SHADER_VERTEX];
|
|
|
|
|
struct d3d12_shader_selector *gs = ctx->gfx_stages[PIPE_SHADER_GEOMETRY];
|
|
|
|
|
|
2022-01-03 20:49:28 +00:00
|
|
|
|
if (gs != NULL && !gs->is_variant) {
|
2019-05-26 09:43:12 +01:00
|
|
|
|
/* There is an user GS; Check if it outputs points with PSIZE */
|
|
|
|
|
return (gs->initial->info.gs.output_primitive == GL_POINTS &&
|
2022-01-14 21:32:26 +00:00
|
|
|
|
(gs->initial->info.outputs_written & VARYING_BIT_PSIZ ||
|
2022-01-14 21:43:15 +00:00
|
|
|
|
ctx->gfx_pipeline_state.rast->base.point_size > 1.0) &&
|
|
|
|
|
(gs->initial->info.gs.active_stream_mask == 1 ||
|
|
|
|
|
!has_stream_out_for_streams(ctx)));
|
2019-05-26 09:43:12 +01:00
|
|
|
|
} else {
|
|
|
|
|
/* No user GS; check if we are drawing wide points */
|
|
|
|
|
return ((dinfo->mode == PIPE_PRIM_POINTS ||
|
|
|
|
|
fill_mode_lowered(ctx, dinfo) == PIPE_POLYGON_MODE_POINT) &&
|
|
|
|
|
(ctx->gfx_pipeline_state.rast->base.point_size > 1.0 ||
|
|
|
|
|
ctx->gfx_pipeline_state.rast->base.offset_point ||
|
|
|
|
|
(ctx->gfx_pipeline_state.rast->base.point_size_per_vertex &&
|
|
|
|
|
vs->initial->info.outputs_written & VARYING_BIT_PSIZ)) &&
|
|
|
|
|
(vs->initial->info.outputs_written & VARYING_BIT_POS));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static unsigned
|
|
|
|
|
cull_mode_lowered(struct d3d12_context *ctx, unsigned fill_mode)
|
|
|
|
|
{
|
|
|
|
|
if ((ctx->gfx_stages[PIPE_SHADER_GEOMETRY] != NULL &&
|
2022-01-03 20:49:28 +00:00
|
|
|
|
!ctx->gfx_stages[PIPE_SHADER_GEOMETRY]->is_variant) ||
|
2019-05-26 09:43:12 +01:00
|
|
|
|
ctx->gfx_pipeline_state.rast == NULL ||
|
|
|
|
|
ctx->gfx_pipeline_state.rast->base.cull_face == PIPE_FACE_NONE)
|
|
|
|
|
return PIPE_FACE_NONE;
|
|
|
|
|
|
|
|
|
|
return ctx->gfx_pipeline_state.rast->base.cull_face;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static unsigned
|
2021-12-31 20:52:05 +00:00
|
|
|
|
get_provoking_vertex(struct d3d12_selection_context *sel_ctx, bool *alternate, const struct pipe_draw_info *dinfo)
|
2019-05-26 09:43:12 +01:00
|
|
|
|
{
|
2022-01-02 21:03:32 +00:00
|
|
|
|
if (dinfo->mode == GL_PATCHES) {
|
|
|
|
|
*alternate = false;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-26 09:43:12 +01:00
|
|
|
|
struct d3d12_shader_selector *vs = sel_ctx->ctx->gfx_stages[PIPE_SHADER_VERTEX];
|
|
|
|
|
struct d3d12_shader_selector *gs = sel_ctx->ctx->gfx_stages[PIPE_SHADER_GEOMETRY];
|
2022-01-03 20:49:28 +00:00
|
|
|
|
struct d3d12_shader_selector *last_vertex_stage = gs && !gs->is_variant ? gs : vs;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
|
|
|
|
|
/* Make sure GL prims match Gallium prims */
|
|
|
|
|
STATIC_ASSERT(GL_POINTS == PIPE_PRIM_POINTS);
|
|
|
|
|
STATIC_ASSERT(GL_LINES == PIPE_PRIM_LINES);
|
|
|
|
|
STATIC_ASSERT(GL_LINE_STRIP == PIPE_PRIM_LINE_STRIP);
|
|
|
|
|
|
|
|
|
|
enum pipe_prim_type mode;
|
|
|
|
|
switch (last_vertex_stage->stage) {
|
|
|
|
|
case PIPE_SHADER_GEOMETRY:
|
|
|
|
|
mode = (enum pipe_prim_type)last_vertex_stage->current->nir->info.gs.output_primitive;
|
|
|
|
|
break;
|
|
|
|
|
case PIPE_SHADER_VERTEX:
|
2021-12-31 20:52:05 +00:00
|
|
|
|
mode = (enum pipe_prim_type)dinfo->mode;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
unreachable("Tesselation shaders are not supported");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool flatshade_first = sel_ctx->ctx->gfx_pipeline_state.rast &&
|
|
|
|
|
sel_ctx->ctx->gfx_pipeline_state.rast->base.flatshade_first;
|
|
|
|
|
*alternate = (mode == GL_TRIANGLE_STRIP || mode == GL_TRIANGLE_STRIP_ADJACENCY) &&
|
2022-01-03 20:49:28 +00:00
|
|
|
|
(!gs || gs->is_variant ||
|
2019-05-26 09:43:12 +01:00
|
|
|
|
gs->initial->info.gs.vertices_out > u_prim_vertex_count(mode)->min);
|
|
|
|
|
return flatshade_first ? 0 : u_prim_vertex_count(mode)->min - 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
has_flat_varyings(struct d3d12_context *ctx)
|
|
|
|
|
{
|
|
|
|
|
struct d3d12_shader_selector *fs = ctx->gfx_stages[PIPE_SHADER_FRAGMENT];
|
|
|
|
|
|
|
|
|
|
if (!fs || !fs->current)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
nir_foreach_variable_with_modes(input, fs->current->nir,
|
|
|
|
|
nir_var_shader_in) {
|
2022-02-04 16:23:42 +00:00
|
|
|
|
if (input->data.interpolation == INTERP_MODE_FLAT &&
|
|
|
|
|
/* Disregard sysvals */
|
|
|
|
|
(input->data.location >= VARYING_SLOT_VAR0 ||
|
|
|
|
|
input->data.location <= VARYING_SLOT_TEX7))
|
2019-05-26 09:43:12 +01:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool
|
2021-12-31 20:52:05 +00:00
|
|
|
|
needs_vertex_reordering(struct d3d12_selection_context *sel_ctx, const struct pipe_draw_info *dinfo)
|
2019-05-26 09:43:12 +01:00
|
|
|
|
{
|
|
|
|
|
struct d3d12_context *ctx = sel_ctx->ctx;
|
|
|
|
|
bool flat = has_flat_varyings(ctx);
|
|
|
|
|
bool xfb = ctx->gfx_pipeline_state.num_so_targets > 0;
|
|
|
|
|
|
2021-12-31 20:52:05 +00:00
|
|
|
|
if (fill_mode_lowered(ctx, dinfo) != PIPE_POLYGON_MODE_FILL)
|
2019-05-26 09:43:12 +01:00
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
/* TODO add support for line primitives */
|
|
|
|
|
|
|
|
|
|
/* When flat shading a triangle and provoking vertex is not the first one, we use load_at_vertex.
|
|
|
|
|
If not available for this adapter, or if it's a triangle strip, we need to reorder the vertices */
|
|
|
|
|
if (flat && sel_ctx->provoking_vertex >= 2 && (!d3d12_screen(ctx->base.screen)->have_load_at_vertex ||
|
|
|
|
|
sel_ctx->alternate_tri))
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
/* When transform feedback is enabled and the output is alternating (triangle strip or triangle
|
|
|
|
|
strip with adjacency), we need to reorder vertices to get the order expected by OpenGL. This
|
|
|
|
|
only works when there is no flat shading involved. In that scenario, we don't care about
|
|
|
|
|
the provoking vertex. */
|
|
|
|
|
if (xfb && !flat && sel_ctx->alternate_tri) {
|
|
|
|
|
sel_ctx->provoking_vertex = 0;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static nir_variable *
|
|
|
|
|
create_varying_from_info(nir_shader *nir, struct d3d12_varying_info *info,
|
2022-01-05 15:38:38 +00:00
|
|
|
|
unsigned slot, unsigned slot_frac, nir_variable_mode mode, bool patch)
|
2019-05-26 09:43:12 +01:00
|
|
|
|
{
|
|
|
|
|
nir_variable *var;
|
|
|
|
|
char tmp[100];
|
|
|
|
|
|
|
|
|
|
snprintf(tmp, ARRAY_SIZE(tmp),
|
|
|
|
|
mode == nir_var_shader_in ? "in_%d" : "out_%d",
|
2022-01-05 15:38:38 +00:00
|
|
|
|
info->slots[slot].vars[slot_frac].driver_location);
|
|
|
|
|
var = nir_variable_create(nir, mode, info->slots[slot].types[slot_frac], tmp);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
var->data.location = slot;
|
2022-01-05 15:38:38 +00:00
|
|
|
|
var->data.location_frac = slot_frac;
|
|
|
|
|
var->data.driver_location = info->slots[slot].vars[slot_frac].driver_location;
|
|
|
|
|
var->data.interpolation = info->slots[slot].vars[slot_frac].interpolation;
|
|
|
|
|
var->data.patch = info->slots[slot].patch;
|
|
|
|
|
var->data.compact = info->slots[slot].vars[slot_frac].compact;
|
2022-01-02 21:03:32 +00:00
|
|
|
|
if (patch)
|
|
|
|
|
var->data.location += VARYING_SLOT_PATCH0;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
|
2022-02-04 16:24:02 +00:00
|
|
|
|
if (mode == nir_var_shader_out)
|
|
|
|
|
NIR_PASS_V(nir, d3d12_write_0_to_new_varying, var);
|
|
|
|
|
|
2019-05-26 09:43:12 +01:00
|
|
|
|
return var;
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-05 15:38:38 +00:00
|
|
|
|
void
|
|
|
|
|
create_varyings_from_info(nir_shader *nir, struct d3d12_varying_info *info,
|
|
|
|
|
unsigned slot, nir_variable_mode mode, bool patch)
|
|
|
|
|
{
|
|
|
|
|
unsigned mask = info->slots[slot].location_frac_mask;
|
|
|
|
|
while (mask)
|
|
|
|
|
create_varying_from_info(nir, info, slot, u_bit_scan(&mask), mode, patch);
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-26 09:43:12 +01:00
|
|
|
|
static void
|
|
|
|
|
fill_varyings(struct d3d12_varying_info *info, nir_shader *s,
|
2022-01-02 21:03:32 +00:00
|
|
|
|
nir_variable_mode modes, uint64_t mask, bool patch)
|
2019-05-26 09:43:12 +01:00
|
|
|
|
{
|
|
|
|
|
nir_foreach_variable_with_modes(var, s, modes) {
|
|
|
|
|
unsigned slot = var->data.location;
|
2022-01-02 21:03:32 +00:00
|
|
|
|
bool is_generic_patch = slot >= VARYING_SLOT_PATCH0;
|
|
|
|
|
if (patch ^ is_generic_patch)
|
|
|
|
|
continue;
|
|
|
|
|
if (is_generic_patch)
|
|
|
|
|
slot -= VARYING_SLOT_PATCH0;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
uint64_t slot_bit = BITFIELD64_BIT(slot);
|
|
|
|
|
|
|
|
|
|
if (!(mask & slot_bit))
|
|
|
|
|
continue;
|
2022-02-04 17:49:29 +00:00
|
|
|
|
|
|
|
|
|
const struct glsl_type *type = var->type;
|
|
|
|
|
if ((s->info.stage == MESA_SHADER_GEOMETRY ||
|
|
|
|
|
s->info.stage == MESA_SHADER_TESS_CTRL) &&
|
|
|
|
|
(modes & nir_var_shader_in) &&
|
|
|
|
|
glsl_type_is_array(type))
|
|
|
|
|
type = glsl_get_array_element(type);
|
|
|
|
|
info->slots[slot].types[var->data.location_frac] = type;
|
|
|
|
|
|
2022-01-05 15:38:38 +00:00
|
|
|
|
info->slots[slot].patch = var->data.patch;
|
|
|
|
|
auto& var_slot = info->slots[slot].vars[var->data.location_frac];
|
|
|
|
|
var_slot.driver_location = var->data.driver_location;
|
|
|
|
|
var_slot.interpolation = var->data.interpolation;
|
|
|
|
|
var_slot.compact = var->data.compact;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
info->mask |= slot_bit;
|
2022-01-05 15:38:38 +00:00
|
|
|
|
info->slots[slot].location_frac_mask |= (1 << var->data.location_frac);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
fill_flat_varyings(struct d3d12_gs_variant_key *key, d3d12_shader_selector *fs)
|
|
|
|
|
{
|
|
|
|
|
if (!fs || !fs->current)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
nir_foreach_variable_with_modes(input, fs->current->nir,
|
|
|
|
|
nir_var_shader_in) {
|
|
|
|
|
if (input->data.interpolation == INTERP_MODE_FLAT)
|
|
|
|
|
key->flat_varyings |= BITFIELD64_BIT(input->data.location);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
validate_geometry_shader_variant(struct d3d12_selection_context *sel_ctx)
|
|
|
|
|
{
|
|
|
|
|
struct d3d12_context *ctx = sel_ctx->ctx;
|
|
|
|
|
d3d12_shader_selector *vs = ctx->gfx_stages[PIPE_SHADER_VERTEX];
|
|
|
|
|
d3d12_shader_selector *fs = ctx->gfx_stages[PIPE_SHADER_FRAGMENT];
|
|
|
|
|
struct d3d12_gs_variant_key key = {0};
|
|
|
|
|
bool variant_needed = false;
|
|
|
|
|
|
|
|
|
|
d3d12_shader_selector *gs = ctx->gfx_stages[PIPE_SHADER_GEOMETRY];
|
|
|
|
|
|
|
|
|
|
/* Nothing to do if there is a user geometry shader bound */
|
2022-01-03 20:49:28 +00:00
|
|
|
|
if (gs != NULL && !gs->is_variant)
|
2019-05-26 09:43:12 +01:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* Fill the geometry shader variant key */
|
|
|
|
|
if (sel_ctx->fill_mode_lowered != PIPE_POLYGON_MODE_FILL) {
|
|
|
|
|
key.fill_mode = sel_ctx->fill_mode_lowered;
|
|
|
|
|
key.cull_mode = sel_ctx->cull_mode_lowered;
|
2021-01-20 01:14:28 +00:00
|
|
|
|
key.has_front_face = BITSET_TEST(fs->initial->info.system_values_read, SYSTEM_VALUE_FRONT_FACE);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
if (key.cull_mode != PIPE_FACE_NONE || key.has_front_face)
|
|
|
|
|
key.front_ccw = ctx->gfx_pipeline_state.rast->base.front_ccw ^ (ctx->flip_y < 0);
|
|
|
|
|
key.edge_flag_fix = needs_edge_flag_fix(ctx->initial_api_prim);
|
|
|
|
|
fill_flat_varyings(&key, fs);
|
|
|
|
|
if (key.flat_varyings != 0)
|
|
|
|
|
key.flatshade_first = ctx->gfx_pipeline_state.rast->base.flatshade_first;
|
|
|
|
|
variant_needed = true;
|
|
|
|
|
} else if (sel_ctx->needs_point_sprite_lowering) {
|
|
|
|
|
key.passthrough = true;
|
|
|
|
|
variant_needed = true;
|
|
|
|
|
} else if (sel_ctx->needs_vertex_reordering) {
|
|
|
|
|
/* TODO support cases where flat shading (pv != 0) and xfb are enabled */
|
|
|
|
|
key.provoking_vertex = sel_ctx->provoking_vertex;
|
|
|
|
|
key.alternate_tri = sel_ctx->alternate_tri;
|
|
|
|
|
variant_needed = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (variant_needed) {
|
|
|
|
|
fill_varyings(&key.varyings, vs->initial, nir_var_shader_out,
|
2022-01-02 21:03:32 +00:00
|
|
|
|
vs->initial->info.outputs_written, false);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Check if the currently bound geometry shader variant is correct */
|
|
|
|
|
if (gs && memcmp(&gs->gs_key, &key, sizeof(key)) == 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* Find/create the proper variant and bind it */
|
|
|
|
|
gs = variant_needed ? d3d12_get_gs_variant(ctx, &key) : NULL;
|
|
|
|
|
ctx->gfx_stages[PIPE_SHADER_GEOMETRY] = gs;
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-03 20:49:28 +00:00
|
|
|
|
static void
|
|
|
|
|
validate_tess_ctrl_shader_variant(struct d3d12_selection_context *sel_ctx)
|
|
|
|
|
{
|
|
|
|
|
struct d3d12_context *ctx = sel_ctx->ctx;
|
|
|
|
|
d3d12_shader_selector *vs = ctx->gfx_stages[PIPE_SHADER_VERTEX];
|
|
|
|
|
d3d12_shader_selector *tcs = ctx->gfx_stages[PIPE_SHADER_TESS_CTRL];
|
|
|
|
|
d3d12_shader_selector *tes = ctx->gfx_stages[PIPE_SHADER_TESS_EVAL];
|
|
|
|
|
struct d3d12_tcs_variant_key key = {0};
|
|
|
|
|
|
|
|
|
|
/* Nothing to do if there is a user tess ctrl shader bound */
|
|
|
|
|
if (tcs != NULL && !tcs->is_variant)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
bool variant_needed = tes != nullptr;
|
|
|
|
|
|
|
|
|
|
/* Fill the variant key */
|
|
|
|
|
if (variant_needed) {
|
|
|
|
|
fill_varyings(&key.varyings, vs->initial, nir_var_shader_out,
|
|
|
|
|
vs->initial->info.outputs_written, false);
|
|
|
|
|
key.vertices_out = ctx->patch_vertices;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Check if the currently bound tessellation control shader variant is correct */
|
|
|
|
|
if (tcs && memcmp(&tcs->tcs_key, &key, sizeof(key)) == 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* Find/create the proper variant and bind it */
|
|
|
|
|
tcs = variant_needed ? d3d12_get_tcs_variant(ctx, &key) : NULL;
|
|
|
|
|
ctx->gfx_stages[PIPE_SHADER_TESS_CTRL] = tcs;
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-08 02:48:22 +01:00
|
|
|
|
static bool
|
|
|
|
|
d3d12_compare_varying_info(const d3d12_varying_info *expect, const d3d12_varying_info *have)
|
|
|
|
|
{
|
|
|
|
|
if (expect->mask != have->mask)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (!expect->mask)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
/* 6 is a rough (wild) guess for a bulk memcmp cross-over point. When there
|
|
|
|
|
* are a small number of slots present, individual memcmp is much faster. */
|
|
|
|
|
if (util_bitcount64(expect->mask) < 6) {
|
|
|
|
|
uint64_t mask = expect->mask;
|
|
|
|
|
while (mask) {
|
|
|
|
|
int slot = u_bit_scan64(&mask);
|
|
|
|
|
if (memcmp(&expect->slots[slot], &have->slots[slot], sizeof(have->slots[slot])))
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return !memcmp(expect, have, sizeof(struct d3d12_varying_info));
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-26 09:43:12 +01:00
|
|
|
|
static bool
|
|
|
|
|
d3d12_compare_shader_keys(const d3d12_shader_key *expect, const d3d12_shader_key *have)
|
|
|
|
|
{
|
|
|
|
|
assert(expect->stage == have->stage);
|
|
|
|
|
assert(expect);
|
|
|
|
|
assert(have);
|
|
|
|
|
|
2022-05-08 02:48:22 +01:00
|
|
|
|
if (expect->hash != have->hash)
|
|
|
|
|
return false;
|
|
|
|
|
|
2019-05-26 09:43:12 +01:00
|
|
|
|
/* Because we only add varyings we check that a shader has at least the expected in-
|
|
|
|
|
* and outputs. */
|
2022-05-08 02:48:22 +01:00
|
|
|
|
|
|
|
|
|
if (!d3d12_compare_varying_info(&expect->required_varying_inputs,
|
2022-05-27 20:47:25 +01:00
|
|
|
|
&have->required_varying_inputs) ||
|
|
|
|
|
expect->next_varying_inputs != have->next_varying_inputs)
|
2022-05-08 02:48:22 +01:00
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (!d3d12_compare_varying_info(&expect->required_varying_outputs,
|
2022-05-27 20:47:25 +01:00
|
|
|
|
&have->required_varying_outputs) ||
|
|
|
|
|
expect->prev_varying_outputs != have->prev_varying_outputs)
|
2019-05-26 09:43:12 +01:00
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (expect->stage == PIPE_SHADER_GEOMETRY) {
|
|
|
|
|
if (expect->gs.writes_psize) {
|
|
|
|
|
if (!have->gs.writes_psize ||
|
|
|
|
|
expect->gs.point_pos_stream_out != have->gs.point_pos_stream_out ||
|
|
|
|
|
expect->gs.sprite_coord_enable != have->gs.sprite_coord_enable ||
|
|
|
|
|
expect->gs.sprite_origin_upper_left != have->gs.sprite_origin_upper_left ||
|
|
|
|
|
expect->gs.point_size_per_vertex != have->gs.point_size_per_vertex)
|
|
|
|
|
return false;
|
|
|
|
|
} else if (have->gs.writes_psize) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (expect->gs.primitive_id != have->gs.primitive_id ||
|
|
|
|
|
expect->gs.triangle_strip != have->gs.triangle_strip)
|
|
|
|
|
return false;
|
|
|
|
|
} else if (expect->stage == PIPE_SHADER_FRAGMENT) {
|
|
|
|
|
if (expect->fs.frag_result_color_lowering != have->fs.frag_result_color_lowering ||
|
|
|
|
|
expect->fs.manual_depth_range != have->fs.manual_depth_range ||
|
|
|
|
|
expect->fs.polygon_stipple != have->fs.polygon_stipple ||
|
|
|
|
|
expect->fs.cast_to_uint != have->fs.cast_to_uint ||
|
2022-01-14 00:44:32 +00:00
|
|
|
|
expect->fs.cast_to_int != have->fs.cast_to_int ||
|
|
|
|
|
expect->fs.remap_front_facing != have->fs.remap_front_facing ||
|
|
|
|
|
expect->fs.missing_dual_src_outputs != have->fs.missing_dual_src_outputs ||
|
|
|
|
|
expect->fs.multisample_disabled != have->fs.multisample_disabled)
|
2019-05-26 09:43:12 +01:00
|
|
|
|
return false;
|
2021-12-31 20:54:04 +00:00
|
|
|
|
} else if (expect->stage == PIPE_SHADER_COMPUTE) {
|
|
|
|
|
if (memcmp(expect->cs.workgroup_size, have->cs.workgroup_size,
|
|
|
|
|
sizeof(have->cs.workgroup_size)))
|
|
|
|
|
return false;
|
2022-01-02 21:03:32 +00:00
|
|
|
|
} else if (expect->stage == PIPE_SHADER_TESS_CTRL) {
|
|
|
|
|
if (expect->hs.primitive_mode != have->hs.primitive_mode ||
|
|
|
|
|
expect->hs.ccw != have->hs.ccw ||
|
|
|
|
|
expect->hs.point_mode != have->hs.point_mode ||
|
|
|
|
|
expect->hs.spacing != have->hs.spacing ||
|
2022-06-07 22:49:59 +01:00
|
|
|
|
expect->hs.patch_vertices_in != have->hs.patch_vertices_in ||
|
2022-01-02 21:03:32 +00:00
|
|
|
|
memcmp(&expect->hs.required_patch_outputs, &have->hs.required_patch_outputs,
|
|
|
|
|
sizeof(struct d3d12_varying_info)) ||
|
|
|
|
|
expect->hs.next_patch_inputs != have->hs.next_patch_inputs)
|
|
|
|
|
return false;
|
|
|
|
|
} else if (expect->stage == PIPE_SHADER_TESS_EVAL) {
|
|
|
|
|
if (expect->ds.tcs_vertices_out != have->ds.tcs_vertices_out ||
|
|
|
|
|
memcmp(&expect->ds.required_patch_inputs, &have->ds.required_patch_inputs,
|
|
|
|
|
sizeof(struct d3d12_varying_info)) ||
|
|
|
|
|
expect->ds.prev_patch_outputs != have ->ds.prev_patch_outputs)
|
|
|
|
|
return false;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
}
|
|
|
|
|
|
2022-01-06 15:42:22 +00:00
|
|
|
|
if (expect->input_clip_size != have->input_clip_size)
|
|
|
|
|
return false;
|
|
|
|
|
|
2019-05-26 09:43:12 +01:00
|
|
|
|
if (expect->tex_saturate_s != have->tex_saturate_s ||
|
|
|
|
|
expect->tex_saturate_r != have->tex_saturate_r ||
|
|
|
|
|
expect->tex_saturate_t != have->tex_saturate_t)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (expect->samples_int_textures != have->samples_int_textures)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (expect->n_texture_states != have->n_texture_states)
|
|
|
|
|
return false;
|
|
|
|
|
|
2021-12-31 01:54:05 +00:00
|
|
|
|
if (expect->n_images != have->n_images)
|
|
|
|
|
return false;
|
|
|
|
|
|
2019-05-26 09:43:12 +01:00
|
|
|
|
if (memcmp(expect->tex_wrap_states, have->tex_wrap_states,
|
|
|
|
|
expect->n_texture_states * sizeof(dxil_wrap_sampler_state)))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (memcmp(expect->swizzle_state, have->swizzle_state,
|
|
|
|
|
expect->n_texture_states * sizeof(dxil_texture_swizzle_state)))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (memcmp(expect->sampler_compare_funcs, have->sampler_compare_funcs,
|
|
|
|
|
expect->n_texture_states * sizeof(enum compare_func)))
|
|
|
|
|
return false;
|
|
|
|
|
|
2021-12-31 01:54:05 +00:00
|
|
|
|
if (memcmp(expect->image_format_conversion, have->image_format_conversion,
|
|
|
|
|
expect->n_images * sizeof(struct d3d12_image_format_conversion_info)))
|
|
|
|
|
return false;
|
|
|
|
|
|
2022-02-07 17:49:33 +00:00
|
|
|
|
if (expect->invert_depth != have->invert_depth ||
|
|
|
|
|
expect->halfz != have->halfz)
|
2019-05-26 09:43:12 +01:00
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (expect->stage == PIPE_SHADER_VERTEX) {
|
|
|
|
|
if (expect->vs.needs_format_emulation != have->vs.needs_format_emulation)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (expect->vs.needs_format_emulation) {
|
|
|
|
|
if (memcmp(expect->vs.format_conversion, have->vs.format_conversion,
|
|
|
|
|
PIPE_MAX_ATTRIBS * sizeof (enum pipe_format)))
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (expect->fs.provoking_vertex != have->fs.provoking_vertex)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-08 02:48:22 +01:00
|
|
|
|
static uint32_t
|
|
|
|
|
d3d12_shader_key_hash(const d3d12_shader_key *key)
|
|
|
|
|
{
|
|
|
|
|
uint32_t hash;
|
|
|
|
|
|
|
|
|
|
hash = (uint32_t)key->stage;
|
|
|
|
|
hash += key->required_varying_inputs.mask;
|
|
|
|
|
hash += key->required_varying_outputs.mask;
|
|
|
|
|
hash += key->next_varying_inputs;
|
|
|
|
|
hash += key->prev_varying_outputs;
|
|
|
|
|
switch (key->stage) {
|
|
|
|
|
case PIPE_SHADER_VERTEX:
|
|
|
|
|
/* (Probably) not worth the bit extraction for needs_format_emulation and
|
|
|
|
|
* the rest of the the format_conversion data is large. Don't bother
|
|
|
|
|
* hashing for now until this is shown to be worthwhile. */
|
|
|
|
|
break;
|
|
|
|
|
case PIPE_SHADER_GEOMETRY:
|
|
|
|
|
hash = _mesa_hash_data_with_seed(&key->gs, sizeof(key->gs), hash);
|
|
|
|
|
break;
|
|
|
|
|
case PIPE_SHADER_FRAGMENT:
|
|
|
|
|
hash = _mesa_hash_data_with_seed(&key->fs, sizeof(key->fs), hash);
|
|
|
|
|
break;
|
|
|
|
|
case PIPE_SHADER_COMPUTE:
|
|
|
|
|
hash = _mesa_hash_data_with_seed(&key->cs, sizeof(key->cs), hash);
|
|
|
|
|
break;
|
|
|
|
|
case PIPE_SHADER_TESS_CTRL:
|
|
|
|
|
hash += key->hs.next_patch_inputs;
|
|
|
|
|
break;
|
|
|
|
|
case PIPE_SHADER_TESS_EVAL:
|
|
|
|
|
hash += key->ds.tcs_vertices_out;
|
|
|
|
|
hash += key->ds.prev_patch_outputs;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
/* No type specific information to hash for other stages. */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hash += key->n_texture_states;
|
|
|
|
|
hash += key->n_images;
|
|
|
|
|
return hash;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-26 09:43:12 +01:00
|
|
|
|
static void
|
|
|
|
|
d3d12_fill_shader_key(struct d3d12_selection_context *sel_ctx,
|
|
|
|
|
d3d12_shader_key *key, d3d12_shader_selector *sel,
|
|
|
|
|
d3d12_shader_selector *prev, d3d12_shader_selector *next)
|
|
|
|
|
{
|
|
|
|
|
pipe_shader_type stage = sel->stage;
|
|
|
|
|
|
|
|
|
|
uint64_t system_generated_in_values =
|
|
|
|
|
VARYING_BIT_PNTC |
|
|
|
|
|
VARYING_BIT_PRIMITIVE_ID;
|
|
|
|
|
|
|
|
|
|
uint64_t system_out_values =
|
|
|
|
|
VARYING_BIT_CLIP_DIST0 |
|
|
|
|
|
VARYING_BIT_CLIP_DIST1;
|
|
|
|
|
|
|
|
|
|
memset(key, 0, sizeof(d3d12_shader_key));
|
|
|
|
|
key->stage = stage;
|
|
|
|
|
|
|
|
|
|
if (prev) {
|
|
|
|
|
/* We require as inputs what the previous stage has written,
|
|
|
|
|
* except certain system values */
|
|
|
|
|
if (stage == PIPE_SHADER_FRAGMENT || stage == PIPE_SHADER_GEOMETRY)
|
|
|
|
|
system_out_values |= VARYING_BIT_POS;
|
|
|
|
|
if (stage == PIPE_SHADER_FRAGMENT)
|
2022-06-14 21:28:39 +01:00
|
|
|
|
system_out_values |= VARYING_BIT_PSIZ | VARYING_BIT_VIEWPORT | VARYING_BIT_LAYER;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
uint64_t mask = prev->current->nir->info.outputs_written & ~system_out_values;
|
|
|
|
|
fill_varyings(&key->required_varying_inputs, prev->current->nir,
|
2022-01-02 21:03:32 +00:00
|
|
|
|
nir_var_shader_out, mask, false);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
key->prev_varying_outputs = prev->current->nir->info.outputs_written;
|
|
|
|
|
|
2022-01-02 21:03:32 +00:00
|
|
|
|
if (stage == PIPE_SHADER_TESS_EVAL) {
|
|
|
|
|
uint32_t patch_mask = prev->current->nir->info.patch_outputs_written;
|
|
|
|
|
fill_varyings(&key->ds.required_patch_inputs, prev->current->nir,
|
|
|
|
|
nir_var_shader_out, patch_mask, true);
|
|
|
|
|
key->ds.prev_patch_outputs = patch_mask;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-26 09:43:12 +01:00
|
|
|
|
/* Set the provoking vertex based on the previous shader output. Only set the
|
|
|
|
|
* key value if the driver actually supports changing the provoking vertex though */
|
|
|
|
|
if (stage == PIPE_SHADER_FRAGMENT && sel_ctx->ctx->gfx_pipeline_state.rast &&
|
|
|
|
|
!sel_ctx->needs_vertex_reordering &&
|
|
|
|
|
d3d12_screen(sel_ctx->ctx->base.screen)->have_load_at_vertex)
|
|
|
|
|
key->fs.provoking_vertex = sel_ctx->provoking_vertex;
|
2022-01-06 15:42:22 +00:00
|
|
|
|
|
|
|
|
|
/* Get the input clip distance size. The info's clip_distance_array_size corresponds
|
|
|
|
|
* to the output, and in cases of TES or GS you could have differently-sized inputs
|
|
|
|
|
* and outputs. For FS, there is no output, so it's repurposed to mean input.
|
|
|
|
|
*/
|
|
|
|
|
if (stage != PIPE_SHADER_FRAGMENT)
|
|
|
|
|
key->input_clip_size = prev->current->nir->info.clip_distance_array_size;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* We require as outputs what the next stage reads,
|
|
|
|
|
* except certain system values */
|
|
|
|
|
if (next) {
|
2022-01-03 20:49:28 +00:00
|
|
|
|
if (!next->is_variant) {
|
2019-05-26 09:43:12 +01:00
|
|
|
|
if (stage == PIPE_SHADER_VERTEX)
|
|
|
|
|
system_generated_in_values |= VARYING_BIT_POS;
|
|
|
|
|
uint64_t mask = next->current->nir->info.inputs_read & ~system_generated_in_values;
|
|
|
|
|
fill_varyings(&key->required_varying_outputs, next->current->nir,
|
2022-01-02 21:03:32 +00:00
|
|
|
|
nir_var_shader_in, mask, false);
|
|
|
|
|
|
|
|
|
|
if (stage == PIPE_SHADER_TESS_CTRL) {
|
|
|
|
|
uint32_t patch_mask = next->current->nir->info.patch_outputs_read;
|
|
|
|
|
fill_varyings(&key->hs.required_patch_outputs, prev->current->nir,
|
|
|
|
|
nir_var_shader_in, patch_mask, true);
|
|
|
|
|
key->hs.next_patch_inputs = patch_mask;
|
|
|
|
|
}
|
2019-05-26 09:43:12 +01:00
|
|
|
|
}
|
|
|
|
|
key->next_varying_inputs = next->current->nir->info.inputs_read;
|
2022-01-02 21:03:32 +00:00
|
|
|
|
|
2019-05-26 09:43:12 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (stage == PIPE_SHADER_GEOMETRY ||
|
2022-01-02 21:03:32 +00:00
|
|
|
|
((stage == PIPE_SHADER_VERTEX || stage == PIPE_SHADER_TESS_EVAL) &&
|
|
|
|
|
(!next || next->stage == PIPE_SHADER_FRAGMENT))) {
|
2019-05-26 09:43:12 +01:00
|
|
|
|
key->last_vertex_processing_stage = 1;
|
|
|
|
|
key->invert_depth = sel_ctx->ctx->reverse_depth_range;
|
2022-02-07 17:49:33 +00:00
|
|
|
|
key->halfz = sel_ctx->ctx->gfx_pipeline_state.rast ?
|
|
|
|
|
sel_ctx->ctx->gfx_pipeline_state.rast->base.clip_halfz : false;
|
2022-04-29 21:14:34 +01:00
|
|
|
|
if (sel_ctx->ctx->pstipple.enabled &&
|
|
|
|
|
sel_ctx->ctx->gfx_pipeline_state.rast->base.poly_stipple_enable)
|
2019-05-26 09:43:12 +01:00
|
|
|
|
key->next_varying_inputs |= VARYING_BIT_POS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (stage == PIPE_SHADER_GEOMETRY && sel_ctx->ctx->gfx_pipeline_state.rast) {
|
|
|
|
|
struct pipe_rasterizer_state *rast = &sel_ctx->ctx->gfx_pipeline_state.rast->base;
|
|
|
|
|
if (sel_ctx->needs_point_sprite_lowering) {
|
|
|
|
|
key->gs.writes_psize = 1;
|
|
|
|
|
key->gs.point_size_per_vertex = rast->point_size_per_vertex;
|
|
|
|
|
key->gs.sprite_coord_enable = rast->sprite_coord_enable;
|
|
|
|
|
key->gs.sprite_origin_upper_left = (rast->sprite_coord_mode != PIPE_SPRITE_COORD_LOWER_LEFT);
|
|
|
|
|
if (sel_ctx->ctx->flip_y < 0)
|
|
|
|
|
key->gs.sprite_origin_upper_left = !key->gs.sprite_origin_upper_left;
|
|
|
|
|
key->gs.aa_point = rast->point_smooth;
|
|
|
|
|
key->gs.stream_output_factor = 6;
|
|
|
|
|
} else if (sel_ctx->fill_mode_lowered == PIPE_POLYGON_MODE_LINE) {
|
|
|
|
|
key->gs.stream_output_factor = 2;
|
2022-01-03 20:49:28 +00:00
|
|
|
|
} else if (sel_ctx->needs_vertex_reordering && !sel->is_variant) {
|
2019-05-26 09:43:12 +01:00
|
|
|
|
key->gs.triangle_strip = 1;
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-03 20:49:28 +00:00
|
|
|
|
if (sel->is_variant && next && next->initial->info.inputs_read & VARYING_BIT_PRIMITIVE_ID)
|
2019-05-26 09:43:12 +01:00
|
|
|
|
key->gs.primitive_id = 1;
|
|
|
|
|
} else if (stage == PIPE_SHADER_FRAGMENT) {
|
|
|
|
|
key->fs.missing_dual_src_outputs = sel_ctx->missing_dual_src_outputs;
|
|
|
|
|
key->fs.frag_result_color_lowering = sel_ctx->frag_result_color_lowering;
|
|
|
|
|
key->fs.manual_depth_range = sel_ctx->manual_depth_range;
|
2022-04-29 21:14:34 +01:00
|
|
|
|
key->fs.polygon_stipple = sel_ctx->ctx->pstipple.enabled &&
|
|
|
|
|
sel_ctx->ctx->gfx_pipeline_state.rast->base.poly_stipple_enable;
|
2022-01-14 00:44:32 +00:00
|
|
|
|
key->fs.multisample_disabled = sel_ctx->ctx->gfx_pipeline_state.rast &&
|
|
|
|
|
!sel_ctx->ctx->gfx_pipeline_state.rast->desc.MultisampleEnable;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
if (sel_ctx->ctx->gfx_pipeline_state.blend &&
|
|
|
|
|
sel_ctx->ctx->gfx_pipeline_state.blend->desc.RenderTarget[0].LogicOpEnable &&
|
|
|
|
|
!sel_ctx->ctx->gfx_pipeline_state.has_float_rtv) {
|
|
|
|
|
key->fs.cast_to_uint = util_format_is_unorm(sel_ctx->ctx->fb.cbufs[0]->format);
|
|
|
|
|
key->fs.cast_to_int = !key->fs.cast_to_uint;
|
|
|
|
|
}
|
2022-01-02 21:03:32 +00:00
|
|
|
|
} else if (stage == PIPE_SHADER_TESS_CTRL) {
|
|
|
|
|
if (next && next->current->nir->info.stage == MESA_SHADER_TESS_EVAL) {
|
|
|
|
|
key->hs.primitive_mode = next->current->nir->info.tess._primitive_mode;
|
|
|
|
|
key->hs.ccw = next->current->nir->info.tess.ccw;
|
|
|
|
|
key->hs.point_mode = next->current->nir->info.tess.point_mode;
|
|
|
|
|
key->hs.spacing = next->current->nir->info.tess.spacing;
|
|
|
|
|
} else {
|
|
|
|
|
key->hs.primitive_mode = TESS_PRIMITIVE_QUADS;
|
|
|
|
|
key->hs.ccw = true;
|
|
|
|
|
key->hs.point_mode = false;
|
|
|
|
|
key->hs.spacing = TESS_SPACING_EQUAL;
|
|
|
|
|
}
|
2022-06-07 22:49:59 +01:00
|
|
|
|
key->hs.patch_vertices_in = MAX2(sel_ctx->ctx->patch_vertices, 1);
|
2022-01-02 21:03:32 +00:00
|
|
|
|
} else if (stage == PIPE_SHADER_TESS_EVAL) {
|
|
|
|
|
if (prev && prev->current->nir->info.stage == MESA_SHADER_TESS_CTRL)
|
|
|
|
|
key->ds.tcs_vertices_out = prev->current->nir->info.tess.tcs_vertices_out;
|
|
|
|
|
else
|
|
|
|
|
key->ds.tcs_vertices_out = 32;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (sel->samples_int_textures) {
|
|
|
|
|
key->samples_int_textures = sel->samples_int_textures;
|
|
|
|
|
key->n_texture_states = sel_ctx->ctx->num_sampler_views[stage];
|
|
|
|
|
/* Copy only states with integer textures */
|
|
|
|
|
for(int i = 0; i < key->n_texture_states; ++i) {
|
|
|
|
|
auto& wrap_state = sel_ctx->ctx->tex_wrap_states[stage][i];
|
|
|
|
|
if (wrap_state.is_int_sampler) {
|
|
|
|
|
memcpy(&key->tex_wrap_states[i], &wrap_state, sizeof(wrap_state));
|
|
|
|
|
key->swizzle_state[i] = sel_ctx->ctx->tex_swizzle_state[stage][i];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-28 18:47:48 +00:00
|
|
|
|
for (unsigned i = 0; i < sel_ctx->ctx->num_samplers[stage]; ++i) {
|
2020-12-01 13:37:06 +00:00
|
|
|
|
if (!sel_ctx->ctx->samplers[stage][i] ||
|
|
|
|
|
sel_ctx->ctx->samplers[stage][i]->filter == PIPE_TEX_FILTER_NEAREST)
|
2019-05-26 09:43:12 +01:00
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (sel_ctx->ctx->samplers[stage][i]->wrap_r == PIPE_TEX_WRAP_CLAMP)
|
|
|
|
|
key->tex_saturate_r |= 1 << i;
|
|
|
|
|
if (sel_ctx->ctx->samplers[stage][i]->wrap_s == PIPE_TEX_WRAP_CLAMP)
|
|
|
|
|
key->tex_saturate_s |= 1 << i;
|
|
|
|
|
if (sel_ctx->ctx->samplers[stage][i]->wrap_t == PIPE_TEX_WRAP_CLAMP)
|
|
|
|
|
key->tex_saturate_t |= 1 << i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (sel->compare_with_lod_bias_grad) {
|
|
|
|
|
key->n_texture_states = sel_ctx->ctx->num_sampler_views[stage];
|
|
|
|
|
memcpy(key->sampler_compare_funcs, sel_ctx->ctx->tex_compare_func[stage],
|
|
|
|
|
key->n_texture_states * sizeof(enum compare_func));
|
|
|
|
|
memcpy(key->swizzle_state, sel_ctx->ctx->tex_swizzle_state[stage],
|
|
|
|
|
key->n_texture_states * sizeof(dxil_texture_swizzle_state));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (stage == PIPE_SHADER_VERTEX && sel_ctx->ctx->gfx_pipeline_state.ves) {
|
|
|
|
|
key->vs.needs_format_emulation = sel_ctx->ctx->gfx_pipeline_state.ves->needs_format_emulation;
|
|
|
|
|
if (key->vs.needs_format_emulation) {
|
|
|
|
|
memcpy(key->vs.format_conversion, sel_ctx->ctx->gfx_pipeline_state.ves->format_conversion,
|
|
|
|
|
sel_ctx->ctx->gfx_pipeline_state.ves->num_elements * sizeof(enum pipe_format));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (stage == PIPE_SHADER_FRAGMENT &&
|
|
|
|
|
sel_ctx->ctx->gfx_stages[PIPE_SHADER_GEOMETRY] &&
|
2022-01-03 20:49:28 +00:00
|
|
|
|
sel_ctx->ctx->gfx_stages[PIPE_SHADER_GEOMETRY]->is_variant &&
|
2019-05-26 09:43:12 +01:00
|
|
|
|
sel_ctx->ctx->gfx_stages[PIPE_SHADER_GEOMETRY]->gs_key.has_front_face) {
|
|
|
|
|
key->fs.remap_front_facing = 1;
|
|
|
|
|
}
|
2021-12-31 01:54:05 +00:00
|
|
|
|
|
2021-12-31 20:54:04 +00:00
|
|
|
|
if (stage == PIPE_SHADER_COMPUTE && sel_ctx->variable_workgroup_size) {
|
|
|
|
|
memcpy(key->cs.workgroup_size, sel_ctx->variable_workgroup_size, sizeof(key->cs.workgroup_size));
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-31 01:54:05 +00:00
|
|
|
|
key->n_images = sel_ctx->ctx->num_image_views[stage];
|
|
|
|
|
for (int i = 0; i < key->n_images; ++i) {
|
|
|
|
|
key->image_format_conversion[i].emulated_format = sel_ctx->ctx->image_view_emulation_formats[stage][i];
|
|
|
|
|
if (key->image_format_conversion[i].emulated_format != PIPE_FORMAT_NONE)
|
|
|
|
|
key->image_format_conversion[i].view_format = sel_ctx->ctx->image_views[stage][i].format;
|
|
|
|
|
}
|
2022-05-08 02:48:22 +01:00
|
|
|
|
|
|
|
|
|
key->hash = d3d12_shader_key_hash(key);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
select_shader_variant(struct d3d12_selection_context *sel_ctx, d3d12_shader_selector *sel,
|
|
|
|
|
d3d12_shader_selector *prev, d3d12_shader_selector *next)
|
|
|
|
|
{
|
|
|
|
|
struct d3d12_context *ctx = sel_ctx->ctx;
|
|
|
|
|
d3d12_shader_key key;
|
|
|
|
|
nir_shader *new_nir_variant;
|
|
|
|
|
unsigned pstipple_binding = UINT32_MAX;
|
|
|
|
|
|
|
|
|
|
d3d12_fill_shader_key(sel_ctx, &key, sel, prev, next);
|
|
|
|
|
|
|
|
|
|
/* Check for an existing variant */
|
|
|
|
|
for (d3d12_shader *variant = sel->first; variant;
|
|
|
|
|
variant = variant->next_variant) {
|
|
|
|
|
|
|
|
|
|
if (d3d12_compare_shader_keys(&key, &variant->key)) {
|
|
|
|
|
sel->current = variant;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Clone the NIR shader */
|
|
|
|
|
new_nir_variant = nir_shader_clone(sel, sel->initial);
|
|
|
|
|
|
|
|
|
|
/* Apply any needed lowering passes */
|
|
|
|
|
if (key.gs.writes_psize) {
|
|
|
|
|
NIR_PASS_V(new_nir_variant, d3d12_lower_point_sprite,
|
|
|
|
|
!key.gs.sprite_origin_upper_left,
|
|
|
|
|
key.gs.point_size_per_vertex,
|
|
|
|
|
key.gs.sprite_coord_enable,
|
|
|
|
|
key.next_varying_inputs);
|
|
|
|
|
|
|
|
|
|
nir_function_impl *impl = nir_shader_get_entrypoint(new_nir_variant);
|
|
|
|
|
nir_shader_gather_info(new_nir_variant, impl);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (key.gs.primitive_id) {
|
|
|
|
|
NIR_PASS_V(new_nir_variant, d3d12_lower_primitive_id);
|
|
|
|
|
|
|
|
|
|
nir_function_impl *impl = nir_shader_get_entrypoint(new_nir_variant);
|
|
|
|
|
nir_shader_gather_info(new_nir_variant, impl);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (key.gs.triangle_strip)
|
|
|
|
|
NIR_PASS_V(new_nir_variant, d3d12_lower_triangle_strip);
|
|
|
|
|
|
|
|
|
|
if (key.fs.polygon_stipple) {
|
|
|
|
|
NIR_PASS_V(new_nir_variant, nir_lower_pstipple_fs,
|
|
|
|
|
&pstipple_binding, 0, false);
|
|
|
|
|
|
|
|
|
|
nir_function_impl *impl = nir_shader_get_entrypoint(new_nir_variant);
|
|
|
|
|
nir_shader_gather_info(new_nir_variant, impl);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (key.fs.remap_front_facing) {
|
|
|
|
|
d3d12_forward_front_face(new_nir_variant);
|
|
|
|
|
|
|
|
|
|
nir_function_impl *impl = nir_shader_get_entrypoint(new_nir_variant);
|
|
|
|
|
nir_shader_gather_info(new_nir_variant, impl);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (key.fs.missing_dual_src_outputs) {
|
|
|
|
|
NIR_PASS_V(new_nir_variant, d3d12_add_missing_dual_src_target,
|
|
|
|
|
key.fs.missing_dual_src_outputs);
|
|
|
|
|
} else if (key.fs.frag_result_color_lowering) {
|
2021-04-22 16:29:51 +01:00
|
|
|
|
NIR_PASS_V(new_nir_variant, nir_lower_fragcolor,
|
2019-05-26 09:43:12 +01:00
|
|
|
|
key.fs.frag_result_color_lowering);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (key.fs.manual_depth_range)
|
|
|
|
|
NIR_PASS_V(new_nir_variant, d3d12_lower_depth_range);
|
|
|
|
|
|
2021-12-23 12:25:53 +00:00
|
|
|
|
if (sel->compare_with_lod_bias_grad) {
|
|
|
|
|
STATIC_ASSERT(sizeof(dxil_texture_swizzle_state) ==
|
|
|
|
|
sizeof(nir_lower_tex_shadow_swizzle));
|
|
|
|
|
|
|
|
|
|
NIR_PASS_V(new_nir_variant, nir_lower_tex_shadow, key.n_texture_states,
|
|
|
|
|
key.sampler_compare_funcs, (nir_lower_tex_shadow_swizzle *)key.swizzle_state);
|
|
|
|
|
}
|
2019-05-26 09:43:12 +01:00
|
|
|
|
|
|
|
|
|
if (key.fs.cast_to_uint)
|
|
|
|
|
NIR_PASS_V(new_nir_variant, d3d12_lower_uint_cast, false);
|
|
|
|
|
if (key.fs.cast_to_int)
|
|
|
|
|
NIR_PASS_V(new_nir_variant, d3d12_lower_uint_cast, true);
|
|
|
|
|
|
2021-12-31 01:54:05 +00:00
|
|
|
|
if (key.n_images)
|
|
|
|
|
NIR_PASS_V(new_nir_variant, d3d12_lower_image_casts, key.image_format_conversion);
|
|
|
|
|
|
2021-12-31 20:54:04 +00:00
|
|
|
|
if (sel->workgroup_size_variable) {
|
|
|
|
|
new_nir_variant->info.workgroup_size[0] = key.cs.workgroup_size[0];
|
|
|
|
|
new_nir_variant->info.workgroup_size[1] = key.cs.workgroup_size[1];
|
|
|
|
|
new_nir_variant->info.workgroup_size[2] = key.cs.workgroup_size[2];
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-02 21:03:32 +00:00
|
|
|
|
if (new_nir_variant->info.stage == MESA_SHADER_TESS_CTRL) {
|
|
|
|
|
new_nir_variant->info.tess._primitive_mode = (tess_primitive_mode)key.hs.primitive_mode;
|
|
|
|
|
new_nir_variant->info.tess.ccw = key.hs.ccw;
|
|
|
|
|
new_nir_variant->info.tess.point_mode = key.hs.point_mode;
|
|
|
|
|
new_nir_variant->info.tess.spacing = key.hs.spacing;
|
2022-06-07 22:49:59 +01:00
|
|
|
|
|
|
|
|
|
NIR_PASS_V(new_nir_variant, dxil_nir_set_tcs_patches_in, key.hs.patch_vertices_in);
|
2022-01-02 21:03:32 +00:00
|
|
|
|
} else if (new_nir_variant->info.stage == MESA_SHADER_TESS_EVAL) {
|
|
|
|
|
new_nir_variant->info.tess.tcs_vertices_out = key.ds.tcs_vertices_out;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-26 09:43:12 +01:00
|
|
|
|
{
|
|
|
|
|
struct nir_lower_tex_options tex_options = { };
|
|
|
|
|
tex_options.lower_txp = ~0u; /* No equivalent for textureProj */
|
|
|
|
|
tex_options.lower_rect = true;
|
|
|
|
|
tex_options.lower_rect_offset = true;
|
|
|
|
|
tex_options.saturate_s = key.tex_saturate_s;
|
|
|
|
|
tex_options.saturate_r = key.tex_saturate_r;
|
|
|
|
|
tex_options.saturate_t = key.tex_saturate_t;
|
2022-04-26 00:55:45 +01:00
|
|
|
|
tex_options.lower_invalid_implicit_lod = true;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
|
|
|
|
|
NIR_PASS_V(new_nir_variant, nir_lower_tex, &tex_options);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Add the needed in and outputs, and re-sort */
|
|
|
|
|
if (prev) {
|
2022-01-02 21:03:32 +00:00
|
|
|
|
uint64_t mask = key.required_varying_inputs.mask & ~new_nir_variant->info.inputs_read;
|
2022-02-04 16:22:08 +00:00
|
|
|
|
new_nir_variant->info.inputs_read |= mask;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
while (mask) {
|
|
|
|
|
int slot = u_bit_scan64(&mask);
|
2022-01-05 15:38:38 +00:00
|
|
|
|
create_varyings_from_info(new_nir_variant, &key.required_varying_inputs, slot, nir_var_shader_in, false);
|
2022-01-02 21:03:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (sel->stage == PIPE_SHADER_TESS_EVAL) {
|
|
|
|
|
uint32_t patch_mask = (uint32_t)key.ds.required_patch_inputs.mask & ~new_nir_variant->info.patch_inputs_read;
|
2022-02-04 16:22:08 +00:00
|
|
|
|
new_nir_variant->info.patch_inputs_read |= patch_mask;
|
2022-01-02 21:03:32 +00:00
|
|
|
|
while (patch_mask) {
|
|
|
|
|
int slot = u_bit_scan(&patch_mask);
|
2022-01-05 15:38:38 +00:00
|
|
|
|
create_varyings_from_info(new_nir_variant, &key.ds.required_patch_inputs, slot, nir_var_shader_in, true);
|
2022-01-02 21:03:32 +00:00
|
|
|
|
}
|
2019-05-26 09:43:12 +01:00
|
|
|
|
}
|
2021-05-25 22:40:09 +01:00
|
|
|
|
dxil_reassign_driver_locations(new_nir_variant, nir_var_shader_in,
|
2019-05-26 09:43:12 +01:00
|
|
|
|
key.prev_varying_outputs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (next) {
|
2022-01-02 21:03:32 +00:00
|
|
|
|
uint64_t mask = key.required_varying_outputs.mask & ~new_nir_variant->info.outputs_written;
|
2022-02-04 16:22:08 +00:00
|
|
|
|
new_nir_variant->info.outputs_written |= mask;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
while (mask) {
|
|
|
|
|
int slot = u_bit_scan64(&mask);
|
2022-01-05 15:38:38 +00:00
|
|
|
|
create_varyings_from_info(new_nir_variant, &key.required_varying_outputs, slot, nir_var_shader_out, false);
|
2022-01-02 21:03:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (sel->stage == PIPE_SHADER_TESS_CTRL) {
|
|
|
|
|
uint32_t patch_mask = (uint32_t)key.hs.required_patch_outputs.mask & ~new_nir_variant->info.patch_outputs_written;
|
2022-02-04 16:22:08 +00:00
|
|
|
|
new_nir_variant->info.patch_outputs_written |= patch_mask;
|
2022-01-02 21:03:32 +00:00
|
|
|
|
while (patch_mask) {
|
|
|
|
|
int slot = u_bit_scan(&patch_mask);
|
2022-01-05 15:38:38 +00:00
|
|
|
|
create_varyings_from_info(new_nir_variant, &key.ds.required_patch_inputs, slot, nir_var_shader_out, true);
|
2022-01-02 21:03:32 +00:00
|
|
|
|
}
|
2019-05-26 09:43:12 +01:00
|
|
|
|
}
|
2021-05-25 22:40:09 +01:00
|
|
|
|
dxil_reassign_driver_locations(new_nir_variant, nir_var_shader_out,
|
2022-01-02 21:03:32 +00:00
|
|
|
|
key.next_varying_inputs);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
d3d12_shader *new_variant = compile_nir(ctx, sel, &key, new_nir_variant);
|
|
|
|
|
assert(new_variant);
|
|
|
|
|
|
|
|
|
|
/* keep track of polygon stipple texture binding */
|
|
|
|
|
new_variant->pstipple_binding = pstipple_binding;
|
|
|
|
|
|
|
|
|
|
/* prepend the new shader in the selector chain and pick it */
|
|
|
|
|
new_variant->next_variant = sel->first;
|
|
|
|
|
sel->current = sel->first = new_variant;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static d3d12_shader_selector *
|
|
|
|
|
get_prev_shader(struct d3d12_context *ctx, pipe_shader_type current)
|
|
|
|
|
{
|
|
|
|
|
switch (current) {
|
|
|
|
|
case PIPE_SHADER_VERTEX:
|
|
|
|
|
return NULL;
|
|
|
|
|
case PIPE_SHADER_FRAGMENT:
|
|
|
|
|
if (ctx->gfx_stages[PIPE_SHADER_GEOMETRY])
|
|
|
|
|
return ctx->gfx_stages[PIPE_SHADER_GEOMETRY];
|
2020-12-28 18:48:54 +00:00
|
|
|
|
FALLTHROUGH;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
case PIPE_SHADER_GEOMETRY:
|
2022-01-01 22:49:28 +00:00
|
|
|
|
if (ctx->gfx_stages[PIPE_SHADER_TESS_EVAL])
|
|
|
|
|
return ctx->gfx_stages[PIPE_SHADER_TESS_EVAL];
|
|
|
|
|
FALLTHROUGH;
|
|
|
|
|
case PIPE_SHADER_TESS_EVAL:
|
|
|
|
|
if (ctx->gfx_stages[PIPE_SHADER_TESS_CTRL])
|
|
|
|
|
return ctx->gfx_stages[PIPE_SHADER_TESS_CTRL];
|
|
|
|
|
FALLTHROUGH;
|
|
|
|
|
case PIPE_SHADER_TESS_CTRL:
|
2019-05-26 09:43:12 +01:00
|
|
|
|
return ctx->gfx_stages[PIPE_SHADER_VERTEX];
|
|
|
|
|
default:
|
|
|
|
|
unreachable("shader type not supported");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static d3d12_shader_selector *
|
|
|
|
|
get_next_shader(struct d3d12_context *ctx, pipe_shader_type current)
|
|
|
|
|
{
|
|
|
|
|
switch (current) {
|
|
|
|
|
case PIPE_SHADER_VERTEX:
|
2022-01-01 22:49:28 +00:00
|
|
|
|
if (ctx->gfx_stages[PIPE_SHADER_TESS_CTRL])
|
|
|
|
|
return ctx->gfx_stages[PIPE_SHADER_TESS_CTRL];
|
|
|
|
|
FALLTHROUGH;
|
|
|
|
|
case PIPE_SHADER_TESS_CTRL:
|
|
|
|
|
if (ctx->gfx_stages[PIPE_SHADER_TESS_EVAL])
|
|
|
|
|
return ctx->gfx_stages[PIPE_SHADER_TESS_EVAL];
|
|
|
|
|
FALLTHROUGH;
|
|
|
|
|
case PIPE_SHADER_TESS_EVAL:
|
2019-05-26 09:43:12 +01:00
|
|
|
|
if (ctx->gfx_stages[PIPE_SHADER_GEOMETRY])
|
|
|
|
|
return ctx->gfx_stages[PIPE_SHADER_GEOMETRY];
|
2020-12-28 18:48:54 +00:00
|
|
|
|
FALLTHROUGH;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
case PIPE_SHADER_GEOMETRY:
|
|
|
|
|
return ctx->gfx_stages[PIPE_SHADER_FRAGMENT];
|
|
|
|
|
case PIPE_SHADER_FRAGMENT:
|
|
|
|
|
return NULL;
|
|
|
|
|
default:
|
|
|
|
|
unreachable("shader type not supported");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum tex_scan_flags {
|
|
|
|
|
TEX_SAMPLE_INTEGER_TEXTURE = 1 << 0,
|
|
|
|
|
TEX_CMP_WITH_LOD_BIAS_GRAD = 1 << 1,
|
|
|
|
|
TEX_SCAN_ALL_FLAGS = (1 << 2) - 1
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static unsigned
|
|
|
|
|
scan_texture_use(nir_shader *nir)
|
|
|
|
|
{
|
|
|
|
|
unsigned result = 0;
|
|
|
|
|
nir_foreach_function(func, nir) {
|
|
|
|
|
nir_foreach_block(block, func->impl) {
|
|
|
|
|
nir_foreach_instr(instr, block) {
|
|
|
|
|
if (instr->type == nir_instr_type_tex) {
|
|
|
|
|
auto tex = nir_instr_as_tex(instr);
|
|
|
|
|
switch (tex->op) {
|
|
|
|
|
case nir_texop_txb:
|
|
|
|
|
case nir_texop_txl:
|
|
|
|
|
case nir_texop_txd:
|
|
|
|
|
if (tex->is_shadow)
|
|
|
|
|
result |= TEX_CMP_WITH_LOD_BIAS_GRAD;
|
2020-12-28 18:48:54 +00:00
|
|
|
|
FALLTHROUGH;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
case nir_texop_tex:
|
|
|
|
|
if (tex->dest_type & (nir_type_int | nir_type_uint))
|
|
|
|
|
result |= TEX_SAMPLE_INTEGER_TEXTURE;
|
|
|
|
|
default:
|
|
|
|
|
;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (TEX_SCAN_ALL_FLAGS == result)
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static uint64_t
|
|
|
|
|
update_so_info(struct pipe_stream_output_info *so_info,
|
|
|
|
|
uint64_t outputs_written)
|
|
|
|
|
{
|
|
|
|
|
uint64_t so_outputs = 0;
|
|
|
|
|
uint8_t reverse_map[64] = {0};
|
|
|
|
|
unsigned slot = 0;
|
|
|
|
|
|
|
|
|
|
while (outputs_written)
|
|
|
|
|
reverse_map[slot++] = u_bit_scan64(&outputs_written);
|
|
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < so_info->num_outputs; i++) {
|
|
|
|
|
struct pipe_stream_output *output = &so_info->output[i];
|
|
|
|
|
|
|
|
|
|
/* Map Gallium's condensed "slots" back to real VARYING_SLOT_* enums */
|
|
|
|
|
output->register_index = reverse_map[output->register_index];
|
|
|
|
|
|
|
|
|
|
so_outputs |= 1ull << output->register_index;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return so_outputs;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-31 17:58:50 +00:00
|
|
|
|
static struct d3d12_shader_selector *
|
|
|
|
|
d3d12_create_shader_impl(struct d3d12_context *ctx,
|
|
|
|
|
struct d3d12_shader_selector *sel,
|
|
|
|
|
struct nir_shader *nir,
|
|
|
|
|
struct d3d12_shader_selector *prev,
|
|
|
|
|
struct d3d12_shader_selector *next)
|
|
|
|
|
{
|
|
|
|
|
unsigned tex_scan_result = scan_texture_use(nir);
|
|
|
|
|
sel->samples_int_textures = (tex_scan_result & TEX_SAMPLE_INTEGER_TEXTURE) != 0;
|
|
|
|
|
sel->compare_with_lod_bias_grad = (tex_scan_result & TEX_CMP_WITH_LOD_BIAS_GRAD) != 0;
|
2021-12-31 20:54:04 +00:00
|
|
|
|
sel->workgroup_size_variable = nir->info.workgroup_size_variable;
|
2021-12-31 17:58:50 +00:00
|
|
|
|
|
|
|
|
|
/* Integer cube maps are not supported in DirectX because sampling is not supported
|
|
|
|
|
* on integer textures and TextureLoad is not supported for cube maps, so we have to
|
|
|
|
|
* lower integer cube maps to be handled like 2D textures arrays*/
|
2022-06-08 15:03:37 +01:00
|
|
|
|
NIR_PASS_V(nir, dxil_nir_lower_int_cubemaps, true);
|
2021-12-31 17:58:50 +00:00
|
|
|
|
|
|
|
|
|
/* Keep this initial shader as the blue print for possible variants */
|
|
|
|
|
sel->initial = nir;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* We must compile some shader here, because if the previous or a next shaders exists later
|
|
|
|
|
* when the shaders are bound, then the key evaluation in the shader selector will access
|
|
|
|
|
* the current variant of these prev and next shader, and we can only assign
|
|
|
|
|
* a current variant when it has been successfully compiled.
|
|
|
|
|
*
|
|
|
|
|
* For shaders that require lowering because certain instructions are not available
|
|
|
|
|
* and their emulation is state depended (like sampling an integer texture that must be
|
|
|
|
|
* emulated and needs handling of boundary conditions, or shadow compare sampling with LOD),
|
|
|
|
|
* we must go through the shader selector here to create a compilable variant.
|
|
|
|
|
* For shaders that are not depended on the state this is just compiling the original
|
|
|
|
|
* shader.
|
|
|
|
|
*
|
|
|
|
|
* TODO: get rid of having to compiling the shader here if it can be forseen that it will
|
|
|
|
|
* be thrown away (i.e. it depends on states that are likely to change before the shader is
|
|
|
|
|
* used for the first time)
|
|
|
|
|
*/
|
|
|
|
|
struct d3d12_selection_context sel_ctx = {0};
|
|
|
|
|
sel_ctx.ctx = ctx;
|
|
|
|
|
select_shader_variant(&sel_ctx, sel, prev, next);
|
|
|
|
|
|
|
|
|
|
if (!sel->current) {
|
|
|
|
|
ralloc_free(sel);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return sel;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-26 09:43:12 +01:00
|
|
|
|
struct d3d12_shader_selector *
|
|
|
|
|
d3d12_create_shader(struct d3d12_context *ctx,
|
|
|
|
|
pipe_shader_type stage,
|
|
|
|
|
const struct pipe_shader_state *shader)
|
|
|
|
|
{
|
|
|
|
|
struct d3d12_shader_selector *sel = rzalloc(nullptr, d3d12_shader_selector);
|
|
|
|
|
sel->stage = stage;
|
|
|
|
|
|
|
|
|
|
struct nir_shader *nir = NULL;
|
|
|
|
|
|
|
|
|
|
if (shader->type == PIPE_SHADER_IR_NIR) {
|
|
|
|
|
nir = (nir_shader *)shader->ir.nir;
|
|
|
|
|
} else {
|
|
|
|
|
assert(shader->type == PIPE_SHADER_IR_TGSI);
|
|
|
|
|
nir = tgsi_to_nir(shader->tokens, ctx->base.screen, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nir_shader_gather_info(nir, nir_shader_get_entrypoint(nir));
|
|
|
|
|
memcpy(&sel->so_info, &shader->stream_output, sizeof(sel->so_info));
|
|
|
|
|
update_so_info(&sel->so_info, nir->info.outputs_written);
|
|
|
|
|
|
|
|
|
|
assert(nir != NULL);
|
|
|
|
|
d3d12_shader_selector *prev = get_prev_shader(ctx, sel->stage);
|
|
|
|
|
d3d12_shader_selector *next = get_next_shader(ctx, sel->stage);
|
|
|
|
|
|
2021-03-26 01:21:37 +00:00
|
|
|
|
NIR_PASS_V(nir, dxil_nir_split_clip_cull_distance);
|
2022-01-28 19:46:02 +00:00
|
|
|
|
NIR_PASS_V(nir, d3d12_split_multistream_varyings);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
|
|
|
|
|
if (nir->info.stage != MESA_SHADER_VERTEX)
|
|
|
|
|
nir->info.inputs_read =
|
2021-05-25 22:40:09 +01:00
|
|
|
|
dxil_reassign_driver_locations(nir, nir_var_shader_in,
|
2019-05-26 09:43:12 +01:00
|
|
|
|
prev ? prev->current->nir->info.outputs_written : 0);
|
|
|
|
|
else
|
2021-05-25 22:40:09 +01:00
|
|
|
|
nir->info.inputs_read = dxil_sort_by_driver_location(nir, nir_var_shader_in);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
|
|
|
|
|
if (nir->info.stage != MESA_SHADER_FRAGMENT) {
|
|
|
|
|
nir->info.outputs_written =
|
2021-05-25 22:40:09 +01:00
|
|
|
|
dxil_reassign_driver_locations(nir, nir_var_shader_out,
|
2019-05-26 09:43:12 +01:00
|
|
|
|
next ? next->current->nir->info.inputs_read : 0);
|
|
|
|
|
} else {
|
|
|
|
|
NIR_PASS_V(nir, nir_lower_fragcoord_wtrans);
|
2022-01-13 19:17:17 +00:00
|
|
|
|
NIR_PASS_V(nir, d3d12_lower_sample_pos);
|
2021-05-25 22:40:09 +01:00
|
|
|
|
dxil_sort_ps_outputs(nir);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
}
|
|
|
|
|
|
2021-12-31 17:58:50 +00:00
|
|
|
|
return d3d12_create_shader_impl(ctx, sel, nir, prev, next);
|
|
|
|
|
}
|
2019-05-26 09:43:12 +01:00
|
|
|
|
|
2021-12-31 17:58:50 +00:00
|
|
|
|
struct d3d12_shader_selector *
|
|
|
|
|
d3d12_create_compute_shader(struct d3d12_context *ctx,
|
|
|
|
|
const struct pipe_compute_state *shader)
|
|
|
|
|
{
|
|
|
|
|
struct d3d12_shader_selector *sel = rzalloc(nullptr, d3d12_shader_selector);
|
|
|
|
|
sel->stage = PIPE_SHADER_COMPUTE;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
|
2021-12-31 17:58:50 +00:00
|
|
|
|
struct nir_shader *nir = NULL;
|
2019-05-26 09:43:12 +01:00
|
|
|
|
|
2021-12-31 17:58:50 +00:00
|
|
|
|
if (shader->ir_type == PIPE_SHADER_IR_NIR) {
|
|
|
|
|
nir = (nir_shader *)shader->prog;
|
|
|
|
|
} else {
|
|
|
|
|
assert(shader->ir_type == PIPE_SHADER_IR_TGSI);
|
|
|
|
|
nir = tgsi_to_nir(shader->prog, ctx->base.screen, false);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
}
|
|
|
|
|
|
2021-12-31 17:58:50 +00:00
|
|
|
|
nir_shader_gather_info(nir, nir_shader_get_entrypoint(nir));
|
|
|
|
|
|
2021-12-31 22:50:07 +00:00
|
|
|
|
NIR_PASS_V(nir, d3d12_lower_compute_state_vars);
|
|
|
|
|
|
2021-12-31 17:58:50 +00:00
|
|
|
|
return d3d12_create_shader_impl(ctx, sel, nir, nullptr, nullptr);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
d3d12_select_shader_variants(struct d3d12_context *ctx, const struct pipe_draw_info *dinfo)
|
|
|
|
|
{
|
2022-01-01 22:49:28 +00:00
|
|
|
|
static unsigned order[] = {
|
|
|
|
|
PIPE_SHADER_VERTEX,
|
|
|
|
|
PIPE_SHADER_TESS_CTRL,
|
|
|
|
|
PIPE_SHADER_TESS_EVAL,
|
|
|
|
|
PIPE_SHADER_GEOMETRY,
|
|
|
|
|
PIPE_SHADER_FRAGMENT
|
|
|
|
|
};
|
2019-05-26 09:43:12 +01:00
|
|
|
|
struct d3d12_selection_context sel_ctx;
|
|
|
|
|
|
|
|
|
|
sel_ctx.ctx = ctx;
|
|
|
|
|
sel_ctx.needs_point_sprite_lowering = needs_point_sprite_lowering(ctx, dinfo);
|
|
|
|
|
sel_ctx.fill_mode_lowered = fill_mode_lowered(ctx, dinfo);
|
|
|
|
|
sel_ctx.cull_mode_lowered = cull_mode_lowered(ctx, sel_ctx.fill_mode_lowered);
|
2021-12-31 20:52:05 +00:00
|
|
|
|
sel_ctx.provoking_vertex = get_provoking_vertex(&sel_ctx, &sel_ctx.alternate_tri, dinfo);
|
|
|
|
|
sel_ctx.needs_vertex_reordering = needs_vertex_reordering(&sel_ctx, dinfo);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
sel_ctx.missing_dual_src_outputs = missing_dual_src_outputs(ctx);
|
|
|
|
|
sel_ctx.frag_result_color_lowering = frag_result_color_lowering(ctx);
|
|
|
|
|
sel_ctx.manual_depth_range = manual_depth_range(ctx);
|
|
|
|
|
|
|
|
|
|
validate_geometry_shader_variant(&sel_ctx);
|
2022-01-03 20:49:28 +00:00
|
|
|
|
validate_tess_ctrl_shader_variant(&sel_ctx);
|
2019-05-26 09:43:12 +01:00
|
|
|
|
|
2020-12-28 18:47:48 +00:00
|
|
|
|
for (unsigned i = 0; i < ARRAY_SIZE(order); ++i) {
|
2019-05-26 09:43:12 +01:00
|
|
|
|
auto sel = ctx->gfx_stages[order[i]];
|
|
|
|
|
if (!sel)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
d3d12_shader_selector *prev = get_prev_shader(ctx, sel->stage);
|
|
|
|
|
d3d12_shader_selector *next = get_next_shader(ctx, sel->stage);
|
|
|
|
|
|
|
|
|
|
select_shader_variant(&sel_ctx, sel, prev, next);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-31 20:54:04 +00:00
|
|
|
|
static const unsigned *
|
|
|
|
|
workgroup_size_variable(struct d3d12_context *ctx,
|
|
|
|
|
const struct pipe_grid_info *info)
|
|
|
|
|
{
|
|
|
|
|
if (ctx->compute_state->workgroup_size_variable)
|
|
|
|
|
return info->block;
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
d3d12_select_compute_shader_variants(struct d3d12_context *ctx, const struct pipe_grid_info *info)
|
|
|
|
|
{
|
|
|
|
|
struct d3d12_selection_context sel_ctx = {};
|
|
|
|
|
|
|
|
|
|
sel_ctx.ctx = ctx;
|
|
|
|
|
sel_ctx.variable_workgroup_size = workgroup_size_variable(ctx, info);
|
|
|
|
|
|
|
|
|
|
select_shader_variant(&sel_ctx, ctx->compute_state, nullptr, nullptr);
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-26 09:43:12 +01:00
|
|
|
|
void
|
|
|
|
|
d3d12_shader_free(struct d3d12_shader_selector *sel)
|
|
|
|
|
{
|
|
|
|
|
auto shader = sel->first;
|
|
|
|
|
while (shader) {
|
|
|
|
|
free(shader->bytecode);
|
|
|
|
|
shader = shader->next_variant;
|
|
|
|
|
}
|
|
|
|
|
ralloc_free(sel->initial);
|
|
|
|
|
ralloc_free(sel);
|
|
|
|
|
}
|