st/mesa: fix reversed copyimage canonical format
[mesa.git] / src / mesa / state_tracker / st_cb_copyimage.c
1 /*
2 * Copyright 2015 Advanced Micro Devices, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * on the rights to use, copy, modify, merge, publish, distribute, sub
8 * license, and/or sell copies of the Software, and to permit persons to whom
9 * the Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 * USE OR OTHER DEALINGS IN THE SOFTWARE.
22 *
23 */
24
25 #include "state_tracker/st_context.h"
26 #include "state_tracker/st_cb_copyimage.h"
27 #include "state_tracker/st_cb_fbo.h"
28 #include "state_tracker/st_texture.h"
29
30 #include "util/u_box.h"
31 #include "util/u_format.h"
32 #include "util/u_inlines.h"
33
34
35 /**
36 * Return an equivalent canonical format without "X" channels.
37 *
38 * Copying between incompatible formats is easier when the format is
39 * canonicalized, meaning that it is in a standard form.
40 *
41 * The returned format has the same component sizes and swizzles as
42 * the source format, the type is changed to UINT or UNORM, depending on
43 * which one has the most swizzle combinations in their group.
44 *
45 * If it's not an array format, return a memcpy-equivalent array format.
46 *
47 * The key feature is that swizzled versions of formats of the same
48 * component size always return the same component type.
49 *
50 * X returns A.
51 * Luminance, intensity, alpha, depth, stencil, and 8-bit and 16-bit packed
52 * formats are not supported. (same as ARB_copy_image)
53 */
54 static enum pipe_format
55 get_canonical_format(enum pipe_format format)
56 {
57 const struct util_format_description *desc =
58 util_format_description(format);
59
60 /* Packed formats. Return the equivalent array format. */
61 if (format == PIPE_FORMAT_R11G11B10_FLOAT ||
62 format == PIPE_FORMAT_R9G9B9E5_FLOAT)
63 return get_canonical_format(PIPE_FORMAT_R8G8B8A8_UINT);
64
65 if (desc->nr_channels == 4 &&
66 desc->channel[0].size == 10 &&
67 desc->channel[1].size == 10 &&
68 desc->channel[2].size == 10 &&
69 desc->channel[3].size == 2) {
70 if (desc->swizzle[0] == PIPE_SWIZZLE_X &&
71 desc->swizzle[1] == PIPE_SWIZZLE_Y &&
72 desc->swizzle[2] == PIPE_SWIZZLE_Z)
73 return get_canonical_format(PIPE_FORMAT_R8G8B8A8_UINT);
74
75 return PIPE_FORMAT_NONE;
76 }
77
78 #define RETURN_FOR_SWIZZLE1(x, format) \
79 if (desc->swizzle[0] == PIPE_SWIZZLE_##x) \
80 return format
81
82 #define RETURN_FOR_SWIZZLE2(x, y, format) \
83 if (desc->swizzle[0] == PIPE_SWIZZLE_##x && \
84 desc->swizzle[1] == PIPE_SWIZZLE_##y) \
85 return format
86
87 #define RETURN_FOR_SWIZZLE3(x, y, z, format) \
88 if (desc->swizzle[0] == PIPE_SWIZZLE_##x && \
89 desc->swizzle[1] == PIPE_SWIZZLE_##y && \
90 desc->swizzle[2] == PIPE_SWIZZLE_##z) \
91 return format
92
93 #define RETURN_FOR_SWIZZLE4(x, y, z, w, format) \
94 if (desc->swizzle[0] == PIPE_SWIZZLE_##x && \
95 desc->swizzle[1] == PIPE_SWIZZLE_##y && \
96 desc->swizzle[2] == PIPE_SWIZZLE_##z && \
97 desc->swizzle[3] == PIPE_SWIZZLE_##w) \
98 return format
99
100 /* Array formats. */
101 if (desc->is_array) {
102 switch (desc->nr_channels) {
103 case 1:
104 switch (desc->channel[0].size) {
105 case 8:
106 RETURN_FOR_SWIZZLE1(X, PIPE_FORMAT_R8_UINT);
107 break;
108
109 case 16:
110 RETURN_FOR_SWIZZLE1(X, PIPE_FORMAT_R16_UINT);
111 break;
112
113 case 32:
114 RETURN_FOR_SWIZZLE1(X, PIPE_FORMAT_R32_UINT);
115 break;
116 }
117 break;
118
119 case 2:
120 switch (desc->channel[0].size) {
121 case 8:
122 /* All formats in each group must be of the same type.
123 * We can't use UINT for R8G8 while using UNORM for G8R8.
124 */
125 RETURN_FOR_SWIZZLE2(X, Y, PIPE_FORMAT_R8G8_UNORM);
126 RETURN_FOR_SWIZZLE2(Y, X, PIPE_FORMAT_G8R8_UNORM);
127 break;
128
129 case 16:
130 RETURN_FOR_SWIZZLE2(X, Y, PIPE_FORMAT_R16G16_UNORM);
131 RETURN_FOR_SWIZZLE2(Y, X, PIPE_FORMAT_G16R16_UNORM);
132 break;
133
134 case 32:
135 RETURN_FOR_SWIZZLE2(X, Y, PIPE_FORMAT_R32G32_UINT);
136 break;
137 }
138 break;
139
140 case 3:
141 switch (desc->channel[0].size) {
142 case 8:
143 RETURN_FOR_SWIZZLE3(X, Y, Z, PIPE_FORMAT_R8G8B8_UINT);
144 break;
145
146 case 16:
147 RETURN_FOR_SWIZZLE3(X, Y, Z, PIPE_FORMAT_R16G16B16_UINT);
148 break;
149
150 case 32:
151 RETURN_FOR_SWIZZLE3(X, Y, Z, PIPE_FORMAT_R32G32B32_UINT);
152 break;
153 }
154 break;
155
156 case 4:
157 switch (desc->channel[0].size) {
158 case 8:
159 RETURN_FOR_SWIZZLE4(X, Y, Z, W, PIPE_FORMAT_R8G8B8A8_UNORM);
160 RETURN_FOR_SWIZZLE4(X, Y, Z, 1, PIPE_FORMAT_R8G8B8A8_UNORM);
161 RETURN_FOR_SWIZZLE4(Z, Y, X, W, PIPE_FORMAT_B8G8R8A8_UNORM);
162 RETURN_FOR_SWIZZLE4(Z, Y, X, 1, PIPE_FORMAT_B8G8R8A8_UNORM);
163 RETURN_FOR_SWIZZLE4(W, Z, Y, X, PIPE_FORMAT_A8B8G8R8_UNORM);
164 RETURN_FOR_SWIZZLE4(W, Z, Y, 1, PIPE_FORMAT_A8B8G8R8_UNORM);
165 RETURN_FOR_SWIZZLE4(Y, Z, W, X, PIPE_FORMAT_A8R8G8B8_UNORM);
166 RETURN_FOR_SWIZZLE4(Y, Z, W, 1, PIPE_FORMAT_A8R8G8B8_UNORM);
167 break;
168
169 case 16:
170 RETURN_FOR_SWIZZLE4(X, Y, Z, W, PIPE_FORMAT_R16G16B16A16_UINT);
171 RETURN_FOR_SWIZZLE4(X, Y, Z, 1, PIPE_FORMAT_R16G16B16A16_UINT);
172 break;
173
174 case 32:
175 RETURN_FOR_SWIZZLE4(X, Y, Z, W, PIPE_FORMAT_R32G32B32A32_UINT);
176 RETURN_FOR_SWIZZLE4(X, Y, Z, 1, PIPE_FORMAT_R32G32B32A32_UINT);
177 break;
178 }
179 }
180
181 assert(!"unknown array format");
182 return PIPE_FORMAT_NONE;
183 }
184
185 assert(!"unknown packed format");
186 return PIPE_FORMAT_NONE;
187 }
188
189 /**
190 * Return true if the swizzle is XYZW in case of a 4-channel format,
191 * XY in case of a 2-channel format, or X in case of a 1-channel format.
192 */
193 static bool
194 has_identity_swizzle(const struct util_format_description *desc)
195 {
196 int i;
197
198 for (i = 0; i < desc->nr_channels; i++)
199 if (desc->swizzle[i] != PIPE_SWIZZLE_X + i)
200 return false;
201
202 return true;
203 }
204
205 /**
206 * Return a canonical format for the given bits and channel size.
207 */
208 static enum pipe_format
209 canonical_format_from_bits(unsigned bits, unsigned channel_size)
210 {
211 switch (bits) {
212 case 8:
213 if (channel_size == 8)
214 return get_canonical_format(PIPE_FORMAT_R8_UINT);
215 break;
216
217 case 16:
218 if (channel_size == 8)
219 return get_canonical_format(PIPE_FORMAT_R8G8_UINT);
220 if (channel_size == 16)
221 return get_canonical_format(PIPE_FORMAT_R16_UINT);
222 break;
223
224 case 32:
225 if (channel_size == 8)
226 return get_canonical_format(PIPE_FORMAT_R8G8B8A8_UINT);
227 if (channel_size == 16)
228 return get_canonical_format(PIPE_FORMAT_R16G16_UINT);
229 if (channel_size == 32)
230 return get_canonical_format(PIPE_FORMAT_R32_UINT);
231 break;
232
233 case 64:
234 if (channel_size == 16)
235 return get_canonical_format(PIPE_FORMAT_R16G16B16A16_UINT);
236 if (channel_size == 32)
237 return get_canonical_format(PIPE_FORMAT_R32G32_UINT);
238 break;
239
240 case 128:
241 if (channel_size == 32)
242 return get_canonical_format(PIPE_FORMAT_R32G32B32A32_UINT);
243 break;
244 }
245
246 assert(!"impossible format");
247 return PIPE_FORMAT_NONE;
248 }
249
250 static void
251 blit(struct pipe_context *pipe,
252 struct pipe_resource *dst,
253 enum pipe_format dst_format,
254 unsigned dst_level,
255 unsigned dstx, unsigned dsty, unsigned dstz,
256 struct pipe_resource *src,
257 enum pipe_format src_format,
258 unsigned src_level,
259 const struct pipe_box *src_box)
260 {
261 struct pipe_blit_info blit = {{0}};
262
263 blit.src.resource = src;
264 blit.dst.resource = dst;
265 blit.src.format = src_format;
266 blit.dst.format = dst_format;
267 blit.src.level = src_level;
268 blit.dst.level = dst_level;
269 blit.src.box = *src_box;
270 u_box_3d(dstx, dsty, dstz, src_box->width, src_box->height,
271 src_box->depth, &blit.dst.box);
272 blit.mask = PIPE_MASK_RGBA;
273 blit.filter = PIPE_TEX_FILTER_NEAREST;
274
275 pipe->blit(pipe, &blit);
276 }
277
278 static void
279 swizzled_copy(struct pipe_context *pipe,
280 struct pipe_resource *dst,
281 unsigned dst_level,
282 unsigned dstx, unsigned dsty, unsigned dstz,
283 struct pipe_resource *src,
284 unsigned src_level,
285 const struct pipe_box *src_box)
286 {
287 const struct util_format_description *src_desc, *dst_desc;
288 unsigned bits;
289 enum pipe_format blit_src_format, blit_dst_format;
290
291 /* Get equivalent canonical formats. Those are always array formats and
292 * copying between compatible canonical formats behaves either like
293 * memcpy or like swizzled memcpy. The idea is that we won't have to care
294 * about the channel type from this point on.
295 * Only the swizzle and channel size.
296 */
297 blit_src_format = get_canonical_format(src->format);
298 blit_dst_format = get_canonical_format(dst->format);
299
300 assert(blit_src_format != PIPE_FORMAT_NONE);
301 assert(blit_dst_format != PIPE_FORMAT_NONE);
302
303 src_desc = util_format_description(blit_src_format);
304 dst_desc = util_format_description(blit_dst_format);
305
306 assert(src_desc->block.bits == dst_desc->block.bits);
307 bits = src_desc->block.bits;
308
309 if (dst_desc->channel[0].size == src_desc->channel[0].size) {
310 /* Only the swizzle is different, which means we can just blit,
311 * e.g. RGBA -> BGRA.
312 */
313 } else if (has_identity_swizzle(src_desc)) {
314 /* Src is unswizzled and dst can be swizzled, so src is typecast
315 * to an equivalent dst-compatible format.
316 * e.g. R32 -> BGRA8 is realized as RGBA8 -> BGRA8
317 */
318 blit_src_format =
319 canonical_format_from_bits(bits, dst_desc->channel[0].size);
320 } else if (has_identity_swizzle(dst_desc)) {
321 /* Dst is unswizzled and src can be swizzled, so dst is typecast
322 * to an equivalent src-compatible format.
323 * e.g. BGRA8 -> R32 is realized as BGRA8 -> RGBA8
324 */
325 blit_dst_format =
326 canonical_format_from_bits(bits, src_desc->channel[0].size);
327 } else {
328 assert(!"This should have been handled by handle_complex_copy.");
329 return;
330 }
331
332 blit(pipe, dst, blit_dst_format, dst_level, dstx, dsty, dstz,
333 src, blit_src_format, src_level, src_box);
334 }
335
336 static bool
337 same_size_and_swizzle(const struct util_format_description *d1,
338 const struct util_format_description *d2)
339 {
340 int i;
341
342 if (d1->layout != d2->layout ||
343 d1->nr_channels != d2->nr_channels ||
344 d1->is_array != d2->is_array)
345 return false;
346
347 for (i = 0; i < d1->nr_channels; i++) {
348 if (d1->channel[i].size != d2->channel[i].size)
349 return false;
350
351 if (d1->swizzle[i] <= PIPE_SWIZZLE_W &&
352 d2->swizzle[i] <= PIPE_SWIZZLE_W &&
353 d1->swizzle[i] != d2->swizzle[i])
354 return false;
355 }
356
357 return true;
358 }
359
360 static struct pipe_resource *
361 create_texture(struct pipe_screen *screen, enum pipe_format format,
362 unsigned nr_samples,
363 unsigned width, unsigned height, unsigned depth)
364 {
365 struct pipe_resource templ;
366
367 memset(&templ, 0, sizeof(templ));
368 templ.format = format;
369 templ.width0 = width;
370 templ.height0 = height;
371 templ.depth0 = 1;
372 templ.array_size = depth;
373 templ.nr_samples = nr_samples;
374 templ.usage = PIPE_USAGE_DEFAULT;
375 templ.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET;
376
377 if (depth > 1)
378 templ.target = PIPE_TEXTURE_2D_ARRAY;
379 else
380 templ.target = PIPE_TEXTURE_2D;
381
382 return screen->resource_create(screen, &templ);
383 }
384
385 /**
386 * Handle complex format conversions using 2 blits with a temporary texture
387 * in between, e.g. blitting from B10G10R10A2 to G16R16.
388 *
389 * This example is implemented this way:
390 * 1) First, blit from B10G10R10A2 to R10G10B10A2, which is canonical, so it
391 * can be reinterpreted as a different canonical format of the same bpp,
392 * such as R16G16. This blit only swaps R and B 10-bit components.
393 * 2) Finally, blit the result, which is R10G10B10A2, as R16G16 to G16R16.
394 * This blit only swaps R and G 16-bit components.
395 */
396 static bool
397 handle_complex_copy(struct pipe_context *pipe,
398 struct pipe_resource *dst,
399 unsigned dst_level,
400 unsigned dstx, unsigned dsty, unsigned dstz,
401 struct pipe_resource *src,
402 unsigned src_level,
403 const struct pipe_box *src_box,
404 enum pipe_format noncanon_format,
405 enum pipe_format canon_format)
406 {
407 struct pipe_box temp_box;
408 struct pipe_resource *temp = NULL;
409 const struct util_format_description *src_desc, *dst_desc;
410 const struct util_format_description *canon_desc, *noncanon_desc;
411 bool src_is_canon;
412 bool src_is_noncanon;
413 bool dst_is_canon;
414 bool dst_is_noncanon;
415
416 src_desc = util_format_description(src->format);
417 dst_desc = util_format_description(dst->format);
418 canon_desc = util_format_description(canon_format);
419 noncanon_desc = util_format_description(noncanon_format);
420
421 src_is_canon = same_size_and_swizzle(src_desc, canon_desc);
422 dst_is_canon = same_size_and_swizzle(dst_desc, canon_desc);
423 src_is_noncanon = same_size_and_swizzle(src_desc, noncanon_desc);
424 dst_is_noncanon = same_size_and_swizzle(dst_desc, noncanon_desc);
425
426 if (src_is_noncanon) {
427 /* Simple case - only types differ (e.g. UNORM and UINT). */
428 if (dst_is_noncanon) {
429 blit(pipe, dst, noncanon_format, dst_level, dstx, dsty, dstz, src,
430 noncanon_format, src_level, src_box);
431 return true;
432 }
433
434 /* Simple case - only types and swizzles differ. */
435 if (dst_is_canon) {
436 blit(pipe, dst, canon_format, dst_level, dstx, dsty, dstz, src,
437 noncanon_format, src_level, src_box);
438 return true;
439 }
440
441 /* Use the temporary texture. Src is converted to a canonical format,
442 * then proceed the generic swizzled_copy.
443 */
444 temp = create_texture(pipe->screen, canon_format, src->nr_samples,
445 src_box->width,
446 src_box->height, src_box->depth);
447
448 u_box_3d(0, 0, 0, src_box->width, src_box->height, src_box->depth,
449 &temp_box);
450
451 blit(pipe, temp, canon_format, 0, 0, 0, 0, src, noncanon_format,
452 src_level, src_box);
453 swizzled_copy(pipe, dst, dst_level, dstx, dsty, dstz, temp, 0,
454 &temp_box);
455 pipe_resource_reference(&temp, NULL);
456 return true;
457 }
458
459 if (dst_is_noncanon) {
460 /* Simple case - only types and swizzles differ. */
461 if (src_is_canon) {
462 blit(pipe, dst, noncanon_format, dst_level, dstx, dsty, dstz, src,
463 canon_format, src_level, src_box);
464 return true;
465 }
466
467 /* Use the temporary texture. First, use the generic copy, but use
468 * a canonical format in the destination. Then convert */
469 temp = create_texture(pipe->screen, canon_format, dst->nr_samples,
470 src_box->width,
471 src_box->height, src_box->depth);
472
473 u_box_3d(0, 0, 0, src_box->width, src_box->height, src_box->depth,
474 &temp_box);
475
476 swizzled_copy(pipe, temp, 0, 0, 0, 0, src, src_level, src_box);
477 blit(pipe, dst, noncanon_format, dst_level, dstx, dsty, dstz, temp,
478 canon_format, 0, &temp_box);
479 pipe_resource_reference(&temp, NULL);
480 return true;
481 }
482
483 return false;
484 }
485
486 static void
487 copy_image(struct pipe_context *pipe,
488 struct pipe_resource *dst,
489 unsigned dst_level,
490 unsigned dstx, unsigned dsty, unsigned dstz,
491 struct pipe_resource *src,
492 unsigned src_level,
493 const struct pipe_box *src_box)
494 {
495 if (src->format == dst->format ||
496 util_format_is_compressed(src->format) ||
497 util_format_is_compressed(dst->format)) {
498 pipe->resource_copy_region(pipe, dst, dst_level, dstx, dsty, dstz,
499 src, src_level, src_box);
500 return;
501 }
502
503 /* Copying to/from B10G10R10*2 needs 2 blits with R10G10B10A2
504 * as a temporary texture in between.
505 */
506 if (handle_complex_copy(pipe, dst, dst_level, dstx, dsty, dstz, src,
507 src_level, src_box, PIPE_FORMAT_B10G10R10A2_UINT,
508 PIPE_FORMAT_R10G10B10A2_UINT))
509 return;
510
511 /* Copying to/from G8R8 needs 2 blits with R8G8 as a temporary texture
512 * in between.
513 */
514 if (handle_complex_copy(pipe, dst, dst_level, dstx, dsty, dstz, src,
515 src_level, src_box, PIPE_FORMAT_G8R8_UNORM,
516 PIPE_FORMAT_R8G8_UNORM))
517 return;
518
519 /* Copying to/from G16R16 needs 2 blits with R16G16 as a temporary texture
520 * in between.
521 */
522 if (handle_complex_copy(pipe, dst, dst_level, dstx, dsty, dstz, src,
523 src_level, src_box, PIPE_FORMAT_G16R16_UNORM,
524 PIPE_FORMAT_R16G16_UNORM))
525 return;
526
527 /* Only allow non-identity swizzling on RGBA8 formats. */
528
529 /* Simple copy, memcpy with swizzling, no format conversion. */
530 swizzled_copy(pipe, dst, dst_level, dstx, dsty, dstz, src, src_level,
531 src_box);
532 }
533
534 static void
535 st_CopyImageSubData(struct gl_context *ctx,
536 struct gl_texture_image *src_image,
537 struct gl_renderbuffer *src_renderbuffer,
538 int src_x, int src_y, int src_z,
539 struct gl_texture_image *dst_image,
540 struct gl_renderbuffer *dst_renderbuffer,
541 int dst_x, int dst_y, int dst_z,
542 int src_width, int src_height)
543 {
544 struct st_context *st = st_context(ctx);
545 struct pipe_context *pipe = st->pipe;
546 struct pipe_resource *src_res, *dst_res;
547 struct pipe_box box;
548 int src_level, dst_level;
549
550 if (src_image) {
551 struct st_texture_image *src = st_texture_image(src_image);
552 src_res = src->pt;
553 src_level = src_image->Level;
554 src_z += src_image->Face;
555 if (src_image->TexObject->Immutable) {
556 src_level += src_image->TexObject->MinLevel;
557 src_z += src_image->TexObject->MinLayer;
558 }
559 } else {
560 struct st_renderbuffer *src = st_renderbuffer(src_renderbuffer);
561 src_res = src->texture;
562 src_level = 0;
563 }
564
565 if (dst_image) {
566 struct st_texture_image *dst = st_texture_image(dst_image);
567 dst_res = dst->pt;
568 dst_level = dst_image->Level;
569 dst_z += dst_image->Face;
570 if (dst_image->TexObject->Immutable) {
571 dst_level += dst_image->TexObject->MinLevel;
572 dst_z += dst_image->TexObject->MinLayer;
573 }
574 } else {
575 struct st_renderbuffer *dst = st_renderbuffer(dst_renderbuffer);
576 dst_res = dst->texture;
577 dst_level = 0;
578 }
579
580 u_box_2d_zslice(src_x, src_y, src_z, src_width, src_height, &box);
581
582 copy_image(pipe, dst_res, dst_level, dst_x, dst_y, dst_z,
583 src_res, src_level, &box);
584 }
585
586 void
587 st_init_copy_image_functions(struct dd_function_table *functions)
588 {
589 functions->CopyImageSubData = st_CopyImageSubData;
590 }