diff options
Diffstat (limited to 'mesalib/src/mesa/state_tracker')
-rw-r--r-- | mesalib/src/mesa/state_tracker/st_context.h | 1 | ||||
-rw-r--r-- | mesalib/src/mesa/state_tracker/st_draw.c | 245 | ||||
-rw-r--r-- | mesalib/src/mesa/state_tracker/st_extensions.c | 5 | ||||
-rw-r--r-- | mesalib/src/mesa/state_tracker/st_glsl_to_tgsi.cpp | 138 |
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; |