i965/gen6/gs: Fix binding table clash between TF surfaces and textures.

For gen6 geometry shaders we use the first BRW_MAX_SOL_BINDINGS entries of the
binding table for transform feedback surfaces. However, vec4_visitor will
setup the binding table so that textures use the same space in the binding
table. This is done when calling assign_common_binding_table_offsets(0) as
part if its run() method.

To fix this clash we add a virtual method to the vec4_visitor hierarchy to
assign the binding table offsets, so that we can change this behavior
specifically for gen6 geometry shaders by mapping textures right after the
first BRW_MAX_SOL_BINDINGS entries.

Also, when there is no user-provided geometry shader, we only need to upload
the binding table if we have transform feedback, however, in the case of a
user-provided geometry shader, we can't only look into transform feedback
to make that decision.

This fixes multiple piglit tests for textureSize() and texelFetch() when these
functions are called from a geometry shader in gen6, like these:

bin/textureSize gs sampler2D -fbo -auto
bin/texelFetch gs usampler2D -fbo -auto

Acked-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
This commit is contained in:
Iago Toral Quiroga 2014-08-01 10:35:20 +02:00
parent 2614cde998
commit c66165ab2b
6 changed files with 82 additions and 33 deletions

View file

@ -600,7 +600,6 @@ struct brw_vs_prog_data {
2 /* shader time, pull constants */)
#define SURF_INDEX_GEN6_SOL_BINDING(t) (t)
#define BRW_MAX_GEN6_GS_SURFACES SURF_INDEX_GEN6_SOL_BINDING(BRW_MAX_SOL_BINDINGS)
/* Note: brw_gs_prog_data_compare() must be updated when adding fields to
* this struct!
@ -1260,7 +1259,12 @@ struct brw_context
uint32_t state_offset;
uint32_t bind_bo_offset;
uint32_t surf_offset[BRW_MAX_GEN6_GS_SURFACES];
/**
* Surface offsets for the binding table. We only need surfaces to
* implement transform feedback so BRW_MAX_SOL_BINDINGS is all that we
* need in this case.
*/
uint32_t surf_offset[BRW_MAX_SOL_BINDINGS];
} ff_gs;
struct {

View file

@ -1612,6 +1612,12 @@ vec4_vs_visitor::setup_payload(void)
this->first_non_payload_grf = reg;
}
void
vec4_visitor::assign_binding_table_offsets()
{
assign_common_binding_table_offsets(0);
}
src_reg
vec4_visitor::get_timestamp()
{
@ -1711,7 +1717,7 @@ vec4_visitor::run()
if (INTEL_DEBUG & DEBUG_SHADER_TIME)
emit_shader_time_begin();
assign_common_binding_table_offsets(0);
assign_binding_table_offsets();
emit_prolog();

View file

@ -589,6 +589,7 @@ protected:
void setup_payload_interference(struct ra_graph *g, int first_payload_node,
int reg_node_count);
virtual dst_reg *make_reg_for_system_value(ir_variable *ir) = 0;
virtual void assign_binding_table_offsets();
virtual void setup_payload() = 0;
virtual void emit_prolog() = 0;
virtual void emit_program_code() = 0;

View file

@ -35,6 +35,15 @@ const unsigned MAX_GS_INPUT_VERTICES = 6;
namespace brw {
void
gen6_gs_visitor::assign_binding_table_offsets()
{
/* In gen6 we reserve the first BRW_MAX_SOL_BINDINGS entries for transform
* feedback surfaces.
*/
assign_common_binding_table_offsets(BRW_MAX_SOL_BINDINGS);
}
void
gen6_gs_visitor::emit_prolog()
{

View file

@ -43,6 +43,7 @@ public:
vec4_gs_visitor(brw, c, prog, mem_ctx, no_spills) {}
protected:
virtual void assign_binding_table_offsets();
virtual void emit_prolog();
virtual void emit_thread_end();
virtual void visit(ir_emit_vertex *);

View file

@ -108,48 +108,76 @@ static void
brw_gs_upload_binding_table(struct brw_context *brw)
{
uint32_t *bind;
struct gl_context *ctx = &brw->ctx;
const struct gl_shader_program *shaderprog;
bool need_binding_table = false;
/* We have two scenarios here:
* 1) We are using a geometry shader only to implement transform feedback
* for a vertex shader (brw->geometry_program == NULL). In this case, we
* only need surfaces for transform feedback in the GS stage.
* 2) We have a user-provided geometry shader. In this case we may need
* surfaces for transform feedback and/or other stuff, like textures,
* in the GS stage.
*/
if (!brw->geometry_program) {
struct gl_context *ctx = &brw->ctx;
/* BRW_NEW_VERTEX_PROGRAM */
const struct gl_shader_program *shaderprog =
ctx->_Shader->CurrentProgram[MESA_SHADER_VERTEX];
bool has_surfaces = false;
shaderprog = ctx->_Shader->CurrentProgram[MESA_SHADER_VERTEX];
if (shaderprog) {
/* Skip making a binding table if we don't have anything to put in it */
const struct gl_transform_feedback_info *linked_xfb_info =
&shaderprog->LinkedTransformFeedback;
/* Currently we only ever upload surfaces for SOL. */
has_surfaces = linked_xfb_info->NumOutputs != 0;
/* Skip making a binding table if we don't have anything to put in it. */
if (!has_surfaces) {
if (brw->ff_gs.bind_bo_offset != 0) {
brw->state.dirty.brw |= BRW_NEW_GS_BINDING_TABLE;
brw->ff_gs.bind_bo_offset = 0;
}
return;
}
need_binding_table = linked_xfb_info->NumOutputs > 0;
}
if (!need_binding_table) {
if (brw->ff_gs.bind_bo_offset != 0) {
brw->state.dirty.brw |= BRW_NEW_GS_BINDING_TABLE;
brw->ff_gs.bind_bo_offset = 0;
}
return;
}
}
/* Might want to calculate nr_surfaces first, to avoid taking up so much
* space for the binding table.
*/
if (brw->geometry_program) {
/* Might want to calculate nr_surfaces first, to avoid taking up so much
* space for the binding table. Anyway, in this case we know that we only
* use BRW_MAX_SOL_BINDINGS surfaces at most.
*/
bind = brw_state_batch(brw, AUB_TRACE_BINDING_TABLE,
sizeof(uint32_t) * BRW_MAX_GEN6_GS_SURFACES,
32, &brw->gs.base.bind_bo_offset);
/* BRW_NEW_SURFACES */
memcpy(bind, brw->gs.base.surf_offset, BRW_MAX_GEN6_GS_SURFACES * sizeof(uint32_t));
} else {
bind = brw_state_batch(brw, AUB_TRACE_BINDING_TABLE,
sizeof(uint32_t) * BRW_MAX_GEN6_GS_SURFACES,
sizeof(uint32_t) * BRW_MAX_SOL_BINDINGS,
32, &brw->ff_gs.bind_bo_offset);
/* BRW_NEW_SURFACES */
memcpy(bind, brw->ff_gs.surf_offset, BRW_MAX_GEN6_GS_SURFACES * sizeof(uint32_t));
memcpy(bind, brw->ff_gs.surf_offset,
BRW_MAX_SOL_BINDINGS * sizeof(uint32_t));
} else {
/* BRW_NEW_GEOMETRY_PROGRAM */
shaderprog = ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY];
if (shaderprog) {
/* Skip making a binding table if we don't have anything to put in it */
struct brw_stage_prog_data *prog_data = brw->gs.base.prog_data;
const struct gl_transform_feedback_info *linked_xfb_info =
&shaderprog->LinkedTransformFeedback;
need_binding_table = linked_xfb_info->NumOutputs > 0 ||
prog_data->binding_table.size_bytes > 0;
}
if (!need_binding_table) {
if (brw->gs.base.bind_bo_offset != 0) {
brw->gs.base.bind_bo_offset = 0;
brw->state.dirty.brw |= BRW_NEW_GS_BINDING_TABLE;
}
return;
}
/* Might want to calculate nr_surfaces first, to avoid taking up so much
* space for the binding table.
*/
bind = brw_state_batch(brw, AUB_TRACE_BINDING_TABLE,
sizeof(uint32_t) * BRW_MAX_SURFACES,
32, &brw->gs.base.bind_bo_offset);
/* BRW_NEW_SURFACES */
memcpy(bind, brw->gs.base.surf_offset,
BRW_MAX_SURFACES * sizeof(uint32_t));
}
brw->state.dirty.brw |= BRW_NEW_GS_BINDING_TABLE;