X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fstate_tracker%2Fst_cb_drawpixels.c;h=2a1ac8f4f0269df4ab47c4e94d5720eaacb32c14;hb=caa98246a0e180a96f3fcdcd3bfcbef0b136bc11;hp=f49884cb94b344d65e8b09b2f19c857685038e45;hpb=5239832cf1f3a441594fe7d610f929c8c7e066c9;p=mesa.git diff --git a/src/mesa/state_tracker/st_cb_drawpixels.c b/src/mesa/state_tracker/st_cb_drawpixels.c index f49884cb94b..2a1ac8f4f02 100644 --- a/src/mesa/state_tracker/st_cb_drawpixels.c +++ b/src/mesa/state_tracker/st_cb_drawpixels.c @@ -1,8 +1,8 @@ /************************************************************************** - * + * * Copyright 2007 VMware, Inc. * All Rights Reserved. - * + * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including @@ -10,11 +10,11 @@ * distribute, sub license, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: - * + * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial portions * of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. @@ -22,7 +22,7 @@ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * + * **************************************************************************/ /* @@ -30,7 +30,8 @@ * Brian Paul */ -#include "main/imports.h" +#include "main/errors.h" + #include "main/image.h" #include "main/bufferobj.h" #include "main/blit.h" @@ -41,6 +42,7 @@ #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" @@ -60,46 +62,154 @@ #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_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 "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, enum glsl_base_type base_type, + nir_alu_type alu_type) +{ + const struct glsl_type *sampler2D = + glsl_sampler_type(GLSL_SAMPLER_DIM_2D, false, false, base_type); + + 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 = alu_type; + 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, + GLSL_TYPE_FLOAT, nir_type_float); + 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, + GLSL_TYPE_UINT, nir_type_uint); + 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 +221,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 +256,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 +301,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; - - if (!st->drawpix.vert_shaders[passColor]) { - struct ureg_program *ureg = ureg_create( TGSI_PROCESSOR_VERTEX ); - - if (ureg == NULL) - return NULL; + struct pipe_context *pipe = st->pipe; + struct pipe_screen *screen = pipe->screen; - /* MOV result.pos, vertex.pos; */ - ureg_MOV(ureg, - ureg_DECL_output( ureg, TGSI_SEMANTIC_POSITION, 0 ), - ureg_DECL_vs_input( ureg, 0 )); + if (st->passthrough_vs) + return; - if (passColor) { - /* MOV result.color0, vertex.attr[1]; */ - ureg_MOV(ureg, - ureg_DECL_output( ureg, TGSI_SEMANTIC_COLOR, 0 ), - ureg_DECL_vs_input( ureg, 1 )); - } + enum pipe_shader_ir preferred_ir = + screen->get_shader_param(screen, PIPE_SHADER_VERTEX, + PIPE_SHADER_CAP_PREFERRED_IR); - /* MOV result.texcoord0, vertex.attr[2]; */ - ureg_MOV(ureg, - ureg_DECL_output( ureg, texcoord_semantic, 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 +484,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 || + 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 +616,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 +644,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 +666,6 @@ make_texture(struct st_context *st, { struct pipe_transfer *transfer; - GLboolean success; GLubyte *dest; const GLbitfield imageTransferStateSave = ctx->_ImageTransferState; @@ -390,7 +676,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 +702,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,17 +714,21 @@ 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; } +#if USE_DRAWPIXELS_CACHE + cache_drawpixels_image(st, width, height, format, type, unpack, pixels, pt); +#endif + _mesa_unmap_pbo_source(ctx, unpack); return pt; @@ -460,7 +754,7 @@ draw_textured_quad(struct gl_context *ctx, GLint x, GLint y, GLfloat z, 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; @@ -470,8 +764,8 @@ 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); @@ -479,14 +773,10 @@ draw_textured_quad(struct gl_context *ctx, GLint x, GLint y, GLfloat z, CSO_BIT_VIEWPORT | CSO_BIT_FRAGMENT_SAMPLERS | CSO_BIT_FRAGMENT_SAMPLER_VIEWS | - CSO_BIT_FRAGMENT_SHADER | CSO_BIT_STREAM_OUTPUTS | - CSO_BIT_VERTEX_SHADER | - CSO_BIT_TESSCTRL_SHADER | - CSO_BIT_TESSEVAL_SHADER | - CSO_BIT_GEOMETRY_SHADER | CSO_BIT_VERTEX_ELEMENTS | - CSO_BIT_AUX_VERTEX_BUFFER_SLOT); + CSO_BIT_AUX_VERTEX_BUFFER_SLOT | + CSO_BITS_ALL_SHADERS); if (write_stencil) { cso_state_mask |= (CSO_BIT_DEPTH_STENCIL_ALPHA | CSO_BIT_BLEND); @@ -501,7 +791,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); } @@ -561,11 +854,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]) @@ -588,7 +881,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]; @@ -603,7 +896,8 @@ draw_textured_quad(struct gl_context *ctx, GLint x, GLint y, GLfloat z, /* viewport state: viewport matching window dims */ cso_set_viewport_dims(cso, fb_width, fb_height, TRUE); - cso_set_vertex_elements(cso, 3, st->util_velems); + st->util_velems.count = 3; + cso_set_vertex_elements(cso, &st->util_velems); cso_set_stream_outputs(cso, 0, NULL, NULL); /* Compute Gallium window coords (y=0=top) with pixel zoom. @@ -636,7 +930,7 @@ draw_textured_quad(struct gl_context *ctx, GLint x, GLint y, GLfloat z, const float tTop = invertTex ? maxYcoord : 0.0f; const float tBot = invertTex ? 0.0f : maxYcoord; - if (!st_draw_quad(ctx->st, clip_x0, clip_y0, clip_x1, clip_y1, z, + 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"); } @@ -655,7 +949,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; @@ -683,7 +977,7 @@ draw_stencil_pixels(struct gl_context *ctx, GLint x, GLint y, y = ctx->DrawBuffer->Height - y - height; } - if (format == GL_STENCIL_INDEX && + if (format == GL_STENCIL_INDEX && _mesa_is_format_packed_depth_stencil(strb->Base.Format)) { /* writing stencil to a combined depth+stencil buffer */ usage = PIPE_TRANSFER_READ_WRITE; @@ -709,7 +1003,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); @@ -852,7 +1146,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); @@ -867,9 +1190,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) @@ -922,17 +1244,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); @@ -945,6 +1267,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() */ @@ -952,9 +1302,9 @@ 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); struct pipe_context *pipe = st->pipe; GLboolean write_stencil = GL_FALSE, write_depth = GL_FALSE; @@ -967,9 +1317,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_PIPELINE_RENDER); + 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 @@ -994,21 +1347,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); } 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); + driver_fp = fpv->base.driver_shader; - 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++; @@ -1017,15 +1378,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 */ @@ -1058,12 +1411,12 @@ 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, ctx->Current.RasterColor, GL_FALSE, write_depth, write_stencil); @@ -1071,6 +1424,7 @@ st_DrawPixels(struct gl_context *ctx, GLint x, GLint y, 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); } @@ -1198,20 +1552,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; @@ -1244,8 +1599,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) { @@ -1286,16 +1651,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; @@ -1316,7 +1694,7 @@ 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; @@ -1326,27 +1704,34 @@ st_CopyPixels(struct gl_context *ctx, GLint srcx, GLint srcy, GLboolean invertTex = GL_FALSE; GLint readX, readY, readW, readH; struct gl_pixelstore_attrib pack = ctx->DefaultPacking; + GLboolean write_stencil = GL_FALSE; + GLboolean write_depth = GL_FALSE; + + _mesa_update_draw_buffer_bounds(ctx, ctx->DrawBuffer); st_flush_bitmap_cache(st); + st_invalidate_readpix_cache(st); - st_validate_state(st, ST_PIPELINE_RENDER); + st_validate_state(st, ST_PIPELINE_META); - if (type == GL_DEPTH_STENCIL) { - /* XXX make this more efficient */ + if (blit_copy_pixels(ctx, srcx, srcy, width, height, dstx, dsty, type)) + return; + + /* fallback if the driver can't do stencil exports */ + if (type == GL_DEPTH_STENCIL && + !pipe->screen->get_param(pipe->screen, PIPE_CAP_SHADER_STENCIL_EXPORT)) { st_CopyPixels(ctx, srcx, srcy, width, height, dstx, dsty, GL_STENCIL); st_CopyPixels(ctx, srcx, srcy, width, height, dstx, dsty, GL_DEPTH); return; } - if (type == GL_STENCIL) { - /* can't use texturing to do stencil */ + /* fallback if the driver can't do stencil exports */ + if (type == GL_STENCIL && + !pipe->screen->get_param(pipe->screen, PIPE_CAP_SHADER_STENCIL_EXPORT)) { copy_stencil_pixels(ctx, srcx, srcy, width, height, dstx, dsty); 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. @@ -1354,6 +1739,7 @@ st_CopyPixels(struct gl_context *ctx, GLint srcx, GLint srcy, * are handled. */ + st_make_passthrough_vertex_shader(st); /* * Get vertex/fragment shaders @@ -1363,8 +1749,7 @@ st_CopyPixels(struct gl_context *ctx, GLint srcx, GLint srcy, rbRead = st_get_color_read_renderbuffer(ctx); - driver_fp = fpv->driver_shader; - driver_vp = make_passthrough_vertex_shader(st, GL_FALSE); + driver_fp = fpv->base.driver_shader; if (ctx->Pixel.MapColorFlag) { pipe_sampler_view_reference(&sv[1], @@ -1375,58 +1760,68 @@ 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); - } - else { - assert(type == GL_DEPTH); + st_upload_constants(st, &st->fp->Base); + } else if (type == GL_DEPTH) { rbRead = st_renderbuffer(ctx->ReadBuffer-> Attachment[BUFFER_DEPTH].Renderbuffer); - driver_fp = get_drawpix_z_stencil_program(st, GL_TRUE, GL_FALSE); - driver_vp = make_passthrough_vertex_shader(st, GL_TRUE); + } else if (type == GL_STENCIL) { + rbRead = st_renderbuffer(ctx->ReadBuffer-> + Attachment[BUFFER_STENCIL].Renderbuffer); + driver_fp = get_drawpix_z_stencil_program(st, GL_FALSE, GL_TRUE); + } else { + assert(type == GL_DEPTH_STENCIL); + rbRead = st_renderbuffer(ctx->ReadBuffer-> + Attachment[BUFFER_DEPTH].Renderbuffer); + driver_fp = get_drawpix_z_stencil_program(st, GL_TRUE, GL_TRUE); } + /* Choose the format for the temporary texture. */ srcFormat = rbRead->texture->format; srcBind = PIPE_BIND_SAMPLER_VIEW | (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 if (type == GL_STENCIL) { + /* can't use texturing, fallback to copy */ + copy_stencil_pixels(ctx, srcx, srcy, width, height, dstx, dsty); + return; } 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); } } @@ -1475,6 +1870,25 @@ st_CopyPixels(struct gl_context *ctx, GLint srcx, GLint srcy, return; } + /* Create a second sampler view to read stencil */ + if (type == GL_STENCIL || type == GL_DEPTH_STENCIL) { + write_stencil = GL_TRUE; + if (type == GL_DEPTH_STENCIL) + write_depth = GL_TRUE; + enum pipe_format stencil_format = + util_format_stencil_only(pt->format); + /* we should not be doing pixel map/transfer (see above) */ + assert(num_sampler_view == 1); + sv[1] = st_create_texture_sampler_view_format(st->pipe, pt, + stencil_format); + if (!sv[1]) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels"); + pipe_resource_reference(&pt, NULL); + pipe_sampler_view_reference(&sv[0], NULL); + return; + } + num_sampler_view++; + } /* Copy the src region to the temporary texture. */ { struct pipe_blit_info blit; @@ -1498,7 +1912,12 @@ st_CopyPixels(struct gl_context *ctx, GLint srcx, GLint srcy, blit.dst.box.width = readW; blit.dst.box.height = readH; blit.dst.box.depth = 1; - blit.mask = util_format_get_mask(pt->format) & ~PIPE_MASK_S; + if (type == GL_DEPTH) + blit.mask = util_format_get_mask(pt->format) & ~PIPE_MASK_S; + else if (type == GL_STENCIL) + blit.mask = util_format_get_mask(pt->format) & ~PIPE_MASK_Z; + else + blit.mask = util_format_get_mask(pt->format); blit.filter = PIPE_TEX_FILTER_NEAREST; pipe->blit(pipe, &blit); @@ -1507,14 +1926,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, ctx->Current.Attrib[VERT_ATTRIB_COLOR0], - invertTex, GL_FALSE, GL_FALSE); + invertTex, write_depth, write_stencil); pipe_resource_reference(&pt, NULL); pipe_sampler_view_reference(&sv[0], NULL); @@ -1536,12 +1956,16 @@ st_destroy_drawpix(struct st_context *st) for (i = 0; i < ARRAY_SIZE(st->drawpix.zs_shaders); i++) { if (st->drawpix.zs_shaders[i]) - cso_delete_fragment_shader(st->cso_context, - st->drawpix.zs_shaders[i]); + st->pipe->delete_fs_state(st->pipe, 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) + st->pipe->delete_vs_state(st->pipe, 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); + } }