glsl: validate global out xfb_stride qualifiers and set stride on empty buffers
Here we use the built-in validation in ast_layout_expression::process_qualifier_constant() to check for mismatching global out strides on buffers in a single shader. From the ARB_enhanced_layouts spec: "While *xfb_stride* can be declared multiple times for the same buffer, it is a compile-time or link-time error to have different values specified for the stride for the same buffer." For intrastage validation a new helper link_xfb_stride_layout_qualifiers() is created. We also take this opportunity to make sure stride is at least a multiple of 4, we will validate doubles at a later stage. From the ARB_enhanced_layouts spec: "If the buffer is capturing any double-typed outputs, the stride must be a multiple of 8, otherwise it must be a multiple of 4, or a compile-time or link-time error results." Finally we update store_tfeedback_info() to apply the strides to LinkedTransformFeedback and update the buffers bitmask to mark any global buffers with a stride as active. For example a shader with: layout (xfb_buffer = 0, xfb_offset = 0) out vec4 gs_fs; layout (xfb_buffer = 1, xfb_stride = 64) out; Is expected to have a buffer bound to both 0 and 1. From the ARB_enhanced_layouts spec: "A binding point requires a bound buffer object if and only if its associated stride in the program object used for transform feedback primitive capture is non-zero." Reviewed-by: Dave Airlie <airlied@redhat.com>
This commit is contained in:
@@ -1617,6 +1617,17 @@ set_shader_inout_layout(struct gl_shader *shader,
|
||||
assert(!state->fs_early_fragment_tests);
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < MAX_FEEDBACK_BUFFERS; i++) {
|
||||
if (state->out_qualifier->out_xfb_stride[i]) {
|
||||
unsigned xfb_stride;
|
||||
if (state->out_qualifier->out_xfb_stride[i]->
|
||||
process_qualifier_constant(state, "xfb_stride", &xfb_stride,
|
||||
true)) {
|
||||
shader->TransformFeedback.BufferStride[i] = xfb_stride;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (shader->Stage) {
|
||||
case MESA_SHADER_TESS_CTRL:
|
||||
shader->TessCtrl.VerticesOut = 0;
|
||||
|
@@ -930,6 +930,17 @@ store_tfeedback_info(struct gl_context *ctx, struct gl_shader_program *prog,
|
||||
unsigned buffer =
|
||||
num_tfeedback_decls ? tfeedback_decls[0].get_buffer() : 0;
|
||||
|
||||
/* Apply any xfb_stride global qualifiers */
|
||||
if (has_xfb_qualifiers) {
|
||||
for (unsigned j = 0; j < MAX_FEEDBACK_BUFFERS; j++) {
|
||||
if (prog->TransformFeedback.BufferStride[j]) {
|
||||
buffers |= 1 << j;
|
||||
prog->LinkedTransformFeedback.Buffers[j].Stride =
|
||||
prog->TransformFeedback.BufferStride[j] / 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < num_tfeedback_decls; ++i) {
|
||||
if (tfeedback_decls[i].is_next_buffer_separator()) {
|
||||
num_buffers++;
|
||||
|
@@ -1584,6 +1584,69 @@ private:
|
||||
hash_table *unnamed_interfaces;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check for conflicting xfb_stride default qualifiers and store buffer stride
|
||||
* for later use.
|
||||
*/
|
||||
static void
|
||||
link_xfb_stride_layout_qualifiers(struct gl_context *ctx,
|
||||
struct gl_shader_program *prog,
|
||||
struct gl_shader *linked_shader,
|
||||
struct gl_shader **shader_list,
|
||||
unsigned num_shaders)
|
||||
{
|
||||
for (unsigned i = 0; i < MAX_FEEDBACK_BUFFERS; i++) {
|
||||
linked_shader->TransformFeedback.BufferStride[i] = 0;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < num_shaders; i++) {
|
||||
struct gl_shader *shader = shader_list[i];
|
||||
|
||||
for (unsigned j = 0; j < MAX_FEEDBACK_BUFFERS; j++) {
|
||||
if (shader->TransformFeedback.BufferStride[j]) {
|
||||
if (linked_shader->TransformFeedback.BufferStride[j] != 0 &&
|
||||
shader->TransformFeedback.BufferStride[j] != 0 &&
|
||||
linked_shader->TransformFeedback.BufferStride[j] !=
|
||||
shader->TransformFeedback.BufferStride[j]) {
|
||||
linker_error(prog,
|
||||
"intrastage shaders defined with conflicting "
|
||||
"xfb_stride for buffer %d (%d and %d)\n", j,
|
||||
linked_shader->TransformFeedback.BufferStride[j],
|
||||
shader->TransformFeedback.BufferStride[j]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (shader->TransformFeedback.BufferStride[j])
|
||||
linked_shader->TransformFeedback.BufferStride[j] =
|
||||
shader->TransformFeedback.BufferStride[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned j = 0; j < MAX_FEEDBACK_BUFFERS; j++) {
|
||||
if (linked_shader->TransformFeedback.BufferStride[j]) {
|
||||
prog->TransformFeedback.BufferStride[j] =
|
||||
linked_shader->TransformFeedback.BufferStride[j];
|
||||
|
||||
/* We will validate doubles at a later stage */
|
||||
if (prog->TransformFeedback.BufferStride[j] % 4) {
|
||||
linker_error(prog, "invalid qualifier xfb_stride=%d must be a "
|
||||
"multiple of 4 or if its applied to a type that is "
|
||||
"or contains a double a multiple of 8.",
|
||||
prog->TransformFeedback.BufferStride[j]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (prog->TransformFeedback.BufferStride[j] / 4 >
|
||||
ctx->Const.MaxTransformFeedbackInterleavedComponents) {
|
||||
linker_error(prog,
|
||||
"The MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS "
|
||||
"limit has been exceeded.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the cross-validation of tessellation control shader vertices and
|
||||
@@ -2101,6 +2164,8 @@ link_intrastage_shaders(void *mem_ctx,
|
||||
link_tes_in_layout_qualifiers(prog, linked, shader_list, num_shaders);
|
||||
link_gs_inout_layout_qualifiers(prog, linked, shader_list, num_shaders);
|
||||
link_cs_input_layout_qualifiers(prog, linked, shader_list, num_shaders);
|
||||
link_xfb_stride_layout_qualifiers(ctx, prog, linked, shader_list,
|
||||
num_shaders);
|
||||
|
||||
populate_symbol_table(linked);
|
||||
|
||||
|
@@ -2337,6 +2337,11 @@ struct gl_shader
|
||||
bool origin_upper_left;
|
||||
bool pixel_center_integer;
|
||||
|
||||
struct {
|
||||
/** Global xfb_stride out qualifier if any */
|
||||
GLuint BufferStride[MAX_FEEDBACK_BUFFERS];
|
||||
} TransformFeedback;
|
||||
|
||||
/**
|
||||
* Tessellation Control shader state from layout qualifiers.
|
||||
*/
|
||||
@@ -2674,6 +2679,8 @@ struct gl_shader_program
|
||||
*/
|
||||
struct {
|
||||
GLenum BufferMode;
|
||||
/** Global xfb_stride out qualifier if any */
|
||||
GLuint BufferStride[MAX_FEEDBACK_BUFFERS];
|
||||
GLuint NumVarying;
|
||||
GLchar **VaryingNames; /**< Array [NumVarying] of char * */
|
||||
} TransformFeedback;
|
||||
|
Reference in New Issue
Block a user