X-Git-Url: https://git.libre-soc.org/?p=mesa.git;a=blobdiff_plain;f=src%2Fmesa%2Fstate_tracker%2Fst_cb_drawpixels.c;h=6b47548d33ba7ab7355a3bf4c5a12728d7fe9bef;hp=fd58886a7824280ec704f6bd5bc9e790fdc115e3;hb=b30589cbd3dd61a8bb27757fecd536cb559732ad;hpb=7ef3e47c27fb9b11b113bb699019785960d6bf9a diff --git a/src/mesa/state_tracker/st_cb_drawpixels.c b/src/mesa/state_tracker/st_cb_drawpixels.c index fd58886a782..6b47548d33b 100644 --- a/src/mesa/state_tracker/st_cb_drawpixels.c +++ b/src/mesa/state_tracker/st_cb_drawpixels.c @@ -30,16 +30,19 @@ * Brian Paul */ +#include "main/errors.h" #include "main/imports.h" #include "main/image.h" #include "main/bufferobj.h" #include "main/blit.h" #include "main/format_pack.h" +#include "main/framebuffer.h" #include "main/macros.h" #include "main/mtypes.h" #include "main/pack.h" #include "main/pbo.h" #include "main/readpix.h" +#include "main/state.h" #include "main/texformat.h" #include "main/teximage.h" #include "main/texstore.h" @@ -56,50 +59,154 @@ #include "st_cb_fbo.h" #include "st_context.h" #include "st_debug.h" +#include "st_draw.h" #include "st_format.h" #include "st_program.h" +#include "st_sampler_view.h" +#include "st_scissor.h" #include "st_texture.h" +#include "st_util.h" +#include "st_nir.h" #include "pipe/p_context.h" #include "pipe/p_defines.h" #include "tgsi/tgsi_ureg.h" -#include "util/u_draw_quad.h" -#include "util/u_format.h" +#include "util/format/u_format.h" #include "util/u_inlines.h" #include "util/u_math.h" +#include "util/u_simple_shaders.h" #include "util/u_tile.h" -#include "util/u_upload_mgr.h" #include "cso_cache/cso_context.h" +#include "compiler/nir/nir_builder.h" /** - * Create fragment program 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. + * We have a simple glDrawPixels cache to try to optimize the case where the + * same image is drawn over and over again. It basically works as follows: * - * \return CSO of the fragment shader. + * 1. After we construct a texture map with the image and draw it, we do + * not discard the texture. We keep it around, plus we note the + * glDrawPixels width, height, format, etc. parameters and keep a copy + * of the image in a malloc'd buffer. + * + * 2. On the next glDrawPixels we check if the parameters match the previous + * call. If those match, we check if the image matches the previous image + * via a memcmp() call. If everything matches, we re-use the previous + * texture, thereby avoiding the cost creating a new texture and copying + * the image to it. + * + * The effectiveness of this cache depends upon: + * 1. If the memcmp() finds a difference, it happens relatively quickly. + Hopefully, not just the last pixels differ! + * 2. If the memcmp() finds no difference, doing that check is faster than + * creating and loading a texture. + * + * Notes: + * 1. We don't support any pixel unpacking parameters. + * 2. We don't try to cache images in Pixel Buffer Objects. + * 3. Instead of saving the whole image, perhaps some sort of reliable + * checksum function could be used instead. */ +#define USE_DRAWPIXELS_CACHE 1 + +static nir_ssa_def * +sample_via_nir(nir_builder *b, nir_variable *texcoord, + const char *name, int sampler) +{ + const struct glsl_type *sampler2D = + glsl_sampler_type(GLSL_SAMPLER_DIM_2D, false, false, GLSL_TYPE_FLOAT); + + nir_variable *var = + nir_variable_create(b->shader, nir_var_uniform, sampler2D, name); + var->data.binding = sampler; + var->data.explicit_binding = true; + + nir_deref_instr *deref = nir_build_deref_var(b, var); + + nir_tex_instr *tex = nir_tex_instr_create(b->shader, 3); + tex->op = nir_texop_tex; + tex->sampler_dim = GLSL_SAMPLER_DIM_2D; + tex->coord_components = 2; + tex->dest_type = nir_type_float; + tex->src[0].src_type = nir_tex_src_texture_deref; + tex->src[0].src = nir_src_for_ssa(&deref->dest.ssa); + tex->src[1].src_type = nir_tex_src_sampler_deref; + tex->src[1].src = nir_src_for_ssa(&deref->dest.ssa); + tex->src[2].src_type = nir_tex_src_coord; + tex->src[2].src = + nir_src_for_ssa(nir_channels(b, nir_load_var(b, texcoord), + (1 << tex->coord_components) - 1)); + + nir_ssa_dest_init(&tex->instr, &tex->dest, 4, 32, NULL); + nir_builder_instr_insert(b, &tex->instr); + return nir_channel(b, &tex->dest.ssa, 0); +} + static void * -get_drawpix_z_stencil_program(struct st_context *st, - GLboolean write_depth, - GLboolean write_stencil) +make_drawpix_z_stencil_program_nir(struct st_context *st, + bool write_depth, + bool write_stencil) +{ + struct nir_builder b; + const nir_shader_compiler_options *options = + st->ctx->Const.ShaderCompilerOptions[MESA_SHADER_FRAGMENT].NirOptions; + + nir_builder_init_simple_shader(&b, NULL, MESA_SHADER_FRAGMENT, options); + + nir_variable *texcoord = + nir_variable_create(b.shader, nir_var_shader_in, glsl_vec_type(2), + "texcoord"); + texcoord->data.location = VARYING_SLOT_TEX0; + + if (write_depth) { + nir_variable *out = + nir_variable_create(b.shader, nir_var_shader_out, glsl_float_type(), + "gl_FragDepth"); + out->data.location = FRAG_RESULT_DEPTH; + nir_ssa_def *depth = sample_via_nir(&b, texcoord, "depth", 0); + nir_store_var(&b, out, depth, 0x1); + + /* Also copy color */ + nir_variable *color_in = + nir_variable_create(b.shader, nir_var_shader_in, glsl_vec_type(4), + "v_color"); + color_in->data.location = VARYING_SLOT_COL0; + + nir_variable *color_out = + nir_variable_create(b.shader, nir_var_shader_out, glsl_vec_type(4), + "gl_FragColor"); + color_out->data.location = FRAG_RESULT_COLOR; + nir_copy_var(&b, color_out, color_in); + } + + if (write_stencil) { + nir_variable *out = + nir_variable_create(b.shader, nir_var_shader_out, glsl_uint_type(), + "gl_FragStencilRefARB"); + out->data.location = FRAG_RESULT_STENCIL; + nir_ssa_def *stencil = sample_via_nir(&b, texcoord, "stencil", 1); + nir_store_var(&b, out, stencil, 0x1); + } + + char name[14]; + snprintf(name, 14, "drawpixels %s%s", + write_depth ? "Z" : "", write_stencil ? "S" : ""); + + return st_nir_finish_builtin_shader(st, b.shader, name); +} + + +static void * +make_drawpix_z_stencil_program_tgsi(struct st_context *st, + bool write_depth, + bool write_stencil) { struct ureg_program *ureg; struct ureg_src depth_sampler, stencil_sampler; struct ureg_src texcoord, color; struct ureg_dst out_color, out_depth, out_stencil; - const GLuint shaderIndex = write_depth * 2 + write_stencil; - void *cso; - - assert(shaderIndex < ARRAY_SIZE(st->drawpix.zs_shaders)); - - if (st->drawpix.zs_shaders[shaderIndex]) { - /* already have the proper shader */ - return st->drawpix.zs_shaders[shaderIndex]; - } - ureg = ureg_create(TGSI_PROCESSOR_FRAGMENT); + ureg = ureg_create(PIPE_SHADER_FRAGMENT); if (ureg == NULL) return NULL; @@ -111,11 +218,21 @@ get_drawpix_z_stencil_program(struct st_context *st, out_color = ureg_DECL_output(ureg, TGSI_SEMANTIC_COLOR, 0); depth_sampler = ureg_DECL_sampler(ureg, 0); + ureg_DECL_sampler_view(ureg, 0, TGSI_TEXTURE_2D, + TGSI_RETURN_TYPE_FLOAT, + TGSI_RETURN_TYPE_FLOAT, + TGSI_RETURN_TYPE_FLOAT, + TGSI_RETURN_TYPE_FLOAT); out_depth = ureg_DECL_output(ureg, TGSI_SEMANTIC_POSITION, 0); } if (write_stencil) { stencil_sampler = ureg_DECL_sampler(ureg, 1); + ureg_DECL_sampler_view(ureg, 1, TGSI_TEXTURE_2D, + TGSI_RETURN_TYPE_UINT, + TGSI_RETURN_TYPE_UINT, + TGSI_RETURN_TYPE_UINT, + TGSI_RETURN_TYPE_UINT); out_stencil = ureg_DECL_output(ureg, TGSI_SEMANTIC_STENCIL, 0); } @@ -136,7 +253,42 @@ get_drawpix_z_stencil_program(struct st_context *st, TGSI_TEXTURE_2D, texcoord, stencil_sampler); ureg_END(ureg); - cso = ureg_create_shader_and_destroy(ureg, st->pipe); + return ureg_create_shader_and_destroy(ureg, st->pipe); +} + + +/** + * Create fragment program 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 CSO of the fragment shader. + */ +static void * +get_drawpix_z_stencil_program(struct st_context *st, + bool write_depth, + bool write_stencil) +{ + struct pipe_screen *pscreen = st->pipe->screen; + const GLuint shaderIndex = write_depth * 2 + write_stencil; + void *cso; + + assert(shaderIndex < ARRAY_SIZE(st->drawpix.zs_shaders)); + + if (st->drawpix.zs_shaders[shaderIndex]) { + /* already have the proper shader */ + return st->drawpix.zs_shaders[shaderIndex]; + } + + enum pipe_shader_ir preferred_ir = + pscreen->get_shader_param(pscreen, PIPE_SHADER_FRAGMENT, + PIPE_SHADER_CAP_PREFERRED_IR); + + if (preferred_ir == PIPE_SHADER_IR_NIR) + cso = make_drawpix_z_stencil_program_nir(st, write_depth, write_stencil); + else + cso = make_drawpix_z_stencil_program_tgsi(st, write_depth, write_stencil); /* save the new shader */ st->drawpix.zs_shaders[shaderIndex] = cso; @@ -146,45 +298,44 @@ get_drawpix_z_stencil_program(struct st_context *st, /** * Create a simple vertex shader that just passes through the - * vertex position and texcoord (and optionally, color). + * vertex position, texcoord, and color. */ -static void * -make_passthrough_vertex_shader(struct st_context *st, - GLboolean passColor) +void +st_make_passthrough_vertex_shader(struct st_context *st) { - const unsigned texcoord_semantic = st->needs_texcoord_semantic ? - TGSI_SEMANTIC_TEXCOORD : TGSI_SEMANTIC_GENERIC; + struct pipe_context *pipe = st->pipe; + struct pipe_screen *screen = pipe->screen; - if (!st->drawpix.vert_shaders[passColor]) { - struct ureg_program *ureg = ureg_create( TGSI_PROCESSOR_VERTEX ); + if (st->passthrough_vs) + return; - if (ureg == NULL) - return NULL; + enum pipe_shader_ir preferred_ir = + screen->get_shader_param(screen, PIPE_SHADER_VERTEX, + PIPE_SHADER_CAP_PREFERRED_IR); - /* MOV result.pos, vertex.pos; */ - ureg_MOV(ureg, - ureg_DECL_output( ureg, TGSI_SEMANTIC_POSITION, 0 ), - ureg_DECL_vs_input( ureg, 0 )); - - /* MOV result.texcoord0, vertex.attr[1]; */ - ureg_MOV(ureg, - ureg_DECL_output( ureg, texcoord_semantic, 0 ), - ureg_DECL_vs_input( ureg, 1 )); - - if (passColor) { - /* MOV result.color0, vertex.attr[2]; */ - ureg_MOV(ureg, - ureg_DECL_output( ureg, TGSI_SEMANTIC_COLOR, 0 ), - ureg_DECL_vs_input( ureg, 2 )); - } + if (preferred_ir == PIPE_SHADER_IR_NIR) { + unsigned inputs[] = + { VERT_ATTRIB_POS, VERT_ATTRIB_COLOR0, VERT_ATTRIB_GENERIC0 }; + unsigned outputs[] = + { VARYING_SLOT_POS, VARYING_SLOT_COL0, VARYING_SLOT_TEX0 }; - ureg_END( ureg ); - - st->drawpix.vert_shaders[passColor] = - ureg_create_shader_and_destroy( ureg, st->pipe ); + st->passthrough_vs = + st_nir_make_passthrough_shader(st, "drawpixels VS", + MESA_SHADER_VERTEX, 3, + inputs, outputs, NULL, 0); + } else { + const enum tgsi_semantic semantic_names[] = { + TGSI_SEMANTIC_POSITION, + TGSI_SEMANTIC_COLOR, + st->needs_texcoord_semantic ? TGSI_SEMANTIC_TEXCOORD : + TGSI_SEMANTIC_GENERIC + }; + const uint semantic_indexes[] = { 0, 0, 0 }; + + st->passthrough_vs = + util_make_vertex_passthrough_shader(st->pipe, 3, semantic_names, + semantic_indexes, false); } - - return st->drawpix.vert_shaders[passColor]; } @@ -330,6 +481,130 @@ alloc_texture(struct st_context *st, GLsizei width, GLsizei height, } +/** + * Search the cache for an image which matches the given parameters. + * \return pipe_resource pointer if found, NULL if not found. + */ +static struct pipe_resource * +search_drawpixels_cache(struct st_context *st, + GLsizei width, GLsizei height, + GLenum format, GLenum type, + const struct gl_pixelstore_attrib *unpack, + const void *pixels) +{ + struct pipe_resource *pt = NULL; + const GLint bpp = _mesa_bytes_per_pixel(format, type); + unsigned i; + + if ((unpack->RowLength != 0 && unpack->RowLength != width) || + unpack->SkipPixels != 0 || + unpack->SkipRows != 0 || + unpack->SwapBytes || + _mesa_is_bufferobj(unpack->BufferObj)) { + /* we don't allow non-default pixel unpacking values */ + return NULL; + } + + /* Search cache entries for a match */ + for (i = 0; i < ARRAY_SIZE(st->drawpix_cache.entries); i++) { + struct drawpix_cache_entry *entry = &st->drawpix_cache.entries[i]; + + if (width == entry->width && + height == entry->height && + format == entry->format && + type == entry->type && + pixels == entry->user_pointer && + entry->image) { + assert(entry->texture); + + /* check if the pixel data is the same */ + if (memcmp(pixels, entry->image, width * height * bpp) == 0) { + /* Success - found a cache match */ + pipe_resource_reference(&pt, entry->texture); + /* refcount of returned texture should be at least two here. One + * reference for the cache to hold on to, one for the caller (which + * it will release), and possibly more held by the driver. + */ + assert(pt->reference.count >= 2); + + /* update the age of this entry */ + entry->age = ++st->drawpix_cache.age; + + return pt; + } + } + } + + /* no cache match found */ + return NULL; +} + + +/** + * Find the oldest entry in the glDrawPixels cache. We'll replace this + * one when we need to store a new image. + */ +static struct drawpix_cache_entry * +find_oldest_drawpixels_cache_entry(struct st_context *st) +{ + unsigned oldest_age = ~0u, oldest_index = ~0u; + unsigned i; + + /* Find entry with oldest (lowest) age */ + for (i = 0; i < ARRAY_SIZE(st->drawpix_cache.entries); i++) { + const struct drawpix_cache_entry *entry = &st->drawpix_cache.entries[i]; + if (entry->age < oldest_age) { + oldest_age = entry->age; + oldest_index = i; + } + } + + assert(oldest_index != ~0u); + + return &st->drawpix_cache.entries[oldest_index]; +} + + +/** + * Try to save the given glDrawPixels image in the cache. + */ +static void +cache_drawpixels_image(struct st_context *st, + GLsizei width, GLsizei height, + GLenum format, GLenum type, + const struct gl_pixelstore_attrib *unpack, + const void *pixels, + struct pipe_resource *pt) +{ + if ((unpack->RowLength == 0 || unpack->RowLength == width) && + unpack->SkipPixels == 0 && + unpack->SkipRows == 0) { + const GLint bpp = _mesa_bytes_per_pixel(format, type); + struct drawpix_cache_entry *entry = + find_oldest_drawpixels_cache_entry(st); + assert(entry); + entry->width = width; + entry->height = height; + entry->format = format; + entry->type = type; + entry->user_pointer = pixels; + free(entry->image); + entry->image = malloc(width * height * bpp); + if (entry->image) { + memcpy(entry->image, pixels, width * height * bpp); + pipe_resource_reference(&entry->texture, pt); + entry->age = ++st->drawpix_cache.age; + } + else { + /* out of memory, free/disable cached texture */ + entry->width = 0; + entry->height = 0; + pipe_resource_reference(&entry->texture, NULL); + } + } +} + + /** * Make texture containing an image for glDrawPixels image. * If 'pixels' is NULL, leave the texture image data undefined. @@ -338,15 +613,23 @@ 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) + const void *pixels) { struct gl_context *ctx = st->ctx; struct pipe_context *pipe = st->pipe; mesa_format mformat; - struct pipe_resource *pt; + struct pipe_resource *pt = NULL; enum pipe_format pipeFormat; GLenum baseInternalFormat; +#if USE_DRAWPIXELS_CACHE + pt = search_drawpixels_cache(st, width, height, format, type, + unpack, pixels); + if (pt) { + return pt; + } +#endif + /* Choose a pixel format for the temp texture which will hold the * image to draw. */ @@ -358,8 +641,9 @@ make_texture(struct st_context *st, GLenum intFormat = internal_format(ctx, format, type); pipeFormat = st_choose_format(st, intFormat, format, type, - st->internal_target, 0, - PIPE_BIND_SAMPLER_VIEW, FALSE); + st->internal_target, 0, 0, + PIPE_BIND_SAMPLER_VIEW, + false, false); assert(pipeFormat != PIPE_FORMAT_NONE); } @@ -379,7 +663,6 @@ make_texture(struct st_context *st, { struct pipe_transfer *transfer; - GLboolean success; GLubyte *dest; const GLbitfield imageTransferStateSave = ctx->_ImageTransferState; @@ -390,7 +673,11 @@ make_texture(struct st_context *st, dest = pipe_transfer_map(pipe, pt, 0, 0, PIPE_TRANSFER_WRITE, 0, 0, width, height, &transfer); - + if (!dest) { + pipe_resource_reference(&pt, NULL); + _mesa_unmap_pbo_source(ctx, unpack); + return NULL; + } /* Put image into texture transfer. * Note that the image is actually going to be upside down in @@ -412,9 +699,9 @@ make_texture(struct st_context *st, format, type, /* src format/type */ pixels, /* data source */ unpack); - success = GL_TRUE; } else { + ASSERTED bool success; success = _mesa_texstore(ctx, 2, /* dims */ baseInternalFormat, /* baseInternalFormat */ mformat, /* mesa_format */ @@ -424,120 +711,27 @@ make_texture(struct st_context *st, format, type, /* src format/type */ pixels, /* data source */ unpack); + + assert(success); } /* unmap */ pipe_transfer_unmap(pipe, transfer); - assert(success); - /* restore */ ctx->_ImageTransferState = imageTransferStateSave; } _mesa_unmap_pbo_source(ctx, unpack); - return pt; -} - - -/** - * Draw quad with texcoords and optional color. - * Coords are gallium window coords with y=0=top. - * \param color may be null - * \param invertTex if true, flip texcoords vertically - */ -static void -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) -{ - struct st_context *st = st_context(ctx); - struct pipe_context *pipe = st->pipe; - GLfloat (*verts)[3][4]; /* four verts, three attribs, XYZW */ - struct pipe_resource *buf = NULL; - unsigned offset; - - u_upload_alloc(st->uploader, 0, 4 * sizeof(verts[0]), 4, &offset, - &buf, (void **) &verts); - if (!buf) { - return; - } - - /* setup vertex data */ - { - const struct gl_framebuffer *fb = st->ctx->DrawBuffer; - const GLfloat fb_width = (GLfloat) fb->Width; - const GLfloat fb_height = (GLfloat) fb->Height; - const GLfloat clip_x0 = x0 / fb_width * 2.0f - 1.0f; - const GLfloat clip_y0 = y0 / fb_height * 2.0f - 1.0f; - const GLfloat clip_x1 = x1 / fb_width * 2.0f - 1.0f; - const GLfloat clip_y1 = y1 / fb_height * 2.0f - 1.0f; - const GLfloat sLeft = 0.0f, sRight = maxXcoord; - const GLfloat tTop = invertTex ? maxYcoord : 0.0f; - const GLfloat tBot = invertTex ? 0.0f : maxYcoord; - GLuint i; - - /* upper-left */ - verts[0][0][0] = clip_x0; /* v[0].attr[0].x */ - verts[0][0][1] = clip_y0; /* v[0].attr[0].y */ - - /* upper-right */ - verts[1][0][0] = clip_x1; - verts[1][0][1] = clip_y0; - - /* lower-right */ - verts[2][0][0] = clip_x1; - verts[2][0][1] = clip_y1; - - /* lower-left */ - verts[3][0][0] = clip_x0; - verts[3][0][1] = clip_y1; - - 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; /* 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][3] = 1.0f; /*W*/ - verts[i][1][2] = 0.0f; /*R*/ - verts[i][1][3] = 1.0f; /*Q*/ - } - } - } +#if USE_DRAWPIXELS_CACHE + cache_drawpixels_image(st, width, height, format, type, unpack, pixels, pt); +#endif - u_upload_unmap(st->uploader); - util_draw_vertex_buffer(pipe, st->cso_context, buf, - cso_get_aux_vertex_buffer_slot(st->cso_context), - offset, - PIPE_PRIM_QUADS, - 4, /* verts */ - 3); /* attribs/vert */ - pipe_resource_reference(&buf, NULL); + return pt; } - static void draw_textured_quad(struct gl_context *ctx, GLint x, GLint y, GLfloat z, GLsizei width, GLsizei height, @@ -554,9 +748,12 @@ draw_textured_quad(struct gl_context *ctx, GLint x, GLint y, GLfloat z, struct st_context *st = st_context(ctx); struct pipe_context *pipe = st->pipe; struct cso_context *cso = st->cso_context; + const unsigned fb_width = _mesa_geometric_width(ctx->DrawBuffer); + const unsigned fb_height = _mesa_geometric_height(ctx->DrawBuffer); GLfloat x0, y0, x1, y1; - GLsizei maxSize; + ASSERTED GLsizei maxSize; boolean normalized = sv[0]->texture->target == PIPE_TEXTURE_2D; + unsigned cso_state_mask; assert(sv[0]->texture->target == st->internal_target); @@ -564,27 +761,24 @@ draw_textured_quad(struct gl_context *ctx, GLint x, GLint y, GLfloat z, /* 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 = pipe->screen->get_param(pipe->screen, + PIPE_CAP_MAX_TEXTURE_2D_SIZE); assert(width <= maxSize); assert(height <= maxSize); - cso_save_rasterizer(cso); - cso_save_viewport(cso); - cso_save_fragment_samplers(cso); - cso_save_fragment_sampler_views(cso); - cso_save_fragment_shader(cso); - cso_save_stream_outputs(cso); - cso_save_vertex_shader(cso); - cso_save_tessctrl_shader(cso); - cso_save_tesseval_shader(cso); - cso_save_geometry_shader(cso); - cso_save_vertex_elements(cso); - cso_save_aux_vertex_buffer_slot(cso); + cso_state_mask = (CSO_BIT_RASTERIZER | + CSO_BIT_VIEWPORT | + CSO_BIT_FRAGMENT_SAMPLERS | + CSO_BIT_FRAGMENT_SAMPLER_VIEWS | + CSO_BIT_STREAM_OUTPUTS | + CSO_BIT_VERTEX_ELEMENTS | + CSO_BIT_AUX_VERTEX_BUFFER_SLOT | + CSO_BITS_ALL_SHADERS); if (write_stencil) { - cso_save_depth_stencil_alpha(cso); - cso_save_blend(cso); + cso_state_mask |= (CSO_BIT_DEPTH_STENCIL_ALPHA | + CSO_BIT_BLEND); } + cso_save_state(cso, cso_state_mask); /* rasterizer state: just scissor */ { @@ -594,7 +788,10 @@ draw_textured_quad(struct gl_context *ctx, GLint x, GLint y, GLfloat z, ctx->Color._ClampFragmentColor; rasterizer.half_pixel_center = 1; rasterizer.bottom_edge_rule = 1; - rasterizer.depth_clip = !ctx->Transform.DepthClamp; + rasterizer.depth_clip_near = st->clamp_frag_depth_in_shader || + !ctx->Transform.DepthClampNear; + rasterizer.depth_clip_far = st->clamp_frag_depth_in_shader || + !ctx->Transform.DepthClampFar; rasterizer.scissor = ctx->Scissor.EnableFlags; cso_set_rasterizer(cso, &rasterizer); } @@ -654,11 +851,11 @@ draw_textured_quad(struct gl_context *ctx, GLint x, GLint y, GLfloat z, const struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS]; uint num = MAX3(fpv->drawpix_sampler + 1, fpv->pixelmap_sampler + 1, - st->state.num_samplers[PIPE_SHADER_FRAGMENT]); + st->state.num_frag_samplers); uint i; - for (i = 0; i < st->state.num_samplers[PIPE_SHADER_FRAGMENT]; i++) - samplers[i] = &st->state.samplers[PIPE_SHADER_FRAGMENT][i]; + for (i = 0; i < st->state.num_frag_samplers; i++) + samplers[i] = &st->state.frag_samplers[i]; samplers[fpv->drawpix_sampler] = &sampler; if (sv[1]) @@ -681,7 +878,7 @@ draw_textured_quad(struct gl_context *ctx, GLint x, GLint y, GLfloat z, fpv->pixelmap_sampler + 1, st->state.num_sampler_views[PIPE_SHADER_FRAGMENT]); - memcpy(sampler_views, st->state.sampler_views[PIPE_SHADER_FRAGMENT], + memcpy(sampler_views, st->state.frag_sampler_views, sizeof(sampler_views)); sampler_views[fpv->drawpix_sampler] = sv[0]; @@ -694,28 +891,17 @@ draw_textured_quad(struct gl_context *ctx, GLint x, GLint y, GLfloat z, } /* viewport state: viewport matching window dims */ - { - const float w = (float) ctx->DrawBuffer->Width; - const float h = (float) ctx->DrawBuffer->Height; - struct pipe_viewport_state vp; - vp.scale[0] = 0.5f * w; - vp.scale[1] = -0.5f * h; - vp.scale[2] = 0.5f; - vp.translate[0] = 0.5f * w; - vp.translate[1] = 0.5f * h; - vp.translate[2] = 0.5f; - cso_set_viewport(cso, &vp); - } + cso_set_viewport_dims(cso, fb_width, fb_height, TRUE); - cso_set_vertex_elements(cso, 3, st->velems_util_draw); - cso_set_stream_outputs(st->cso_context, 0, NULL, NULL); + cso_set_vertex_elements(cso, 3, st->util_velems); + cso_set_stream_outputs(cso, 0, NULL, NULL); /* Compute Gallium window coords (y=0=top) with pixel zoom. * Recall that these coords are transformed by the current * vertex shader and viewport transformation. */ if (st_fb_orientation(ctx->DrawBuffer) == Y_0_BOTTOM) { - y = ctx->DrawBuffer->Height - (int) (y + height * ctx->Pixel.ZoomY); + y = fb_height - (int) (y + height * ctx->Pixel.ZoomY); invertTex = !invertTex; } @@ -727,27 +913,27 @@ draw_textured_quad(struct gl_context *ctx, GLint x, GLint y, GLfloat z, /* convert Z from [0,1] to [-1,-1] to match viewport Z scale/bias */ z = z * 2.0f - 1.0f; - draw_quad(ctx, x0, y0, z, x1, y1, color, invertTex, - normalized ? ((GLfloat) width / sv[0]->texture->width0) : (GLfloat)width, - normalized ? ((GLfloat) height / sv[0]->texture->height0) : (GLfloat)height); + { + const float clip_x0 = x0 / (float) fb_width * 2.0f - 1.0f; + const float clip_y0 = y0 / (float) fb_height * 2.0f - 1.0f; + const float clip_x1 = x1 / (float) fb_width * 2.0f - 1.0f; + const float clip_y1 = y1 / (float) fb_height * 2.0f - 1.0f; + const float maxXcoord = normalized ? + ((float) width / sv[0]->texture->width0) : (float) width; + const float maxYcoord = normalized + ? ((float) height / sv[0]->texture->height0) : (float) height; + const float sLeft = 0.0f, sRight = maxXcoord; + const float tTop = invertTex ? maxYcoord : 0.0f; + const float tBot = invertTex ? 0.0f : maxYcoord; + + if (!st_draw_quad(st, clip_x0, clip_y0, clip_x1, clip_y1, z, + sLeft, tBot, sRight, tTop, color, 0)) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels"); + } + } /* restore state */ - cso_restore_rasterizer(cso); - cso_restore_viewport(cso); - cso_restore_fragment_samplers(cso); - cso_restore_fragment_sampler_views(cso); - cso_restore_fragment_shader(cso); - cso_restore_vertex_shader(cso); - cso_restore_tessctrl_shader(cso); - cso_restore_tesseval_shader(cso); - cso_restore_geometry_shader(cso); - cso_restore_vertex_elements(cso); - cso_restore_aux_vertex_buffer_slot(cso); - cso_restore_stream_outputs(cso); - if (write_stencil) { - cso_restore_depth_stencil_alpha(cso); - cso_restore_blend(cso); - } + cso_restore_state(cso); } @@ -759,7 +945,7 @@ static void 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) + const void *pixels) { struct st_context *st = st_context(ctx); struct pipe_context *pipe = st->pipe; @@ -813,7 +999,7 @@ draw_stencil_pixels(struct gl_context *ctx, GLint x, GLint y, for (row = 0; row < height; row++) { GLfloat *zValuesFloat = (GLfloat*)zValues; GLenum destType = GL_UNSIGNED_BYTE; - const GLvoid *source = _mesa_image_address2d(&clippedUnpack, pixels, + const void *source = _mesa_image_address2d(&clippedUnpack, pixels, width, height, format, type, row, 0); @@ -956,7 +1142,36 @@ get_color_fp_variant(struct st_context *st) ctx->Pixel.AlphaScale != 1.0); key.pixelMaps = ctx->Pixel.MapColorFlag; key.clamp_color = st->clamp_frag_color_in_shader && - st->ctx->Color._ClampFragmentColor; + ctx->Color._ClampFragmentColor; + + fpv = st_get_fp_variant(st, st->fp, &key); + + return fpv; +} + +/** + * Get fragment program variant for a glDrawPixels command + * for COLOR_INDEX data + */ +static struct st_fp_variant * +get_color_index_fp_variant(struct st_context *st) +{ + struct gl_context *ctx = st->ctx; + struct st_fp_variant_key key; + struct st_fp_variant *fpv; + + memset(&key, 0, sizeof(key)); + + key.st = st->has_shareable_shaders ? NULL : st; + key.drawpixels = 1; + /* Since GL is always in RGBA mode MapColorFlag does not + * affect GL_COLOR_INDEX format. + * Scale and bias also never affect GL_COLOR_INDEX format. + */ + key.scaleAndBias = 0; + key.pixelMaps = 0; + key.clamp_color = st->clamp_frag_color_in_shader && + ctx->Color._ClampFragmentColor; fpv = st_get_fp_variant(st, st->fp, &key); @@ -971,9 +1186,8 @@ static void clamp_size(struct pipe_context *pipe, GLsizei *width, GLsizei *height, struct gl_pixelstore_attrib *unpack) { - const int maxSize = - 1 << (pipe->screen->get_param(pipe->screen, - PIPE_CAP_MAX_TEXTURE_2D_LEVELS) - 1); + const int maxSize = pipe->screen->get_param(pipe->screen, + PIPE_CAP_MAX_TEXTURE_2D_SIZE); if (*width > maxSize) { if (unpack->RowLength == 0) @@ -1026,17 +1240,17 @@ setup_sampler_swizzle(struct pipe_sampler_view *sv, GLenum format, GLenum type) /* invert the format's swizzle to setup the sampler's swizzle */ if (format == GL_RGBA) { - c0 = UTIL_FORMAT_SWIZZLE_X; - c1 = UTIL_FORMAT_SWIZZLE_Y; - c2 = UTIL_FORMAT_SWIZZLE_Z; - c3 = UTIL_FORMAT_SWIZZLE_W; + c0 = PIPE_SWIZZLE_X; + c1 = PIPE_SWIZZLE_Y; + c2 = PIPE_SWIZZLE_Z; + c3 = PIPE_SWIZZLE_W; } else { assert(format == GL_BGRA); - c0 = UTIL_FORMAT_SWIZZLE_Z; - c1 = UTIL_FORMAT_SWIZZLE_Y; - c2 = UTIL_FORMAT_SWIZZLE_X; - c3 = UTIL_FORMAT_SWIZZLE_W; + c0 = PIPE_SWIZZLE_Z; + c1 = PIPE_SWIZZLE_Y; + c2 = PIPE_SWIZZLE_X; + c3 = PIPE_SWIZZLE_W; } sv->swizzle_r = search_swizzle(desc->swizzle, c0); sv->swizzle_g = search_swizzle(desc->swizzle, c1); @@ -1049,6 +1263,34 @@ setup_sampler_swizzle(struct pipe_sampler_view *sv, GLenum format, GLenum type) } +/** + * Compute the effective raster z position. This performs depth-clamping + * if needed. + */ +static float +get_effective_raster_z(struct gl_context *ctx) +{ + float z = ctx->Current.RasterPos[2]; + if (st_context(ctx)->clamp_frag_depth_in_shader) { + GLfloat depth_near; + GLfloat depth_far; + if (ctx->ViewportArray[0].Near < ctx->ViewportArray[0].Far) { + depth_near = ctx->ViewportArray[0].Near; + depth_far = ctx->ViewportArray[0].Far; + } else { + depth_near = ctx->ViewportArray[0].Far; + depth_far = ctx->ViewportArray[0].Near; + } + + if (ctx->Transform.DepthClampNear) + z = MAX2(z, depth_near); + if (ctx->Transform.DepthClampFar) + z = MIN2(z, depth_far); + } + return z; +} + + /** * Called via ctx->Driver.DrawPixels() */ @@ -1056,11 +1298,10 @@ static void 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) + const struct gl_pixelstore_attrib *unpack, const void *pixels) { - void *driver_vp, *driver_fp; + void *driver_fp; struct st_context *st = st_context(ctx); - const GLfloat *color; struct pipe_context *pipe = st->pipe; GLboolean write_stencil = GL_FALSE, write_depth = GL_FALSE; struct pipe_sampler_view *sv[2] = { NULL }; @@ -1072,9 +1313,12 @@ st_DrawPixels(struct gl_context *ctx, GLint x, GLint y, /* Mesa state should be up to date by now */ assert(ctx->NewState == 0x0); + _mesa_update_draw_buffer_bounds(ctx, ctx->DrawBuffer); + st_flush_bitmap_cache(st); + st_invalidate_readpix_cache(st); - st_validate_state(st); + st_validate_state(st, ST_PIPELINE_META); /* Limit the size of the glDrawPixels to the max texture size. * Strictly speaking, that's not correct but since we don't handle @@ -1099,23 +1343,29 @@ st_DrawPixels(struct gl_context *ctx, GLint x, GLint y, return; } + /* Put glDrawPixels image into a texture */ + pt = make_texture(st, width, height, format, type, unpack, pixels); + if (!pt) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels"); + return; + } + + st_make_passthrough_vertex_shader(st); + /* * Get vertex/fragment shaders */ if (write_depth || write_stencil) { driver_fp = get_drawpix_z_stencil_program(st, write_depth, write_stencil); - driver_vp = make_passthrough_vertex_shader(st, GL_TRUE); - color = ctx->Current.RasterColor; } else { - fpv = get_color_fp_variant(st); + fpv = (format != GL_COLOR_INDEX) ? get_color_fp_variant(st) : + get_color_index_fp_variant(st); driver_fp = fpv->driver_shader; - driver_vp = make_passthrough_vertex_shader(st, GL_FALSE); - color = NULL; - if (ctx->Pixel.MapColorFlag) { + if (ctx->Pixel.MapColorFlag && format != GL_COLOR_INDEX) { pipe_sampler_view_reference(&sv[1], st->pixel_xfer.pixelmap_sampler_view); num_sampler_view++; @@ -1124,15 +1374,7 @@ st_DrawPixels(struct gl_context *ctx, GLint x, GLint y, /* compiling a new fragment shader variant added new state constants * into the constant buffer, we need to update them */ - st_upload_constants(st, st->fp->Base.Base.Parameters, - PIPE_SHADER_FRAGMENT); - } - - /* Put glDrawPixels image into a texture */ - pt = make_texture(st, width, height, format, type, unpack, pixels); - if (!pt) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels"); - return; + st_upload_constants(st, &st->fp->Base); } /* create sampler view for the image */ @@ -1165,18 +1407,20 @@ st_DrawPixels(struct gl_context *ctx, GLint x, GLint y, num_sampler_view++; } - draw_textured_quad(ctx, x, y, ctx->Current.RasterPos[2], + draw_textured_quad(ctx, x, y, get_effective_raster_z(ctx), width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY, sv, num_sampler_view, - driver_vp, + st->passthrough_vs, driver_fp, fpv, - color, GL_FALSE, write_depth, write_stencil); + ctx->Current.RasterColor, + 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); + /* free the texture (but may persist in the cache) */ pipe_resource_reference(&pt, NULL); } @@ -1304,20 +1548,21 @@ blit_copy_pixels(struct gl_context *ctx, GLint srcx, GLint srcy, struct gl_pixelstore_attrib pack, unpack; GLint readX, readY, readW, readH, drawX, drawY, drawW, drawH; - if (type == GL_COLOR && - ctx->Pixel.ZoomX == 1.0 && + if (ctx->Pixel.ZoomX == 1.0 && ctx->Pixel.ZoomY == 1.0 && - ctx->_ImageTransferState == 0x0 && - !ctx->Color.BlendEnabled && - !ctx->Color.AlphaEnabled && - (!ctx->Color.ColorLogicOpEnabled || ctx->Color.LogicOp == GL_COPY) && - !ctx->Depth.Test && - !ctx->Fog.Enabled && - !ctx->Stencil.Enabled && - !ctx->FragmentProgram.Enabled && - !ctx->VertexProgram.Enabled && - !ctx->_Shader->CurrentProgram[MESA_SHADER_FRAGMENT] && - ctx->DrawBuffer->_NumColorDrawBuffers == 1 && + (type != GL_COLOR || + (ctx->_ImageTransferState == 0x0 && + !ctx->Color.BlendEnabled && + !ctx->Color.AlphaEnabled && + (!ctx->Color.ColorLogicOpEnabled || ctx->Color.LogicOp == GL_COPY) && + !ctx->Depth.Test && + !ctx->Fog.Enabled && + !ctx->Stencil.Enabled && + !ctx->FragmentProgram.Enabled && + !ctx->VertexProgram.Enabled && + !ctx->_Shader->CurrentProgram[MESA_SHADER_FRAGMENT] && + !_mesa_ati_fragment_shader_enabled(ctx) && + ctx->DrawBuffer->_NumColorDrawBuffers == 1)) && !ctx->Query.CondRenderQuery && !ctx->Query.CurrentOcclusionObject) { struct st_renderbuffer *rbRead, *rbDraw; @@ -1350,8 +1595,18 @@ blit_copy_pixels(struct gl_context *ctx, GLint srcx, GLint srcy, drawW = readW; drawH = readH; - rbRead = st_get_color_read_renderbuffer(ctx); - rbDraw = st_renderbuffer(ctx->DrawBuffer->_ColorDrawBuffers[0]); + if (type == GL_COLOR) { + rbRead = st_get_color_read_renderbuffer(ctx); + rbDraw = st_renderbuffer(ctx->DrawBuffer->_ColorDrawBuffers[0]); + } else if (type == GL_DEPTH || type == GL_DEPTH_STENCIL) { + rbRead = st_renderbuffer(ctx->ReadBuffer->Attachment[BUFFER_DEPTH].Renderbuffer); + rbDraw = st_renderbuffer(ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer); + } else if (type == GL_STENCIL) { + rbRead = st_renderbuffer(ctx->ReadBuffer->Attachment[BUFFER_STENCIL].Renderbuffer); + rbDraw = st_renderbuffer(ctx->DrawBuffer->Attachment[BUFFER_STENCIL].Renderbuffer); + } else { + return false; + } /* Flip src/dst position depending on the orientation of buffers. */ if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { @@ -1392,16 +1647,29 @@ blit_copy_pixels(struct gl_context *ctx, GLint srcx, GLint srcy, blit.dst.box.width = drawW; blit.dst.box.height = drawH; blit.dst.box.depth = 1; - blit.mask = PIPE_MASK_RGBA; blit.filter = PIPE_TEX_FILTER_NEAREST; + if (type == GL_COLOR) + blit.mask |= PIPE_MASK_RGBA; + if (type == GL_DEPTH) + blit.mask |= PIPE_MASK_Z; + if (type == GL_STENCIL) + blit.mask |= PIPE_MASK_S; + if (type == GL_DEPTH_STENCIL) + blit.mask |= PIPE_MASK_ZS; + + if (ctx->DrawBuffer != ctx->WinSysDrawBuffer) + st_window_rectangles_to_blit(ctx, &blit); + if (screen->is_format_supported(screen, blit.src.format, blit.src.resource->target, blit.src.resource->nr_samples, + blit.src.resource->nr_storage_samples, PIPE_BIND_SAMPLER_VIEW) && screen->is_format_supported(screen, blit.dst.format, blit.dst.resource->target, blit.dst.resource->nr_samples, + blit.dst.resource->nr_storage_samples, PIPE_BIND_RENDER_TARGET)) { pipe->blit(pipe, &blit); return GL_TRUE; @@ -1422,21 +1690,26 @@ st_CopyPixels(struct gl_context *ctx, GLint srcx, GLint srcy, struct pipe_context *pipe = st->pipe; struct pipe_screen *screen = pipe->screen; struct st_renderbuffer *rbRead; - void *driver_vp, *driver_fp; + void *driver_fp; struct pipe_resource *pt; struct pipe_sampler_view *sv[2] = { NULL }; struct st_fp_variant *fpv = NULL; int num_sampler_view = 1; - GLfloat *color; enum pipe_format srcFormat; unsigned srcBind; GLboolean invertTex = GL_FALSE; GLint readX, readY, readW, readH; struct gl_pixelstore_attrib pack = ctx->DefaultPacking; + _mesa_update_draw_buffer_bounds(ctx, ctx->DrawBuffer); + st_flush_bitmap_cache(st); + st_invalidate_readpix_cache(st); - st_validate_state(st); + st_validate_state(st, ST_PIPELINE_META); + + if (blit_copy_pixels(ctx, srcx, srcy, width, height, dstx, dsty, type)) + return; if (type == GL_DEPTH_STENCIL) { /* XXX make this more efficient */ @@ -1451,9 +1724,6 @@ st_CopyPixels(struct gl_context *ctx, GLint srcx, GLint srcy, return; } - if (blit_copy_pixels(ctx, srcx, srcy, width, height, dstx, dsty, type)) - return; - /* * The subsequent code implements glCopyPixels by copying the source * pixels into a temporary texture that's then applied to a textured quad. @@ -1461,6 +1731,7 @@ st_CopyPixels(struct gl_context *ctx, GLint srcx, GLint srcy, * are handled. */ + st_make_passthrough_vertex_shader(st); /* * Get vertex/fragment shaders @@ -1469,10 +1740,8 @@ st_CopyPixels(struct gl_context *ctx, GLint srcx, GLint srcy, fpv = get_color_fp_variant(st); rbRead = st_get_color_read_renderbuffer(ctx); - color = NULL; driver_fp = fpv->driver_shader; - driver_vp = make_passthrough_vertex_shader(st, GL_FALSE); if (ctx->Pixel.MapColorFlag) { pipe_sampler_view_reference(&sv[1], @@ -1483,17 +1752,14 @@ st_CopyPixels(struct gl_context *ctx, GLint srcx, GLint srcy, /* compiling a new fragment shader variant added new state constants * into the constant buffer, we need to update them */ - st_upload_constants(st, st->fp->Base.Base.Parameters, - PIPE_SHADER_FRAGMENT); + st_upload_constants(st, &st->fp->Base); } else { assert(type == GL_DEPTH); rbRead = st_renderbuffer(ctx->ReadBuffer-> Attachment[BUFFER_DEPTH].Renderbuffer); - color = ctx->Current.Attrib[VERT_ATTRIB_COLOR0]; driver_fp = get_drawpix_z_stencil_program(st, GL_TRUE, GL_FALSE); - driver_vp = make_passthrough_vertex_shader(st, GL_TRUE); } /* Choose the format for the temporary texture. */ @@ -1502,40 +1768,40 @@ st_CopyPixels(struct gl_context *ctx, GLint srcx, GLint srcy, (type == GL_COLOR ? PIPE_BIND_RENDER_TARGET : PIPE_BIND_DEPTH_STENCIL); if (!screen->is_format_supported(screen, srcFormat, st->internal_target, 0, - srcBind)) { + 0, srcBind)) { /* srcFormat is non-renderable. Find a compatible renderable format. */ if (type == GL_DEPTH) { srcFormat = st_choose_format(st, GL_DEPTH_COMPONENT, GL_NONE, - GL_NONE, st->internal_target, 0, - srcBind, FALSE); + GL_NONE, st->internal_target, 0, 0, + srcBind, false, false); } else { assert(type == GL_COLOR); if (util_format_is_float(srcFormat)) { srcFormat = st_choose_format(st, GL_RGBA32F, GL_NONE, - GL_NONE, st->internal_target, 0, - srcBind, FALSE); + GL_NONE, st->internal_target, 0, 0, + srcBind, false, false); } else if (util_format_is_pure_sint(srcFormat)) { srcFormat = st_choose_format(st, GL_RGBA32I, GL_NONE, - GL_NONE, st->internal_target, 0, - srcBind, FALSE); + GL_NONE, st->internal_target, 0, 0, + srcBind, false, false); } else if (util_format_is_pure_uint(srcFormat)) { srcFormat = st_choose_format(st, GL_RGBA32UI, GL_NONE, - GL_NONE, st->internal_target, 0, - srcBind, FALSE); + GL_NONE, st->internal_target, 0, 0, + srcBind, false, false); } else if (util_format_is_snorm(srcFormat)) { srcFormat = st_choose_format(st, GL_RGBA16_SNORM, GL_NONE, - GL_NONE, st->internal_target, 0, - srcBind, FALSE); + GL_NONE, st->internal_target, 0, 0, + srcBind, false, false); } else { srcFormat = st_choose_format(st, GL_RGBA, GL_NONE, - GL_NONE, st->internal_target, 0, - srcBind, FALSE); + GL_NONE, st->internal_target, 0, 0, + srcBind, false, false); } } @@ -1616,13 +1882,15 @@ st_CopyPixels(struct gl_context *ctx, GLint srcx, GLint srcy, /* 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], + + draw_textured_quad(ctx, dstx, dsty, get_effective_raster_z(ctx), width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY, sv, num_sampler_view, - driver_vp, + st->passthrough_vs, driver_fp, fpv, - color, invertTex, GL_FALSE, GL_FALSE); + ctx->Current.Attrib[VERT_ATTRIB_COLOR0], + invertTex, GL_FALSE, GL_FALSE); pipe_resource_reference(&pt, NULL); pipe_sampler_view_reference(&sv[0], NULL); @@ -1648,8 +1916,13 @@ st_destroy_drawpix(struct st_context *st) st->drawpix.zs_shaders[i]); } - if (st->drawpix.vert_shaders[0]) - cso_delete_vertex_shader(st->cso_context, st->drawpix.vert_shaders[0]); - if (st->drawpix.vert_shaders[1]) - cso_delete_vertex_shader(st->cso_context, st->drawpix.vert_shaders[1]); + if (st->passthrough_vs) + cso_delete_vertex_shader(st->cso_context, st->passthrough_vs); + + /* Free cache data */ + for (i = 0; i < ARRAY_SIZE(st->drawpix_cache.entries); i++) { + struct drawpix_cache_entry *entry = &st->drawpix_cache.entries[i]; + free(entry->image); + pipe_resource_reference(&entry->texture, NULL); + } }