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 <[email protected]>
> + 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
[email protected]
https://lists.freedesktop.org/mailman/listinfo/mesa-dev