radeonsi: port texture improvements from r600g
[mesa.git] / src / gallium / drivers / radeonsi / 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_format_s3tc.h"
31 #include "util/u_math.h"
32 #include "util/u_inlines.h"
33 #include "util/u_memory.h"
34 #include "pipebuffer/pb_buffer.h"
35 #include "radeonsi_pipe.h"
36 #include "r600_resource.h"
37 #include "sid.h"
38
39 /* Same as resource_copy_region, except that both upsampling and downsampling are allowed. */
40 static void r600_copy_region_with_blit(struct pipe_context *pipe,
41 struct pipe_resource *dst,
42 unsigned dst_level,
43 unsigned dstx, unsigned dsty, unsigned dstz,
44 struct pipe_resource *src,
45 unsigned src_level,
46 const struct pipe_box *src_box)
47 {
48 struct pipe_blit_info blit;
49
50 memset(&blit, 0, sizeof(blit));
51 blit.src.resource = src;
52 blit.src.format = src->format;
53 blit.src.level = src_level;
54 blit.src.box = *src_box;
55 blit.dst.resource = dst;
56 blit.dst.format = dst->format;
57 blit.dst.level = dst_level;
58 blit.dst.box.x = dstx;
59 blit.dst.box.y = dsty;
60 blit.dst.box.z = dstz;
61 blit.dst.box.width = src_box->width;
62 blit.dst.box.height = src_box->height;
63 blit.dst.box.depth = src_box->depth;
64 blit.mask = util_format_get_mask(src->format) &
65 util_format_get_mask(dst->format);
66 blit.filter = PIPE_TEX_FILTER_NEAREST;
67
68 if (blit.mask) {
69 pipe->blit(pipe, &blit);
70 }
71 }
72
73 /* Copy from a full GPU texture to a transfer's staging one. */
74 static void r600_copy_to_staging_texture(struct pipe_context *ctx, struct r600_transfer *rtransfer)
75 {
76 struct pipe_transfer *transfer = (struct pipe_transfer*)rtransfer;
77 struct pipe_resource *dst = &rtransfer->staging->b.b;
78 struct pipe_resource *src = transfer->resource;
79
80 if (src->nr_samples > 1) {
81 r600_copy_region_with_blit(ctx, dst, 0, 0, 0, 0,
82 src, transfer->level, &transfer->box);
83 return;
84 }
85
86 ctx->resource_copy_region(ctx, dst, 0, 0, 0, 0,
87 src, transfer->level, &transfer->box);
88 }
89
90 /* Copy from a transfer's staging texture to a full GPU one. */
91 static void r600_copy_from_staging_texture(struct pipe_context *ctx, struct r600_transfer *rtransfer)
92 {
93 struct pipe_transfer *transfer = (struct pipe_transfer*)rtransfer;
94 struct pipe_resource *dst = transfer->resource;
95 struct pipe_resource *src = &rtransfer->staging->b.b;
96 struct pipe_box sbox;
97
98 u_box_3d(0, 0, 0, transfer->box.width, transfer->box.height, transfer->box.depth, &sbox);
99
100 if (dst->nr_samples > 1) {
101 r600_copy_region_with_blit(ctx, dst, transfer->level,
102 transfer->box.x, transfer->box.y, transfer->box.z,
103 src, 0, &sbox);
104 return;
105 }
106
107 ctx->resource_copy_region(ctx, dst, transfer->level,
108 transfer->box.x, transfer->box.y, transfer->box.z,
109 src, 0, &sbox);
110 }
111
112 static unsigned r600_texture_get_offset(struct r600_texture *rtex, unsigned level,
113 const struct pipe_box *box)
114 {
115 enum pipe_format format = rtex->resource.b.b.format;
116
117 return rtex->surface.level[level].offset +
118 box->z * rtex->surface.level[level].slice_size +
119 box->y / util_format_get_blockheight(format) * rtex->surface.level[level].pitch_bytes +
120 box->x / util_format_get_blockwidth(format) * util_format_get_blocksize(format);
121 }
122
123 static int r600_init_surface(struct r600_screen *rscreen,
124 struct radeon_surface *surface,
125 const struct pipe_resource *ptex,
126 unsigned array_mode,
127 bool is_flushed_depth)
128 {
129 const struct util_format_description *desc =
130 util_format_description(ptex->format);
131 bool is_depth, is_stencil;
132
133 is_depth = util_format_has_depth(desc);
134 is_stencil = util_format_has_stencil(desc);
135
136 surface->npix_x = ptex->width0;
137 surface->npix_y = ptex->height0;
138 surface->npix_z = ptex->depth0;
139 surface->blk_w = util_format_get_blockwidth(ptex->format);
140 surface->blk_h = util_format_get_blockheight(ptex->format);
141 surface->blk_d = 1;
142 surface->array_size = 1;
143 surface->last_level = ptex->last_level;
144
145 if (!is_flushed_depth &&
146 ptex->format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT) {
147 surface->bpe = 4; /* stencil is allocated separately on evergreen */
148 } else {
149 surface->bpe = util_format_get_blocksize(ptex->format);
150 /* align byte per element on dword */
151 if (surface->bpe == 3) {
152 surface->bpe = 4;
153 }
154 }
155
156 surface->nsamples = ptex->nr_samples ? ptex->nr_samples : 1;
157 surface->flags = 0;
158
159 switch (array_mode) {
160 case V_009910_ARRAY_1D_TILED_THIN1:
161 surface->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE);
162 break;
163 case V_009910_ARRAY_2D_TILED_THIN1:
164 surface->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_2D, MODE);
165 break;
166 case V_009910_ARRAY_LINEAR_ALIGNED:
167 surface->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_LINEAR_ALIGNED, MODE);
168 break;
169 case V_009910_ARRAY_LINEAR_GENERAL:
170 default:
171 surface->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_LINEAR, MODE);
172 break;
173 }
174 switch (ptex->target) {
175 case PIPE_TEXTURE_1D:
176 surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_1D, TYPE);
177 break;
178 case PIPE_TEXTURE_RECT:
179 case PIPE_TEXTURE_2D:
180 surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_2D, TYPE);
181 break;
182 case PIPE_TEXTURE_3D:
183 surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_3D, TYPE);
184 break;
185 case PIPE_TEXTURE_1D_ARRAY:
186 surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_1D_ARRAY, TYPE);
187 surface->array_size = ptex->array_size;
188 break;
189 case PIPE_TEXTURE_2D_ARRAY:
190 surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_2D_ARRAY, TYPE);
191 surface->array_size = ptex->array_size;
192 break;
193 case PIPE_TEXTURE_CUBE:
194 surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_CUBEMAP, TYPE);
195 break;
196 case PIPE_BUFFER:
197 default:
198 return -EINVAL;
199 }
200 if (ptex->bind & PIPE_BIND_SCANOUT) {
201 surface->flags |= RADEON_SURF_SCANOUT;
202 }
203
204 if (!is_flushed_depth && is_depth) {
205 surface->flags |= RADEON_SURF_ZBUFFER;
206 if (is_stencil) {
207 surface->flags |= RADEON_SURF_SBUFFER |
208 RADEON_SURF_HAS_SBUFFER_MIPTREE;
209 }
210 }
211 surface->flags |= RADEON_SURF_HAS_TILE_MODE_INDEX;
212 return 0;
213 }
214
215 static int r600_setup_surface(struct pipe_screen *screen,
216 struct r600_texture *rtex,
217 unsigned pitch_in_bytes_override)
218 {
219 struct r600_screen *rscreen = (struct r600_screen*)screen;
220 int r;
221
222 r = rscreen->ws->surface_init(rscreen->ws, &rtex->surface);
223 if (r) {
224 return r;
225 }
226
227 rtex->size = rtex->surface.bo_size;
228
229 if (pitch_in_bytes_override && pitch_in_bytes_override != rtex->surface.level[0].pitch_bytes) {
230 /* old ddx on evergreen over estimate alignment for 1d, only 1 level
231 * for those
232 */
233 rtex->surface.level[0].nblk_x = pitch_in_bytes_override / rtex->surface.bpe;
234 rtex->surface.level[0].pitch_bytes = pitch_in_bytes_override;
235 rtex->surface.level[0].slice_size = pitch_in_bytes_override * rtex->surface.level[0].nblk_y;
236 if (rtex->surface.flags & RADEON_SURF_SBUFFER) {
237 rtex->surface.stencil_offset =
238 rtex->surface.stencil_level[0].offset = rtex->surface.level[0].slice_size;
239 }
240 }
241 return 0;
242 }
243
244 static boolean r600_texture_get_handle(struct pipe_screen* screen,
245 struct pipe_resource *ptex,
246 struct winsys_handle *whandle)
247 {
248 struct r600_texture *rtex = (struct r600_texture*)ptex;
249 struct si_resource *resource = &rtex->resource;
250 struct radeon_surface *surface = &rtex->surface;
251 struct r600_screen *rscreen = (struct r600_screen*)screen;
252
253 rscreen->ws->buffer_set_tiling(resource->buf,
254 NULL,
255 surface->level[0].mode >= RADEON_SURF_MODE_1D ?
256 RADEON_LAYOUT_TILED : RADEON_LAYOUT_LINEAR,
257 surface->level[0].mode >= RADEON_SURF_MODE_2D ?
258 RADEON_LAYOUT_TILED : RADEON_LAYOUT_LINEAR,
259 surface->bankw, surface->bankh,
260 surface->tile_split,
261 surface->stencil_tile_split,
262 surface->mtilea,
263 surface->level[0].pitch_bytes);
264
265 return rscreen->ws->buffer_get_handle(resource->buf,
266 surface->level[0].pitch_bytes, whandle);
267 }
268
269 static void r600_texture_destroy(struct pipe_screen *screen,
270 struct pipe_resource *ptex)
271 {
272 struct r600_texture *rtex = (struct r600_texture*)ptex;
273 struct si_resource *resource = &rtex->resource;
274
275 if (rtex->flushed_depth_texture)
276 si_resource_reference((struct si_resource **)&rtex->flushed_depth_texture, NULL);
277
278 pb_reference(&resource->buf, NULL);
279 FREE(rtex);
280 }
281
282 static const struct u_resource_vtbl r600_texture_vtbl;
283
284 DEBUG_GET_ONCE_BOOL_OPTION(print_texdepth, "RADEON_PRINT_TEXDEPTH", FALSE);
285
286 /* The number of samples can be specified independently of the texture. */
287 static void r600_texture_get_fmask_info(struct r600_screen *rscreen,
288 struct r600_texture *rtex,
289 unsigned nr_samples,
290 struct r600_fmask_info *out)
291 {
292 /* FMASK is allocated like an ordinary texture. */
293 struct radeon_surface fmask = rtex->surface;
294
295 memset(out, 0, sizeof(*out));
296
297 fmask.bo_alignment = 0;
298 fmask.bo_size = 0;
299 fmask.nsamples = 1;
300 fmask.flags |= RADEON_SURF_FMASK | RADEON_SURF_HAS_TILE_MODE_INDEX;
301
302 switch (nr_samples) {
303 case 2:
304 case 4:
305 fmask.bpe = 1;
306 break;
307 case 8:
308 fmask.bpe = 4;
309 break;
310 default:
311 R600_ERR("Invalid sample count for FMASK allocation.\n");
312 return;
313 }
314
315 if (rscreen->ws->surface_init(rscreen->ws, &fmask)) {
316 R600_ERR("Got error in surface_init while allocating FMASK.\n");
317 return;
318 }
319
320 assert(fmask.level[0].mode == RADEON_SURF_MODE_2D);
321
322 out->slice_tile_max = (fmask.level[0].nblk_x * fmask.level[0].nblk_y) / 64;
323 if (out->slice_tile_max)
324 out->slice_tile_max -= 1;
325
326 out->tile_mode_index = fmask.tiling_index[0];
327 out->pitch = fmask.level[0].nblk_x;
328 out->bank_height = fmask.bankh;
329 out->alignment = MAX2(256, fmask.bo_alignment);
330 out->size = fmask.bo_size;
331 }
332
333 static void r600_texture_allocate_fmask(struct r600_screen *rscreen,
334 struct r600_texture *rtex)
335 {
336 r600_texture_get_fmask_info(rscreen, rtex,
337 rtex->resource.b.b.nr_samples, &rtex->fmask);
338
339 rtex->fmask.offset = align(rtex->size, rtex->fmask.alignment);
340 rtex->size = rtex->fmask.offset + rtex->fmask.size;
341 }
342
343 static void si_texture_get_cmask_info(struct r600_screen *rscreen,
344 struct r600_texture *rtex,
345 struct r600_cmask_info *out)
346 {
347 unsigned pipe_interleave_bytes = rscreen->tiling_info.group_bytes;
348 unsigned num_pipes = rscreen->tiling_info.num_channels;
349 unsigned cl_width, cl_height;
350
351 switch (num_pipes) {
352 case 2:
353 cl_width = 32;
354 cl_height = 16;
355 break;
356 case 4:
357 cl_width = 32;
358 cl_height = 32;
359 break;
360 case 8:
361 cl_width = 64;
362 cl_height = 32;
363 break;
364 default:
365 assert(0);
366 return;
367 }
368
369 unsigned base_align = num_pipes * pipe_interleave_bytes;
370
371 unsigned width = align(rtex->surface.npix_x, cl_width*8);
372 unsigned height = align(rtex->surface.npix_y, cl_height*8);
373 unsigned slice_elements = (width * height) / (8*8);
374
375 /* Each element of CMASK is a nibble. */
376 unsigned slice_bytes = slice_elements / 2;
377
378 out->slice_tile_max = (width * height) / (128*128);
379 if (out->slice_tile_max)
380 out->slice_tile_max -= 1;
381
382 out->alignment = MAX2(256, base_align);
383 out->size = rtex->surface.array_size * align(slice_bytes, base_align);
384 }
385
386 static void r600_texture_allocate_cmask(struct r600_screen *rscreen,
387 struct r600_texture *rtex)
388 {
389 si_texture_get_cmask_info(rscreen, rtex, &rtex->cmask);
390
391 if (rtex->cmask.size) {
392 rtex->cmask.offset = align(rtex->size, rtex->cmask.alignment);
393 rtex->size = rtex->cmask.offset + rtex->cmask.size;
394 }
395 }
396
397 static struct r600_texture *
398 r600_texture_create_object(struct pipe_screen *screen,
399 const struct pipe_resource *base,
400 unsigned pitch_in_bytes_override,
401 struct pb_buffer *buf,
402 struct radeon_surface *surface)
403 {
404 struct r600_texture *rtex;
405 struct si_resource *resource;
406 struct r600_screen *rscreen = (struct r600_screen*)screen;
407 int r;
408
409 rtex = CALLOC_STRUCT(r600_texture);
410 if (rtex == NULL)
411 return NULL;
412
413 resource = &rtex->resource;
414 resource->b.b = *base;
415 resource->b.vtbl = &r600_texture_vtbl;
416 pipe_reference_init(&resource->b.b.reference, 1);
417 resource->b.b.screen = screen;
418 rtex->pitch_override = pitch_in_bytes_override;
419
420 /* don't include stencil-only formats which we don't support for rendering */
421 rtex->is_depth = util_format_has_depth(util_format_description(rtex->resource.b.b.format));
422
423 rtex->surface = *surface;
424 r = r600_setup_surface(screen, rtex, pitch_in_bytes_override);
425 if (r) {
426 FREE(rtex);
427 return NULL;
428 }
429
430 if (base->nr_samples > 1 && !rtex->is_depth && !buf) {
431 r600_texture_allocate_fmask(rscreen, rtex);
432 r600_texture_allocate_cmask(rscreen, rtex);
433 }
434
435 if (!rtex->is_depth && base->nr_samples > 1 &&
436 (!rtex->fmask.size || !rtex->cmask.size)) {
437 FREE(rtex);
438 return NULL;
439 }
440
441 /* Now create the backing buffer. */
442 if (!buf) {
443 unsigned base_align = rtex->surface.bo_alignment;
444
445 if (!si_init_resource(rscreen, resource, rtex->size, base_align, FALSE, base->usage)) {
446 FREE(rtex);
447 return NULL;
448 }
449 } else if (buf) {
450 resource->buf = buf;
451 resource->cs_buf = rscreen->ws->buffer_get_cs_handle(buf);
452 resource->domains = RADEON_DOMAIN_GTT | RADEON_DOMAIN_VRAM;
453 }
454
455 if (rtex->cmask.size) {
456 /* Initialize the cmask to 0xCC (= compressed state). */
457 char *map = rscreen->ws->buffer_map(resource->cs_buf, NULL, PIPE_TRANSFER_WRITE);
458 memset(map + rtex->cmask.offset, 0xCC, rtex->cmask.size);
459 }
460
461 if (debug_get_option_print_texdepth() && rtex->is_depth) {
462 printf("Texture: npix_x=%u, npix_y=%u, npix_z=%u, blk_w=%u, "
463 "blk_h=%u, blk_d=%u, array_size=%u, last_level=%u, "
464 "bpe=%u, nsamples=%u, flags=%u\n",
465 rtex->surface.npix_x, rtex->surface.npix_y,
466 rtex->surface.npix_z, rtex->surface.blk_w,
467 rtex->surface.blk_h, rtex->surface.blk_d,
468 rtex->surface.array_size, rtex->surface.last_level,
469 rtex->surface.bpe, rtex->surface.nsamples,
470 rtex->surface.flags);
471 if (rtex->surface.flags & RADEON_SURF_ZBUFFER) {
472 for (int i = 0; i <= rtex->surface.last_level; i++) {
473 printf(" Z %i: offset=%llu, slice_size=%llu, npix_x=%u, "
474 "npix_y=%u, npix_z=%u, nblk_x=%u, nblk_y=%u, "
475 "nblk_z=%u, pitch_bytes=%u, mode=%u\n",
476 i, rtex->surface.level[i].offset,
477 rtex->surface.level[i].slice_size,
478 rtex->surface.level[i].npix_x,
479 rtex->surface.level[i].npix_y,
480 rtex->surface.level[i].npix_z,
481 rtex->surface.level[i].nblk_x,
482 rtex->surface.level[i].nblk_y,
483 rtex->surface.level[i].nblk_z,
484 rtex->surface.level[i].pitch_bytes,
485 rtex->surface.level[i].mode);
486 }
487 }
488 if (rtex->surface.flags & RADEON_SURF_SBUFFER) {
489 for (int i = 0; i <= rtex->surface.last_level; i++) {
490 printf(" S %i: offset=%llu, slice_size=%llu, npix_x=%u, "
491 "npix_y=%u, npix_z=%u, nblk_x=%u, nblk_y=%u, "
492 "nblk_z=%u, pitch_bytes=%u, mode=%u\n",
493 i, rtex->surface.stencil_level[i].offset,
494 rtex->surface.stencil_level[i].slice_size,
495 rtex->surface.stencil_level[i].npix_x,
496 rtex->surface.stencil_level[i].npix_y,
497 rtex->surface.stencil_level[i].npix_z,
498 rtex->surface.stencil_level[i].nblk_x,
499 rtex->surface.stencil_level[i].nblk_y,
500 rtex->surface.stencil_level[i].nblk_z,
501 rtex->surface.stencil_level[i].pitch_bytes,
502 rtex->surface.stencil_level[i].mode);
503 }
504 }
505 }
506 return rtex;
507 }
508
509 struct pipe_resource *si_texture_create(struct pipe_screen *screen,
510 const struct pipe_resource *templ)
511 {
512 struct r600_screen *rscreen = (struct r600_screen*)screen;
513 struct radeon_surface surface = {0};
514 unsigned array_mode = V_009910_ARRAY_LINEAR_ALIGNED;
515 int r;
516
517 if (!(templ->flags & R600_RESOURCE_FLAG_TRANSFER) &&
518 !(templ->bind & PIPE_BIND_SCANOUT)) {
519 if (templ->flags & R600_RESOURCE_FLAG_FORCE_TILING ||
520 templ->nr_samples > 1) {
521 array_mode = V_009910_ARRAY_2D_TILED_THIN1;
522 } else if (util_format_is_compressed(templ->format)) {
523 array_mode = V_009910_ARRAY_1D_TILED_THIN1;
524 } else if (templ->usage != PIPE_USAGE_STAGING &&
525 templ->usage != PIPE_USAGE_STREAM &&
526 templ->target != PIPE_TEXTURE_1D &&
527 templ->target != PIPE_TEXTURE_1D_ARRAY &&
528 templ->height0 > 3 &&
529 rscreen->chip_class < CIK /* XXX fix me */) {
530 array_mode = V_009910_ARRAY_2D_TILED_THIN1;
531 } else {
532 array_mode = V_009910_ARRAY_1D_TILED_THIN1;
533 }
534 }
535
536 r = r600_init_surface(rscreen, &surface, templ, array_mode,
537 templ->flags & R600_RESOURCE_FLAG_FLUSHED_DEPTH);
538 if (r) {
539 return NULL;
540 }
541 r = rscreen->ws->surface_best(rscreen->ws, &surface);
542 if (r) {
543 return NULL;
544 }
545 return (struct pipe_resource *)r600_texture_create_object(screen, templ,
546 0, NULL, &surface);
547 }
548
549 static struct pipe_surface *r600_create_surface(struct pipe_context *pipe,
550 struct pipe_resource *texture,
551 const struct pipe_surface *surf_tmpl)
552 {
553 struct r600_texture *rtex = (struct r600_texture*)texture;
554 struct r600_surface *surface = CALLOC_STRUCT(r600_surface);
555 unsigned level = surf_tmpl->u.tex.level;
556
557 assert(surf_tmpl->u.tex.first_layer <= util_max_layer(texture, surf_tmpl->u.tex.level));
558 assert(surf_tmpl->u.tex.last_layer <= util_max_layer(texture, surf_tmpl->u.tex.level));
559 assert(surf_tmpl->u.tex.first_layer == surf_tmpl->u.tex.last_layer);
560 if (surface == NULL)
561 return NULL;
562 /* XXX no offset */
563 /* offset = r600_texture_get_offset(rtex, level, surf_tmpl->u.tex.first_layer);*/
564 pipe_reference_init(&surface->base.reference, 1);
565 pipe_resource_reference(&surface->base.texture, texture);
566 surface->base.context = pipe;
567 surface->base.format = surf_tmpl->format;
568 surface->base.width = rtex->surface.level[level].npix_x;
569 surface->base.height = rtex->surface.level[level].npix_y;
570 surface->base.texture = texture;
571 surface->base.u.tex.first_layer = surf_tmpl->u.tex.first_layer;
572 surface->base.u.tex.last_layer = surf_tmpl->u.tex.last_layer;
573 surface->base.u.tex.level = level;
574
575 return &surface->base;
576 }
577
578 static void r600_surface_destroy(struct pipe_context *pipe,
579 struct pipe_surface *surface)
580 {
581 pipe_resource_reference(&surface->texture, NULL);
582 FREE(surface);
583 }
584
585 struct pipe_resource *si_texture_from_handle(struct pipe_screen *screen,
586 const struct pipe_resource *templ,
587 struct winsys_handle *whandle)
588 {
589 struct r600_screen *rscreen = (struct r600_screen*)screen;
590 struct pb_buffer *buf = NULL;
591 unsigned stride = 0;
592 unsigned array_mode;
593 enum radeon_bo_layout micro, macro;
594 struct radeon_surface surface;
595 int r;
596
597 /* Support only 2D textures without mipmaps */
598 if ((templ->target != PIPE_TEXTURE_2D && templ->target != PIPE_TEXTURE_RECT) ||
599 templ->depth0 != 1 || templ->last_level != 0)
600 return NULL;
601
602 buf = rscreen->ws->buffer_from_handle(rscreen->ws, whandle, &stride);
603 if (!buf)
604 return NULL;
605
606 rscreen->ws->buffer_get_tiling(buf, &micro, &macro,
607 &surface.bankw, &surface.bankh,
608 &surface.tile_split,
609 &surface.stencil_tile_split,
610 &surface.mtilea);
611
612 if (macro == RADEON_LAYOUT_TILED)
613 array_mode = V_009910_ARRAY_2D_TILED_THIN1;
614 else if (micro == RADEON_LAYOUT_TILED)
615 array_mode = V_009910_ARRAY_1D_TILED_THIN1;
616 else
617 array_mode = V_009910_ARRAY_LINEAR_ALIGNED;
618
619 r = r600_init_surface(rscreen, &surface, templ, array_mode, false);
620 if (r) {
621 return NULL;
622 }
623
624 /* always set the scanout flags */
625 surface.flags |= RADEON_SURF_SCANOUT;
626
627 return (struct pipe_resource *)r600_texture_create_object(screen, templ,
628 stride, buf, &surface);
629 }
630
631 bool r600_init_flushed_depth_texture(struct pipe_context *ctx,
632 struct pipe_resource *texture,
633 struct r600_texture **staging)
634 {
635 struct r600_texture *rtex = (struct r600_texture*)texture;
636 struct pipe_resource resource;
637 struct r600_texture **flushed_depth_texture = staging ?
638 staging : &rtex->flushed_depth_texture;
639
640 if (!staging && rtex->flushed_depth_texture)
641 return true; /* it's ready */
642
643 resource.target = texture->target;
644 resource.format = texture->format;
645 resource.width0 = texture->width0;
646 resource.height0 = texture->height0;
647 resource.depth0 = texture->depth0;
648 resource.array_size = texture->array_size;
649 resource.last_level = texture->last_level;
650 resource.nr_samples = texture->nr_samples;
651 resource.usage = staging ? PIPE_USAGE_DYNAMIC : PIPE_USAGE_DEFAULT;
652 resource.bind = texture->bind & ~PIPE_BIND_DEPTH_STENCIL;
653 resource.flags = texture->flags | R600_RESOURCE_FLAG_FLUSHED_DEPTH;
654
655 if (staging)
656 resource.flags |= R600_RESOURCE_FLAG_TRANSFER;
657
658 *flushed_depth_texture = (struct r600_texture *)ctx->screen->resource_create(ctx->screen, &resource);
659 if (*flushed_depth_texture == NULL) {
660 R600_ERR("failed to create temporary texture to hold flushed depth\n");
661 return false;
662 }
663
664 (*flushed_depth_texture)->is_flushing_texture = TRUE;
665 return true;
666 }
667
668 /**
669 * Initialize the pipe_resource descriptor to be of the same size as the box,
670 * which is supposed to hold a subregion of the texture "orig" at the given
671 * mipmap level.
672 */
673 static void r600_init_temp_resource_from_box(struct pipe_resource *res,
674 struct pipe_resource *orig,
675 const struct pipe_box *box,
676 unsigned level, unsigned flags)
677 {
678 memset(res, 0, sizeof(*res));
679 res->format = orig->format;
680 res->width0 = box->width;
681 res->height0 = box->height;
682 res->depth0 = 1;
683 res->array_size = 1;
684 res->usage = flags & R600_RESOURCE_FLAG_TRANSFER ? PIPE_USAGE_STAGING : PIPE_USAGE_STATIC;
685 res->flags = flags;
686
687 /* We must set the correct texture target and dimensions for a 3D box. */
688 if (box->depth > 1 && util_max_layer(orig, level) > 0)
689 res->target = orig->target;
690 else
691 res->target = PIPE_TEXTURE_2D;
692
693 switch (res->target) {
694 case PIPE_TEXTURE_1D_ARRAY:
695 case PIPE_TEXTURE_2D_ARRAY:
696 case PIPE_TEXTURE_CUBE_ARRAY:
697 res->array_size = box->depth;
698 break;
699 case PIPE_TEXTURE_3D:
700 res->depth0 = box->depth;
701 break;
702 default:;
703 }
704 }
705
706 static void *si_texture_transfer_map(struct pipe_context *ctx,
707 struct pipe_resource *texture,
708 unsigned level,
709 unsigned usage,
710 const struct pipe_box *box,
711 struct pipe_transfer **ptransfer)
712 {
713 struct r600_context *rctx = (struct r600_context *)ctx;
714 struct r600_texture *rtex = (struct r600_texture*)texture;
715 struct r600_transfer *trans;
716 boolean use_staging_texture = FALSE;
717 struct radeon_winsys_cs_handle *buf;
718 unsigned offset = 0;
719 char *map;
720
721 /* We cannot map a tiled texture directly because the data is
722 * in a different order, therefore we do detiling using a blit.
723 *
724 * Also, use a temporary in GTT memory for read transfers, as
725 * the CPU is much happier reading out of cached system memory
726 * than uncached VRAM.
727 */
728 if (rtex->surface.level[level].mode != RADEON_SURF_MODE_LINEAR_ALIGNED &&
729 rtex->surface.level[level].mode != RADEON_SURF_MODE_LINEAR)
730 use_staging_texture = TRUE;
731
732 /* Use a staging texture for uploads if the underlying BO is busy. */
733 if (!(usage & PIPE_TRANSFER_READ) &&
734 (rctx->ws->cs_is_buffer_referenced(rctx->cs, rtex->resource.cs_buf, RADEON_USAGE_READWRITE) ||
735 rctx->ws->buffer_is_busy(rtex->resource.buf, RADEON_USAGE_READWRITE))) {
736 use_staging_texture = TRUE;
737 }
738
739 if (texture->flags & R600_RESOURCE_FLAG_TRANSFER) {
740 use_staging_texture = FALSE;
741 }
742
743 if (use_staging_texture && (usage & PIPE_TRANSFER_MAP_DIRECTLY)) {
744 return NULL;
745 }
746
747 trans = CALLOC_STRUCT(r600_transfer);
748 if (trans == NULL)
749 return NULL;
750 trans->transfer.resource = texture;
751 trans->transfer.level = level;
752 trans->transfer.usage = usage;
753 trans->transfer.box = *box;
754
755 if (rtex->is_depth) {
756 struct r600_texture *staging_depth;
757
758 if (rtex->resource.b.b.nr_samples > 1) {
759 /* MSAA depth buffers need to be converted to single sample buffers.
760 *
761 * Mapping MSAA depth buffers can occur if ReadPixels is called
762 * with a multisample GLX visual.
763 *
764 * First downsample the depth buffer to a temporary texture,
765 * then decompress the temporary one to staging.
766 *
767 * Only the region being mapped is transfered.
768 */
769 struct pipe_resource resource;
770
771 r600_init_temp_resource_from_box(&resource, texture, box, level, 0);
772
773 if (!r600_init_flushed_depth_texture(ctx, &resource, &staging_depth)) {
774 R600_ERR("failed to create temporary texture to hold untiled copy\n");
775 FREE(trans);
776 return NULL;
777 }
778
779 if (usage & PIPE_TRANSFER_READ) {
780 struct pipe_resource *temp = ctx->screen->resource_create(ctx->screen, &resource);
781
782 r600_copy_region_with_blit(ctx, temp, 0, 0, 0, 0, texture, level, box);
783 r600_blit_decompress_depth(ctx, (struct r600_texture*)temp, staging_depth,
784 0, 0, 0, box->depth, 0, 0);
785 pipe_resource_reference((struct pipe_resource**)&temp, NULL);
786 }
787 }
788 else {
789 /* XXX: only readback the rectangle which is being mapped? */
790 /* XXX: when discard is true, no need to read back from depth texture */
791 if (!r600_init_flushed_depth_texture(ctx, texture, &staging_depth)) {
792 R600_ERR("failed to create temporary texture to hold untiled copy\n");
793 FREE(trans);
794 return NULL;
795 }
796
797 r600_blit_decompress_depth(ctx, rtex, staging_depth,
798 level, level,
799 box->z, box->z + box->depth - 1,
800 0, 0);
801
802 offset = r600_texture_get_offset(staging_depth, level, box);
803 }
804
805 trans->transfer.stride = staging_depth->surface.level[level].pitch_bytes;
806 trans->transfer.layer_stride = staging_depth->surface.level[level].slice_size;
807 trans->staging = (struct si_resource*)staging_depth;
808 } else if (use_staging_texture) {
809 struct pipe_resource resource;
810 struct r600_texture *staging;
811
812 r600_init_temp_resource_from_box(&resource, texture, box, level,
813 R600_RESOURCE_FLAG_TRANSFER);
814
815 /* Create the temporary texture. */
816 staging = (struct r600_texture*)ctx->screen->resource_create(ctx->screen, &resource);
817 if (staging == NULL) {
818 R600_ERR("failed to create temporary texture to hold untiled copy\n");
819 FREE(trans);
820 return NULL;
821 }
822 trans->staging = &staging->resource;
823 trans->transfer.stride = staging->surface.level[0].pitch_bytes;
824 trans->transfer.layer_stride = staging->surface.level[0].slice_size;
825 if (usage & PIPE_TRANSFER_READ) {
826 r600_copy_to_staging_texture(ctx, trans);
827 }
828 } else {
829 /* the resource is mapped directly */
830 trans->transfer.stride = rtex->surface.level[level].pitch_bytes;
831 trans->transfer.layer_stride = rtex->surface.level[level].slice_size;
832 offset = r600_texture_get_offset(rtex, level, box);
833 }
834
835 if (trans->staging) {
836 buf = trans->staging->cs_buf;
837 } else {
838 buf = rtex->resource.cs_buf;
839 }
840
841 if (!(map = rctx->ws->buffer_map(buf, rctx->cs, usage))) {
842 pipe_resource_reference((struct pipe_resource**)&trans->staging, NULL);
843 FREE(trans);
844 return NULL;
845 }
846
847 *ptransfer = &trans->transfer;
848 return map + offset;
849 }
850
851 static void si_texture_transfer_unmap(struct pipe_context *ctx,
852 struct pipe_transfer* transfer)
853 {
854 struct r600_transfer *rtransfer = (struct r600_transfer*)transfer;
855 struct r600_context *rctx = (struct r600_context*)ctx;
856 struct radeon_winsys_cs_handle *buf;
857 struct pipe_resource *texture = transfer->resource;
858 struct r600_texture *rtex = (struct r600_texture*)texture;
859
860 if (rtransfer->staging) {
861 buf = rtransfer->staging->cs_buf;
862 } else {
863 buf = si_resource(transfer->resource)->cs_buf;
864 }
865 rctx->ws->buffer_unmap(buf);
866
867 if ((transfer->usage & PIPE_TRANSFER_WRITE) && rtransfer->staging) {
868 if (rtex->is_depth && rtex->resource.b.b.nr_samples <= 1) {
869 ctx->resource_copy_region(ctx, texture, transfer->level,
870 transfer->box.x, transfer->box.y, transfer->box.z,
871 &rtransfer->staging->b.b, transfer->level,
872 &transfer->box);
873 } else {
874 r600_copy_from_staging_texture(ctx, rtransfer);
875 }
876 }
877
878 if (rtransfer->staging)
879 pipe_resource_reference((struct pipe_resource**)&rtransfer->staging, NULL);
880
881 FREE(transfer);
882 }
883
884 void si_init_surface_functions(struct r600_context *r600)
885 {
886 r600->context.create_surface = r600_create_surface;
887 r600->context.surface_destroy = r600_surface_destroy;
888 }
889
890 static const struct u_resource_vtbl r600_texture_vtbl =
891 {
892 r600_texture_get_handle, /* get_handle */
893 r600_texture_destroy, /* resource_destroy */
894 si_texture_transfer_map, /* transfer_map */
895 u_default_transfer_flush_region,/* transfer_flush_region */
896 si_texture_transfer_unmap, /* transfer_unmap */
897 NULL /* transfer_inline_write */
898 };