aboutsummaryrefslogtreecommitdiff
path: root/mesalib/src/mesa/state_tracker
diff options
context:
space:
mode:
Diffstat (limited to 'mesalib/src/mesa/state_tracker')
-rw-r--r--mesalib/src/mesa/state_tracker/st_context.h1
-rw-r--r--mesalib/src/mesa/state_tracker/st_draw.c245
-rw-r--r--mesalib/src/mesa/state_tracker/st_extensions.c5
-rw-r--r--mesalib/src/mesa/state_tracker/st_glsl_to_tgsi.cpp138
4 files changed, 303 insertions, 86 deletions
diff --git a/mesalib/src/mesa/state_tracker/st_context.h b/mesalib/src/mesa/state_tracker/st_context.h
index 0a3220221..c60780989 100644
--- a/mesalib/src/mesa/state_tracker/st_context.h
+++ b/mesalib/src/mesa/state_tracker/st_context.h
@@ -75,6 +75,7 @@ struct st_context
struct draw_stage *feedback_stage; /**< For GL_FEEDBACK rendermode */
struct draw_stage *selection_stage; /**< For GL_SELECT rendermode */
struct draw_stage *rastpos_stage; /**< For glRasterPos */
+ GLboolean sw_primitive_restart;
/* On old libGL's for linux we need to invalidate the drawables
diff --git a/mesalib/src/mesa/state_tracker/st_draw.c b/mesalib/src/mesa/state_tracker/st_draw.c
index 574802084..ff3008a5f 100644
--- a/mesalib/src/mesa/state_tracker/st_draw.c
+++ b/mesalib/src/mesa/state_tracker/st_draw.c
@@ -353,9 +353,26 @@ setup_interleaved_attribs(struct gl_context *ctx,
struct pipe_context *pipe = st->pipe;
GLuint attr;
const GLubyte *low_addr = NULL;
-
- /* Find the lowest address of the arrays we're drawing */
+ GLboolean usingVBO; /* all arrays in a VBO? */
+ struct gl_buffer_object *bufobj;
+ GLuint user_buffer_size = 0;
+ GLuint vertex_size = 0; /* bytes per vertex, in bytes */
+ GLsizei stride;
+
+ /* Find the lowest address of the arrays we're drawing,
+ * Init bufobj and stride.
+ */
if (vpv->num_inputs) {
+ const GLuint mesaAttr0 = vp->index_to_input[0];
+ const struct gl_client_array *array = arrays[mesaAttr0];
+
+ /* Since we're doing interleaved arrays, we know there'll be at most
+ * one buffer object and the stride will be the same for all arrays.
+ * Grab them now.
+ */
+ bufobj = array->BufferObj;
+ stride = array->StrideB;
+
low_addr = arrays[vp->index_to_input[0]]->Ptr;
for (attr = 1; attr < vpv->num_inputs; attr++) {
@@ -363,44 +380,24 @@ setup_interleaved_attribs(struct gl_context *ctx,
low_addr = MIN2(low_addr, start);
}
}
+ else {
+ /* not sure we'll ever have zero inputs, but play it safe */
+ bufobj = NULL;
+ stride = 0;
+ low_addr = 0;
+ }
+
+ /* are the arrays in user space? */
+ usingVBO = bufobj && _mesa_is_bufferobj(bufobj);
for (attr = 0; attr < vpv->num_inputs; attr++) {
const GLuint mesaAttr = vp->index_to_input[attr];
const struct gl_client_array *array = arrays[mesaAttr];
- struct gl_buffer_object *bufobj = array->BufferObj;
- struct st_buffer_object *stobj = st_buffer_object(bufobj);
unsigned src_offset = (unsigned) (array->Ptr - low_addr);
GLuint element_size = array->_ElementSize;
- GLsizei stride = array->StrideB;
assert(element_size == array->Size * _mesa_sizeof_type(array->Type));
- if (attr == 0) {
- if (bufobj && _mesa_is_bufferobj(bufobj)) {
- vbuffer->buffer = NULL;
- pipe_resource_reference(&vbuffer->buffer, stobj->buffer);
- vbuffer->buffer_offset = pointer_to_offset(low_addr);
- }
- else {
- uint divisor = array->InstanceDivisor;
- uint last_index = divisor ? num_instances / divisor : max_index;
- uint bytes = src_offset + stride * last_index + element_size;
-
- vbuffer->buffer = pipe_user_buffer_create(pipe->screen,
- (void*) low_addr,
- bytes,
- PIPE_BIND_VERTEX_BUFFER);
- vbuffer->buffer_offset = 0;
-
- /* Track user vertex buffers. */
- pipe_resource_reference(&st->user_attrib[0].buffer, vbuffer->buffer);
- st->user_attrib[0].element_size = element_size;
- st->user_attrib[0].stride = stride;
- st->num_user_attribs = 1;
- }
- vbuffer->stride = stride; /* in bytes */
- }
-
velements[attr].src_offset = src_offset;
velements[attr].instance_divisor = array->InstanceDivisor;
velements[attr].vertex_buffer_index = 0;
@@ -409,6 +406,54 @@ setup_interleaved_attribs(struct gl_context *ctx,
array->Format,
array->Normalized);
assert(velements[attr].src_format);
+
+ if (!usingVBO) {
+ /* how many bytes referenced by this attribute array? */
+ uint divisor = array->InstanceDivisor;
+ uint last_index = divisor ? num_instances / divisor : max_index;
+ uint bytes = src_offset + stride * last_index + element_size;
+
+ user_buffer_size = MAX2(user_buffer_size, bytes);
+
+ /* update vertex size */
+ vertex_size = MAX2(vertex_size, src_offset + element_size);
+ }
+ }
+
+ /*
+ * Return the vbuffer info and setup user-space attrib info, if needed.
+ */
+ if (vpv->num_inputs == 0) {
+ /* just defensive coding here */
+ vbuffer->buffer = NULL;
+ vbuffer->buffer_offset = 0;
+ vbuffer->stride = 0;
+ st->num_user_attribs = 0;
+ }
+ else if (usingVBO) {
+ /* all interleaved arrays in a VBO */
+ struct st_buffer_object *stobj = st_buffer_object(bufobj);
+
+ vbuffer->buffer = NULL;
+ pipe_resource_reference(&vbuffer->buffer, stobj->buffer);
+ vbuffer->buffer_offset = pointer_to_offset(low_addr);
+ vbuffer->stride = stride;
+ st->num_user_attribs = 0;
+ }
+ else {
+ /* all interleaved arrays in user memory */
+ vbuffer->buffer = pipe_user_buffer_create(pipe->screen,
+ (void*) low_addr,
+ user_buffer_size,
+ PIPE_BIND_VERTEX_BUFFER);
+ vbuffer->buffer_offset = 0;
+ vbuffer->stride = stride;
+
+ /* Track user vertex buffers. */
+ pipe_resource_reference(&st->user_attrib[0].buffer, vbuffer->buffer);
+ st->user_attrib[0].element_size = vertex_size;
+ st->user_attrib[0].stride = stride;
+ st->num_user_attribs = 1;
}
}
@@ -582,6 +627,127 @@ check_uniforms(struct gl_context *ctx)
}
}
+/** Helper code for primitive restart fallback */
+#define DO_DRAW(pipe, cur_start, cur_count) \
+ do { \
+ info.start = cur_start; \
+ info.count = cur_count; \
+ if (u_trim_pipe_prim(info.mode, &info.count)) { \
+ if (transfer) \
+ pipe_buffer_unmap(pipe, transfer); \
+ pipe->draw_vbo(pipe, &info); \
+ if (transfer) { \
+ ptr = pipe_buffer_map(pipe, ibuffer->buffer, PIPE_TRANSFER_READ, &transfer); \
+ assert(ptr != NULL); \
+ ptr = ADD_POINTERS(ptr, ibuffer->offset); \
+ } \
+ } \
+ } while(0)
+
+/** More helper code for primitive restart fallback */
+#define PRIM_RESTART_LOOP(elements) \
+ do { \
+ for (i = start; i < end; i++) { \
+ if (elements[i] == info.restart_index) { \
+ if (cur_count > 0) { \
+ /* draw elts up to prev pos */ \
+ DO_DRAW(pipe, cur_start, cur_count); \
+ } \
+ /* begin new prim at next elt */ \
+ cur_start = i + 1; \
+ cur_count = 0; \
+ } \
+ else { \
+ cur_count++; \
+ } \
+ } \
+ if (cur_count > 0) { \
+ DO_DRAW(pipe, cur_start, cur_count); \
+ } \
+ } while (0)
+
+static void
+handle_fallback_primitive_restart(struct pipe_context *pipe,
+ const struct _mesa_index_buffer *ib,
+ struct pipe_index_buffer *ibuffer,
+ struct pipe_draw_info *orig_info)
+{
+ const unsigned start = orig_info->start;
+ const unsigned count = orig_info->count;
+ const unsigned end = start + count;
+ struct pipe_draw_info info = *orig_info;
+ struct pipe_transfer *transfer = NULL;
+ unsigned instance, i, cur_start, cur_count;
+ const void *ptr;
+
+ info.primitive_restart = FALSE;
+
+ if (!info.indexed) {
+ /* Splitting the draw arrays call is handled by the VBO module */
+ if (u_trim_pipe_prim(info.mode, &info.count))
+ pipe->draw_vbo(pipe, &info);
+
+ return;
+ }
+
+ /* info.indexed == TRUE */
+ assert(ibuffer);
+ assert(ibuffer->buffer);
+
+ if (ib) {
+ struct gl_buffer_object *bufobj = ib->obj;
+ if (bufobj && bufobj->Name) {
+ ptr = NULL;
+ }
+ else {
+ ptr = ib->ptr;
+ }
+ } else {
+ ptr = NULL;
+ }
+
+ if (!ptr)
+ ptr = pipe_buffer_map(pipe, ibuffer->buffer, PIPE_TRANSFER_READ, &transfer);
+
+ if (!ptr)
+ return;
+ ptr = ADD_POINTERS(ptr, ibuffer->offset);
+
+ /* Need to loop over instances as well to preserve draw order */
+ for (instance = 0; instance < orig_info->instance_count; instance++) {
+ info.start_instance = instance + orig_info->start_instance;
+ info.instance_count = 1;
+ cur_start = start;
+ cur_count = 0;
+
+ switch (ibuffer->index_size) {
+ case 1:
+ {
+ const ubyte *elt_ub = (const ubyte *)ptr;
+ PRIM_RESTART_LOOP(elt_ub);
+ }
+ break;
+ case 2:
+ {
+ const ushort *elt_us = (const ushort *)ptr;
+ PRIM_RESTART_LOOP(elt_us);
+ }
+ break;
+ case 4:
+ {
+ const uint *elt_ui = (const uint *)ptr;
+ PRIM_RESTART_LOOP(elt_ui);
+ }
+ break;
+ default:
+ assert(0 && "bad index_size in handle_fallback_primitive_restart()");
+ }
+ }
+
+ if (transfer)
+ pipe_buffer_unmap(pipe, transfer);
+}
+
/**
* Translate OpenGL primtive type (GL_POINTS, GL_TRIANGLE_STRIP, etc) to
@@ -794,7 +960,22 @@ st_draw_vbo(struct gl_context *ctx,
info.max_index = info.start + info.count - 1;
}
- if (u_trim_pipe_prim(info.mode, &info.count))
+ if (info.primitive_restart) {
+ /*
+ * Handle primitive restart for drivers that doesn't support it.
+ *
+ * The VBO module handles restart inside of draw_arrays for us,
+ * but we should still remove the primitive_restart flag on the
+ * info struct, the fallback function does this for us. Just
+ * remove the flag for all drivers in this case as well.
+ */
+ if (st->sw_primitive_restart || !info.indexed)
+ handle_fallback_primitive_restart(pipe, ib, &ibuffer, &info);
+ else
+ /* don't trim, restarts might be inside index list */
+ pipe->draw_vbo(pipe, &info);
+ }
+ else if (u_trim_pipe_prim(info.mode, &info.count))
pipe->draw_vbo(pipe, &info);
}
diff --git a/mesalib/src/mesa/state_tracker/st_extensions.c b/mesalib/src/mesa/state_tracker/st_extensions.c
index a1f029089..37f36de93 100644
--- a/mesalib/src/mesa/state_tracker/st_extensions.c
+++ b/mesalib/src/mesa/state_tracker/st_extensions.c
@@ -555,8 +555,9 @@ void st_init_extensions(struct st_context *st)
#endif
}
- if (screen->get_param(screen, PIPE_CAP_PRIMITIVE_RESTART)) {
- ctx->Extensions.NV_primitive_restart = GL_TRUE;
+ ctx->Extensions.NV_primitive_restart = GL_TRUE;
+ if (!screen->get_param(screen, PIPE_CAP_PRIMITIVE_RESTART)) {
+ st->sw_primitive_restart = GL_TRUE;
}
if (screen->get_param(screen, PIPE_CAP_DEPTH_CLAMP)) {
diff --git a/mesalib/src/mesa/state_tracker/st_glsl_to_tgsi.cpp b/mesalib/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
index 18e8a1db4..145bd7dcd 100644
--- a/mesalib/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
+++ b/mesalib/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
@@ -4322,37 +4322,15 @@ compile_tgsi_instruction(struct st_translate *t,
}
/**
- * Emit the TGSI instructions to adjust the WPOS pixel center convention
- * Basically, add (adjX, adjY) to the fragment position.
- */
-static void
-emit_adjusted_wpos(struct st_translate *t,
- const struct gl_program *program,
- float adjX, float adjY)
-{
- struct ureg_program *ureg = t->ureg;
- struct ureg_dst wpos_temp = ureg_DECL_temporary(ureg);
- struct ureg_src wpos_input = t->inputs[t->inputMapping[FRAG_ATTRIB_WPOS]];
-
- /* Note that we bias X and Y and pass Z and W through unchanged.
- * The shader might also use gl_FragCoord.w and .z.
- */
- ureg_ADD(ureg, wpos_temp, wpos_input,
- ureg_imm4f(ureg, adjX, adjY, 0.0f, 0.0f));
-
- t->inputs[t->inputMapping[FRAG_ATTRIB_WPOS]] = ureg_src(wpos_temp);
-}
-
-
-/**
- * Emit the TGSI instructions for inverting the WPOS y coordinate.
+ * Emit the TGSI instructions for inverting and adjusting WPOS.
* This code is unavoidable because it also depends on whether
* a FBO is bound (STATE_FB_WPOS_Y_TRANSFORM).
*/
static void
-emit_wpos_inversion(struct st_translate *t,
- const struct gl_program *program,
- bool invert)
+emit_wpos_adjustment( struct st_translate *t,
+ const struct gl_program *program,
+ boolean invert,
+ GLfloat adjX, GLfloat adjY[2])
{
struct ureg_program *ureg = t->ureg;
@@ -4371,35 +4349,55 @@ emit_wpos_inversion(struct st_translate *t,
unsigned wposTransConst = _mesa_add_state_reference(program->Parameters,
wposTransformState);
- struct ureg_src wpostrans = ureg_DECL_constant(ureg, wposTransConst);
- struct ureg_dst wpos_temp;
+ struct ureg_src wpostrans = ureg_DECL_constant( ureg, wposTransConst );
+ struct ureg_dst wpos_temp = ureg_DECL_temporary( ureg );
struct ureg_src wpos_input = t->inputs[t->inputMapping[FRAG_ATTRIB_WPOS]];
- /* MOV wpos_temp, input[wpos]
- */
- if (wpos_input.File == TGSI_FILE_TEMPORARY)
- wpos_temp = ureg_dst(wpos_input);
- else {
- wpos_temp = ureg_DECL_temporary(ureg);
- ureg_MOV(ureg, wpos_temp, wpos_input);
+ /* First, apply the coordinate shift: */
+ if (adjX || adjY[0] || adjY[1]) {
+ if (adjY[0] != adjY[1]) {
+ /* Adjust the y coordinate by adjY[1] or adjY[0] respectively
+ * depending on whether inversion is actually going to be applied
+ * or not, which is determined by testing against the inversion
+ * state variable used below, which will be either +1 or -1.
+ */
+ struct ureg_dst adj_temp = ureg_DECL_temporary(ureg);
+
+ ureg_CMP(ureg, adj_temp,
+ ureg_scalar(wpostrans, invert ? 2 : 0),
+ ureg_imm4f(ureg, adjX, adjY[0], 0.0f, 0.0f),
+ ureg_imm4f(ureg, adjX, adjY[1], 0.0f, 0.0f));
+ ureg_ADD(ureg, wpos_temp, wpos_input, ureg_src(adj_temp));
+ } else {
+ ureg_ADD(ureg, wpos_temp, wpos_input,
+ ureg_imm4f(ureg, adjX, adjY[0], 0.0f, 0.0f));
+ }
+ wpos_input = ureg_src(wpos_temp);
+ } else {
+ /* MOV wpos_temp, input[wpos]
+ */
+ ureg_MOV( ureg, wpos_temp, wpos_input );
}
+ /* Now the conditional y flip: STATE_FB_WPOS_Y_TRANSFORM.xy/zw will be
+ * inversion/identity, or the other way around if we're drawing to an FBO.
+ */
if (invert) {
/* MAD wpos_temp.y, wpos_input, wpostrans.xxxx, wpostrans.yyyy
*/
- ureg_MAD(ureg,
- ureg_writemask(wpos_temp, TGSI_WRITEMASK_Y),
- wpos_input,
- ureg_scalar(wpostrans, 0),
- ureg_scalar(wpostrans, 1));
+ ureg_MAD( ureg,
+ ureg_writemask(wpos_temp, TGSI_WRITEMASK_Y ),
+ wpos_input,
+ ureg_scalar(wpostrans, 0),
+ ureg_scalar(wpostrans, 1));
} else {
/* MAD wpos_temp.y, wpos_input, wpostrans.zzzz, wpostrans.wwww
*/
- ureg_MAD(ureg,
- ureg_writemask(wpos_temp, TGSI_WRITEMASK_Y),
- wpos_input,
- ureg_scalar(wpostrans, 2),
- ureg_scalar(wpostrans, 3));
+ ureg_MAD( ureg,
+ ureg_writemask(wpos_temp, TGSI_WRITEMASK_Y ),
+ wpos_input,
+ ureg_scalar(wpostrans, 2),
+ ureg_scalar(wpostrans, 3));
}
/* Use wpos_temp as position input from here on:
@@ -4420,8 +4418,37 @@ emit_wpos(struct st_context *st,
const struct gl_fragment_program *fp =
(const struct gl_fragment_program *) program;
struct pipe_screen *pscreen = st->pipe->screen;
+ GLfloat adjX = 0.0f;
+ GLfloat adjY[2] = { 0.0f, 0.0f };
boolean invert = FALSE;
+ /* Query the pixel center conventions supported by the pipe driver and set
+ * adjX, adjY to help out if it cannot handle the requested one internally.
+ *
+ * The bias of the y-coordinate depends on whether y-inversion takes place
+ * (adjY[1]) or not (adjY[0]), which is in turn dependent on whether we are
+ * drawing to an FBO (causes additional inversion), and whether the the pipe
+ * driver origin and the requested origin differ (the latter condition is
+ * stored in the 'invert' variable).
+ *
+ * For height = 100 (i = integer, h = half-integer, l = lower, u = upper):
+ *
+ * center shift only:
+ * i -> h: +0.5
+ * h -> i: -0.5
+ *
+ * inversion only:
+ * l,i -> u,i: ( 0.0 + 1.0) * -1 + 100 = 99
+ * l,h -> u,h: ( 0.5 + 0.0) * -1 + 100 = 99.5
+ * u,i -> l,i: (99.0 + 1.0) * -1 + 100 = 0
+ * u,h -> l,h: (99.5 + 0.0) * -1 + 100 = 0.5
+ *
+ * inversion and center shift:
+ * l,i -> u,h: ( 0.0 + 0.5) * -1 + 100 = 99.5
+ * l,h -> u,i: ( 0.5 + 0.5) * -1 + 100 = 99
+ * u,i -> l,h: (99.0 + 0.5) * -1 + 100 = 0.5
+ * u,h -> l,i: (99.5 + 0.5) * -1 + 100 = 0
+ */
if (fp->OriginUpperLeft) {
/* Fragment shader wants origin in upper-left */
if (pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_ORIGIN_UPPER_LEFT)) {
@@ -4449,12 +4476,17 @@ emit_wpos(struct st_context *st,
if (fp->PixelCenterInteger) {
/* Fragment shader wants pixel center integer */
- if (pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_INTEGER))
+ if (pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_INTEGER)) {
/* the driver supports pixel center integer */
+ adjY[1] = 1.0f;
ureg_property_fs_coord_pixel_center(ureg, TGSI_FS_COORD_PIXEL_CENTER_INTEGER);
- else if (pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_HALF_INTEGER))
+ }
+ else if (pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_HALF_INTEGER)) {
/* the driver supports pixel center half integer, need to bias X,Y */
- emit_adjusted_wpos(t, program, 0.5f, invert ? 0.5f : -0.5f);
+ adjX = -0.5f;
+ adjY[0] = -0.5f;
+ adjY[1] = 0.5f;
+ }
else
assert(0);
}
@@ -4465,8 +4497,8 @@ emit_wpos(struct st_context *st,
}
else if (pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_INTEGER)) {
/* the driver supports pixel center integer, need to bias X,Y */
+ adjX = adjY[0] = adjY[1] = 0.5f;
ureg_property_fs_coord_pixel_center(ureg, TGSI_FS_COORD_PIXEL_CENTER_INTEGER);
- emit_adjusted_wpos(t, program, 0.5f, invert ? -0.5f : 0.5f);
}
else
assert(0);
@@ -4474,7 +4506,7 @@ emit_wpos(struct st_context *st,
/* we invert after adjustment so that we avoid the MOV to temporary,
* and reuse the adjustment ADD instead */
- emit_wpos_inversion(t, program, invert);
+ emit_wpos_adjustment(t, program, invert, adjX, adjY);
}
/**
@@ -5026,7 +5058,9 @@ st_link_shader(struct gl_context *ctx, struct gl_shader_program *prog)
progress = do_lower_jumps(ir, true, true, options->EmitNoMainReturn, options->EmitNoCont, options->EmitNoLoops) || progress;
- progress = do_common_optimization(ir, true, options->MaxUnrollIterations) || progress;
+ progress = do_common_optimization(ir, true, true,
+ options->MaxUnrollIterations)
+ || progress;
progress = lower_quadop_vector(ir, false) || progress;