glsl: add NV_viewport_array2 support

This enables gl_Layer/gl_ViewportIndex when the ext is enabled, as well
as adding the new gl_ViewportMask[] array and viewport_relative layout
qualifier for gl_Layer.

Signed-off-by: Ilia Mirkin <imirkin@alum.mit.edu>
Acked-by: Marek Olšák <marek.olsak@amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/4529>
This commit is contained in:
Ilia Mirkin 2020-04-10 16:02:09 -04:00
parent 54424a3d13
commit cc6661bfc8
9 changed files with 150 additions and 3 deletions

View File

@ -663,6 +663,12 @@ struct ast_type_qualifier {
/** \{ */
unsigned derivative_group:1;
/** \} */
/**
* Flag set if GL_NV_viewport_array2 viewport_relative layout
* qualifier is used.
*/
unsigned viewport_relative:1;
}
/** \brief Set of flags, accessed by name. */
q;

View File

@ -3548,6 +3548,16 @@ is_conflicting_fragcoord_redeclaration(struct _mesa_glsl_parse_state *state,
return false;
}
static inline bool
is_conflicting_layer_redeclaration(struct _mesa_glsl_parse_state *state,
const struct ast_type_qualifier *qual)
{
if (state->redeclares_gl_layer) {
return state->layer_viewport_relative != qual->flags.q.viewport_relative;
}
return false;
}
static inline void
validate_array_dimensions(const glsl_type *t,
struct _mesa_glsl_parse_state *state,
@ -3937,6 +3947,21 @@ apply_layout_qualifier_to_variable(const struct ast_type_qualifier *qual,
"sample_interlock_ordered and sample_interlock_unordered, "
"only valid in fragment shader input layout declaration.");
}
if (var->name != NULL && strcmp(var->name, "gl_Layer") == 0) {
if (is_conflicting_layer_redeclaration(state, qual)) {
_mesa_glsl_error(loc, state, "gl_Layer redeclaration with "
"different viewport_relative setting than earlier");
}
state->redeclares_gl_layer = 1;
if (qual->flags.q.viewport_relative) {
state->layer_viewport_relative = 1;
}
} else if (qual->flags.q.viewport_relative) {
_mesa_glsl_error(loc, state,
"viewport_relative qualifier "
"can only be applied to gl_Layer.");
}
}
static void
@ -4378,6 +4403,11 @@ get_variable_being_redeclared(ir_variable **var_ptr, YYLTYPE loc,
earlier->data.precision = var->data.precision;
earlier->data.memory_coherent = var->data.memory_coherent;
} else if (state->NV_viewport_array2_enable &&
strcmp(var->name, "gl_Layer") == 0 &&
earlier->data.how_declared == ir_var_declared_implicitly) {
/* No need to do anything, just allow it. Qualifier is stored in state */
} else if ((earlier->data.how_declared == ir_var_declared_implicitly &&
state->allow_builtin_variable_redeclaration) ||
allow_all_redeclarations) {

View File

@ -1097,15 +1097,32 @@ builtin_variable_generator::generate_vs_special_vars()
add_system_value(SYSTEM_VALUE_DRAW_ID, int_t, "gl_DrawIDARB");
}
if (state->AMD_vertex_shader_layer_enable ||
state->ARB_shader_viewport_layer_array_enable) {
state->ARB_shader_viewport_layer_array_enable ||
state->NV_viewport_array2_enable) {
var = add_output(VARYING_SLOT_LAYER, int_t, "gl_Layer");
var->data.interpolation = INTERP_MODE_FLAT;
}
if (state->AMD_vertex_shader_viewport_index_enable ||
state->ARB_shader_viewport_layer_array_enable) {
state->ARB_shader_viewport_layer_array_enable ||
state->NV_viewport_array2_enable) {
var = add_output(VARYING_SLOT_VIEWPORT, int_t, "gl_ViewportIndex");
var->data.interpolation = INTERP_MODE_FLAT;
}
if (state->NV_viewport_array2_enable) {
/* From the NV_viewport_array2 specification:
*
* "The variable gl_ViewportMask[] is available as an output variable
* in the VTG languages. The array has ceil(v/32) elements where v is
* the maximum number of viewports supported by the implementation."
*
* Since no drivers expose more than 16 viewports, we can simply set the
* array size to 1 rather than computing it and dealing with varying
* slot complication.
*/
var = add_output(VARYING_SLOT_VIEWPORT_MASK, array(int_t, 1),
"gl_ViewportMask");
var->data.interpolation = INTERP_MODE_FLAT;
}
if (compatibility) {
add_input(VERT_ATTRIB_POS, vec4_t, "gl_Vertex");
add_input(VERT_ATTRIB_NORMAL, vec3_t, "gl_Normal");
@ -1155,6 +1172,17 @@ builtin_variable_generator::generate_tcs_special_vars()
add_output(bbox_slot, array(vec4_t, 2), GLSL_PRECISION_HIGH,
"gl_BoundingBox")->data.patch = 1;
}
/* NOTE: These are completely pointless. Writing these will never go
* anywhere. But the specs demands it. So we add them with a slot of -1,
* which makes the data go nowhere.
*/
if (state->NV_viewport_array2_enable) {
add_output(-1, int_t, "gl_Layer");
add_output(-1, int_t, "gl_ViewportIndex");
add_output(-1, array(int_t, 1), "gl_ViewportMask");
}
}
@ -1183,12 +1211,18 @@ builtin_variable_generator::generate_tes_special_vars()
add_system_value(SYSTEM_VALUE_TESS_LEVEL_INNER, array(float_t, 2),
GLSL_PRECISION_HIGH, "gl_TessLevelInner");
}
if (state->ARB_shader_viewport_layer_array_enable) {
if (state->ARB_shader_viewport_layer_array_enable ||
state->NV_viewport_array2_enable) {
var = add_output(VARYING_SLOT_LAYER, int_t, "gl_Layer");
var->data.interpolation = INTERP_MODE_FLAT;
var = add_output(VARYING_SLOT_VIEWPORT, int_t, "gl_ViewportIndex");
var->data.interpolation = INTERP_MODE_FLAT;
}
if (state->NV_viewport_array2_enable) {
var = add_output(VARYING_SLOT_VIEWPORT_MASK, array(int_t, 1),
"gl_ViewportMask");
var->data.interpolation = INTERP_MODE_FLAT;
}
}
@ -1208,6 +1242,11 @@ builtin_variable_generator::generate_gs_special_vars()
"gl_ViewportIndex");
var->data.interpolation = INTERP_MODE_FLAT;
}
if (state->NV_viewport_array2_enable) {
var = add_output(VARYING_SLOT_VIEWPORT_MASK, array(int_t, 1),
"gl_ViewportMask");
var->data.interpolation = INTERP_MODE_FLAT;
}
if (state->is_version(400, 320) || state->ARB_gpu_shader5_enable ||
state->OES_geometry_shader_enable || state->EXT_geometry_shader_enable) {
add_system_value(SYSTEM_VALUE_INVOCATION_ID, int_t, GLSL_PRECISION_HIGH,

View File

@ -1709,6 +1709,25 @@ layout_qualifier_id:
}
}
/* Layout qualifier for NV_viewport_array2. */
if (!$$.flags.i && state->stage != MESA_SHADER_FRAGMENT) {
if (match_layout_qualifier($1, "viewport_relative", state) == 0) {
$$.flags.q.viewport_relative = 1;
}
if ($$.flags.i && !state->NV_viewport_array2_enable) {
_mesa_glsl_error(& @1, state,
"qualifier `%s' requires "
"GL_NV_viewport_array2", $1);
}
if ($$.flags.i && state->NV_viewport_array2_warn) {
_mesa_glsl_warning(& @1, state,
"GL_NV_viewport_array2 layout "
"identifier `%s' used", $1);
}
}
if (!$$.flags.i) {
_mesa_glsl_error(& @1, state, "unrecognized layout identifier "
"`%s'", $1);

View File

@ -1929,6 +1929,8 @@ set_shader_inout_layout(struct gl_shader *shader,
shader->bindless_image = state->bindless_image_specified;
shader->bound_sampler = state->bound_sampler_specified;
shader->bound_image = state->bound_image_specified;
shader->redeclares_gl_layer = state->redeclares_gl_layer;
shader->layer_viewport_relative = state->layer_viewport_relative;
}
/* src can be NULL if only the symbols found in the exec_list should be

View File

@ -884,6 +884,8 @@ struct _mesa_glsl_parse_state {
bool NV_image_formats_warn;
bool NV_shader_atomic_float_enable;
bool NV_shader_atomic_float_warn;
bool NV_viewport_array2_enable;
bool NV_viewport_array2_warn;
/*@}*/
/** Extensions supported by the OpenGL implementation. */
@ -926,6 +928,10 @@ struct _mesa_glsl_parse_state {
/** Atomic counter offsets by binding */
unsigned atomic_counter_offsets[MAX_COMBINED_ATOMIC_BUFFERS];
/** Whether gl_Layer output is viewport-relative. */
bool redeclares_gl_layer;
bool layer_viewport_relative;
bool allow_extension_directive_midshader;
bool allow_builtin_variable_redeclaration;
bool allow_layout_qualifier_on_function_parameter;

View File

@ -1816,6 +1816,40 @@ link_bindless_layout_qualifiers(struct gl_shader_program *prog,
}
}
/**
* Check for conflicting viewport_relative settings across shaders, and sets
* the value for the linked shader.
*/
static void
link_layer_viewport_relative_qualifier(struct gl_shader_program *prog,
struct gl_program *gl_prog,
struct gl_shader **shader_list,
unsigned num_shaders)
{
unsigned i;
/* Find first shader with explicit layer declaration */
for (i = 0; i < num_shaders; i++) {
if (shader_list[i]->redeclares_gl_layer) {
gl_prog->info.layer_viewport_relative =
shader_list[i]->layer_viewport_relative;
break;
}
}
/* Now make sure that each subsequent shader's explicit layer declaration
* matches the first one's.
*/
for (; i < num_shaders; i++) {
if (shader_list[i]->redeclares_gl_layer &&
shader_list[i]->layer_viewport_relative !=
gl_prog->info.layer_viewport_relative) {
linker_error(prog, "all gl_Layer redeclarations must have identical "
"viewport_relative settings");
}
}
}
/**
* Performs the cross-validation of tessellation control shader vertices and
* layout qualifiers for the attached tessellation control shaders,
@ -2461,6 +2495,8 @@ link_intrastage_shaders(void *mem_ctx,
link_bindless_layout_qualifiers(prog, shader_list, num_shaders);
link_layer_viewport_relative_qualifier(prog, gl_prog, shader_list, num_shaders);
populate_symbol_table(linked, shader_list[0]->symbols);
/* The pointer to the main function in the final linked shader (i.e., the

View File

@ -191,6 +191,9 @@ typedef struct shader_info {
/* Whether the shader writes memory, including transform feedback. */
bool writes_memory:1;
/* Whether gl_Layer is viewport-relative */
bool layer_viewport_relative:1;
union {
struct {
/* Which inputs are doubles */

View File

@ -2674,6 +2674,12 @@ struct gl_shader
bool bound_sampler;
bool bound_image;
/**
* Whether layer output is viewport-relative.
*/
bool redeclares_gl_layer;
bool layer_viewport_relative;
/** Global xfb_stride out qualifier if any */
GLuint TransformFeedbackBufferStride[MAX_FEEDBACK_BUFFERS];