#include "cso_cache/cso_context.h"
+/**
+ * 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:
+ *
+ * 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
+
+
+
/**
* 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.
return st->drawpix.zs_shaders[shaderIndex];
}
- ureg = ureg_create(TGSI_PROCESSOR_FRAGMENT);
+ ureg = ureg_create(PIPE_SHADER_FRAGMENT);
if (ureg == NULL)
return NULL;
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);
}
TGSI_SEMANTIC_TEXCOORD : TGSI_SEMANTIC_GENERIC;
if (!st->drawpix.vert_shaders[passColor]) {
- struct ureg_program *ureg = ureg_create( TGSI_PROCESSOR_VERTEX );
+ struct ureg_program *ureg = ureg_create( PIPE_SHADER_VERTEX );
if (ureg == NULL)
return NULL;
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
+ const GLint bpp = _mesa_bytes_per_pixel(format, type);
+
+ /* Check if the glDrawPixels() parameters and state matches the cache */
+ if (width == st->drawpix_cache.width &&
+ height == st->drawpix_cache.height &&
+ format == st->drawpix_cache.format &&
+ type == st->drawpix_cache.type &&
+ pixels == st->drawpix_cache.user_pointer &&
+ !_mesa_is_bufferobj(unpack->BufferObj) &&
+ (unpack->RowLength == 0 || unpack->RowLength == width) &&
+ unpack->SkipPixels == 0 &&
+ unpack->SkipRows == 0 &&
+ unpack->SwapBytes == GL_FALSE &&
+ st->drawpix_cache.image) {
+ assert(st->drawpix_cache.texture);
+
+ /* check if the pixel data is the same */
+ if (memcmp(pixels, st->drawpix_cache.image, width * height * bpp) == 0) {
+ /* OK, re-use the cached texture */
+ pipe_resource_reference(&pt, st->drawpix_cache.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);
+ return pt;
+ }
+ }
+
+ /* discard the cached image and texture (if there is one) */
+ st->drawpix_cache.width = 0;
+ st->drawpix_cache.height = 0;
+ st->drawpix_cache.user_pointer = NULL;
+ if (st->drawpix_cache.image) {
+ free(st->drawpix_cache.image);
+ st->drawpix_cache.image = NULL;
+ }
+ pipe_resource_reference(&st->drawpix_cache.texture, NULL);
+#endif
+
/* Choose a pixel format for the temp texture which will hold the
* image to draw.
*/
_mesa_unmap_pbo_source(ctx, unpack);
+#if USE_DRAWPIXELS_CACHE
+ /* Save the glDrawPixels parameter and image in the cache */
+ if ((unpack->RowLength == 0 || unpack->RowLength == width) &&
+ unpack->SkipPixels == 0 &&
+ unpack->SkipRows == 0) {
+ st->drawpix_cache.width = width;
+ st->drawpix_cache.height = height;
+ st->drawpix_cache.format = format;
+ st->drawpix_cache.type = type;
+ st->drawpix_cache.user_pointer = pixels;
+ assert(!st->drawpix_cache.image);
+ st->drawpix_cache.image = malloc(width * height * bpp);
+ if (st->drawpix_cache.image) {
+ memcpy(st->drawpix_cache.image, pixels, width * height * bpp);
+ pipe_resource_reference(&st->drawpix_cache.texture, pt);
+ }
+ else {
+ /* out of memory, free/disable cached texture */
+ st->drawpix_cache.width = 0;
+ st->drawpix_cache.height = 0;
+ pipe_resource_reference(&st->drawpix_cache.texture, NULL);
+ }
+ }
+#endif
+
return pt;
}
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);
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;
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);
/* 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);
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;
struct st_context *st = st_context(ctx);
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);
}
!ctx->FragmentProgram.Enabled &&
!ctx->VertexProgram.Enabled &&
!ctx->_Shader->CurrentProgram[MESA_SHADER_FRAGMENT] &&
+ !ctx->ATIFragmentShader._Enabled &&
ctx->DrawBuffer->_NumColorDrawBuffers == 1 &&
!ctx->Query.CondRenderQuery &&
!ctx->Query.CurrentOcclusionObject) {