From: Brian Paul Date: Sat, 18 Sep 2010 00:41:30 +0000 (-0600) Subject: gallium: rework handling of sprite_coord_enable state X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=e22e3927b056806e9bbb089734132ad0bcb98df1;p=mesa.git gallium: rework handling of sprite_coord_enable state Implement the pipe_rasterizer_state::sprite_coord_enable field in the draw module (and softpipe) according to what's specified in the documentation. The draw module can now add any number of extra vertex attributes to a post-transformed vertex and generate texcoords for those attributes per sprite_coord_enable. Auto-generated texcoords for sprites only worked for one texcoord unit before. The frag shader gl_PointCoord input is now implemented like any other generic/texcoord attribute. The draw module now needs to be informed about fragment shaders since we need to look at the fragment shader's inputs to know which ones need auto-generated texcoords. Only softpipe has been updated so far. --- diff --git a/src/gallium/auxiliary/Makefile b/src/gallium/auxiliary/Makefile index 2de764c4ee3..f05538bbac4 100644 --- a/src/gallium/auxiliary/Makefile +++ b/src/gallium/auxiliary/Makefile @@ -8,6 +8,7 @@ C_SOURCES = \ cso_cache/cso_context.c \ cso_cache/cso_hash.c \ draw/draw_context.c \ + draw/draw_fs.c \ draw/draw_gs.c \ draw/draw_pipe.c \ draw/draw_pipe_aaline.c \ diff --git a/src/gallium/auxiliary/SConscript b/src/gallium/auxiliary/SConscript index 294df300947..baaa26fea92 100644 --- a/src/gallium/auxiliary/SConscript +++ b/src/gallium/auxiliary/SConscript @@ -54,6 +54,7 @@ source = [ 'cso_cache/cso_context.c', 'cso_cache/cso_hash.c', 'draw/draw_context.c', + 'draw/draw_fs.c', 'draw/draw_gs.c', 'draw/draw_pipe.c', 'draw/draw_pipe_aaline.c', diff --git a/src/gallium/auxiliary/draw/draw_context.c b/src/gallium/auxiliary/draw/draw_context.c index 937b0934798..b07de76a498 100644 --- a/src/gallium/auxiliary/draw/draw_context.c +++ b/src/gallium/auxiliary/draw/draw_context.c @@ -413,6 +413,42 @@ draw_set_force_passthrough( struct draw_context *draw, boolean enable ) } + +/** + * Allocate an extra vertex/geometry shader vertex attribute. + * This is used by some of the optional draw module stages such + * as wide_point which may need to allocate additional generic/texcoord + * attributes. + */ +int +draw_alloc_extra_vertex_attrib(struct draw_context *draw, + uint semantic_name, uint semantic_index) +{ + const int num_outputs = draw_current_shader_outputs(draw); + const int n = draw->extra_shader_outputs.num; + + assert(n < Elements(draw->extra_shader_outputs.semantic_name)); + + draw->extra_shader_outputs.semantic_name[n] = semantic_name; + draw->extra_shader_outputs.semantic_index[n] = semantic_index; + draw->extra_shader_outputs.slot[n] = num_outputs + n; + draw->extra_shader_outputs.num++; + + return draw->extra_shader_outputs.slot[n]; +} + + +/** + * Remove all extra vertex attributes that were allocated with + * draw_alloc_extra_vertex_attrib(). + */ +void +draw_remove_extra_vertex_attribs(struct draw_context *draw) +{ + draw->extra_shader_outputs.num = 0; +} + + /** * Ask the draw module for the location/slot of the given vertex attribute in * a post-transformed vertex. @@ -446,12 +482,12 @@ draw_find_shader_output(const struct draw_context *draw, return i; } - /* XXX there may be more than one extra vertex attrib. - * For example, simulated gl_FragCoord and gl_PointCoord. - */ - if (draw->extra_shader_outputs.semantic_name == semantic_name && - draw->extra_shader_outputs.semantic_index == semantic_index) { - return draw->extra_shader_outputs.slot; + /* Search the extra vertex attributes */ + for (i = 0; i < draw->extra_shader_outputs.num; i++) { + if (draw->extra_shader_outputs.semantic_name[i] == semantic_name && + draw->extra_shader_outputs.semantic_index[i] == semantic_index) { + return draw->extra_shader_outputs.slot[i]; + } } return 0; @@ -470,16 +506,18 @@ draw_find_shader_output(const struct draw_context *draw, uint draw_num_shader_outputs(const struct draw_context *draw) { - uint count = draw->vs.vertex_shader->info.num_outputs; + uint count; /* If a geometry shader is present, its outputs go to the * driver, else the vertex shader's outputs. */ if (draw->gs.geometry_shader) count = draw->gs.geometry_shader->info.num_outputs; + else + count = draw->vs.vertex_shader->info.num_outputs; + + count += draw->extra_shader_outputs.num; - if (draw->extra_shader_outputs.slot > 0) - count++; return count; } diff --git a/src/gallium/auxiliary/draw/draw_context.h b/src/gallium/auxiliary/draw/draw_context.h index 4f0d30123a4..1f27cbf488a 100644 --- a/src/gallium/auxiliary/draw/draw_context.h +++ b/src/gallium/auxiliary/draw/draw_context.h @@ -46,6 +46,7 @@ struct draw_context; struct draw_stage; struct draw_vertex_shader; struct draw_geometry_shader; +struct draw_fragment_shader; struct tgsi_sampler; #define DRAW_MAX_TEXTURE_LEVELS 13 /* 4K x 4K for now */ @@ -137,6 +138,17 @@ void draw_delete_vertex_shader(struct draw_context *draw, struct draw_vertex_shader *dvs); +/* + * Fragment shader functions + */ +struct draw_fragment_shader * +draw_create_fragment_shader(struct draw_context *draw, + const struct pipe_shader_state *shader); +void draw_bind_fragment_shader(struct draw_context *draw, + struct draw_fragment_shader *dvs); +void draw_delete_fragment_shader(struct draw_context *draw, + struct draw_fragment_shader *dvs); + /* * Geometry shader functions */ diff --git a/src/gallium/auxiliary/draw/draw_pipe_aaline.c b/src/gallium/auxiliary/draw/draw_pipe_aaline.c index eac21110be4..d1aba763098 100644 --- a/src/gallium/auxiliary/draw/draw_pipe_aaline.c +++ b/src/gallium/auxiliary/draw/draw_pipe_aaline.c @@ -688,10 +688,9 @@ aaline_first_line(struct draw_stage *stage, struct prim_header *header) aaline->tex_slot = draw_current_shader_outputs(draw); aaline->pos_slot = draw_current_shader_position_output(draw);; - /* advertise the extra post-transformed vertex attribute */ - draw->extra_shader_outputs.semantic_name = TGSI_SEMANTIC_GENERIC; - draw->extra_shader_outputs.semantic_index = aaline->fs->generic_attrib; - draw->extra_shader_outputs.slot = aaline->tex_slot; + /* allocate the extra post-transformed vertex attribute */ + (void) draw_alloc_extra_vertex_attrib(draw, TGSI_SEMANTIC_GENERIC, + aaline->fs->generic_attrib); /* how many samplers? */ /* we'll use sampler/texture[pstip->sampler_unit] for the stipple */ @@ -744,7 +743,7 @@ aaline_flush(struct draw_stage *stage, unsigned flags) draw->suspend_flushing = FALSE; - draw->extra_shader_outputs.slot = 0; + draw_remove_extra_vertex_attribs(draw); } diff --git a/src/gallium/auxiliary/draw/draw_pipe_aapoint.c b/src/gallium/auxiliary/draw/draw_pipe_aapoint.c index d406a86ccb5..5ea552f51c1 100644 --- a/src/gallium/auxiliary/draw/draw_pipe_aapoint.c +++ b/src/gallium/auxiliary/draw/draw_pipe_aapoint.c @@ -701,9 +701,9 @@ aapoint_first_point(struct draw_stage *stage, struct prim_header *header) aapoint->pos_slot = draw_current_shader_position_output(draw); - draw->extra_shader_outputs.semantic_name = TGSI_SEMANTIC_GENERIC; - draw->extra_shader_outputs.semantic_index = aapoint->fs->generic_attrib; - draw->extra_shader_outputs.slot = aapoint->tex_slot; + /* allocate the extra post-transformed vertex attribute */ + (void) draw_alloc_extra_vertex_attrib(draw, TGSI_SEMANTIC_GENERIC, + aapoint->fs->generic_attrib); /* find psize slot in post-transform vertex */ aapoint->psize_slot = -1; @@ -754,7 +754,7 @@ aapoint_flush(struct draw_stage *stage, unsigned flags) draw->suspend_flushing = FALSE; - draw->extra_shader_outputs.slot = 0; + draw_remove_extra_vertex_attribs(draw); } diff --git a/src/gallium/auxiliary/draw/draw_pipe_wide_point.c b/src/gallium/auxiliary/draw/draw_pipe_wide_point.c index ee2945c7c97..40843c58c20 100644 --- a/src/gallium/auxiliary/draw/draw_pipe_wide_point.c +++ b/src/gallium/auxiliary/draw/draw_pipe_wide_point.c @@ -57,26 +57,24 @@ #include "util/u_memory.h" #include "pipe/p_defines.h" #include "pipe/p_shader_tokens.h" +#include "draw_fs.h" #include "draw_vs.h" #include "draw_pipe.h" struct widepoint_stage { - struct draw_stage stage; + struct draw_stage stage; /**< base class */ float half_point_size; float xbias; float ybias; - uint texcoord_slot[PIPE_MAX_SHADER_OUTPUTS]; - uint texcoord_enable[PIPE_MAX_SHADER_OUTPUTS]; - uint num_texcoords; - uint texcoord_mode; + /** for automatic texcoord generation/replacement */ + uint num_texcoord_gen; + uint texcoord_gen_slot[PIPE_MAX_SHADER_OUTPUTS]; int psize_slot; - - int point_coord_fs_input; /**< input for pointcoord */ }; @@ -96,30 +94,20 @@ widepoint_stage( struct draw_stage *stage ) static void set_texcoords(const struct widepoint_stage *wide, struct vertex_header *v, const float tc[4]) { + const struct draw_context *draw = wide->stage.draw; + const struct pipe_rasterizer_state *rast = draw->rasterizer; + const uint texcoord_mode = rast->sprite_coord_mode; uint i; - for (i = 0; i < wide->num_texcoords; i++) { - if (wide->texcoord_enable[i]) { - uint j = wide->texcoord_slot[i]; - v->data[j][0] = tc[0]; - if (wide->texcoord_mode == PIPE_SPRITE_COORD_LOWER_LEFT) - v->data[j][1] = 1.0f - tc[1]; - else - v->data[j][1] = tc[1]; - v->data[j][2] = tc[2]; - v->data[j][3] = tc[3]; - } - } - if (wide->point_coord_fs_input >= 0) { - /* put gl_PointCoord into the extra vertex slot */ - uint slot = wide->stage.draw->extra_shader_outputs.slot; + for (i = 0; i < wide->num_texcoord_gen; i++) { + const uint slot = wide->texcoord_gen_slot[i]; v->data[slot][0] = tc[0]; - if (wide->texcoord_mode == PIPE_SPRITE_COORD_LOWER_LEFT) + if (texcoord_mode == PIPE_SPRITE_COORD_LOWER_LEFT) v->data[slot][1] = 1.0f - tc[1]; else v->data[slot][1] = tc[1]; - v->data[slot][2] = 0.0F; - v->data[slot][3] = 1.0F; + v->data[slot][2] = tc[2]; + v->data[slot][3] = tc[3]; } } @@ -201,18 +189,9 @@ static void widepoint_point( struct draw_stage *stage, } -static int -find_pntc_input_attrib(struct draw_context *draw) -{ - /* Scan the fragment program's input decls to find the pointcoord - * attribute. The xy components will store the point coord. - */ - return 0; /* XXX fix this */ -} - - -static void widepoint_first_point( struct draw_stage *stage, - struct prim_header *header ) +static void +widepoint_first_point(struct draw_stage *stage, + struct prim_header *header) { struct widepoint_stage *wide = widepoint_stage(stage); struct draw_context *draw = stage->draw; @@ -244,31 +223,45 @@ static void widepoint_first_point( struct draw_stage *stage, stage->point = draw_pipe_passthrough_point; } + draw_remove_extra_vertex_attribs(draw); + if (rast->point_quad_rasterization) { - /* find vertex shader texcoord outputs */ - const struct draw_vertex_shader *vs = draw->vs.vertex_shader; - uint i, j = 0; - wide->texcoord_mode = rast->sprite_coord_mode; - for (i = 0; i < vs->info.num_outputs; i++) { - if (vs->info.output_semantic_name[i] == TGSI_SEMANTIC_GENERIC) { - wide->texcoord_slot[j] = i; - wide->texcoord_enable[j] = (rast->sprite_coord_enable >> j) & 1; - j++; + const struct draw_fragment_shader *fs = draw->fs.fragment_shader; + uint i; + + wide->num_texcoord_gen = 0; + + /* Loop over fragment shader inputs looking for generic inputs + * for which bit 'k' in sprite_coord_enable is set. + */ + for (i = 0; i < fs->info.num_inputs; i++) { + if (fs->info.input_semantic_name[i] == TGSI_SEMANTIC_GENERIC) { + const int generic_index = fs->info.input_semantic_index[i]; + if (rast->sprite_coord_enable & (1 << generic_index)) { + /* OK, this generic attribute needs to be replaced with a + * texcoord (see above). + */ + int slot = draw_find_shader_output(draw, + TGSI_SEMANTIC_GENERIC, + generic_index); + + if (slot > 0) { + /* there's already a post-vertex shader attribute + * for this fragment shader input attribute. + */ + } + else { + /* need to allocate a new post-vertex shader attribute */ + slot = draw_alloc_extra_vertex_attrib(draw, + TGSI_SEMANTIC_GENERIC, + generic_index); + } + + /* add this slot to the texcoord-gen list */ + wide->texcoord_gen_slot[wide->num_texcoord_gen++] = slot; + } } } - wide->num_texcoords = j; - - /* find fragment shader PointCoord input */ - wide->point_coord_fs_input = find_pntc_input_attrib(draw); - - /* setup extra vp output (point coord implemented as a texcoord) */ - draw->extra_shader_outputs.semantic_name = TGSI_SEMANTIC_GENERIC; - draw->extra_shader_outputs.semantic_index = 0; - draw->extra_shader_outputs.slot = draw_current_shader_outputs(draw); - } - else { - wide->point_coord_fs_input = -1; - draw->extra_shader_outputs.slot = 0; } wide->psize_slot = -1; @@ -295,7 +288,8 @@ static void widepoint_flush( struct draw_stage *stage, unsigned flags ) stage->point = widepoint_first_point; stage->next->flush( stage->next, flags ); - stage->draw->extra_shader_outputs.slot = 0; + + draw_remove_extra_vertex_attribs(draw); /* restore original rasterizer state */ if (draw->rast_handle) { diff --git a/src/gallium/auxiliary/draw/draw_private.h b/src/gallium/auxiliary/draw/draw_private.h index 362f563ba6a..d417f825a0f 100644 --- a/src/gallium/auxiliary/draw/draw_private.h +++ b/src/gallium/auxiliary/draw/draw_private.h @@ -250,6 +250,11 @@ struct draw_context struct tgsi_sampler **samplers; } gs; + /** Fragment shader state */ + struct { + struct draw_fragment_shader *fragment_shader; + } fs; + /** Stream output (vertex feedback) state */ struct { struct pipe_stream_output_state state; @@ -266,9 +271,10 @@ struct draw_context /* If a prim stage introduces new vertex attributes, they'll be stored here */ struct { - uint semantic_name; - uint semantic_index; - int slot; + uint num; + uint semantic_name[10]; + uint semantic_index[10]; + uint slot[10]; } extra_shader_outputs; unsigned reduced_prim; @@ -362,6 +368,11 @@ void draw_gs_destroy( struct draw_context *draw ); uint draw_current_shader_outputs(const struct draw_context *draw); uint draw_current_shader_position_output(const struct draw_context *draw); +int draw_alloc_extra_vertex_attrib(struct draw_context *draw, + uint semantic_name, uint semantic_index); +void draw_remove_extra_vertex_attribs(struct draw_context *draw); + + /******************************************************************************* * Vertex processing (was passthrough) code: */ diff --git a/src/gallium/drivers/softpipe/sp_state.h b/src/gallium/drivers/softpipe/sp_state.h index 39d204de8a9..c5d61f840f2 100644 --- a/src/gallium/drivers/softpipe/sp_state.h +++ b/src/gallium/drivers/softpipe/sp_state.h @@ -70,6 +70,8 @@ struct sp_fragment_shader { struct tgsi_shader_info info; + struct draw_fragment_shader *draw_shader; + boolean origin_lower_left; /**< fragment shader uses lower left position origin? */ boolean pixel_center_integer; /**< fragment shader uses integer pixel center? */ diff --git a/src/gallium/drivers/softpipe/sp_state_fs.c b/src/gallium/drivers/softpipe/sp_state_fs.c index ded242d3dc5..50bc2eea5ff 100644 --- a/src/gallium/drivers/softpipe/sp_state_fs.c +++ b/src/gallium/drivers/softpipe/sp_state_fs.c @@ -60,7 +60,15 @@ softpipe_create_fs_state(struct pipe_context *pipe, state = softpipe_create_fs_exec( softpipe, templ ); } - assert(state); + if (!state) + return NULL; + + /* draw's fs state */ + state->draw_shader = draw_create_fragment_shader(softpipe->draw, templ); + if (!state->draw_shader) { + state->delete( state ); + return NULL; + } /* get/save the summary info for this shader */ tgsi_scan_shader(templ->tokens, &state->info); @@ -90,6 +98,9 @@ softpipe_bind_fs_state(struct pipe_context *pipe, void *fs) softpipe->fs = fs; + draw_bind_fragment_shader(softpipe->draw, + (softpipe->fs ? softpipe->fs->draw_shader : NULL)); + softpipe->dirty |= SP_NEW_FS; } @@ -109,6 +120,8 @@ softpipe_delete_fs_state(struct pipe_context *pipe, void *fs) tgsi_exec_machine_bind_shader(softpipe->fs_machine, NULL, 0, NULL); } + draw_delete_fragment_shader(softpipe->draw, state->draw_shader); + state->delete( state ); } diff --git a/src/mesa/state_tracker/st_atom_rasterizer.c b/src/mesa/state_tracker/st_atom_rasterizer.c index 2599bd5ca03..0fe333ae8aa 100644 --- a/src/mesa/state_tracker/st_atom_rasterizer.c +++ b/src/mesa/state_tracker/st_atom_rasterizer.c @@ -60,6 +60,7 @@ static void update_raster_state( struct st_context *st ) GLcontext *ctx = st->ctx; struct pipe_rasterizer_state *raster = &st->state.rasterizer; const struct gl_vertex_program *vertProg = ctx->VertexProgram._Current; + const struct gl_fragment_program *fragProg = ctx->FragmentProgram._Current; uint i; memset(raster, 0, sizeof(*raster)); @@ -175,17 +176,30 @@ static void update_raster_state( struct st_context *st ) if (!ctx->Point.PointSprite && ctx->Point.SmoothFlag) raster->point_smooth = 1; + /* _NEW_POINT | _NEW_PROGRAM + */ if (ctx->Point.PointSprite) { + /* origin */ if ((ctx->Point.SpriteOrigin == GL_UPPER_LEFT) ^ (st_fb_orientation(ctx->DrawBuffer) == Y_0_BOTTOM)) raster->sprite_coord_mode = PIPE_SPRITE_COORD_UPPER_LEFT; else raster->sprite_coord_mode = PIPE_SPRITE_COORD_LOWER_LEFT; + + /* Coord replacement flags. If bit 'k' is set that means + * that we need to replace GENERIC[k] attrib with an automatically + * computed texture coord. + */ for (i = 0; i < MAX_TEXTURE_COORD_UNITS; i++) { if (ctx->Point.CoordReplace[i]) { raster->sprite_coord_enable |= 1 << i; } } + if (fragProg->Base.InputsRead & FRAG_BIT_PNTC) { + raster->sprite_coord_enable |= + 1 << (FRAG_ATTRIB_PNTC - FRAG_ATTRIB_TEX0); + } + raster->point_quad_rasterization = 1; } diff --git a/src/mesa/state_tracker/st_program.c b/src/mesa/state_tracker/st_program.c index 8c2d8b6154b..18a7bbe0f90 100644 --- a/src/mesa/state_tracker/st_program.c +++ b/src/mesa/state_tracker/st_program.c @@ -338,17 +338,6 @@ st_translate_fragment_program(struct st_context *st, input_semantic_index[slot] = 0; interpMode[slot] = TGSI_INTERPOLATE_CONSTANT; break; - case FRAG_ATTRIB_PNTC: - /* This is a hack. We really need a new semantic label for - * point coord. The draw module needs to know which fragment - * shader input is the point coord attribute so that it can set - * up the right vertex attribute values. - */ - input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; - input_semantic_index[slot] = 0; - interpMode[slot] = TGSI_INTERPOLATE_PERSPECTIVE; - break; - /* In most cases, there is nothing special about these * inputs, so adopt a convention to use the generic * semantic name and the mesa FRAG_ATTRIB_ number as the @@ -364,6 +353,7 @@ st_translate_fragment_program(struct st_context *st, * zero or be restricted to a particular range -- nobody * should be building tables based on semantic index. */ + case FRAG_ATTRIB_PNTC: case FRAG_ATTRIB_TEX0: case FRAG_ATTRIB_TEX1: case FRAG_ATTRIB_TEX2: @@ -380,7 +370,10 @@ st_translate_fragment_program(struct st_context *st, assert(attr >= FRAG_ATTRIB_TEX0); input_semantic_index[slot] = (attr - FRAG_ATTRIB_TEX0); input_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; - interpMode[slot] = TGSI_INTERPOLATE_PERSPECTIVE; + if (attr == FRAG_ATTRIB_PNTC) + interpMode[slot] = TGSI_INTERPOLATE_LINEAR; + else + interpMode[slot] = TGSI_INTERPOLATE_PERSPECTIVE; break; } }