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.tags/snb-magic
@@ -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 \ |
@@ -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', |
@@ -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; | |||
} | |||
@@ -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 | |||
*/ |
@@ -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); | |||
} | |||
@@ -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); | |||
} | |||
@@ -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) { |
@@ -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: | |||
*/ |
@@ -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? */ | |||
@@ -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 ); | |||
} | |||
@@ -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; | |||
} | |||
@@ -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; | |||
} | |||
} |