r600g: introduce a per-driver resource flag for transfers.
[mesa.git] / src / gallium / drivers / r600 / r600_texture.c
1 /*
2 * Copyright 2010 Jerome Glisse <glisse@freedesktop.org>
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 * Authors:
24 * Jerome Glisse
25 * Corbin Simpson
26 */
27 #include <errno.h>
28 #include <pipe/p_screen.h>
29 #include <util/u_format.h>
30 #include <util/u_math.h>
31 #include <util/u_inlines.h>
32 #include <util/u_memory.h>
33 #include "state_tracker/drm_driver.h"
34 #include "r600_pipe.h"
35 #include "r600_resource.h"
36 #include "r600_state_inlines.h"
37 #include "r600d.h"
38 #include "r600_formats.h"
39
40 extern struct u_resource_vtbl r600_texture_vtbl;
41
42 /* Copy from a tiled texture to a detiled one. */
43 static void r600_copy_from_tiled_texture(struct pipe_context *ctx, struct r600_transfer *rtransfer)
44 {
45 struct pipe_transfer *transfer = (struct pipe_transfer*)rtransfer;
46 struct pipe_resource *texture = transfer->resource;
47 struct pipe_subresource subdst;
48
49 subdst.face = 0;
50 subdst.level = 0;
51 ctx->resource_copy_region(ctx, rtransfer->linear_texture,
52 subdst, 0, 0, 0, texture, transfer->sr,
53 transfer->box.x, transfer->box.y, transfer->box.z,
54 transfer->box.width, transfer->box.height);
55 }
56
57
58 /* Copy from a detiled texture to a tiled one. */
59 static void r600_copy_into_tiled_texture(struct pipe_context *ctx, struct r600_transfer *rtransfer)
60 {
61 struct pipe_transfer *transfer = (struct pipe_transfer*)rtransfer;
62 struct pipe_resource *texture = transfer->resource;
63 struct pipe_subresource subsrc;
64
65 subsrc.face = 0;
66 subsrc.level = 0;
67 ctx->resource_copy_region(ctx, texture, transfer->sr,
68 transfer->box.x, transfer->box.y, transfer->box.z,
69 rtransfer->linear_texture, subsrc,
70 0, 0, 0,
71 transfer->box.width, transfer->box.height);
72
73 ctx->flush(ctx, 0, NULL);
74 }
75
76 static unsigned r600_texture_get_offset(struct r600_resource_texture *rtex,
77 unsigned level, unsigned zslice,
78 unsigned face)
79 {
80 unsigned offset = rtex->offset[level];
81
82 switch (rtex->resource.base.b.target) {
83 case PIPE_TEXTURE_3D:
84 assert(face == 0);
85 return offset + zslice * rtex->layer_size[level];
86 case PIPE_TEXTURE_CUBE:
87 assert(zslice == 0);
88 return offset + face * rtex->layer_size[level];
89 default:
90 assert(zslice == 0 && face == 0);
91 return offset;
92 }
93 }
94
95 static unsigned r600_get_pixel_alignment(struct pipe_screen *screen,
96 enum pipe_format format,
97 unsigned array_mode)
98 {
99 return 64;
100 }
101
102 static unsigned r600_get_height_alignment(struct pipe_screen *screen,
103 unsigned array_mode)
104 {
105 return 1;
106 }
107
108 static unsigned mip_minify(unsigned size, unsigned level)
109 {
110 unsigned val;
111 val = u_minify(size, level);
112 if (level > 0)
113 val = util_next_power_of_two(val);
114 return val;
115 }
116
117 static unsigned r600_texture_get_stride(struct pipe_screen *screen,
118 struct r600_resource_texture *rtex,
119 unsigned level)
120 {
121 struct pipe_resource *ptex = &rtex->resource.base.b;
122 struct radeon *radeon = (struct radeon *)screen->winsys;
123 enum chip_class chipc = r600_get_family_class(radeon);
124 unsigned width, stride, tile_width;
125
126 if (rtex->pitch_override)
127 return rtex->pitch_override;
128
129 width = mip_minify(ptex->width0, level);
130 if (util_format_is_plain(ptex->format)) {
131 tile_width = r600_get_pixel_alignment(screen, ptex->format,
132 rtex->array_mode[level]);
133 width = align(width, tile_width);
134 }
135 stride = util_format_get_stride(ptex->format, width);
136 if (chipc == EVERGREEN)
137 stride = align(stride, 512);
138 else
139 stride = align(stride, 256);
140 return stride;
141 }
142
143 static unsigned r600_texture_get_nblocksy(struct pipe_screen *screen,
144 struct r600_resource_texture *rtex,
145 unsigned level)
146 {
147 struct pipe_resource *ptex = &rtex->resource.base.b;
148 unsigned height, tile_height;
149
150 height = mip_minify(ptex->height0, level);
151 if (util_format_is_plain(ptex->format)) {
152 tile_height = r600_get_height_alignment(screen,
153 rtex->array_mode[level]);
154 height = align(height, tile_height);
155 }
156 return util_format_get_nblocksy(ptex->format, height);
157 }
158
159 /* Get a width in pixels from a stride in bytes. */
160 static unsigned pitch_to_width(enum pipe_format format,
161 unsigned pitch_in_bytes)
162 {
163 return (pitch_in_bytes / util_format_get_blocksize(format)) *
164 util_format_get_blockwidth(format);
165 }
166
167 static void r600_texture_set_array_mode(struct pipe_screen *screen,
168 struct r600_resource_texture *rtex,
169 unsigned level, unsigned array_mode)
170 {
171 rtex->array_mode[level] = array_mode;
172 }
173
174 static void r600_setup_miptree(struct pipe_screen *screen,
175 struct r600_resource_texture *rtex,
176 unsigned array_mode)
177 {
178 struct pipe_resource *ptex = &rtex->resource.base.b;
179 struct radeon *radeon = (struct radeon *)screen->winsys;
180 enum chip_class chipc = r600_get_family_class(radeon);
181 unsigned pitch, size, layer_size, i, offset;
182 unsigned nblocksy;
183
184 for (i = 0, offset = 0; i <= ptex->last_level; i++) {
185 r600_texture_set_array_mode(screen, rtex, i, array_mode);
186
187 pitch = r600_texture_get_stride(screen, rtex, i);
188 nblocksy = r600_texture_get_nblocksy(screen, rtex, i);
189
190 layer_size = pitch * nblocksy;
191
192 if (ptex->target == PIPE_TEXTURE_CUBE) {
193 if (chipc >= R700)
194 size = layer_size * 8;
195 else
196 size = layer_size * 6;
197 }
198 else
199 size = layer_size * u_minify(ptex->depth0, i);
200 rtex->offset[i] = offset;
201 rtex->layer_size[i] = layer_size;
202 rtex->pitch_in_bytes[i] = pitch;
203 rtex->pitch_in_pixels[i] = pitch_to_width(ptex->format, pitch);
204 offset += size;
205 }
206 rtex->size = offset;
207 }
208
209 static struct r600_resource_texture *
210 r600_texture_create_object(struct pipe_screen *screen,
211 const struct pipe_resource *base,
212 unsigned array_mode,
213 unsigned pitch_in_bytes_override,
214 unsigned max_buffer_size,
215 struct r600_bo *bo)
216 {
217 struct r600_resource_texture *rtex;
218 struct r600_resource *resource;
219 struct radeon *radeon = (struct radeon *)screen->winsys;
220
221 rtex = CALLOC_STRUCT(r600_resource_texture);
222 if (rtex == NULL)
223 return NULL;
224
225 resource = &rtex->resource;
226 resource->base.b = *base;
227 resource->base.vtbl = &r600_texture_vtbl;
228 pipe_reference_init(&resource->base.b.reference, 1);
229 resource->base.b.screen = screen;
230 resource->bo = bo;
231 resource->domain = r600_domain_from_usage(resource->base.b.bind);
232 rtex->pitch_override = pitch_in_bytes_override;
233
234 if (array_mode)
235 rtex->tiled = 1;
236 r600_setup_miptree(screen, rtex, array_mode);
237
238 resource->size = rtex->size;
239
240 if (!resource->bo) {
241 resource->bo = r600_bo(radeon, rtex->size, 4096, 0);
242 if (!resource->bo) {
243 FREE(rtex);
244 return NULL;
245 }
246 }
247 return rtex;
248 }
249
250 struct pipe_resource *r600_texture_create(struct pipe_screen *screen,
251 const struct pipe_resource *templ)
252 {
253 unsigned array_mode = 0;
254
255 return (struct pipe_resource *)r600_texture_create_object(screen, templ, array_mode,
256 0, 0, NULL);
257
258 }
259
260 static void r600_texture_destroy(struct pipe_screen *screen,
261 struct pipe_resource *ptex)
262 {
263 struct r600_resource_texture *rtex = (struct r600_resource_texture*)ptex;
264 struct r600_resource *resource = &rtex->resource;
265 struct radeon *radeon = (struct radeon *)screen->winsys;
266
267 if (rtex->flushed_depth_texture)
268 pipe_resource_reference((struct pipe_resource **)&rtex->flushed_depth_texture, NULL);
269
270 if (resource->bo) {
271 r600_bo_reference(radeon, &resource->bo, NULL);
272 }
273 FREE(rtex);
274 }
275
276 static struct pipe_surface *r600_get_tex_surface(struct pipe_screen *screen,
277 struct pipe_resource *texture,
278 unsigned face, unsigned level,
279 unsigned zslice, unsigned flags)
280 {
281 struct r600_resource_texture *rtex = (struct r600_resource_texture*)texture;
282 struct r600_surface *surface = CALLOC_STRUCT(r600_surface);
283 unsigned offset, tile_height;
284
285 if (surface == NULL)
286 return NULL;
287 offset = r600_texture_get_offset(rtex, level, zslice, face);
288 pipe_reference_init(&surface->base.reference, 1);
289 pipe_resource_reference(&surface->base.texture, texture);
290 surface->base.format = texture->format;
291 surface->base.width = mip_minify(texture->width0, level);
292 surface->base.height = mip_minify(texture->height0, level);
293 surface->base.offset = offset;
294 surface->base.usage = flags;
295 surface->base.zslice = zslice;
296 surface->base.texture = texture;
297 surface->base.face = face;
298 surface->base.level = level;
299
300 tile_height = r600_get_height_alignment(screen, rtex->array_mode[level]);
301 surface->aligned_height = align(surface->base.height, tile_height);
302 return &surface->base;
303 }
304
305 static void r600_tex_surface_destroy(struct pipe_surface *surface)
306 {
307 pipe_resource_reference(&surface->texture, NULL);
308 FREE(surface);
309 }
310
311
312 struct pipe_resource *r600_texture_from_handle(struct pipe_screen *screen,
313 const struct pipe_resource *templ,
314 struct winsys_handle *whandle)
315 {
316 struct radeon *rw = (struct radeon*)screen->winsys;
317 struct r600_bo *bo = NULL;
318 unsigned array_mode = 0;
319
320 /* Support only 2D textures without mipmaps */
321 if ((templ->target != PIPE_TEXTURE_2D && templ->target != PIPE_TEXTURE_RECT) ||
322 templ->depth0 != 1 || templ->last_level != 0)
323 return NULL;
324
325 bo = r600_bo_handle(rw, whandle->handle, &array_mode);
326 if (bo == NULL) {
327 return NULL;
328 }
329
330 return (struct pipe_resource *)r600_texture_create_object(screen, templ, array_mode,
331 whandle->stride,
332 0,
333 bo);
334 }
335
336 static unsigned int r600_texture_is_referenced(struct pipe_context *context,
337 struct pipe_resource *texture,
338 unsigned face, unsigned level)
339 {
340 /* FIXME */
341 return PIPE_REFERENCED_FOR_READ | PIPE_REFERENCED_FOR_WRITE;
342 }
343
344 int (*r600_blit_uncompress_depth_ptr)(struct pipe_context *ctx, struct r600_resource_texture *texture);
345
346 int r600_texture_depth_flush(struct pipe_context *ctx,
347 struct pipe_resource *texture)
348 {
349 struct r600_resource_texture *rtex = (struct r600_resource_texture*)texture;
350 struct pipe_resource resource;
351
352 if (rtex->flushed_depth_texture)
353 goto out;
354
355 resource.target = PIPE_TEXTURE_2D;
356 resource.format = texture->format;
357 resource.width0 = texture->width0;
358 resource.height0 = texture->height0;
359 resource.depth0 = 1;
360 resource.last_level = 0;
361 resource.nr_samples = 0;
362 resource.usage = PIPE_USAGE_DYNAMIC;
363 resource.bind = 0;
364 resource.flags = R600_RESOURCE_FLAG_TRANSFER;
365
366 resource.bind |= PIPE_BIND_DEPTH_STENCIL;
367
368 rtex->flushed_depth_texture = (struct r600_resource_texture *)ctx->screen->resource_create(ctx->screen, &resource);
369 if (rtex->flushed_depth_texture == NULL) {
370 R600_ERR("failed to create temporary texture to hold untiled copy\n");
371 return -ENOMEM;
372 }
373
374 out:
375 r600_blit_uncompress_depth_ptr(ctx, rtex);
376 return 0;
377 }
378
379 struct pipe_transfer* r600_texture_get_transfer(struct pipe_context *ctx,
380 struct pipe_resource *texture,
381 struct pipe_subresource sr,
382 unsigned usage,
383 const struct pipe_box *box)
384 {
385 struct r600_resource_texture *rtex = (struct r600_resource_texture*)texture;
386 struct pipe_resource resource;
387 struct r600_transfer *trans;
388 int r;
389
390 trans = CALLOC_STRUCT(r600_transfer);
391 if (trans == NULL)
392 return NULL;
393 pipe_resource_reference(&trans->transfer.resource, texture);
394 trans->transfer.sr = sr;
395 trans->transfer.usage = usage;
396 trans->transfer.box = *box;
397 if (rtex->depth) {
398 r = r600_texture_depth_flush(ctx, texture);
399 if (r < 0) {
400 R600_ERR("failed to create temporary texture to hold untiled copy\n");
401 pipe_resource_reference(&trans->transfer.resource, NULL);
402 FREE(trans);
403 return NULL;
404 }
405 } else if (rtex->tiled) {
406 resource.target = PIPE_TEXTURE_2D;
407 resource.format = texture->format;
408 resource.width0 = box->width;
409 resource.height0 = box->height;
410 resource.depth0 = 1;
411 resource.last_level = 0;
412 resource.nr_samples = 0;
413 resource.usage = PIPE_USAGE_DYNAMIC;
414 resource.bind = 0;
415 resource.flags = R600_RESOURCE_FLAG_TRANSFER;
416 /* For texture reading, the temporary (detiled) texture is used as
417 * a render target when blitting from a tiled texture. */
418 if (usage & PIPE_TRANSFER_READ) {
419 resource.bind |= PIPE_BIND_RENDER_TARGET;
420 }
421 /* For texture writing, the temporary texture is used as a sampler
422 * when blitting into a tiled texture. */
423 if (usage & PIPE_TRANSFER_WRITE) {
424 resource.bind |= PIPE_BIND_SAMPLER_VIEW;
425 }
426 /* Create the temporary texture. */
427 trans->linear_texture = ctx->screen->resource_create(ctx->screen, &resource);
428 if (trans->linear_texture == NULL) {
429 R600_ERR("failed to create temporary texture to hold untiled copy\n");
430 pipe_resource_reference(&trans->transfer.resource, NULL);
431 FREE(trans);
432 return NULL;
433 }
434
435 trans->transfer.stride =
436 ((struct r600_resource_texture *)trans->linear_texture)->pitch_in_bytes[0];
437 if (usage & PIPE_TRANSFER_READ) {
438 /* We cannot map a tiled texture directly because the data is
439 * in a different order, therefore we do detiling using a blit. */
440 r600_copy_from_tiled_texture(ctx, trans);
441 /* Always referenced in the blit. */
442 ctx->flush(ctx, 0, NULL);
443 }
444 return &trans->transfer;
445 }
446 trans->transfer.stride = rtex->pitch_in_bytes[sr.level];
447 trans->offset = r600_texture_get_offset(rtex, sr.level, box->z, sr.face);
448 return &trans->transfer;
449 }
450
451 void r600_texture_transfer_destroy(struct pipe_context *ctx,
452 struct pipe_transfer *transfer)
453 {
454 struct r600_transfer *rtransfer = (struct r600_transfer*)transfer;
455 struct r600_resource_texture *rtex = (struct r600_resource_texture*)transfer->resource;
456
457 if (rtransfer->linear_texture) {
458 if (transfer->usage & PIPE_TRANSFER_WRITE) {
459 r600_copy_into_tiled_texture(ctx, rtransfer);
460 }
461 pipe_resource_reference(&rtransfer->linear_texture, NULL);
462 }
463 if (rtex->flushed_depth_texture) {
464 pipe_resource_reference((struct pipe_resource **)&rtex->flushed_depth_texture, NULL);
465 }
466 pipe_resource_reference(&transfer->resource, NULL);
467 FREE(transfer);
468 }
469
470 void* r600_texture_transfer_map(struct pipe_context *ctx,
471 struct pipe_transfer* transfer)
472 {
473 struct r600_transfer *rtransfer = (struct r600_transfer*)transfer;
474 struct r600_bo *bo;
475 enum pipe_format format = transfer->resource->format;
476 struct radeon *radeon = (struct radeon *)ctx->screen->winsys;
477 unsigned offset = 0;
478 char *map;
479
480 if (rtransfer->linear_texture) {
481 bo = ((struct r600_resource *)rtransfer->linear_texture)->bo;
482 } else {
483 struct r600_resource_texture *rtex = (struct r600_resource_texture*)transfer->resource;
484
485 if (rtex->flushed_depth_texture)
486 bo = ((struct r600_resource *)rtex->flushed_depth_texture)->bo;
487 else
488 bo = ((struct r600_resource *)transfer->resource)->bo;
489
490 offset = rtransfer->offset +
491 transfer->box.y / util_format_get_blockheight(format) * transfer->stride +
492 transfer->box.x / util_format_get_blockwidth(format) * util_format_get_blocksize(format);
493 }
494 map = r600_bo_map(radeon, bo, 0, ctx);
495 if (!map) {
496 return NULL;
497 }
498
499 return map + offset;
500 }
501
502 void r600_texture_transfer_unmap(struct pipe_context *ctx,
503 struct pipe_transfer* transfer)
504 {
505 struct r600_transfer *rtransfer = (struct r600_transfer*)transfer;
506 struct radeon *radeon = (struct radeon *)ctx->screen->winsys;
507 struct r600_bo *bo;
508
509 if (rtransfer->linear_texture) {
510 bo = ((struct r600_resource *)rtransfer->linear_texture)->bo;
511 } else {
512 struct r600_resource_texture *rtex = (struct r600_resource_texture*)transfer->resource;
513
514 if (rtex->flushed_depth_texture) {
515 bo = ((struct r600_resource *)rtex->flushed_depth_texture)->bo;
516 } else {
517 bo = ((struct r600_resource *)transfer->resource)->bo;
518 }
519 }
520 r600_bo_unmap(radeon, bo);
521 }
522
523 struct u_resource_vtbl r600_texture_vtbl =
524 {
525 u_default_resource_get_handle, /* get_handle */
526 r600_texture_destroy, /* resource_destroy */
527 r600_texture_is_referenced, /* is_resource_referenced */
528 r600_texture_get_transfer, /* get_transfer */
529 r600_texture_transfer_destroy, /* transfer_destroy */
530 r600_texture_transfer_map, /* transfer_map */
531 u_default_transfer_flush_region,/* transfer_flush_region */
532 r600_texture_transfer_unmap, /* transfer_unmap */
533 u_default_transfer_inline_write /* transfer_inline_write */
534 };
535
536 void r600_init_screen_texture_functions(struct pipe_screen *screen)
537 {
538 screen->get_tex_surface = r600_get_tex_surface;
539 screen->tex_surface_destroy = r600_tex_surface_destroy;
540 }
541
542 static unsigned r600_get_swizzle_combined(const unsigned char *swizzle_format,
543 const unsigned char *swizzle_view)
544 {
545 unsigned i;
546 unsigned char swizzle[4];
547 unsigned result = 0;
548 const uint32_t swizzle_shift[4] = {
549 16, 19, 22, 25,
550 };
551 const uint32_t swizzle_bit[4] = {
552 0, 1, 2, 3,
553 };
554
555 if (swizzle_view) {
556 /* Combine two sets of swizzles. */
557 for (i = 0; i < 4; i++) {
558 swizzle[i] = swizzle_view[i] <= UTIL_FORMAT_SWIZZLE_W ?
559 swizzle_format[swizzle_view[i]] : swizzle_view[i];
560 }
561 } else {
562 memcpy(swizzle, swizzle_format, 4);
563 }
564
565 /* Get swizzle. */
566 for (i = 0; i < 4; i++) {
567 switch (swizzle[i]) {
568 case UTIL_FORMAT_SWIZZLE_Y:
569 result |= swizzle_bit[1] << swizzle_shift[i];
570 break;
571 case UTIL_FORMAT_SWIZZLE_Z:
572 result |= swizzle_bit[2] << swizzle_shift[i];
573 break;
574 case UTIL_FORMAT_SWIZZLE_W:
575 result |= swizzle_bit[3] << swizzle_shift[i];
576 break;
577 case UTIL_FORMAT_SWIZZLE_0:
578 result |= V_038010_SQ_SEL_0 << swizzle_shift[i];
579 break;
580 case UTIL_FORMAT_SWIZZLE_1:
581 result |= V_038010_SQ_SEL_1 << swizzle_shift[i];
582 break;
583 default: /* UTIL_FORMAT_SWIZZLE_X */
584 result |= swizzle_bit[0] << swizzle_shift[i];
585 }
586 }
587 return result;
588 }
589
590 /* texture format translate */
591 uint32_t r600_translate_texformat(enum pipe_format format,
592 const unsigned char *swizzle_view,
593 uint32_t *word4_p, uint32_t *yuv_format_p)
594 {
595 uint32_t result = 0, word4 = 0, yuv_format = 0;
596 const struct util_format_description *desc;
597 boolean uniform = TRUE;
598 int i;
599 const uint32_t sign_bit[4] = {
600 S_038010_FORMAT_COMP_X(V_038010_SQ_FORMAT_COMP_SIGNED),
601 S_038010_FORMAT_COMP_Y(V_038010_SQ_FORMAT_COMP_SIGNED),
602 S_038010_FORMAT_COMP_Z(V_038010_SQ_FORMAT_COMP_SIGNED),
603 S_038010_FORMAT_COMP_W(V_038010_SQ_FORMAT_COMP_SIGNED)
604 };
605 desc = util_format_description(format);
606
607 word4 |= r600_get_swizzle_combined(desc->swizzle, swizzle_view);
608
609 /* Colorspace (return non-RGB formats directly). */
610 switch (desc->colorspace) {
611 /* Depth stencil formats */
612 case UTIL_FORMAT_COLORSPACE_ZS:
613 switch (format) {
614 case PIPE_FORMAT_Z16_UNORM:
615 result = FMT_16;
616 goto out_word4;
617 case PIPE_FORMAT_X24S8_USCALED:
618 word4 |= S_038010_NUM_FORMAT_ALL(V_038010_SQ_NUM_FORMAT_INT);
619 case PIPE_FORMAT_Z24X8_UNORM:
620 case PIPE_FORMAT_Z24_UNORM_S8_USCALED:
621 result = FMT_8_24;
622 goto out_word4;
623 case PIPE_FORMAT_S8X24_USCALED:
624 word4 |= S_038010_NUM_FORMAT_ALL(V_038010_SQ_NUM_FORMAT_INT);
625 case PIPE_FORMAT_X8Z24_UNORM:
626 case PIPE_FORMAT_S8_USCALED_Z24_UNORM:
627 result = FMT_24_8;
628 goto out_word4;
629 case PIPE_FORMAT_S8_USCALED:
630 result = V_0280A0_COLOR_8;
631 word4 |= S_038010_NUM_FORMAT_ALL(V_038010_SQ_NUM_FORMAT_INT);
632 goto out_word4;
633 default:
634 goto out_unknown;
635 }
636
637 case UTIL_FORMAT_COLORSPACE_YUV:
638 yuv_format |= (1 << 30);
639 switch (format) {
640 case PIPE_FORMAT_UYVY:
641 case PIPE_FORMAT_YUYV:
642 default:
643 break;
644 }
645 goto out_unknown; /* TODO */
646
647 case UTIL_FORMAT_COLORSPACE_SRGB:
648 word4 |= S_038010_FORCE_DEGAMMA(1);
649 if (format == PIPE_FORMAT_L8A8_SRGB || format == PIPE_FORMAT_L8_SRGB)
650 goto out_unknown; /* fails for some reason - TODO */
651 break;
652
653 default:
654 break;
655 }
656
657 /* S3TC formats. TODO */
658 if (desc->layout == UTIL_FORMAT_LAYOUT_S3TC) {
659 goto out_unknown;
660 }
661
662
663 for (i = 0; i < desc->nr_channels; i++) {
664 if (desc->channel[i].type == UTIL_FORMAT_TYPE_SIGNED) {
665 word4 |= sign_bit[i];
666 }
667 }
668
669 /* R8G8Bx_SNORM - TODO CxV8U8 */
670
671 /* RGTC - TODO */
672
673 /* See whether the components are of the same size. */
674 for (i = 1; i < desc->nr_channels; i++) {
675 uniform = uniform && desc->channel[0].size == desc->channel[i].size;
676 }
677
678 /* Non-uniform formats. */
679 if (!uniform) {
680 switch(desc->nr_channels) {
681 case 3:
682 if (desc->channel[0].size == 5 &&
683 desc->channel[1].size == 6 &&
684 desc->channel[2].size == 5) {
685 result = FMT_5_6_5;
686 goto out_word4;
687 }
688 goto out_unknown;
689 case 4:
690 if (desc->channel[0].size == 5 &&
691 desc->channel[1].size == 5 &&
692 desc->channel[2].size == 5 &&
693 desc->channel[3].size == 1) {
694 result = FMT_1_5_5_5;
695 goto out_word4;
696 }
697 if (desc->channel[0].size == 10 &&
698 desc->channel[1].size == 10 &&
699 desc->channel[2].size == 10 &&
700 desc->channel[3].size == 2) {
701 result = FMT_10_10_10_2;
702 goto out_word4;
703 }
704 goto out_unknown;
705 }
706 goto out_unknown;
707 }
708
709 /* Find the first non-VOID channel. */
710 for (i = 0; i < 4; i++) {
711 if (desc->channel[i].type != UTIL_FORMAT_TYPE_VOID) {
712 break;
713 }
714 }
715
716 if (i == 4)
717 goto out_unknown;
718
719 /* uniform formats */
720 switch (desc->channel[i].type) {
721 case UTIL_FORMAT_TYPE_UNSIGNED:
722 case UTIL_FORMAT_TYPE_SIGNED:
723 if (!desc->channel[i].normalized &&
724 desc->colorspace != UTIL_FORMAT_COLORSPACE_SRGB) {
725 goto out_unknown;
726 }
727
728 switch (desc->channel[i].size) {
729 case 4:
730 switch (desc->nr_channels) {
731 case 2:
732 result = FMT_4_4;
733 goto out_word4;
734 case 4:
735 result = FMT_4_4_4_4;
736 goto out_word4;
737 }
738 goto out_unknown;
739 case 8:
740 switch (desc->nr_channels) {
741 case 1:
742 result = FMT_8;
743 goto out_word4;
744 case 2:
745 result = FMT_8_8;
746 goto out_word4;
747 case 4:
748 result = FMT_8_8_8_8;
749 goto out_word4;
750 }
751 goto out_unknown;
752 case 16:
753 switch (desc->nr_channels) {
754 case 1:
755 result = FMT_16;
756 goto out_word4;
757 case 2:
758 result = FMT_16_16;
759 goto out_word4;
760 case 4:
761 result = FMT_16_16_16_16;
762 goto out_word4;
763 }
764 }
765 goto out_unknown;
766
767 case UTIL_FORMAT_TYPE_FLOAT:
768 switch (desc->channel[i].size) {
769 case 16:
770 switch (desc->nr_channels) {
771 case 1:
772 result = FMT_16_FLOAT;
773 goto out_word4;
774 case 2:
775 result = FMT_16_16_FLOAT;
776 goto out_word4;
777 case 4:
778 result = FMT_16_16_16_16_FLOAT;
779 goto out_word4;
780 }
781 goto out_unknown;
782 case 32:
783 switch (desc->nr_channels) {
784 case 1:
785 result = FMT_32_FLOAT;
786 goto out_word4;
787 case 2:
788 result = FMT_32_32_FLOAT;
789 goto out_word4;
790 case 4:
791 result = FMT_32_32_32_32_FLOAT;
792 goto out_word4;
793 }
794 }
795
796 }
797 out_word4:
798 if (word4_p)
799 *word4_p = word4;
800 if (yuv_format_p)
801 *yuv_format_p = yuv_format;
802 return result;
803 out_unknown:
804 // R600_ERR("Unable to handle texformat %d %s\n", format, util_format_name(format));
805 return ~0;
806 }