Am 25.01.2018 um 16:55 schrieb Brian Paul: > The newest version of WSI Fusion makes several glDrawPixels calls > per frame. By caching more than one image, we get better performance > when panning/zomming the map. Still zooming :-)
> > v2: move pixel unpack param checking out of cache search loop, per Roland > --- > src/mesa/state_tracker/st_cb_drawpixels.c | 196 > +++++++++++++++++++++--------- > src/mesa/state_tracker/st_context.c | 4 - > src/mesa/state_tracker/st_context.h | 22 +++- > 3 files changed, 154 insertions(+), 68 deletions(-) > > diff --git a/src/mesa/state_tracker/st_cb_drawpixels.c > b/src/mesa/state_tracker/st_cb_drawpixels.c > index 1d88976..e63f6f7 100644 > --- a/src/mesa/state_tracker/st_cb_drawpixels.c > +++ b/src/mesa/state_tracker/st_cb_drawpixels.c > @@ -375,6 +375,131 @@ 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) { > + /* 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 && > + !_mesa_is_bufferobj(unpack->BufferObj) && Move this line as well? > + 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_age != ~0u); Ok, if it takes 2 years to hit it, that's probably ok... Reviewed-by: Roland Scheidegger <srol...@vmware.com> > + 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. > */ > @@ -392,44 +517,11 @@ make_texture(struct st_context *st, > 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; > + pt = search_drawpixels_cache(st, width, height, format, type, > + unpack, pixels); > + if (pt) { > + return pt; > } > - pipe_resource_reference(&st->drawpix_cache.texture, NULL); > #endif > > /* Choose a pixel format for the temp texture which will hold the > @@ -522,28 +614,7 @@ make_texture(struct st_context *st, > _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); > - } > - } > + cache_drawpixels_image(st, width, height, format, type, unpack, pixels, > pt); > #endif > > return pt; > @@ -1658,4 +1729,11 @@ st_destroy_drawpix(struct st_context *st) > 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]); > + > + /* 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); > + } > } > diff --git a/src/mesa/state_tracker/st_context.c > b/src/mesa/state_tracker/st_context.c > index 3ba4847..eb6c458 100644 > --- a/src/mesa/state_tracker/st_context.c > +++ b/src/mesa/state_tracker/st_context.c > @@ -273,10 +273,6 @@ st_destroy_context_priv(struct st_context *st, bool > destroy_pipe) > } > } > > - /* free glDrawPixels cache data */ > - free(st->drawpix_cache.image); > - pipe_resource_reference(&st->drawpix_cache.texture, NULL); > - > /* free glReadPixels cache data */ > st_invalidate_readpix_cache(st); > > diff --git a/src/mesa/state_tracker/st_context.h > b/src/mesa/state_tracker/st_context.h > index 0258bed..ae2bdf5 100644 > --- a/src/mesa/state_tracker/st_context.h > +++ b/src/mesa/state_tracker/st_context.h > @@ -86,6 +86,20 @@ struct st_bound_handles > uint64_t *handles; > }; > > + > +#define NUM_DRAWPIX_CACHE_ENTRIES 4 > + > +struct drawpix_cache_entry > +{ > + GLsizei width, height; > + GLenum format, type; > + const void *user_pointer; /**< Last user 'pixels' pointer */ > + void *image; /**< Copy of the glDrawPixels image data */ > + struct pipe_resource *texture; > + unsigned age; > +}; > + > + > struct st_context > { > struct st_context_iface iface; > @@ -208,12 +222,10 @@ struct st_context > void *vert_shaders[2]; /**< ureg shaders */ > } drawpix; > > + /** Cache of glDrawPixels images */ > struct { > - GLsizei width, height; > - GLenum format, type; > - const void *user_pointer; /**< Last user 'pixels' pointer */ > - void *image; /**< Copy of the glDrawPixels image data */ > - struct pipe_resource *texture; > + struct drawpix_cache_entry entries[NUM_DRAWPIX_CACHE_ENTRIES]; > + unsigned age; > } drawpix_cache; > > /** for glReadPixels */ > _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev