gallium,st/mesa: don't use blit-based transfers with software rasterizers
[mesa.git] / src / mesa / state_tracker / st_cb_readpixels.c
1 /**************************************************************************
2 *
3 * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
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 TUNGSTEN GRAPHICS 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/image.h"
29 #include "main/pbo.h"
30 #include "main/imports.h"
31 #include "main/readpix.h"
32 #include "main/enums.h"
33 #include "main/framebuffer.h"
34 #include "util/u_inlines.h"
35 #include "util/u_format.h"
36
37 #include "st_cb_fbo.h"
38 #include "st_atom.h"
39 #include "st_context.h"
40 #include "st_cb_bitmap.h"
41 #include "st_cb_readpixels.h"
42 #include "state_tracker/st_cb_texture.h"
43 #include "state_tracker/st_format.h"
44 #include "state_tracker/st_texture.h"
45
46
47 /**
48 * This uses a blit to copy the read buffer to a texture format which matches
49 * the format and type combo and then a fast read-back is done using memcpy.
50 * We can do arbitrary X/Y/Z/W/0/1 swizzling here as long as there is
51 * a format which matches the swizzling.
52 *
53 * If such a format isn't available, we fall back to _mesa_readpixels.
54 *
55 * NOTE: Some drivers use a blit to convert between tiled and linear
56 * texture layouts during texture uploads/downloads, so the blit
57 * we do here should be free in such cases.
58 */
59 static void
60 st_readpixels(struct gl_context *ctx, GLint x, GLint y,
61 GLsizei width, GLsizei height,
62 GLenum format, GLenum type,
63 const struct gl_pixelstore_attrib *pack,
64 GLvoid *pixels)
65 {
66 struct st_context *st = st_context(ctx);
67 struct gl_renderbuffer *rb =
68 _mesa_get_read_renderbuffer_for_format(ctx, format);
69 struct st_renderbuffer *strb = st_renderbuffer(rb);
70 struct pipe_context *pipe = st->pipe;
71 struct pipe_screen *screen = pipe->screen;
72 struct pipe_resource *src;
73 struct pipe_resource *dst = NULL;
74 struct pipe_resource dst_templ;
75 enum pipe_format dst_format, src_format;
76 struct pipe_blit_info blit;
77 unsigned bind = PIPE_BIND_TRANSFER_READ;
78 struct pipe_transfer *tex_xfer;
79 ubyte *map = NULL;
80
81 /* Validate state (to be sure we have up-to-date framebuffer surfaces)
82 * and flush the bitmap cache prior to reading. */
83 st_validate_state(st);
84 st_flush_bitmap_cache(st);
85
86 if (!st->prefer_blit_based_texture_transfer) {
87 goto fallback;
88 }
89
90 /* This must be done after state validation. */
91 src = strb->texture;
92
93 /* XXX Fallback for depth-stencil formats due to an incomplete
94 * stencil blit implementation in some drivers. */
95 if (format == GL_DEPTH_STENCIL) {
96 goto fallback;
97 }
98
99 /* We are creating a texture of the size of the region being read back.
100 * Need to check for NPOT texture support. */
101 if (!screen->get_param(screen, PIPE_CAP_NPOT_TEXTURES) &&
102 (!util_is_power_of_two(width) ||
103 !util_is_power_of_two(height))) {
104 goto fallback;
105 }
106
107 /* If the base internal format and the texture format don't match, we have
108 * to use the slow path. */
109 if (rb->_BaseFormat !=
110 _mesa_get_format_base_format(rb->Format)) {
111 goto fallback;
112 }
113
114 /* See if the texture format already matches the format and type,
115 * in which case the memcpy-based fast path will likely be used and
116 * we don't have to blit. */
117 if (_mesa_format_matches_format_and_type(rb->Format, format,
118 type, pack->SwapBytes)) {
119 goto fallback;
120 }
121
122 if (_mesa_readpixels_needs_slow_path(ctx, format, type, GL_TRUE)) {
123 goto fallback;
124 }
125
126 /* Convert the source format to what is expected by ReadPixels
127 * and see if it's supported. */
128 src_format = util_format_linear(src->format);
129 src_format = util_format_luminance_to_red(src_format);
130 src_format = util_format_intensity_to_red(src_format);
131
132 if (!src_format ||
133 !screen->is_format_supported(screen, src_format, src->target,
134 src->nr_samples,
135 PIPE_BIND_SAMPLER_VIEW)) {
136 printf("fallback: src format unsupported %s\n", util_format_short_name(src_format));
137 goto fallback;
138 }
139
140 if (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL)
141 bind |= PIPE_BIND_DEPTH_STENCIL;
142 else
143 bind |= PIPE_BIND_RENDER_TARGET;
144
145 /* Choose the destination format by finding the best match
146 * for the format+type combo. */
147 dst_format = st_choose_matching_format(screen, bind, format, type,
148 pack->SwapBytes);
149 if (dst_format == PIPE_FORMAT_NONE) {
150 printf("fallback: no matching format for %s, %s\n",
151 _mesa_lookup_enum_by_nr(format), _mesa_lookup_enum_by_nr(type));
152 goto fallback;
153 }
154
155 /* create the destination texture */
156 memset(&dst_templ, 0, sizeof(dst_templ));
157 dst_templ.target = PIPE_TEXTURE_2D;
158 dst_templ.format = dst_format;
159 dst_templ.bind = bind;
160 dst_templ.usage = PIPE_USAGE_STAGING;
161
162 st_gl_texture_dims_to_pipe_dims(GL_TEXTURE_2D, width, height, 1,
163 &dst_templ.width0, &dst_templ.height0,
164 &dst_templ.depth0, &dst_templ.array_size);
165
166 dst = screen->resource_create(screen, &dst_templ);
167 if (!dst) {
168 goto fallback;
169 }
170
171 blit.src.resource = src;
172 blit.src.level = strb->rtt_level;
173 blit.src.format = src_format;
174 blit.dst.resource = dst;
175 blit.dst.level = 0;
176 blit.dst.format = dst->format;
177 blit.src.box.x = x;
178 blit.dst.box.x = 0;
179 blit.src.box.y = y;
180 blit.dst.box.y = 0;
181 blit.src.box.z = strb->rtt_face + strb->rtt_slice;
182 blit.dst.box.z = 0;
183 blit.src.box.width = blit.dst.box.width = width;
184 blit.src.box.height = blit.dst.box.height = height;
185 blit.src.box.depth = blit.dst.box.depth = 1;
186 blit.mask = st_get_blit_mask(rb->_BaseFormat, format);
187 blit.filter = PIPE_TEX_FILTER_NEAREST;
188 blit.scissor_enable = FALSE;
189
190 if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) {
191 blit.src.box.y = rb->Height - blit.src.box.y;
192 blit.src.box.height = -blit.src.box.height;
193 }
194
195 /* blit */
196 st->pipe->blit(st->pipe, &blit);
197
198 /* map resources */
199 pixels = _mesa_map_pbo_dest(ctx, pack, pixels);
200
201 map = pipe_transfer_map_3d(pipe, dst, 0, PIPE_TRANSFER_READ,
202 0, 0, 0, width, height, 1, &tex_xfer);
203 if (!map) {
204 _mesa_unmap_pbo_dest(ctx, pack);
205 pipe_resource_reference(&dst, NULL);
206 goto fallback;
207 }
208
209 /* memcpy data into a user buffer */
210 {
211 const uint bytesPerRow = width * util_format_get_blocksize(dst_format);
212 GLuint row;
213
214 for (row = 0; row < height; row++) {
215 GLvoid *dest = _mesa_image_address3d(pack, pixels,
216 width, height, format,
217 type, 0, row, 0);
218 memcpy(dest, map, bytesPerRow);
219 map += tex_xfer->stride;
220 }
221 }
222
223 pipe_transfer_unmap(pipe, tex_xfer);
224 _mesa_unmap_pbo_dest(ctx, pack);
225 pipe_resource_reference(&dst, NULL);
226 return;
227
228 fallback:
229 _mesa_readpixels(ctx, x, y, width, height, format, type, pack, pixels);
230 }
231
232 void st_init_readpixels_functions(struct dd_function_table *functions)
233 {
234 functions->ReadPixels = st_readpixels;
235 }