X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fstate_tracker%2Fst_cb_drawpixels.c;h=94b80f69f280f385b748f1c58b4823e6634c30ff;hb=69a07be3e527dbc2148a4e20c50e60266225f5f2;hp=75be79fd4b01ecade82b77f36baa42c8f31d2275;hpb=8cdfd1219a2d13d252a8691ee6dddb0d773bdc77;p=mesa.git diff --git a/src/mesa/state_tracker/st_cb_drawpixels.c b/src/mesa/state_tracker/st_cb_drawpixels.c index 75be79fd4b0..94b80f69f28 100644 --- a/src/mesa/state_tracker/st_cb_drawpixels.c +++ b/src/mesa/state_tracker/st_cb_drawpixels.c @@ -36,34 +36,34 @@ #include "main/macros.h" #include "main/texformat.h" #include "main/texstore.h" -#include "shader/program.h" -#include "shader/prog_print.h" +#include "program/program.h" +#include "program/prog_print.h" +#include "program/prog_instruction.h" -#include "st_debug.h" -#include "st_context.h" #include "st_atom.h" #include "st_atom_constbuf.h" -#include "st_program.h" #include "st_cb_drawpixels.h" #include "st_cb_readpixels.h" #include "st_cb_fbo.h" +#include "st_context.h" +#include "st_debug.h" #include "st_format.h" +#include "st_program.h" #include "st_texture.h" -#include "st_inlines.h" #include "pipe/p_context.h" #include "pipe/p_defines.h" -#include "util/u_inlines.h" #include "tgsi/tgsi_ureg.h" -#include "util/u_tile.h" #include "util/u_draw_quad.h" #include "util/u_format.h" +#include "util/u_inlines.h" #include "util/u_math.h" -#include "util/u_rect.h" -#include "shader/prog_instruction.h" +#include "util/u_tile.h" #include "cso_cache/cso_context.h" +#if FEATURE_drawpix + /** * Check if the given program is: * 0: MOVE result.color, fragment.color; @@ -96,7 +96,7 @@ is_passthrough_program(const struct gl_fragment_program *prog) * \return pointer to Gallium driver fragment shader */ static void * -combined_drawpix_fragment_program(GLcontext *ctx) +combined_drawpix_fragment_program(struct gl_context *ctx) { struct st_context *st = st_context(ctx); struct st_fragment_program *stfp; @@ -162,20 +162,27 @@ combined_drawpix_fragment_program(GLcontext *ctx) /** - * Create fragment shader that does a TEX() instruction to get a Z - * value, then writes to FRAG_RESULT_DEPTH. + * Create fragment shader that does a TEX() instruction to get a Z and/or + * stencil value value, then writes to FRAG_RESULT_DEPTH/FRAG_RESULT_STENCIL. + * Used for glDrawPixels(GL_DEPTH_COMPONENT / GL_STENCIL_INDEX). * Pass fragment color through as-is. * \return pointer to the Gallium driver fragment shader */ static void * -make_fragment_shader_z(struct st_context *st) +make_fragment_shader_z_stencil(struct st_context *st, GLboolean write_depth, + GLboolean write_stencil) { - GLcontext *ctx = st->ctx; + struct gl_context *ctx = st->ctx; struct gl_program *p; + struct st_fragment_program *stp; GLuint ic = 0; + const GLuint shaderIndex = write_depth * 2 + write_stencil; - if (st->drawpix.z_shader) { - return st->drawpix.z_shader->driver_shader; + assert(shaderIndex < Elements(st->drawpix.shaders)); + + if (st->drawpix.shaders[shaderIndex]) { + /* already have the proper shader */ + return st->drawpix.shaders[shaderIndex]->driver_shader; } /* @@ -185,7 +192,8 @@ make_fragment_shader_z(struct st_context *st) if (!p) return NULL; - p->NumInstructions = 3; + p->NumInstructions = write_depth ? 2 : 1; + p->NumInstructions += write_stencil ? 1 : 0; p->Instructions = _mesa_alloc_instructions(p->NumInstructions); if (!p->Instructions) { @@ -194,24 +202,31 @@ make_fragment_shader_z(struct st_context *st) } _mesa_init_instructions(p->Instructions, p->NumInstructions); - /* TEX result.depth, fragment.texcoord[0], texture[0], 2D; */ - p->Instructions[ic].Opcode = OPCODE_TEX; - p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT; - p->Instructions[ic].DstReg.Index = FRAG_RESULT_DEPTH; - p->Instructions[ic].DstReg.WriteMask = WRITEMASK_Z; - p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT; - p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_TEX0; - p->Instructions[ic].TexSrcUnit = 0; - p->Instructions[ic].TexSrcTarget = TEXTURE_2D_INDEX; - ic++; - - /* MOV result.color, fragment.color */ - p->Instructions[ic].Opcode = OPCODE_MOV; - p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT; - p->Instructions[ic].DstReg.Index = FRAG_RESULT_COLOR; - p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT; - p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_COL0; - ic++; + if (write_depth) { + /* TEX result.depth, fragment.texcoord[0], texture[0], 2D; */ + p->Instructions[ic].Opcode = OPCODE_TEX; + p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT; + p->Instructions[ic].DstReg.Index = FRAG_RESULT_DEPTH; + p->Instructions[ic].DstReg.WriteMask = WRITEMASK_Z; + p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT; + p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_TEX0; + p->Instructions[ic].TexSrcUnit = 0; + p->Instructions[ic].TexSrcTarget = TEXTURE_2D_INDEX; + ic++; + } + + if (write_stencil) { + /* TEX result.stencil, fragment.texcoord[0], texture[0], 2D; */ + p->Instructions[ic].Opcode = OPCODE_TEX; + p->Instructions[ic].DstReg.File = PROGRAM_OUTPUT; + p->Instructions[ic].DstReg.Index = FRAG_RESULT_STENCIL; + p->Instructions[ic].DstReg.WriteMask = WRITEMASK_Y; + p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT; + p->Instructions[ic].SrcReg[0].Index = FRAG_ATTRIB_TEX0; + p->Instructions[ic].TexSrcUnit = 1; + p->Instructions[ic].TexSrcTarget = TEXTURE_2D_INDEX; + ic++; + } /* END; */ p->Instructions[ic++].Opcode = OPCODE_END; @@ -219,13 +234,24 @@ make_fragment_shader_z(struct st_context *st) assert(ic == p->NumInstructions); p->InputsRead = FRAG_BIT_TEX0 | FRAG_BIT_COL0; - p->OutputsWritten = (1 << FRAG_RESULT_COLOR) | (1 << FRAG_RESULT_DEPTH); - p->SamplersUsed = 0x1; /* sampler 0 (bit 0) is used */ + p->OutputsWritten = 0; + if (write_depth) + p->OutputsWritten |= (1 << FRAG_RESULT_DEPTH); + if (write_stencil) + p->OutputsWritten |= (1 << FRAG_RESULT_STENCIL); + + p->SamplersUsed = 0x1; /* sampler 0 (bit 0) is used */ + if (write_stencil) + p->SamplersUsed |= 1 << 1; + + stp = st_fragment_program((struct gl_fragment_program *) p); - st->drawpix.z_shader = (struct st_fragment_program *) p; - st_translate_fragment_program(st, st->drawpix.z_shader); + /* save the new shader */ + st->drawpix.shaders[shaderIndex] = stp; - return st->drawpix.z_shader->driver_shader; + st_translate_fragment_program(st, stp); + + return stp->driver_shader; } @@ -239,8 +265,7 @@ make_passthrough_vertex_shader(struct st_context *st, GLboolean passColor) { if (!st->drawpix.vert_shaders[passColor]) { - struct ureg_program *ureg = - ureg_create( TGSI_PROCESSOR_VERTEX ); + struct ureg_program *ureg = ureg_create( TGSI_PROCESSOR_VERTEX ); if (ureg == NULL) return NULL; @@ -250,13 +275,13 @@ make_passthrough_vertex_shader(struct st_context *st, ureg_DECL_output( ureg, TGSI_SEMANTIC_POSITION, 0 ), ureg_DECL_vs_input( ureg, 0 )); - /* MOV result.texcoord0, vertex.texcoord0; */ + /* MOV result.texcoord0, vertex.attr[1]; */ ureg_MOV(ureg, ureg_DECL_output( ureg, TGSI_SEMANTIC_GENERIC, 0 ), ureg_DECL_vs_input( ureg, 1 )); if (passColor) { - /* MOV result.color0, vertex.color0; */ + /* MOV result.color0, vertex.attr[2]; */ ureg_MOV(ureg, ureg_DECL_output( ureg, TGSI_SEMANTIC_COLOR, 0 ), ureg_DECL_vs_input( ureg, 2 )); @@ -297,41 +322,14 @@ base_format(GLenum format) * If width, height are not POT and the driver only handles POT textures, * allocate the next larger size of texture that is POT. */ -static struct pipe_texture * +static struct pipe_resource * alloc_texture(struct st_context *st, GLsizei width, GLsizei height, enum pipe_format texFormat) { - struct pipe_context *pipe = st->pipe; - struct pipe_screen *screen = pipe->screen; - struct pipe_texture *pt; - int ptw, pth; - - ptw = width; - pth = height; - - /* Need to use POT texture? */ - if (!screen->get_param(screen, PIPE_CAP_NPOT_TEXTURES)) { - int l2pt, maxSize; + struct pipe_resource *pt; - l2pt = util_logbase2(width); - if (1 << l2pt != width) { - ptw = 1 << (l2pt + 1); - } - - l2pt = util_logbase2(height); - if (1 << l2pt != height) { - pth = 1 << (l2pt + 1); - } - - /* Check against maximum texture size */ - maxSize = 1 << (pipe->screen->get_param(pipe->screen, - PIPE_CAP_MAX_TEXTURE_2D_LEVELS) - 1); - assert(ptw <= maxSize); - assert(pth <= maxSize); - } - - pt = st_texture_create(st, PIPE_TEXTURE_2D, texFormat, 0, - ptw, pth, 1, PIPE_TEXTURE_USAGE_SAMPLER); + pt = st_texture_create(st, st->internal_target, texFormat, 0, + width, height, 1, PIPE_BIND_SAMPLER_VIEW); return pt; } @@ -341,23 +339,24 @@ alloc_texture(struct st_context *st, GLsizei width, GLsizei height, * Make texture containing an image for glDrawPixels image. * If 'pixels' is NULL, leave the texture image data undefined. */ -static struct pipe_texture * +static struct pipe_resource * make_texture(struct st_context *st, GLsizei width, GLsizei height, GLenum format, GLenum type, const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels) { - GLcontext *ctx = st->ctx; + struct gl_context *ctx = st->ctx; struct pipe_context *pipe = st->pipe; gl_format mformat; - struct pipe_texture *pt; + struct pipe_resource *pt; enum pipe_format pipeFormat; GLuint cpp; GLenum baseFormat; baseFormat = base_format(format); - mformat = st_ChooseTextureFormat(ctx, baseFormat, format, type); + mformat = st_ChooseTextureFormat_renderable(ctx, baseFormat, + format, type, GL_FALSE); assert(mformat); pipeFormat = st_mesa_format_to_pipe_format(mformat); @@ -385,12 +384,12 @@ make_texture(struct st_context *st, /* we'll do pixel transfer in a fragment shader */ ctx->_ImageTransferState = 0x0; - transfer = st_no_flush_get_tex_transfer(st, pt, 0, 0, 0, + transfer = pipe_get_transfer(st->pipe, pt, 0, 0, 0, PIPE_TRANSFER_WRITE, 0, 0, width, height); /* map texture transfer */ - dest = pipe->transfer_map(pipe, transfer); + dest = pipe_transfer_map(pipe, transfer); /* Put image into texture transfer. @@ -410,8 +409,8 @@ make_texture(struct st_context *st, unpack); /* unmap */ - pipe->transfer_unmap(pipe, transfer); - pipe->tex_transfer_destroy(pipe, transfer); + pipe_transfer_unmap(pipe, transfer); + pipe->transfer_destroy(pipe, transfer); assert(success); @@ -432,7 +431,7 @@ make_texture(struct st_context *st, * \param invertTex if true, flip texcoords vertically */ static void -draw_quad(GLcontext *ctx, GLfloat x0, GLfloat y0, GLfloat z, +draw_quad(struct gl_context *ctx, GLfloat x0, GLfloat y0, GLfloat z, GLfloat x1, GLfloat y1, const GLfloat *color, GLboolean invertTex, GLfloat maxXcoord, GLfloat maxYcoord) { @@ -452,7 +451,7 @@ draw_quad(GLcontext *ctx, GLfloat x0, GLfloat y0, GLfloat z, const GLfloat sLeft = 0.0f, sRight = maxXcoord; const GLfloat tTop = invertTex ? maxYcoord : 0.0f; const GLfloat tBot = invertTex ? 0.0f : maxYcoord; - GLuint tex, i; + GLuint i; /* upper-left */ verts[0][0][0] = clip_x0; /* v[0].attr[0].x */ @@ -470,32 +469,31 @@ draw_quad(GLcontext *ctx, GLfloat x0, GLfloat y0, GLfloat z, verts[3][0][0] = clip_x0; verts[3][0][1] = clip_y1; - tex = color ? 2 : 1; - verts[0][tex][0] = sLeft; /* v[0].attr[tex].s */ - verts[0][tex][1] = tTop; /* v[0].attr[tex].t */ - verts[1][tex][0] = sRight; - verts[1][tex][1] = tTop; - verts[2][tex][0] = sRight; - verts[2][tex][1] = tBot; - verts[3][tex][0] = sLeft; - verts[3][tex][1] = tBot; + verts[0][1][0] = sLeft; /* v[0].attr[1].S */ + verts[0][1][1] = tTop; /* v[0].attr[1].T */ + verts[1][1][0] = sRight; + verts[1][1][1] = tTop; + verts[2][1][0] = sRight; + verts[2][1][1] = tBot; + verts[3][1][0] = sLeft; + verts[3][1][1] = tBot; /* same for all verts: */ if (color) { for (i = 0; i < 4; i++) { - verts[i][0][2] = z; /*Z*/ - verts[i][0][3] = 1.0f; /*W*/ - verts[i][1][0] = color[0]; - verts[i][1][1] = color[1]; - verts[i][1][2] = color[2]; - verts[i][1][3] = color[3]; - verts[i][2][2] = 0.0f; /*R*/ - verts[i][2][3] = 1.0f; /*Q*/ + verts[i][0][2] = z; /* v[i].attr[0].z */ + verts[i][0][3] = 1.0f; /* v[i].attr[0].w */ + verts[i][2][0] = color[0]; /* v[i].attr[2].r */ + verts[i][2][1] = color[1]; /* v[i].attr[2].g */ + verts[i][2][2] = color[2]; /* v[i].attr[2].b */ + verts[i][2][3] = color[3]; /* v[i].attr[2].a */ + verts[i][1][2] = 0.0f; /* v[i].attr[1].R */ + verts[i][1][3] = 1.0f; /* v[i].attr[1].Q */ } } else { for (i = 0; i < 4; i++) { - verts[i][0][2] = z; /*Z*/ + verts[i][0][2] = z; /*Z*/ verts[i][0][3] = 1.0f; /*W*/ verts[i][1][2] = 0.0f; /*R*/ verts[i][1][3] = 1.0f; /*Q*/ @@ -504,47 +502,53 @@ draw_quad(GLcontext *ctx, GLfloat x0, GLfloat y0, GLfloat z, } { - struct pipe_buffer *buf; + struct pipe_resource *buf; /* allocate/load buffer object with vertex data */ - buf = pipe_buffer_create(pipe->screen, 32, PIPE_BUFFER_USAGE_VERTEX, + buf = pipe_buffer_create(pipe->screen, + PIPE_BIND_VERTEX_BUFFER, sizeof(verts)); - st_no_flush_pipe_buffer_write(st, buf, 0, sizeof(verts), verts); + pipe_buffer_write(st->pipe, buf, 0, sizeof(verts), verts); util_draw_vertex_buffer(pipe, buf, 0, PIPE_PRIM_QUADS, 4, /* verts */ 3); /* attribs/vert */ - pipe_buffer_reference(&buf, NULL); + pipe_resource_reference(&buf, NULL); } } static void -draw_textured_quad(GLcontext *ctx, GLint x, GLint y, GLfloat z, +draw_textured_quad(struct gl_context *ctx, GLint x, GLint y, GLfloat z, GLsizei width, GLsizei height, GLfloat zoomX, GLfloat zoomY, - struct pipe_sampler_view *sv, + struct pipe_sampler_view **sv, + int num_sampler_view, void *driver_vp, void *driver_fp, const GLfloat *color, - GLboolean invertTex) + GLboolean invertTex, + GLboolean write_depth, GLboolean write_stencil) { struct st_context *st = st_context(ctx); struct pipe_context *pipe = st->pipe; struct cso_context *cso = st->cso_context; GLfloat x0, y0, x1, y1; GLsizei maxSize; + boolean normalized = sv[0]->texture->target != PIPE_TEXTURE_RECT; /* limit checks */ /* XXX if DrawPixels image is larger than max texture size, break * it up into chunks. */ - maxSize = 1 << (pipe->screen->get_param(pipe->screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS) - 1); + maxSize = 1 << (pipe->screen->get_param(pipe->screen, + PIPE_CAP_MAX_TEXTURE_2D_LEVELS) - 1); assert(width <= maxSize); assert(height <= maxSize); + cso_save_depth_stencil_alpha(cso); cso_save_rasterizer(cso); cso_save_viewport(cso); cso_save_samplers(cso); @@ -562,6 +566,24 @@ draw_textured_quad(GLcontext *ctx, GLint x, GLint y, GLfloat z, cso_set_rasterizer(cso, &rasterizer); } + if (write_depth || write_stencil) + { + struct pipe_depth_stencil_alpha_state dsa; + memset(&dsa, 0, sizeof(dsa)); + if (write_depth) { + dsa.depth.enabled = 1; + dsa.depth.func = PIPE_FUNC_ALWAYS; + dsa.depth.writemask = 1; + } + if (write_stencil) { + dsa.stencil[0].enabled = 1; + dsa.stencil[0].func = PIPE_FUNC_ALWAYS; + dsa.stencil[0].writemask = 0xff; + dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_REPLACE; + } + cso_set_depth_stencil_alpha(cso, &dsa); + } + /* fragment shader state: TEX lookup program */ cso_set_fragment_shader_handle(cso, driver_fp); @@ -579,10 +601,10 @@ draw_textured_quad(GLcontext *ctx, GLint x, GLint y, GLfloat z, sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST; sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST; - sampler.normalized_coords = 1; + sampler.normalized_coords = normalized; cso_single_sampler(cso, 0, &sampler); - if (st->pixel_xfer.pixelmap_enabled) { + if (num_sampler_view > 1) { cso_single_sampler(cso, 1, &sampler); } cso_single_sampler_done(cso); @@ -607,15 +629,7 @@ draw_textured_quad(GLcontext *ctx, GLint x, GLint y, GLfloat z, cso_set_vertex_elements(cso, 3, st->velems_util_draw); /* texture state: */ - if (st->pixel_xfer.pixelmap_enabled) { - struct pipe_sampler_view *sampler_views[2]; - sampler_views[0] = sv; - sampler_views[1] = st->pixel_xfer.pixelmap_sampler_view; - cso_set_fragment_sampler_views(cso, 2, sampler_views); - } - else { - cso_set_fragment_sampler_views(cso, 1, &sv); - } + cso_set_fragment_sampler_views(cso, num_sampler_view, sv); /* Compute Gallium window coords (y=0=top) with pixel zoom. * Recall that these coords are transformed by the current @@ -635,10 +649,11 @@ draw_textured_quad(GLcontext *ctx, GLint x, GLint y, GLfloat z, z = z * 2.0 - 1.0; draw_quad(ctx, x0, y0, z, x1, y1, color, invertTex, - (GLfloat) width / sv->texture->width0, - (GLfloat) height / sv->texture->height0); + normalized ? ((GLfloat) width / sv[0]->texture->width0) : (GLfloat)width, + normalized ? ((GLfloat) height / sv[0]->texture->height0) : (GLfloat)height); /* restore state */ + cso_restore_depth_stencil_alpha(cso); cso_restore_rasterizer(cso); cso_restore_viewport(cso); cso_restore_samplers(cso); @@ -649,8 +664,12 @@ draw_textured_quad(GLcontext *ctx, GLint x, GLint y, GLfloat z, } +/** + * Software fallback to do glDrawPixels(GL_STENCIL_INDEX) when we + * can't use a fragment shader to write stencil values. + */ static void -draw_stencil_pixels(GLcontext *ctx, GLint x, GLint y, +draw_stencil_pixels(struct gl_context *ctx, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels) @@ -681,16 +700,17 @@ draw_stencil_pixels(GLcontext *ctx, GLint x, GLint y, } if(format != GL_DEPTH_STENCIL && - util_format_get_component_bits(strb->format, UTIL_FORMAT_COLORSPACE_ZS, 0) != 0) + util_format_get_component_bits(strb->format, + UTIL_FORMAT_COLORSPACE_ZS, 0) != 0) usage = PIPE_TRANSFER_READ_WRITE; else usage = PIPE_TRANSFER_WRITE; - pt = st_cond_flush_get_tex_transfer(st_context(ctx), strb->texture, 0, 0, 0, + pt = pipe_get_transfer(st_context(ctx)->pipe, strb->texture, 0, 0, 0, usage, x, y, width, height); - stmap = pipe->transfer_map(pipe, pt); + stmap = pipe_transfer_map(pipe, pt); pixels = _mesa_map_pbo_source(ctx, &clippedUnpack, pixels); assert(pixels); @@ -735,15 +755,15 @@ draw_stencil_pixels(GLcontext *ctx, GLint x, GLint y, } /* now pack the stencil (and Z) values in the dest format */ - switch (pt->texture->format) { - case PIPE_FORMAT_S8_UNORM: + switch (pt->resource->format) { + case PIPE_FORMAT_S8_USCALED: { ubyte *dest = stmap + spanY * pt->stride + spanX; assert(usage == PIPE_TRANSFER_WRITE); memcpy(dest, sValues, spanWidth); } break; - case PIPE_FORMAT_Z24S8_UNORM: + case PIPE_FORMAT_Z24_UNORM_S8_USCALED: if (format == GL_DEPTH_STENCIL) { uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4); GLint k; @@ -761,7 +781,7 @@ draw_stencil_pixels(GLcontext *ctx, GLint x, GLint y, } } break; - case PIPE_FORMAT_S8Z24_UNORM: + case PIPE_FORMAT_S8_USCALED_Z24_UNORM: if (format == GL_DEPTH_STENCIL) { uint *dest = (uint *) (stmap + spanY * pt->stride + spanX*4); GLint k; @@ -790,8 +810,8 @@ draw_stencil_pixels(GLcontext *ctx, GLint x, GLint y, _mesa_unmap_pbo_source(ctx, &clippedUnpack); /* unmap the stencil buffer */ - pipe->transfer_unmap(pipe, pt); - pipe->tex_transfer_destroy(pipe, pt); + pipe_transfer_unmap(pipe, pt); + pipe->transfer_destroy(pipe, pt); } @@ -799,19 +819,44 @@ draw_stencil_pixels(GLcontext *ctx, GLint x, GLint y, * Called via ctx->Driver.DrawPixels() */ static void -st_DrawPixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height, +st_DrawPixels(struct gl_context *ctx, GLint x, GLint y, + GLsizei width, GLsizei height, GLenum format, GLenum type, const struct gl_pixelstore_attrib *unpack, const GLvoid *pixels) { void *driver_vp, *driver_fp; struct st_context *st = st_context(ctx); const GLfloat *color; - - if (format == GL_STENCIL_INDEX || - format == GL_DEPTH_STENCIL) { - draw_stencil_pixels(ctx, x, y, width, height, format, type, - unpack, pixels); - return; + struct pipe_context *pipe = st->pipe; + GLboolean write_stencil = GL_FALSE, write_depth = GL_FALSE; + struct pipe_sampler_view *sv[2]; + int num_sampler_view = 1; + enum pipe_format stencil_format = PIPE_FORMAT_NONE; + + if (format == GL_DEPTH_STENCIL) + write_stencil = write_depth = GL_TRUE; + else if (format == GL_STENCIL_INDEX) + write_stencil = GL_TRUE; + else if (format == GL_DEPTH_COMPONENT) + write_depth = GL_TRUE; + + if (write_stencil) { + enum pipe_format tex_format; + /* can we write to stencil if not fallback */ + if (!pipe->screen->get_param(pipe->screen, PIPE_CAP_SHADER_STENCIL_EXPORT)) + goto stencil_fallback; + + tex_format = st_choose_format(st->pipe->screen, base_format(format), + PIPE_TEXTURE_2D, + 0, PIPE_BIND_SAMPLER_VIEW); + if (tex_format == PIPE_FORMAT_Z24_UNORM_S8_USCALED) + stencil_format = PIPE_FORMAT_X24S8_USCALED; + else if (tex_format == PIPE_FORMAT_S8_USCALED_Z24_UNORM) + stencil_format = PIPE_FORMAT_S8X24_USCALED; + else + stencil_format = PIPE_FORMAT_S8_USCALED; + if (stencil_format == PIPE_FORMAT_NONE) + goto stencil_fallback; } /* Mesa state should be up to date by now */ @@ -819,8 +864,8 @@ st_DrawPixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height, st_validate_state(st); - if (format == GL_DEPTH_COMPONENT) { - driver_fp = make_fragment_shader_z(st); + if (write_depth || write_stencil) { + driver_fp = make_fragment_shader_z_stencil(st, write_depth, write_stencil); driver_vp = make_passthrough_vertex_shader(st, GL_TRUE); color = ctx->Current.RasterColor; } @@ -828,38 +873,60 @@ st_DrawPixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height, driver_fp = combined_drawpix_fragment_program(ctx); driver_vp = make_passthrough_vertex_shader(st, GL_FALSE); color = NULL; + if (st->pixel_xfer.pixelmap_enabled) { + sv[1] = st->pixel_xfer.pixelmap_sampler_view; + num_sampler_view++; + } } /* draw with textured quad */ { - struct pipe_texture *pt + struct pipe_resource *pt = make_texture(st, width, height, format, type, unpack, pixels); if (pt) { - struct pipe_sampler_view *sv = st_sampler_view_from_texture(st->pipe, pt); + sv[0] = st_create_texture_sampler_view(st->pipe, pt); + + if (sv[0]) { + if (write_stencil) { + sv[1] = st_create_texture_sampler_view_format(st->pipe, pt, + stencil_format); + num_sampler_view++; + } - if (sv) { draw_textured_quad(ctx, x, y, ctx->Current.RasterPos[2], - width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY, + width, height, + ctx->Pixel.ZoomX, ctx->Pixel.ZoomY, sv, - driver_vp, + num_sampler_view, + driver_vp, driver_fp, - color, GL_FALSE); - pipe_sampler_view_reference(&sv, NULL); + color, GL_FALSE, write_depth, write_stencil); + pipe_sampler_view_reference(&sv[0], NULL); + if (num_sampler_view > 1) + pipe_sampler_view_reference(&sv[1], NULL); } - pipe_texture_reference(&pt, NULL); + pipe_resource_reference(&pt, NULL); } } + return; + +stencil_fallback: + draw_stencil_pixels(ctx, x, y, width, height, format, type, + unpack, pixels); } +/** + * Software fallback for glCopyPixels(GL_STENCIL). + */ static void -copy_stencil_pixels(GLcontext *ctx, GLint srcx, GLint srcy, +copy_stencil_pixels(struct gl_context *ctx, GLint srcx, GLint srcy, GLsizei width, GLsizei height, GLint dstx, GLint dsty) { - struct st_renderbuffer *rbDraw = st_renderbuffer(ctx->DrawBuffer->_StencilBuffer); - struct pipe_context *pipe = ctx->st->pipe; + struct st_renderbuffer *rbDraw; + struct pipe_context *pipe = st_context(ctx)->pipe; enum pipe_transfer_usage usage; struct pipe_transfer *ptDraw; ubyte *drawMap; @@ -872,12 +939,20 @@ copy_stencil_pixels(GLcontext *ctx, GLint srcx, GLint srcy, return; } + /* Get the dest renderbuffer. If there's a wrapper, use the + * underlying renderbuffer. + */ + rbDraw = st_renderbuffer(ctx->DrawBuffer->_StencilBuffer); + if (rbDraw->Base.Wrapped) + rbDraw = st_renderbuffer(rbDraw->Base.Wrapped); + /* this will do stencil pixel transfer ops */ st_read_stencil_pixels(ctx, srcx, srcy, width, height, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, &ctx->DefaultPacking, buffer); - if(util_format_get_component_bits(rbDraw->format, UTIL_FORMAT_COLORSPACE_ZS, 0) != 0) + if (util_format_get_component_bits(rbDraw->format, + UTIL_FORMAT_COLORSPACE_ZS, 0) != 0) usage = PIPE_TRANSFER_READ_WRITE; else usage = PIPE_TRANSFER_WRITE; @@ -886,16 +961,16 @@ copy_stencil_pixels(GLcontext *ctx, GLint srcx, GLint srcy, dsty = rbDraw->Base.Height - dsty - height; } - ptDraw = st_cond_flush_get_tex_transfer(st_context(ctx), + ptDraw = pipe_get_transfer(st_context(ctx)->pipe, rbDraw->texture, 0, 0, 0, usage, dstx, dsty, width, height); - assert(util_format_get_blockwidth(ptDraw->texture->format) == 1); - assert(util_format_get_blockheight(ptDraw->texture->format) == 1); + assert(util_format_get_blockwidth(ptDraw->resource->format) == 1); + assert(util_format_get_blockheight(ptDraw->resource->format) == 1); /* map the stencil buffer */ - drawMap = pipe->transfer_map(pipe, ptDraw); + drawMap = pipe_transfer_map(pipe, ptDraw); /* draw */ /* XXX PixelZoom not handled yet */ @@ -913,8 +988,8 @@ copy_stencil_pixels(GLcontext *ctx, GLint srcx, GLint srcy, dst = drawMap + y * ptDraw->stride; src = buffer + i * width; - switch (ptDraw->texture->format) { - case PIPE_FORMAT_Z24S8_UNORM: + switch (ptDraw->resource->format) { + case PIPE_FORMAT_Z24_UNORM_S8_USCALED: { uint *dst4 = (uint *) dst; int j; @@ -925,7 +1000,7 @@ copy_stencil_pixels(GLcontext *ctx, GLint srcx, GLint srcy, } } break; - case PIPE_FORMAT_S8Z24_UNORM: + case PIPE_FORMAT_S8_USCALED_Z24_UNORM: { uint *dst4 = (uint *) dst; int j; @@ -936,7 +1011,7 @@ copy_stencil_pixels(GLcontext *ctx, GLint srcx, GLint srcy, } } break; - case PIPE_FORMAT_S8_UNORM: + case PIPE_FORMAT_S8_USCALED: assert(usage == PIPE_TRANSFER_WRITE); memcpy(dst, src, width); break; @@ -948,13 +1023,13 @@ copy_stencil_pixels(GLcontext *ctx, GLint srcx, GLint srcy, free(buffer); /* unmap the stencil buffer */ - pipe->transfer_unmap(pipe, ptDraw); - pipe->tex_transfer_destroy(pipe, ptDraw); + pipe_transfer_unmap(pipe, ptDraw); + pipe->transfer_destroy(pipe, ptDraw); } static void -st_CopyPixels(GLcontext *ctx, GLint srcx, GLint srcy, +st_CopyPixels(struct gl_context *ctx, GLint srcx, GLint srcy, GLsizei width, GLsizei height, GLint dstx, GLint dsty, GLenum type) { @@ -963,44 +1038,18 @@ st_CopyPixels(GLcontext *ctx, GLint srcx, GLint srcy, struct pipe_screen *screen = pipe->screen; struct st_renderbuffer *rbRead; void *driver_vp, *driver_fp; - struct pipe_texture *pt; - struct pipe_sampler_view *sv; + struct pipe_resource *pt; + struct pipe_sampler_view *sv[2]; + int num_sampler_view = 1; GLfloat *color; enum pipe_format srcFormat, texFormat; GLboolean invertTex = GL_FALSE; - - pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL); + GLint readX, readY, readW, readH; + GLuint sample_count; + struct gl_pixelstore_attrib pack = ctx->DefaultPacking; st_validate_state(st); - if (srcx < 0) { - width -= -srcx; - dstx += -srcx; - srcx = 0; - } - - if (srcy < 0) { - height -= -srcy; - dsty += -srcy; - srcy = 0; - } - - if (dstx < 0) { - width -= -dstx; - srcx += -dstx; - dstx = 0; - } - - if (dsty < 0) { - height -= -dsty; - srcy += -dsty; - dsty = 0; - } - - if (width < 0 || height < 0) - return; - - if (type == GL_STENCIL) { /* can't use texturing to do stencil */ copy_stencil_pixels(ctx, srcx, srcy, width, height, dstx, dsty); @@ -1012,101 +1061,106 @@ st_CopyPixels(GLcontext *ctx, GLint srcx, GLint srcy, color = NULL; driver_fp = combined_drawpix_fragment_program(ctx); driver_vp = make_passthrough_vertex_shader(st, GL_FALSE); + if (st->pixel_xfer.pixelmap_enabled) { + sv[1] = st->pixel_xfer.pixelmap_sampler_view; + num_sampler_view++; + } } else { assert(type == GL_DEPTH); rbRead = st_renderbuffer(ctx->ReadBuffer->_DepthBuffer); color = ctx->Current.Attrib[VERT_ATTRIB_COLOR0]; - driver_fp = make_fragment_shader_z(st); + driver_fp = make_fragment_shader_z_stencil(st, GL_TRUE, GL_FALSE); driver_vp = make_passthrough_vertex_shader(st, GL_TRUE); } + if (rbRead->Base.Wrapped) + rbRead = st_renderbuffer(rbRead->Base.Wrapped); + + sample_count = rbRead->texture->nr_samples; + /* I believe this would be legal, presumably would need to do a resolve + for color, and for depth/stencil spec says to just use one of the + depth/stencil samples per pixel? Need some transfer clarifications. */ + assert(sample_count < 2); + srcFormat = rbRead->texture->format; - if (screen->is_format_supported(screen, srcFormat, PIPE_TEXTURE_2D, - PIPE_TEXTURE_USAGE_SAMPLER, 0)) { + if (screen->is_format_supported(screen, srcFormat, st->internal_target, + sample_count, + PIPE_BIND_SAMPLER_VIEW, 0)) { texFormat = srcFormat; } else { /* srcFormat can't be used as a texture format */ if (type == GL_DEPTH) { texFormat = st_choose_format(screen, GL_DEPTH_COMPONENT, - PIPE_TEXTURE_2D, - PIPE_TEXTURE_USAGE_DEPTH_STENCIL); - assert(texFormat != PIPE_FORMAT_NONE); /* XXX no depth texture formats??? */ + st->internal_target, sample_count, + PIPE_BIND_DEPTH_STENCIL); + assert(texFormat != PIPE_FORMAT_NONE); } else { /* default color format */ - texFormat = st_choose_format(screen, GL_RGBA, PIPE_TEXTURE_2D, - PIPE_TEXTURE_USAGE_SAMPLER); + texFormat = st_choose_format(screen, GL_RGBA, st->internal_target, + sample_count, PIPE_BIND_SAMPLER_VIEW); assert(texFormat != PIPE_FORMAT_NONE); } } + /* Invert src region if needed */ if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { srcy = ctx->ReadBuffer->Height - srcy - height; - - if (srcy < 0) { - height -= -srcy; - srcy = 0; - } - - if (height < 0) - return; - invertTex = !invertTex; } + /* Clip the read region against the src buffer bounds. + * We'll still allocate a temporary buffer/texture for the original + * src region size but we'll only read the region which is on-screen. + * This may mean that we draw garbage pixels into the dest region, but + * that's expected. + */ + readX = srcx; + readY = srcy; + readW = width; + readH = height; + _mesa_clip_readpixels(ctx, &readX, &readY, &readW, &readH, &pack); + readW = MAX2(0, readW); + readH = MAX2(0, readH); + /* alloc temporary texture */ pt = alloc_texture(st, width, height, texFormat); if (!pt) return; - sv = st_sampler_view_from_texture(st->pipe, pt); - if (!sv) { - pipe_texture_reference(&pt, NULL); + sv[0] = st_create_texture_sampler_view(st->pipe, pt); + if (!sv[0]) { + pipe_resource_reference(&pt, NULL); return; } /* Make temporary texture which is a copy of the src region. - * We'll draw a quad with this texture to draw the dest image. */ if (srcFormat == texFormat) { + struct pipe_subresource srcsub, dstsub; + srcsub.face = 0; + srcsub.level = 0; + dstsub.face = 0; + dstsub.level = 0; /* copy source framebuffer surface into mipmap/texture */ - struct pipe_surface *psRead = screen->get_tex_surface(screen, - rbRead->texture, 0, 0, 0, - PIPE_BUFFER_USAGE_GPU_READ); - struct pipe_surface *psTex = screen->get_tex_surface(screen, pt, 0, 0, 0, - PIPE_BUFFER_USAGE_GPU_WRITE ); - if (pipe->surface_copy) { - pipe->surface_copy(pipe, - psTex, /* dest */ - 0, 0, /* destx/y */ - psRead, - srcx, srcy, width, height); - } else { - util_surface_copy(pipe, FALSE, - psTex, - 0, 0, - psRead, - srcx, srcy, width, height); - } - - if (0) { - /* debug */ - debug_dump_surface(pipe, "copypixsrcsurf", psRead); - debug_dump_surface(pipe, "copypixtemptex", psTex); - } + pipe->resource_copy_region(pipe, + pt, /* dest tex */ + dstsub, + pack.SkipPixels, pack.SkipRows, 0, /* dest pos */ + rbRead->texture, /* src tex */ + srcsub, + readX, readY, 0, readW, readH); /* src region */ - pipe_surface_reference(&psRead, NULL); - pipe_surface_reference(&psTex, NULL); } else { /* CPU-based fallback/conversion */ struct pipe_transfer *ptRead = - st_cond_flush_get_tex_transfer(st, rbRead->texture, 0, 0, 0, - PIPE_TRANSFER_READ, srcx, srcy, width, - height); + pipe_get_transfer(st->pipe, rbRead->texture, 0, 0, 0, + PIPE_TRANSFER_READ, + readX, readY, readW, readH); struct pipe_transfer *ptTex; enum pipe_transfer_usage transfer_usage; @@ -1118,40 +1172,44 @@ st_CopyPixels(GLcontext *ctx, GLint srcx, GLint srcy, else transfer_usage = PIPE_TRANSFER_WRITE; - ptTex = st_cond_flush_get_tex_transfer(st, pt, 0, 0, 0, transfer_usage, + ptTex = pipe_get_transfer(st->pipe, pt, 0, 0, 0, transfer_usage, 0, 0, width, height); + /* copy image from ptRead surface to ptTex surface */ if (type == GL_COLOR) { /* alternate path using get/put_tile() */ GLfloat *buf = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat)); - - pipe_get_tile_rgba(pipe, ptRead, 0, 0, width, height, buf); - pipe_put_tile_rgba(pipe, ptTex, 0, 0, width, height, buf); - + pipe_get_tile_rgba(pipe, ptRead, readX, readY, readW, readH, buf); + pipe_put_tile_rgba(pipe, ptTex, pack.SkipPixels, pack.SkipRows, + readW, readH, buf); free(buf); } else { /* GL_DEPTH */ GLuint *buf = (GLuint *) malloc(width * height * sizeof(GLuint)); - pipe_get_tile_z(pipe, ptRead, 0, 0, width, height, buf); - pipe_put_tile_z(pipe, ptTex, 0, 0, width, height, buf); + pipe_get_tile_z(pipe, ptRead, readX, readY, readW, readH, buf); + pipe_put_tile_z(pipe, ptTex, pack.SkipPixels, pack.SkipRows, + readW, readH, buf); free(buf); } - pipe->tex_transfer_destroy(pipe, ptRead); - pipe->tex_transfer_destroy(pipe, ptTex); + pipe->transfer_destroy(pipe, ptRead); + pipe->transfer_destroy(pipe, ptTex); } - /* draw textured quad */ + /* OK, the texture 'pt' contains the src image/pixels. Now draw a + * textured quad with that texture. + */ draw_textured_quad(ctx, dstx, dsty, ctx->Current.RasterPos[2], width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY, - sv, + sv, + num_sampler_view, driver_vp, driver_fp, - color, invertTex); + color, invertTex, GL_FALSE, GL_FALSE); - pipe_texture_reference(&pt, NULL); - pipe_sampler_view_reference(&sv, NULL); + pipe_resource_reference(&pt, NULL); + pipe_sampler_view_reference(&sv[0], NULL); } @@ -1166,10 +1224,18 @@ void st_init_drawpixels_functions(struct dd_function_table *functions) void st_destroy_drawpix(struct st_context *st) { - st_reference_fragprog(st, &st->drawpix.z_shader, NULL); + GLuint i; + + for (i = 0; i < Elements(st->drawpix.shaders); i++) { + if (st->drawpix.shaders[i]) + st_reference_fragprog(st, &st->drawpix.shaders[i], NULL); + } + st_reference_fragprog(st, &st->pixel_xfer.combined_prog, NULL); if (st->drawpix.vert_shaders[0]) - free(st->drawpix.vert_shaders[0]); + ureg_free_tokens(st->drawpix.vert_shaders[0]); if (st->drawpix.vert_shaders[1]) - free(st->drawpix.vert_shaders[1]); + ureg_free_tokens(st->drawpix.vert_shaders[1]); } + +#endif /* FEATURE_drawpix */