• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**************************************************************************
2  *
3  * Copyright 2007 VMware, Inc.
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sub license, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice (including the
15  * next paragraph) shall be included in all copies or substantial portions
16  * of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25  *
26  **************************************************************************/
27 
28 #include "main/bufferobj.h"
29 #include "main/image.h"
30 #include "main/pbo.h"
31 
32 #include "main/readpix.h"
33 #include "main/enums.h"
34 #include "main/framebuffer.h"
35 #include "util/u_inlines.h"
36 #include "util/format/u_format.h"
37 #include "cso_cache/cso_context.h"
38 
39 #include "st_cb_fbo.h"
40 #include "st_atom.h"
41 #include "st_context.h"
42 #include "st_cb_bitmap.h"
43 #include "st_cb_readpixels.h"
44 #include "st_debug.h"
45 #include "state_tracker/st_cb_texture.h"
46 #include "state_tracker/st_format.h"
47 #include "state_tracker/st_pbo.h"
48 #include "state_tracker/st_texture.h"
49 #include "state_tracker/st_util.h"
50 
51 
52 /* The readpixels cache caches a blitted staging texture so that back-to-back
53  * calls to glReadPixels with user pointers require less CPU-GPU synchronization.
54  *
55  * Assumptions:
56  *
57  * (1) Blits have high synchronization overheads, and it is beneficial to
58  *     use a single blit of the entire framebuffer instead of many smaller
59  *     blits (because the smaller blits cannot be batched, and we have to wait
60  *     for the GPU after each one).
61  *
62  * (2) transfer_map implicitly involves a blit as well (for de-tiling, copy
63  *     from VRAM, etc.), so that it is beneficial to replace the
64  *     _mesa_readpixels path as well when possible.
65  *
66  * Change this #define to true to fill and use the cache whenever possible
67  * (this is inefficient and only meant for testing / debugging).
68  */
69 #define ALWAYS_READPIXELS_CACHE false
70 
71 static boolean
needs_integer_signed_unsigned_conversion(const struct gl_context * ctx,GLenum format,GLenum type)72 needs_integer_signed_unsigned_conversion(const struct gl_context *ctx,
73                                          GLenum format, GLenum type)
74 {
75    struct gl_renderbuffer *rb =
76       _mesa_get_read_renderbuffer_for_format(ctx, format);
77 
78    assert(rb);
79 
80    GLenum srcType = _mesa_get_format_datatype(rb->Format);
81 
82     if ((srcType == GL_INT &&
83         (type == GL_UNSIGNED_INT ||
84          type == GL_UNSIGNED_SHORT ||
85          type == GL_UNSIGNED_BYTE)) ||
86        (srcType == GL_UNSIGNED_INT &&
87         (type == GL_INT ||
88          type == GL_SHORT ||
89          type == GL_BYTE))) {
90       return TRUE;
91    }
92 
93    return FALSE;
94 }
95 
96 static bool
try_pbo_readpixels(struct st_context * st,struct st_renderbuffer * strb,bool invert_y,GLint x,GLint y,GLsizei width,GLsizei height,enum pipe_format src_format,enum pipe_format dst_format,const struct gl_pixelstore_attrib * pack,void * pixels)97 try_pbo_readpixels(struct st_context *st, struct st_renderbuffer *strb,
98                    bool invert_y,
99                    GLint x, GLint y, GLsizei width, GLsizei height,
100                    enum pipe_format src_format, enum pipe_format dst_format,
101                    const struct gl_pixelstore_attrib *pack, void *pixels)
102 {
103    struct pipe_context *pipe = st->pipe;
104    struct pipe_screen *screen = pipe->screen;
105    struct cso_context *cso = st->cso_context;
106    struct pipe_surface *surface = strb->surface;
107    struct pipe_resource *texture = strb->texture;
108    const struct util_format_description *desc;
109    struct st_pbo_addresses addr;
110    struct pipe_framebuffer_state fb;
111    enum pipe_texture_target view_target;
112    bool success = false;
113 
114    if (texture->nr_samples > 1)
115       return false;
116 
117    if (!screen->is_format_supported(screen, dst_format, PIPE_BUFFER, 0, 0,
118                                     PIPE_BIND_SHADER_IMAGE))
119       return false;
120 
121    desc = util_format_description(dst_format);
122 
123    /* Compute PBO addresses */
124    addr.bytes_per_pixel = desc->block.bits / 8;
125    addr.xoffset = x;
126    addr.yoffset = y;
127    addr.width = width;
128    addr.height = height;
129    addr.depth = 1;
130    if (!st_pbo_addresses_pixelstore(st, GL_TEXTURE_2D, false, pack, pixels, &addr))
131       return false;
132 
133    cso_save_state(cso, (CSO_BIT_FRAGMENT_SAMPLER_VIEWS |
134                         CSO_BIT_FRAGMENT_SAMPLERS |
135                         CSO_BIT_FRAGMENT_IMAGE0 |
136                         CSO_BIT_BLEND |
137                         CSO_BIT_VERTEX_ELEMENTS |
138                         CSO_BIT_AUX_VERTEX_BUFFER_SLOT |
139                         CSO_BIT_FRAMEBUFFER |
140                         CSO_BIT_VIEWPORT |
141                         CSO_BIT_RASTERIZER |
142                         CSO_BIT_DEPTH_STENCIL_ALPHA |
143                         CSO_BIT_STREAM_OUTPUTS |
144                         (st->active_queries ? CSO_BIT_PAUSE_QUERIES : 0) |
145                         CSO_BIT_SAMPLE_MASK |
146                         CSO_BIT_MIN_SAMPLES |
147                         CSO_BIT_RENDER_CONDITION |
148                         CSO_BITS_ALL_SHADERS));
149    cso_save_constant_buffer_slot0(cso, PIPE_SHADER_FRAGMENT);
150 
151    cso_set_sample_mask(cso, ~0);
152    cso_set_min_samples(cso, 1);
153    cso_set_render_condition(cso, NULL, FALSE, 0);
154 
155    /* Set up the sampler_view */
156    {
157       struct pipe_sampler_view templ;
158       struct pipe_sampler_view *sampler_view;
159       struct pipe_sampler_state sampler = {0};
160       const struct pipe_sampler_state *samplers[1] = {&sampler};
161 
162       u_sampler_view_default_template(&templ, texture, src_format);
163 
164       switch (texture->target) {
165       case PIPE_TEXTURE_CUBE:
166       case PIPE_TEXTURE_CUBE_ARRAY:
167          view_target = PIPE_TEXTURE_2D_ARRAY;
168          break;
169       default:
170          view_target = texture->target;
171          break;
172       }
173 
174       templ.target = view_target;
175       templ.u.tex.first_level = surface->u.tex.level;
176       templ.u.tex.last_level = templ.u.tex.first_level;
177 
178       if (view_target != PIPE_TEXTURE_3D) {
179          templ.u.tex.first_layer = surface->u.tex.first_layer;
180          templ.u.tex.last_layer = templ.u.tex.first_layer;
181       } else {
182          addr.constants.layer_offset = surface->u.tex.first_layer;
183       }
184 
185       sampler_view = pipe->create_sampler_view(pipe, texture, &templ);
186       if (sampler_view == NULL)
187          goto fail;
188 
189       cso_set_sampler_views(cso, PIPE_SHADER_FRAGMENT, 1, &sampler_view);
190 
191       pipe_sampler_view_reference(&sampler_view, NULL);
192 
193       cso_set_samplers(cso, PIPE_SHADER_FRAGMENT, 1, samplers);
194    }
195 
196    /* Set up destination image */
197    {
198       struct pipe_image_view image;
199 
200       memset(&image, 0, sizeof(image));
201       image.resource = addr.buffer;
202       image.format = dst_format;
203       image.access = PIPE_IMAGE_ACCESS_WRITE;
204       image.shader_access = PIPE_IMAGE_ACCESS_WRITE;
205       image.u.buf.offset = addr.first_element * addr.bytes_per_pixel;
206       image.u.buf.size = (addr.last_element - addr.first_element + 1) *
207                          addr.bytes_per_pixel;
208 
209       cso_set_shader_images(cso, PIPE_SHADER_FRAGMENT, 0, 1, &image);
210    }
211 
212    /* Set up no-attachment framebuffer */
213    memset(&fb, 0, sizeof(fb));
214    fb.width = surface->width;
215    fb.height = surface->height;
216    fb.samples = 1;
217    fb.layers = 1;
218    cso_set_framebuffer(cso, &fb);
219 
220    /* Any blend state would do. Set this just to prevent drivers having
221     * blend == NULL.
222     */
223    cso_set_blend(cso, &st->pbo.upload_blend);
224 
225    cso_set_viewport_dims(cso, fb.width, fb.height, invert_y);
226 
227    if (invert_y)
228       st_pbo_addresses_invert_y(&addr, fb.height);
229 
230    {
231       struct pipe_depth_stencil_alpha_state dsa;
232       memset(&dsa, 0, sizeof(dsa));
233       cso_set_depth_stencil_alpha(cso, &dsa);
234    }
235 
236    /* Set up the fragment shader */
237    {
238       void *fs = st_pbo_get_download_fs(st, view_target, src_format, dst_format, addr.depth != 1);
239       if (!fs)
240          goto fail;
241 
242       cso_set_fragment_shader_handle(cso, fs);
243    }
244 
245    success = st_pbo_draw(st, &addr, fb.width, fb.height);
246 
247    /* Buffer written via shader images needs explicit synchronization. */
248    pipe->memory_barrier(pipe, PIPE_BARRIER_ALL);
249 
250 fail:
251    cso_restore_state(cso);
252    cso_restore_constant_buffer_slot0(cso, PIPE_SHADER_FRAGMENT);
253 
254    return success;
255 }
256 
257 /**
258  * Create a staging texture and blit the requested region to it.
259  */
260 static struct pipe_resource *
blit_to_staging(struct st_context * st,struct st_renderbuffer * strb,bool invert_y,GLint x,GLint y,GLsizei width,GLsizei height,GLenum format,enum pipe_format src_format,enum pipe_format dst_format)261 blit_to_staging(struct st_context *st, struct st_renderbuffer *strb,
262                    bool invert_y,
263                    GLint x, GLint y, GLsizei width, GLsizei height,
264                    GLenum format,
265                    enum pipe_format src_format, enum pipe_format dst_format)
266 {
267    struct pipe_context *pipe = st->pipe;
268    struct pipe_screen *screen = pipe->screen;
269    struct pipe_resource dst_templ;
270    struct pipe_resource *dst;
271    struct pipe_blit_info blit;
272 
273    /* We are creating a texture of the size of the region being read back.
274     * Need to check for NPOT texture support. */
275    if (!screen->get_param(screen, PIPE_CAP_NPOT_TEXTURES) &&
276        (!util_is_power_of_two_or_zero(width) ||
277         !util_is_power_of_two_or_zero(height)))
278       return NULL;
279 
280    /* create the destination texture */
281    memset(&dst_templ, 0, sizeof(dst_templ));
282    dst_templ.target = PIPE_TEXTURE_2D;
283    dst_templ.format = dst_format;
284    if (util_format_is_depth_or_stencil(dst_format))
285       dst_templ.bind |= PIPE_BIND_DEPTH_STENCIL;
286    else
287       dst_templ.bind |= PIPE_BIND_RENDER_TARGET;
288    dst_templ.usage = PIPE_USAGE_STAGING;
289 
290    st_gl_texture_dims_to_pipe_dims(GL_TEXTURE_2D, width, height, 1,
291                                    &dst_templ.width0, &dst_templ.height0,
292                                    &dst_templ.depth0, &dst_templ.array_size);
293 
294    dst = screen->resource_create(screen, &dst_templ);
295    if (!dst)
296       return NULL;
297 
298    memset(&blit, 0, sizeof(blit));
299    blit.src.resource = strb->texture;
300    blit.src.level = strb->surface->u.tex.level;
301    blit.src.format = src_format;
302    blit.dst.resource = dst;
303    blit.dst.level = 0;
304    blit.dst.format = dst->format;
305    blit.src.box.x = x;
306    blit.dst.box.x = 0;
307    blit.src.box.y = y;
308    blit.dst.box.y = 0;
309    blit.src.box.z = strb->surface->u.tex.first_layer;
310    blit.dst.box.z = 0;
311    blit.src.box.width = blit.dst.box.width = width;
312    blit.src.box.height = blit.dst.box.height = height;
313    blit.src.box.depth = blit.dst.box.depth = 1;
314    blit.mask = st_get_blit_mask(strb->Base._BaseFormat, format);
315    blit.filter = PIPE_TEX_FILTER_NEAREST;
316    blit.scissor_enable = FALSE;
317 
318    if (invert_y) {
319       blit.src.box.y = strb->Base.Height - blit.src.box.y;
320       blit.src.box.height = -blit.src.box.height;
321    }
322 
323    /* blit */
324    st->pipe->blit(st->pipe, &blit);
325 
326    return dst;
327 }
328 
329 static struct pipe_resource *
try_cached_readpixels(struct st_context * st,struct st_renderbuffer * strb,bool invert_y,GLsizei width,GLsizei height,GLenum format,enum pipe_format src_format,enum pipe_format dst_format)330 try_cached_readpixels(struct st_context *st, struct st_renderbuffer *strb,
331                       bool invert_y,
332                       GLsizei width, GLsizei height,
333                       GLenum format,
334                       enum pipe_format src_format, enum pipe_format dst_format)
335 {
336    struct pipe_resource *src = strb->texture;
337    struct pipe_resource *dst = NULL;
338 
339    if (ST_DEBUG & DEBUG_NOREADPIXCACHE)
340       return NULL;
341 
342    /* Reset cache after invalidation or switch of parameters. */
343    if (st->readpix_cache.src != src ||
344        st->readpix_cache.dst_format != dst_format ||
345        st->readpix_cache.level != strb->surface->u.tex.level ||
346        st->readpix_cache.layer != strb->surface->u.tex.first_layer) {
347       pipe_resource_reference(&st->readpix_cache.src, src);
348       pipe_resource_reference(&st->readpix_cache.cache, NULL);
349       st->readpix_cache.dst_format = dst_format;
350       st->readpix_cache.level = strb->surface->u.tex.level;
351       st->readpix_cache.layer = strb->surface->u.tex.first_layer;
352       st->readpix_cache.hits = 0;
353    }
354 
355    /* Decide whether to trigger the cache. */
356    if (!st->readpix_cache.cache) {
357       if (!strb->use_readpix_cache && !ALWAYS_READPIXELS_CACHE) {
358          /* Heuristic: If previous successive calls read at least a fraction
359           * of the surface _and_ we read again, trigger the cache.
360           */
361          unsigned threshold = MAX2(1, strb->Base.Width * strb->Base.Height / 8);
362 
363          if (st->readpix_cache.hits < threshold) {
364             st->readpix_cache.hits += width * height;
365             return NULL;
366          }
367 
368          strb->use_readpix_cache = true;
369       }
370 
371       /* Fill the cache */
372       st->readpix_cache.cache = blit_to_staging(st, strb, invert_y,
373                                                 0, 0,
374                                                 strb->Base.Width,
375                                                 strb->Base.Height, format,
376                                                 src_format, dst_format);
377    }
378 
379    /* Return an owning reference to stay consistent with the non-cached path */
380    pipe_resource_reference(&dst, st->readpix_cache.cache);
381 
382    return dst;
383 }
384 
385 /**
386  * This uses a blit to copy the read buffer to a texture format which matches
387  * the format and type combo and then a fast read-back is done using memcpy.
388  * We can do arbitrary X/Y/Z/W/0/1 swizzling here as long as there is
389  * a format which matches the swizzling.
390  *
391  * If such a format isn't available, we fall back to _mesa_readpixels.
392  *
393  * NOTE: Some drivers use a blit to convert between tiled and linear
394  *       texture layouts during texture uploads/downloads, so the blit
395  *       we do here should be free in such cases.
396  */
397 static void
st_ReadPixels(struct gl_context * ctx,GLint x,GLint y,GLsizei width,GLsizei height,GLenum format,GLenum type,const struct gl_pixelstore_attrib * pack,void * pixels)398 st_ReadPixels(struct gl_context *ctx, GLint x, GLint y,
399               GLsizei width, GLsizei height,
400               GLenum format, GLenum type,
401               const struct gl_pixelstore_attrib *pack,
402               void *pixels)
403 {
404    struct st_context *st = st_context(ctx);
405    struct gl_renderbuffer *rb =
406          _mesa_get_read_renderbuffer_for_format(ctx, format);
407    struct st_renderbuffer *strb = st_renderbuffer(rb);
408    struct pipe_context *pipe = st->pipe;
409    struct pipe_screen *screen = pipe->screen;
410    struct pipe_resource *src;
411    struct pipe_resource *dst = NULL;
412    enum pipe_format dst_format, src_format;
413    unsigned bind;
414    struct pipe_transfer *tex_xfer;
415    ubyte *map = NULL;
416    int dst_x, dst_y;
417 
418    /* Validate state (to be sure we have up-to-date framebuffer surfaces)
419     * and flush the bitmap cache prior to reading. */
420    st_validate_state(st, ST_PIPELINE_UPDATE_FRAMEBUFFER);
421    st_flush_bitmap_cache(st);
422 
423    if (!st->prefer_blit_based_texture_transfer) {
424       goto fallback;
425    }
426 
427    /* This must be done after state validation. */
428    src = strb->texture;
429 
430    /* XXX Fallback for depth-stencil formats due to an incomplete
431     * stencil blit implementation in some drivers. */
432    if (format == GL_DEPTH_STENCIL) {
433       goto fallback;
434    }
435 
436    /* If the base internal format and the texture format don't match, we have
437     * to use the slow path. */
438    if (rb->_BaseFormat !=
439        _mesa_get_format_base_format(rb->Format)) {
440       goto fallback;
441    }
442 
443    if (_mesa_readpixels_needs_slow_path(ctx, format, type, GL_TRUE)) {
444       goto fallback;
445    }
446 
447    /* Convert the source format to what is expected by ReadPixels
448     * and see if it's supported. */
449    src_format = util_format_linear(src->format);
450    src_format = util_format_luminance_to_red(src_format);
451    src_format = util_format_intensity_to_red(src_format);
452 
453    if (!src_format ||
454        !screen->is_format_supported(screen, src_format, src->target,
455                                     src->nr_samples, src->nr_storage_samples,
456                                     PIPE_BIND_SAMPLER_VIEW)) {
457       goto fallback;
458    }
459 
460    if (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL)
461       bind = PIPE_BIND_DEPTH_STENCIL;
462    else
463       bind = PIPE_BIND_RENDER_TARGET;
464 
465    /* Choose the destination format by finding the best match
466     * for the format+type combo. */
467    dst_format = st_choose_matching_format(st, bind, format, type,
468                                           pack->SwapBytes);
469    if (dst_format == PIPE_FORMAT_NONE) {
470       goto fallback;
471    }
472 
473    if (st->pbo.download_enabled && pack->BufferObj) {
474       if (try_pbo_readpixels(st, strb,
475                              st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP,
476                              x, y, width, height,
477                              src_format, dst_format,
478                              pack, pixels))
479          return;
480    }
481 
482    if (needs_integer_signed_unsigned_conversion(ctx, format, type)) {
483       goto fallback;
484    }
485 
486    /* Cache a staging texture for back-to-back ReadPixels, to avoid CPU-GPU
487     * synchronization overhead.
488     */
489    dst = try_cached_readpixels(st, strb,
490                                st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP,
491                                width, height, format, src_format, dst_format);
492    if (dst) {
493       dst_x = x;
494       dst_y = y;
495    } else {
496       /* See if the texture format already matches the format and type,
497        * in which case the memcpy-based fast path will likely be used and
498        * we don't have to blit. */
499       if (_mesa_format_matches_format_and_type(rb->Format, format,
500                                                type, pack->SwapBytes, NULL)) {
501          goto fallback;
502       }
503 
504       dst = blit_to_staging(st, strb,
505                             st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP,
506                             x, y, width, height, format,
507                             src_format, dst_format);
508       if (!dst)
509          goto fallback;
510 
511       dst_x = 0;
512       dst_y = 0;
513    }
514 
515    /* map resources */
516    pixels = _mesa_map_pbo_dest(ctx, pack, pixels);
517 
518    map = pipe_transfer_map_3d(pipe, dst, 0, PIPE_MAP_READ,
519                               dst_x, dst_y, 0, width, height, 1, &tex_xfer);
520    if (!map) {
521       _mesa_unmap_pbo_dest(ctx, pack);
522       pipe_resource_reference(&dst, NULL);
523       goto fallback;
524    }
525 
526    /* memcpy data into a user buffer */
527    {
528       const uint bytesPerRow = width * util_format_get_blocksize(dst_format);
529       const int destStride = _mesa_image_row_stride(pack, width, format, type);
530       char *dest = _mesa_image_address2d(pack, pixels,
531                                          width, height, format,
532                                          type, 0, 0);
533 
534       if (tex_xfer->stride == bytesPerRow && destStride == bytesPerRow) {
535          memcpy(dest, map, bytesPerRow * height);
536       } else {
537          GLuint row;
538 
539          for (row = 0; row < (unsigned) height; row++) {
540             memcpy(dest, map, bytesPerRow);
541             map += tex_xfer->stride;
542             dest += destStride;
543          }
544       }
545    }
546 
547    pipe_transfer_unmap(pipe, tex_xfer);
548    _mesa_unmap_pbo_dest(ctx, pack);
549    pipe_resource_reference(&dst, NULL);
550    return;
551 
552 fallback:
553    _mesa_readpixels(ctx, x, y, width, height, format, type, pack, pixels);
554 }
555 
st_init_readpixels_functions(struct dd_function_table * functions)556 void st_init_readpixels_functions(struct dd_function_table *functions)
557 {
558    functions->ReadPixels = st_ReadPixels;
559 }
560