gallium: first steps to treat edgeflags as regular vertex element
The idea here is to eliminate the set_edgeflags() call in pipe_context by treating edgeflags as a regular vertex element. Edgeflags provoke special treatment in hardware, which means we need to label them in some way, in this case we'll be passing them through the vertex shader and labelling the vertex shader output with a new TGSI semantic (TGSI_SEMANTIC_EDGEFLAG).
This commit is contained in:

committed by
Roland Scheidegger

parent
59f6af51b8
commit
a08e348a84
@@ -366,13 +366,6 @@ void draw_set_render( struct draw_context *draw,
|
||||
draw->render = render;
|
||||
}
|
||||
|
||||
void draw_set_edgeflags( struct draw_context *draw,
|
||||
const unsigned *edgeflag )
|
||||
{
|
||||
draw->pt.user.edgeflag = edgeflag;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
|
@@ -143,9 +143,6 @@ void draw_set_mapped_constant_buffer(struct draw_context *draw,
|
||||
const void *buffer,
|
||||
unsigned size );
|
||||
|
||||
void draw_set_edgeflags( struct draw_context *draw,
|
||||
const unsigned *edgeflag );
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* draw_prim.c
|
||||
|
@@ -142,8 +142,6 @@ struct draw_context
|
||||
|
||||
/* user-space vertex data, buffers */
|
||||
struct {
|
||||
const unsigned *edgeflag;
|
||||
|
||||
/** vertex element/index buffer (ex: glDrawElements) */
|
||||
const void *elts;
|
||||
/** bytes per index (0, 1, 2 or 4) */
|
||||
|
@@ -318,8 +318,10 @@ draw_arrays(struct draw_context *draw, unsigned prim,
|
||||
boolean draw_pt_get_edgeflag( struct draw_context *draw,
|
||||
unsigned idx )
|
||||
{
|
||||
if (draw->pt.user.edgeflag)
|
||||
if (draw->pt.user.edgeflag) {
|
||||
float *ef = draw->pt.verted_buffer[idx]
|
||||
return (draw->pt.user.edgeflag[idx/32] & (1 << (idx%32))) != 0;
|
||||
}
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
@@ -149,11 +149,6 @@ struct draw_pt_middle_end *draw_pt_middle_fse( struct draw_context *draw );
|
||||
struct draw_pt_middle_end *draw_pt_fetch_pipeline_or_emit(struct draw_context *draw);
|
||||
|
||||
|
||||
/* More helpers:
|
||||
*/
|
||||
boolean draw_pt_get_edgeflag( struct draw_context *draw,
|
||||
unsigned idx );
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
* HW vertex emit:
|
||||
|
@@ -120,7 +120,12 @@ void draw_pt_fetch_prepare( struct pt_fetch *fetch,
|
||||
fetch->translate = translate_cache_find(fetch->cache, &key);
|
||||
|
||||
{
|
||||
static struct vertex_header vh = { 0, 1, 0, UNDEFINED_VERTEX_ID, { .0f, .0f, .0f, .0f } };
|
||||
static struct vertex_header vh = { 0,
|
||||
1,
|
||||
0,
|
||||
UNDEFINED_VERTEX_ID,
|
||||
{ .0f, .0f, .0f, .0f } };
|
||||
|
||||
fetch->translate->set_buffer(fetch->translate,
|
||||
draw->pt.nr_vertex_buffers,
|
||||
&vh,
|
||||
@@ -128,9 +133,6 @@ void draw_pt_fetch_prepare( struct pt_fetch *fetch,
|
||||
}
|
||||
}
|
||||
|
||||
fetch->need_edgeflags = ((draw->rasterizer->fill_cw != PIPE_POLYGON_MODE_FILL ||
|
||||
draw->rasterizer->fill_ccw != PIPE_POLYGON_MODE_FILL) &&
|
||||
draw->pt.user.edgeflag);
|
||||
}
|
||||
|
||||
|
||||
@@ -158,16 +160,10 @@ void draw_pt_fetch_run( struct pt_fetch *fetch,
|
||||
count,
|
||||
verts );
|
||||
|
||||
/* Edgeflags are hard to fit into a translate program, populate
|
||||
* them separately if required. In the setup above they are
|
||||
* defaulted to one, so only need this if there is reason to change
|
||||
* that default:
|
||||
/* Extract edgeflag values from vertex data into the header.
|
||||
*/
|
||||
if (fetch->need_edgeflags) {
|
||||
for (i = 0; i < count; i++) {
|
||||
struct vertex_header *vh = (struct vertex_header *)(verts + i * fetch->vertex_size);
|
||||
vh->edgeflag = draw_pt_get_edgeflag( draw, elts[i] );
|
||||
}
|
||||
extract_edge_flags( fetch, count );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,16 +190,12 @@ void draw_pt_fetch_run_linear( struct pt_fetch *fetch,
|
||||
count,
|
||||
verts );
|
||||
|
||||
/* Edgeflags are hard to fit into a translate program, populate
|
||||
* them separately if required. In the setup above they are
|
||||
* defaulted to one, so only need this if there is reason to change
|
||||
* that default:
|
||||
/* Extract edgeflag values from vertex data into the header. XXX:
|
||||
* this should be done after the vertex shader is run.
|
||||
* Bypass-vs-and-clip interaction with pipeline???
|
||||
*/
|
||||
if (fetch->need_edgeflags) {
|
||||
for (i = 0; i < count; i++) {
|
||||
struct vertex_header *vh = (struct vertex_header *)(verts + i * fetch->vertex_size);
|
||||
vh->edgeflag = draw_pt_get_edgeflag( draw, start + i );
|
||||
}
|
||||
extract_edge_flags( fetch, count );
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -86,7 +86,8 @@ static void fetch_pipeline_prepare( struct draw_pt_middle_end *middle,
|
||||
(boolean)draw->bypass_clipping,
|
||||
(boolean)(draw->identity_viewport ||
|
||||
draw->rasterizer->bypass_vs_clip_and_viewport),
|
||||
(boolean)draw->rasterizer->gl_rasterization_rules );
|
||||
(boolean)draw->rasterizer->gl_rasterization_rules,
|
||||
need_edgeflags );
|
||||
|
||||
|
||||
if (!(opt & PT_PIPELINE)) {
|
||||
|
@@ -147,6 +147,34 @@ static boolean post_vs_cliptest_viewport_gl( struct pt_post_vs *pvs,
|
||||
|
||||
|
||||
|
||||
/* As above plus edgeflags
|
||||
*/
|
||||
static boolean
|
||||
post_vs_cliptest_viewport_gl_edgeflag(struct pt_post_vs *pvs,
|
||||
struct vertex_header *vertices,
|
||||
unsigned count,
|
||||
unsigned stride )
|
||||
{
|
||||
if (!post_vs_cliptest_viewport_gl( pvs, vertices, count, stride))
|
||||
return FALSE;
|
||||
|
||||
/* If present, copy edgeflag VS output into vertex header.
|
||||
* Otherwise, leave header as is.
|
||||
*/
|
||||
if (pvs->draw->vs.edgeflag_output) {
|
||||
struct vertex_header *out = vertices;
|
||||
int ef = pvs->draw->vs.edgeflag_output;
|
||||
|
||||
for (j = 0; j < count; j++) {
|
||||
const float *edgeflag = out->data[ef];
|
||||
out->edgeflag = (edgeflag[0] != 1.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* If bypass_clipping is set, skip cliptest and rhw divide.
|
||||
*/
|
||||
static boolean post_vs_viewport( struct pt_post_vs *pvs,
|
||||
@@ -203,15 +231,26 @@ void draw_pt_post_vs_prepare( struct pt_post_vs *pvs,
|
||||
boolean bypass_viewport,
|
||||
boolean opengl )
|
||||
{
|
||||
if (bypass_clipping) {
|
||||
if (bypass_viewport)
|
||||
pvs->run = post_vs_none;
|
||||
else
|
||||
pvs->run = post_vs_viewport;
|
||||
if (!need_edgeflags) {
|
||||
if (bypass_clipping) {
|
||||
if (bypass_viewport)
|
||||
pvs->run = post_vs_none;
|
||||
else
|
||||
pvs->run = post_vs_viewport;
|
||||
}
|
||||
else {
|
||||
/* if (opengl) */
|
||||
pvs->run = post_vs_cliptest_viewport_gl;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* if (opengl) */
|
||||
pvs->run = post_vs_cliptest_viewport_gl;
|
||||
/* If we need to copy edgeflags to the vertex header, it should
|
||||
* mean we're running the primitive pipeline. Hence the bypass
|
||||
* flags should be false.
|
||||
*/
|
||||
assert(!bypass_clipping);
|
||||
assert(!bypass_viewport);
|
||||
pvs->run = post_vs_cliptest_viewport_gl_edgeflag;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -57,14 +57,6 @@ struct pipe_context {
|
||||
|
||||
void (*destroy)( struct pipe_context * );
|
||||
|
||||
|
||||
/* Possible interface for setting edgeflags. These aren't really
|
||||
* vertex elements, so don't fit there.
|
||||
*/
|
||||
void (*set_edgeflags)( struct pipe_context *,
|
||||
const unsigned *bitfield );
|
||||
|
||||
|
||||
/**
|
||||
* VBO drawing (return false on fallbacks (temporary??))
|
||||
*/
|
||||
|
@@ -127,7 +127,8 @@ struct tgsi_declaration_range
|
||||
#define TGSI_SEMANTIC_GENERIC 5
|
||||
#define TGSI_SEMANTIC_NORMAL 6
|
||||
#define TGSI_SEMANTIC_FACE 7
|
||||
#define TGSI_SEMANTIC_COUNT 8 /**< number of semantic values */
|
||||
#define TGSI_SEMANTIC_EDGEFLAG 8
|
||||
#define TGSI_SEMANTIC_COUNT 9 /**< number of semantic values */
|
||||
|
||||
struct tgsi_declaration_semantic
|
||||
{
|
||||
|
@@ -106,7 +106,16 @@ find_translated_vp(struct st_context *st,
|
||||
/* Nothing in our key yet. This will change:
|
||||
*/
|
||||
memset(&key, 0, sizeof key);
|
||||
key.dummy = 0;
|
||||
|
||||
/* When this is true, we will add an extra input to the vertex
|
||||
* shader translation (for edgeflags), an extra output with
|
||||
* edgeflag semantics, and extend the vertex shader to pass through
|
||||
* the input to the output. We'll need to use similar logic to set
|
||||
* up the extra vertex_element input for edgeflags.
|
||||
*/
|
||||
key.passthrough_edgeflags = (ctx->Polygon.FrontMode != GL_FILL ||
|
||||
ctx->Polygon.BackMode != GL_FILL);
|
||||
|
||||
|
||||
/* Do we need to throw away old translations after a change in the
|
||||
* GL program string?
|
||||
|
@@ -217,59 +217,7 @@ st_pipe_vertex_format(GLenum type, GLuint size, GLenum format,
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* If edge flags are needed, setup an bitvector of flags and call
|
||||
* pipe->set_edgeflags().
|
||||
* XXX memleak: need to free the returned pointer at some point
|
||||
*/
|
||||
static void *
|
||||
setup_edgeflags(GLcontext *ctx, GLenum primMode, GLint start, GLint count,
|
||||
const struct gl_client_array *array)
|
||||
{
|
||||
struct pipe_context *pipe = ctx->st->pipe;
|
||||
|
||||
if ((primMode == GL_TRIANGLES ||
|
||||
primMode == GL_QUADS ||
|
||||
primMode == GL_POLYGON) &&
|
||||
(ctx->Polygon.FrontMode != GL_FILL ||
|
||||
ctx->Polygon.BackMode != GL_FILL)) {
|
||||
/* need edge flags */
|
||||
GLint i;
|
||||
unsigned *vec;
|
||||
struct st_buffer_object *stobj = st_buffer_object(array->BufferObj);
|
||||
ubyte *map;
|
||||
|
||||
if (!stobj || stobj->Base.Name == 0) {
|
||||
/* edge flags are not in a VBO */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vec = (unsigned *) _mesa_calloc(sizeof(unsigned) * ((count + 31) / 32));
|
||||
if (!vec)
|
||||
return NULL;
|
||||
|
||||
map = pipe_buffer_map(pipe->screen, stobj->buffer, PIPE_BUFFER_USAGE_CPU_READ);
|
||||
map = ADD_POINTERS(map, array->Ptr);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (*((float *) map))
|
||||
vec[i/32] |= 1 << (i % 32);
|
||||
|
||||
map += array->StrideB;
|
||||
}
|
||||
|
||||
pipe_buffer_unmap(pipe->screen, stobj->buffer);
|
||||
|
||||
pipe->set_edgeflags(pipe, vec);
|
||||
|
||||
return vec;
|
||||
}
|
||||
else {
|
||||
/* edge flags not needed */
|
||||
pipe->set_edgeflags(pipe, NULL);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -671,10 +619,6 @@ st_draw_vbo(GLcontext *ctx,
|
||||
* through to driver & draw module. These interfaces still
|
||||
* need a bit of work...
|
||||
*/
|
||||
setup_edgeflags(ctx, prims[i].mode,
|
||||
prims[i].start + indexOffset, prims[i].count,
|
||||
arrays[VERT_ATTRIB_EDGEFLAG]);
|
||||
|
||||
pipe->draw_range_elements(pipe, indexBuf, indexSize,
|
||||
min_index,
|
||||
max_index,
|
||||
@@ -683,10 +627,6 @@ st_draw_vbo(GLcontext *ctx,
|
||||
}
|
||||
else {
|
||||
for (i = 0; i < nr_prims; i++) {
|
||||
setup_edgeflags(ctx, prims[i].mode,
|
||||
prims[i].start + indexOffset, prims[i].count,
|
||||
arrays[VERT_ATTRIB_EDGEFLAG]);
|
||||
|
||||
pipe->draw_elements(pipe, indexBuf, indexSize,
|
||||
prims[i].mode,
|
||||
prims[i].start + indexOffset, prims[i].count);
|
||||
@@ -699,10 +639,6 @@ st_draw_vbo(GLcontext *ctx,
|
||||
/* non-indexed */
|
||||
GLuint i;
|
||||
for (i = 0; i < nr_prims; i++) {
|
||||
setup_edgeflags(ctx, prims[i].mode,
|
||||
prims[i].start, prims[i].count,
|
||||
arrays[VERT_ATTRIB_EDGEFLAG]);
|
||||
|
||||
pipe->draw_arrays(pipe, prims[i].mode, prims[i].start, prims[i].count);
|
||||
}
|
||||
}
|
||||
|
@@ -741,6 +741,7 @@ emit_face_var( struct st_translate *t,
|
||||
const struct tgsi_token *
|
||||
st_translate_mesa_program(
|
||||
GLcontext *ctx,
|
||||
struct ureg_program *ureg;
|
||||
uint procType,
|
||||
const struct gl_program *program,
|
||||
GLuint numInputs,
|
||||
@@ -754,7 +755,6 @@ st_translate_mesa_program(
|
||||
const ubyte outputSemanticIndex[] )
|
||||
{
|
||||
struct st_translate translate, *t;
|
||||
struct ureg_program *ureg;
|
||||
const struct tgsi_token *tokens = NULL;
|
||||
unsigned i;
|
||||
|
||||
@@ -764,11 +764,7 @@ st_translate_mesa_program(
|
||||
t->procType = procType;
|
||||
t->inputMapping = inputMapping;
|
||||
t->outputMapping = outputMapping;
|
||||
t->ureg = ureg_create( procType );
|
||||
if (t->ureg == NULL)
|
||||
return NULL;
|
||||
|
||||
ureg = t->ureg;
|
||||
t->ureg = ureg;
|
||||
|
||||
/*_mesa_print_program(program);*/
|
||||
|
||||
@@ -899,8 +895,7 @@ st_translate_mesa_program(
|
||||
t->insn[t->labels[i].branch_target] );
|
||||
}
|
||||
|
||||
tokens = ureg_get_tokens( ureg, NULL );
|
||||
ureg_destroy( ureg );
|
||||
return PIPE_OK;
|
||||
|
||||
out:
|
||||
FREE(t->insn);
|
||||
@@ -919,7 +914,7 @@ out:
|
||||
debug_assert(0);
|
||||
}
|
||||
|
||||
return tokens;
|
||||
return PIPE_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
|
||||
|
@@ -192,10 +192,16 @@ st_translate_vertex_program(struct st_context *st,
|
||||
{
|
||||
struct st_vp_varient *vpv = CALLOC_STRUCT(st_vp_varient);
|
||||
struct pipe_context *pipe = st->pipe;
|
||||
struct ureg_program *ureg;
|
||||
|
||||
vpv->state.tokens =
|
||||
ureg = ureg_create( TGSI_PROCESSOR_VERTEX );
|
||||
if (ureg == NULL)
|
||||
return NULL;
|
||||
|
||||
error =
|
||||
st_translate_mesa_program(st->ctx,
|
||||
TGSI_PROCESSOR_VERTEX,
|
||||
ureg,
|
||||
&stvp->Base.Base,
|
||||
/* inputs */
|
||||
stvp->num_inputs,
|
||||
@@ -209,6 +215,20 @@ st_translate_vertex_program(struct st_context *st,
|
||||
stvp->output_semantic_name,
|
||||
stvp->output_semantic_index );
|
||||
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
/* Edgeflags will be the last input:
|
||||
*/
|
||||
if (key.passthrough_edgeflags) {
|
||||
ureg_MOV( ureg,
|
||||
ureg_DECL_output( ureg, TGSI_SEMANTIC_EDGEFLAG, 0 ),
|
||||
ureg_DECL_next_vs_input(ureg));
|
||||
}
|
||||
|
||||
tokens = ureg_get_tokens( ureg, NULL );
|
||||
ureg_destroy( ureg );
|
||||
|
||||
vpv->driver_shader = pipe->create_vs_state(pipe, &vpv->state);
|
||||
|
||||
if ((ST_DEBUG & DEBUG_TGSI) && (ST_DEBUG & DEBUG_MESA)) {
|
||||
@@ -222,6 +242,10 @@ st_translate_vertex_program(struct st_context *st,
|
||||
}
|
||||
|
||||
return vpv;
|
||||
|
||||
fail:
|
||||
ureg_destroy( ureg );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -243,6 +267,7 @@ st_translate_fragment_program(struct st_context *st,
|
||||
GLuint interpMode[16]; /* XXX size? */
|
||||
GLuint attr;
|
||||
const GLbitfield inputsRead = stfp->Base.Base.InputsRead;
|
||||
struct ureg_program *ureg;
|
||||
GLuint vslot = 0;
|
||||
|
||||
uint fs_num_inputs = 0;
|
||||
@@ -377,6 +402,11 @@ st_translate_fragment_program(struct st_context *st,
|
||||
if (!inputMapping)
|
||||
inputMapping = defaultInputMapping;
|
||||
|
||||
ureg = ureg_create( TGSI_PROCESSOR_FRAGMENT );
|
||||
if (ureg == NULL)
|
||||
return NULL;
|
||||
|
||||
|
||||
stfp->state.tokens =
|
||||
st_translate_mesa_program(st->ctx,
|
||||
TGSI_PROCESSOR_FRAGMENT,
|
||||
|
@@ -73,7 +73,7 @@ struct st_fragment_program
|
||||
|
||||
struct st_vp_varient_key
|
||||
{
|
||||
char dummy; /* currently unused */
|
||||
boolean passthrough_edgeflags;
|
||||
};
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user