vc4: Drop pointless indirections around BO import/export.
[mesa.git] / src / gallium / drivers / vc4 / vc4_resource.c
1 /*
2 * Copyright © 2014 Broadcom
3 * Copyright (C) 2012 Rob Clark <robclark@freedesktop.org>
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 * IN THE SOFTWARE.
23 */
24
25 #include "util/u_blit.h"
26 #include "util/u_memory.h"
27 #include "util/u_format.h"
28 #include "util/u_inlines.h"
29 #include "util/u_surface.h"
30 #include "util/u_upload_mgr.h"
31
32 #include "vc4_screen.h"
33 #include "vc4_context.h"
34 #include "vc4_resource.h"
35 #include "vc4_tiling.h"
36
37 static bool miptree_debug = false;
38
39 static bool
40 vc4_resource_bo_alloc(struct vc4_resource *rsc)
41 {
42 struct pipe_resource *prsc = &rsc->base;
43 struct pipe_screen *pscreen = prsc->screen;
44 struct vc4_bo *bo;
45
46 if (miptree_debug) {
47 fprintf(stderr, "alloc %p: size %d + offset %d -> %d\n",
48 rsc,
49 rsc->slices[0].size,
50 rsc->slices[0].offset,
51 rsc->slices[0].offset +
52 rsc->slices[0].size +
53 rsc->cube_map_stride * (prsc->array_size - 1));
54 }
55
56 bo = vc4_bo_alloc(vc4_screen(pscreen),
57 rsc->slices[0].offset +
58 rsc->slices[0].size +
59 rsc->cube_map_stride * (prsc->array_size - 1),
60 "resource");
61 if (bo) {
62 vc4_bo_unreference(&rsc->bo);
63 rsc->bo = bo;
64 return true;
65 } else {
66 return false;
67 }
68 }
69
70 static void
71 vc4_resource_transfer_unmap(struct pipe_context *pctx,
72 struct pipe_transfer *ptrans)
73 {
74 struct vc4_context *vc4 = vc4_context(pctx);
75 struct vc4_transfer *trans = vc4_transfer(ptrans);
76
77 if (trans->map) {
78 struct vc4_resource *rsc;
79 struct vc4_resource_slice *slice;
80 if (trans->ss_resource) {
81 rsc = vc4_resource(trans->ss_resource);
82 slice = &rsc->slices[0];
83 } else {
84 rsc = vc4_resource(ptrans->resource);
85 slice = &rsc->slices[ptrans->level];
86 }
87
88 if (ptrans->usage & PIPE_TRANSFER_WRITE) {
89 vc4_store_tiled_image(rsc->bo->map + slice->offset +
90 ptrans->box.z * rsc->cube_map_stride,
91 slice->stride,
92 trans->map, ptrans->stride,
93 slice->tiling, rsc->cpp,
94 &ptrans->box);
95 }
96 free(trans->map);
97 }
98
99 if (trans->ss_resource && (ptrans->usage & PIPE_TRANSFER_WRITE)) {
100 struct pipe_blit_info blit;
101 memset(&blit, 0, sizeof(blit));
102
103 blit.src.resource = trans->ss_resource;
104 blit.src.format = trans->ss_resource->format;
105 blit.src.box.width = trans->ss_box.width;
106 blit.src.box.height = trans->ss_box.height;
107 blit.src.box.depth = 1;
108
109 blit.dst.resource = ptrans->resource;
110 blit.dst.format = ptrans->resource->format;
111 blit.dst.level = ptrans->level;
112 blit.dst.box = trans->ss_box;
113
114 blit.mask = util_format_get_mask(ptrans->resource->format);
115 blit.filter = PIPE_TEX_FILTER_NEAREST;
116
117 pctx->blit(pctx, &blit);
118
119 pipe_resource_reference(&trans->ss_resource, NULL);
120 }
121
122 pipe_resource_reference(&ptrans->resource, NULL);
123 slab_free(&vc4->transfer_pool, ptrans);
124 }
125
126 static struct pipe_resource *
127 vc4_get_temp_resource(struct pipe_context *pctx,
128 struct pipe_resource *prsc,
129 const struct pipe_box *box)
130 {
131 struct pipe_resource temp_setup;
132
133 memset(&temp_setup, 0, sizeof(temp_setup));
134 temp_setup.target = prsc->target;
135 temp_setup.format = prsc->format;
136 temp_setup.width0 = box->width;
137 temp_setup.height0 = box->height;
138 temp_setup.depth0 = 1;
139 temp_setup.array_size = 1;
140
141 return pctx->screen->resource_create(pctx->screen, &temp_setup);
142 }
143
144 static void *
145 vc4_resource_transfer_map(struct pipe_context *pctx,
146 struct pipe_resource *prsc,
147 unsigned level, unsigned usage,
148 const struct pipe_box *box,
149 struct pipe_transfer **pptrans)
150 {
151 struct vc4_context *vc4 = vc4_context(pctx);
152 struct vc4_resource *rsc = vc4_resource(prsc);
153 struct vc4_transfer *trans;
154 struct pipe_transfer *ptrans;
155 enum pipe_format format = prsc->format;
156 char *buf;
157
158 /* Upgrade DISCARD_RANGE to WHOLE_RESOURCE if the whole resource is
159 * being mapped.
160 */
161 if ((usage & PIPE_TRANSFER_DISCARD_RANGE) &&
162 !(usage & PIPE_TRANSFER_UNSYNCHRONIZED) &&
163 !(prsc->flags & PIPE_RESOURCE_FLAG_MAP_COHERENT) &&
164 prsc->last_level == 0 &&
165 prsc->width0 == box->width &&
166 prsc->height0 == box->height &&
167 prsc->depth0 == box->depth &&
168 prsc->array_size == 1) {
169 usage |= PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE;
170 }
171
172 if (usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE) {
173 if (vc4_resource_bo_alloc(rsc)) {
174 /* If it might be bound as one of our vertex buffers,
175 * make sure we re-emit vertex buffer state.
176 */
177 if (prsc->bind & PIPE_BIND_VERTEX_BUFFER)
178 vc4->dirty |= VC4_DIRTY_VTXBUF;
179 } else {
180 /* If we failed to reallocate, flush users so that we
181 * don't violate any syncing requirements.
182 */
183 vc4_flush_jobs_reading_resource(vc4, prsc);
184 }
185 } else if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) {
186 /* If we're writing and the buffer is being used by the CL, we
187 * have to flush the CL first. If we're only reading, we need
188 * to flush if the CL has written our buffer.
189 */
190 if (usage & PIPE_TRANSFER_WRITE)
191 vc4_flush_jobs_reading_resource(vc4, prsc);
192 else
193 vc4_flush_jobs_writing_resource(vc4, prsc);
194 }
195
196 if (usage & PIPE_TRANSFER_WRITE) {
197 rsc->writes++;
198 rsc->initialized_buffers = ~0;
199 }
200
201 trans = slab_alloc(&vc4->transfer_pool);
202 if (!trans)
203 return NULL;
204
205 /* XXX: Handle DONTBLOCK, DISCARD_RANGE, PERSISTENT, COHERENT. */
206
207 /* slab_alloc_st() doesn't zero: */
208 memset(trans, 0, sizeof(*trans));
209 ptrans = &trans->base;
210
211 pipe_resource_reference(&ptrans->resource, prsc);
212 ptrans->level = level;
213 ptrans->usage = usage;
214 ptrans->box = *box;
215
216 /* If the resource is multisampled, we need to resolve to single
217 * sample. This seems like it should be handled at a higher layer.
218 */
219 if (prsc->nr_samples > 1) {
220 trans->ss_resource = vc4_get_temp_resource(pctx, prsc, box);
221 if (!trans->ss_resource)
222 goto fail;
223 assert(!trans->ss_resource->nr_samples);
224
225 /* The ptrans->box gets modified for tile alignment, so save
226 * the original box for unmap time.
227 */
228 trans->ss_box = *box;
229
230 if (usage & PIPE_TRANSFER_READ) {
231 struct pipe_blit_info blit;
232 memset(&blit, 0, sizeof(blit));
233
234 blit.src.resource = ptrans->resource;
235 blit.src.format = ptrans->resource->format;
236 blit.src.level = ptrans->level;
237 blit.src.box = trans->ss_box;
238
239 blit.dst.resource = trans->ss_resource;
240 blit.dst.format = trans->ss_resource->format;
241 blit.dst.box.width = trans->ss_box.width;
242 blit.dst.box.height = trans->ss_box.height;
243 blit.dst.box.depth = 1;
244
245 blit.mask = util_format_get_mask(prsc->format);
246 blit.filter = PIPE_TEX_FILTER_NEAREST;
247
248 pctx->blit(pctx, &blit);
249 vc4_flush_jobs_writing_resource(vc4, blit.dst.resource);
250 }
251
252 /* The rest of the mapping process should use our temporary. */
253 prsc = trans->ss_resource;
254 rsc = vc4_resource(prsc);
255 ptrans->box.x = 0;
256 ptrans->box.y = 0;
257 ptrans->box.z = 0;
258 }
259
260 /* Note that the current kernel implementation is synchronous, so no
261 * need to do syncing stuff here yet.
262 */
263
264 if (usage & PIPE_TRANSFER_UNSYNCHRONIZED)
265 buf = vc4_bo_map_unsynchronized(rsc->bo);
266 else
267 buf = vc4_bo_map(rsc->bo);
268 if (!buf) {
269 fprintf(stderr, "Failed to map bo\n");
270 goto fail;
271 }
272
273 *pptrans = ptrans;
274
275 struct vc4_resource_slice *slice = &rsc->slices[level];
276 if (rsc->tiled) {
277 uint32_t utile_w = vc4_utile_width(rsc->cpp);
278 uint32_t utile_h = vc4_utile_height(rsc->cpp);
279
280 /* No direct mappings of tiled, since we need to manually
281 * tile/untile.
282 */
283 if (usage & PIPE_TRANSFER_MAP_DIRECTLY)
284 return NULL;
285
286 if (format == PIPE_FORMAT_ETC1_RGB8) {
287 /* ETC1 is arranged as 64-bit blocks, where each block
288 * is 4x4 pixels. Texture tiling operates on the
289 * 64-bit block the way it would an uncompressed
290 * pixels.
291 */
292 assert(!(ptrans->box.x & 3));
293 assert(!(ptrans->box.y & 3));
294 ptrans->box.x >>= 2;
295 ptrans->box.y >>= 2;
296 ptrans->box.width = (ptrans->box.width + 3) >> 2;
297 ptrans->box.height = (ptrans->box.height + 3) >> 2;
298 }
299
300 /* We need to align the box to utile boundaries, since that's
301 * what load/store operates on. This may cause us to need to
302 * read out the original contents in that border area. Right
303 * now we just read out the entire contents, including the
304 * middle area that will just get overwritten.
305 */
306 uint32_t box_start_x = ptrans->box.x & (utile_w - 1);
307 uint32_t box_start_y = ptrans->box.y & (utile_h - 1);
308 bool needs_load = (usage & PIPE_TRANSFER_READ) != 0;
309
310 if (box_start_x) {
311 ptrans->box.width += box_start_x;
312 ptrans->box.x -= box_start_x;
313 needs_load = true;
314 }
315 if (box_start_y) {
316 ptrans->box.height += box_start_y;
317 ptrans->box.y -= box_start_y;
318 needs_load = true;
319 }
320 if (ptrans->box.width & (utile_w - 1)) {
321 /* We only need to force a load if our border region
322 * we're extending into is actually part of the
323 * texture.
324 */
325 uint32_t slice_width = u_minify(prsc->width0, level);
326 if (ptrans->box.x + ptrans->box.width != slice_width)
327 needs_load = true;
328 ptrans->box.width = align(ptrans->box.width, utile_w);
329 }
330 if (ptrans->box.height & (utile_h - 1)) {
331 uint32_t slice_height = u_minify(prsc->height0, level);
332 if (ptrans->box.y + ptrans->box.height != slice_height)
333 needs_load = true;
334 ptrans->box.height = align(ptrans->box.height, utile_h);
335 }
336
337 ptrans->stride = ptrans->box.width * rsc->cpp;
338 ptrans->layer_stride = ptrans->stride * ptrans->box.height;
339
340 trans->map = malloc(ptrans->layer_stride * ptrans->box.depth);
341
342 if (needs_load) {
343 vc4_load_tiled_image(trans->map, ptrans->stride,
344 buf + slice->offset +
345 ptrans->box.z * rsc->cube_map_stride,
346 slice->stride,
347 slice->tiling, rsc->cpp,
348 &ptrans->box);
349 }
350 return (trans->map +
351 box_start_x * rsc->cpp +
352 box_start_y * ptrans->stride);
353 } else {
354 ptrans->stride = slice->stride;
355 ptrans->layer_stride = ptrans->stride;
356
357 return buf + slice->offset +
358 ptrans->box.y / util_format_get_blockheight(format) * ptrans->stride +
359 ptrans->box.x / util_format_get_blockwidth(format) * rsc->cpp +
360 ptrans->box.z * rsc->cube_map_stride;
361 }
362
363
364 fail:
365 vc4_resource_transfer_unmap(pctx, ptrans);
366 return NULL;
367 }
368
369 static void
370 vc4_resource_destroy(struct pipe_screen *pscreen,
371 struct pipe_resource *prsc)
372 {
373 struct vc4_resource *rsc = vc4_resource(prsc);
374 pipe_resource_reference(&rsc->shadow_parent, NULL);
375 vc4_bo_unreference(&rsc->bo);
376 free(rsc);
377 }
378
379 static boolean
380 vc4_resource_get_handle(struct pipe_screen *pscreen,
381 struct pipe_context *pctx,
382 struct pipe_resource *prsc,
383 struct winsys_handle *whandle,
384 unsigned usage)
385 {
386 struct vc4_resource *rsc = vc4_resource(prsc);
387
388 whandle->stride = rsc->slices[0].stride;
389
390 /* If we're passing some reference to our BO out to some other part of
391 * the system, then we can't do any optimizations about only us being
392 * the ones seeing it (like BO caching or shadow update avoidance).
393 */
394 rsc->bo->private = false;
395
396 switch (whandle->type) {
397 case DRM_API_HANDLE_TYPE_SHARED:
398 return vc4_bo_flink(rsc->bo, &whandle->handle);
399 case DRM_API_HANDLE_TYPE_KMS:
400 whandle->handle = rsc->bo->handle;
401 return TRUE;
402 case DRM_API_HANDLE_TYPE_FD:
403 whandle->handle = vc4_bo_get_dmabuf(rsc->bo);
404 return whandle->handle != -1;
405 }
406
407 return FALSE;
408 }
409
410 static void
411 vc4_setup_slices(struct vc4_resource *rsc)
412 {
413 struct pipe_resource *prsc = &rsc->base;
414 uint32_t width = prsc->width0;
415 uint32_t height = prsc->height0;
416 if (prsc->format == PIPE_FORMAT_ETC1_RGB8) {
417 width = (width + 3) >> 2;
418 height = (height + 3) >> 2;
419 }
420
421 uint32_t pot_width = util_next_power_of_two(width);
422 uint32_t pot_height = util_next_power_of_two(height);
423 uint32_t offset = 0;
424 uint32_t utile_w = vc4_utile_width(rsc->cpp);
425 uint32_t utile_h = vc4_utile_height(rsc->cpp);
426
427 for (int i = prsc->last_level; i >= 0; i--) {
428 struct vc4_resource_slice *slice = &rsc->slices[i];
429
430 uint32_t level_width, level_height;
431 if (i == 0) {
432 level_width = width;
433 level_height = height;
434 } else {
435 level_width = u_minify(pot_width, i);
436 level_height = u_minify(pot_height, i);
437 }
438
439 if (!rsc->tiled) {
440 slice->tiling = VC4_TILING_FORMAT_LINEAR;
441 if (prsc->nr_samples > 1) {
442 /* MSAA (4x) surfaces are stored as raw tile buffer contents. */
443 level_width = align(level_width, 32);
444 level_height = align(level_height, 32);
445 } else {
446 level_width = align(level_width, utile_w);
447 }
448 } else {
449 if (vc4_size_is_lt(level_width, level_height,
450 rsc->cpp)) {
451 slice->tiling = VC4_TILING_FORMAT_LT;
452 level_width = align(level_width, utile_w);
453 level_height = align(level_height, utile_h);
454 } else {
455 slice->tiling = VC4_TILING_FORMAT_T;
456 level_width = align(level_width,
457 4 * 2 * utile_w);
458 level_height = align(level_height,
459 4 * 2 * utile_h);
460 }
461 }
462
463 slice->offset = offset;
464 slice->stride = (level_width * rsc->cpp *
465 MAX2(prsc->nr_samples, 1));
466 slice->size = level_height * slice->stride;
467
468 offset += slice->size;
469
470 if (miptree_debug) {
471 static const char tiling_chars[] = {
472 [VC4_TILING_FORMAT_LINEAR] = 'R',
473 [VC4_TILING_FORMAT_LT] = 'L',
474 [VC4_TILING_FORMAT_T] = 'T'
475 };
476 fprintf(stderr,
477 "rsc setup %p (format %s: vc4 %d), %dx%d: "
478 "level %d (%c) -> %dx%d, stride %d@0x%08x\n",
479 rsc,
480 util_format_short_name(prsc->format),
481 rsc->vc4_format,
482 prsc->width0, prsc->height0,
483 i, tiling_chars[slice->tiling],
484 level_width, level_height,
485 slice->stride, slice->offset);
486 }
487 }
488
489 /* The texture base pointer that has to point to level 0 doesn't have
490 * intra-page bits, so we have to align it, and thus shift up all the
491 * smaller slices.
492 */
493 uint32_t page_align_offset = (align(rsc->slices[0].offset, 4096) -
494 rsc->slices[0].offset);
495 if (page_align_offset) {
496 for (int i = 0; i <= prsc->last_level; i++)
497 rsc->slices[i].offset += page_align_offset;
498 }
499
500 /* Cube map faces appear as whole miptrees at a page-aligned offset
501 * from the first face's miptree.
502 */
503 if (prsc->target == PIPE_TEXTURE_CUBE) {
504 rsc->cube_map_stride = align(rsc->slices[0].offset +
505 rsc->slices[0].size, 4096);
506 }
507 }
508
509 static struct vc4_resource *
510 vc4_resource_setup(struct pipe_screen *pscreen,
511 const struct pipe_resource *tmpl)
512 {
513 struct vc4_resource *rsc = CALLOC_STRUCT(vc4_resource);
514 if (!rsc)
515 return NULL;
516 struct pipe_resource *prsc = &rsc->base;
517
518 *prsc = *tmpl;
519
520 pipe_reference_init(&prsc->reference, 1);
521 prsc->screen = pscreen;
522
523 if (prsc->nr_samples <= 1)
524 rsc->cpp = util_format_get_blocksize(tmpl->format);
525 else
526 rsc->cpp = sizeof(uint32_t);
527
528 assert(rsc->cpp);
529
530 return rsc;
531 }
532
533 static enum vc4_texture_data_type
534 get_resource_texture_format(struct pipe_resource *prsc)
535 {
536 struct vc4_resource *rsc = vc4_resource(prsc);
537 uint8_t format = vc4_get_tex_format(prsc->format);
538
539 if (!rsc->tiled) {
540 if (prsc->nr_samples > 1) {
541 return ~0;
542 } else {
543 assert(format == VC4_TEXTURE_TYPE_RGBA8888);
544 return VC4_TEXTURE_TYPE_RGBA32R;
545 }
546 }
547
548 return format;
549 }
550
551 struct pipe_resource *
552 vc4_resource_create(struct pipe_screen *pscreen,
553 const struct pipe_resource *tmpl)
554 {
555 struct vc4_resource *rsc = vc4_resource_setup(pscreen, tmpl);
556 struct pipe_resource *prsc = &rsc->base;
557
558 /* We have to make shared be untiled, since we don't have any way to
559 * communicate metadata about tiling currently.
560 */
561 if (tmpl->target == PIPE_BUFFER ||
562 tmpl->nr_samples > 1 ||
563 (tmpl->bind & (PIPE_BIND_SCANOUT |
564 PIPE_BIND_LINEAR |
565 PIPE_BIND_SHARED |
566 PIPE_BIND_CURSOR))) {
567 rsc->tiled = false;
568 } else {
569 rsc->tiled = true;
570 }
571
572 if (tmpl->target != PIPE_BUFFER)
573 rsc->vc4_format = get_resource_texture_format(prsc);
574
575 vc4_setup_slices(rsc);
576 if (!vc4_resource_bo_alloc(rsc))
577 goto fail;
578
579 return prsc;
580 fail:
581 vc4_resource_destroy(pscreen, prsc);
582 return NULL;
583 }
584
585 static struct pipe_resource *
586 vc4_resource_from_handle(struct pipe_screen *pscreen,
587 const struct pipe_resource *tmpl,
588 struct winsys_handle *whandle,
589 unsigned usage)
590 {
591 struct vc4_screen *screen = vc4_screen(pscreen);
592 struct vc4_resource *rsc = vc4_resource_setup(pscreen, tmpl);
593 struct pipe_resource *prsc = &rsc->base;
594 struct vc4_resource_slice *slice = &rsc->slices[0];
595 uint32_t expected_stride =
596 align(prsc->width0, vc4_utile_width(rsc->cpp)) * rsc->cpp;
597
598 if (!rsc)
599 return NULL;
600
601 if (whandle->stride != expected_stride) {
602 static bool warned = false;
603 if (!warned) {
604 warned = true;
605 fprintf(stderr,
606 "Attempting to import %dx%d %s with "
607 "unsupported stride %d instead of %d\n",
608 prsc->width0, prsc->height0,
609 util_format_short_name(prsc->format),
610 whandle->stride,
611 expected_stride);
612 }
613 goto fail;
614 }
615
616 rsc->tiled = false;
617
618 if (whandle->offset != 0) {
619 fprintf(stderr,
620 "Attempt to import unsupported winsys offset %u\n",
621 whandle->offset);
622 return NULL;
623 }
624
625 switch (whandle->type) {
626 case DRM_API_HANDLE_TYPE_SHARED:
627 rsc->bo = vc4_bo_open_name(screen,
628 whandle->handle, whandle->stride);
629 break;
630 case DRM_API_HANDLE_TYPE_FD:
631 rsc->bo = vc4_bo_open_dmabuf(screen,
632 whandle->handle, whandle->stride);
633 break;
634 default:
635 fprintf(stderr,
636 "Attempt to import unsupported handle type %d\n",
637 whandle->type);
638 }
639
640 if (!rsc->bo)
641 goto fail;
642
643 slice->stride = whandle->stride;
644 slice->tiling = VC4_TILING_FORMAT_LINEAR;
645
646 rsc->vc4_format = get_resource_texture_format(prsc);
647
648 if (miptree_debug) {
649 fprintf(stderr,
650 "rsc import %p (format %d), %dx%d: "
651 "level 0 (R) -> stride %d@0x%08x\n",
652 rsc, rsc->vc4_format,
653 prsc->width0, prsc->height0,
654 slice->stride, slice->offset);
655 }
656
657 return prsc;
658
659 fail:
660 vc4_resource_destroy(pscreen, prsc);
661 return NULL;
662 }
663
664 static struct pipe_surface *
665 vc4_create_surface(struct pipe_context *pctx,
666 struct pipe_resource *ptex,
667 const struct pipe_surface *surf_tmpl)
668 {
669 struct vc4_surface *surface = CALLOC_STRUCT(vc4_surface);
670 struct vc4_resource *rsc = vc4_resource(ptex);
671
672 if (!surface)
673 return NULL;
674
675 assert(surf_tmpl->u.tex.first_layer == surf_tmpl->u.tex.last_layer);
676
677 struct pipe_surface *psurf = &surface->base;
678 unsigned level = surf_tmpl->u.tex.level;
679
680 pipe_reference_init(&psurf->reference, 1);
681 pipe_resource_reference(&psurf->texture, ptex);
682
683 psurf->context = pctx;
684 psurf->format = surf_tmpl->format;
685 psurf->width = u_minify(ptex->width0, level);
686 psurf->height = u_minify(ptex->height0, level);
687 psurf->u.tex.level = level;
688 psurf->u.tex.first_layer = surf_tmpl->u.tex.first_layer;
689 psurf->u.tex.last_layer = surf_tmpl->u.tex.last_layer;
690 surface->offset = (rsc->slices[level].offset +
691 psurf->u.tex.first_layer * rsc->cube_map_stride);
692 surface->tiling = rsc->slices[level].tiling;
693
694 return &surface->base;
695 }
696
697 static void
698 vc4_surface_destroy(struct pipe_context *pctx, struct pipe_surface *psurf)
699 {
700 pipe_resource_reference(&psurf->texture, NULL);
701 FREE(psurf);
702 }
703
704 static void
705 vc4_dump_surface_non_msaa(struct pipe_surface *psurf)
706 {
707 struct pipe_resource *prsc = psurf->texture;
708 struct vc4_resource *rsc = vc4_resource(prsc);
709 uint32_t *map = vc4_bo_map(rsc->bo);
710 uint32_t stride = rsc->slices[0].stride / 4;
711 uint32_t width = psurf->width;
712 uint32_t height = psurf->height;
713 uint32_t chunk_w = width / 79;
714 uint32_t chunk_h = height / 40;
715 uint32_t found_colors[10];
716 uint32_t num_found_colors = 0;
717
718 if (rsc->vc4_format != VC4_TEXTURE_TYPE_RGBA32R) {
719 fprintf(stderr, "%s: Unsupported format %s\n",
720 __func__, util_format_short_name(psurf->format));
721 return;
722 }
723
724 for (int by = 0; by < height; by += chunk_h) {
725 for (int bx = 0; bx < width; bx += chunk_w) {
726 int all_found_color = -1; /* nothing found */
727
728 for (int y = by; y < MIN2(height, by + chunk_h); y++) {
729 for (int x = bx; x < MIN2(width, bx + chunk_w); x++) {
730 uint32_t pix = map[y * stride + x];
731
732 int i;
733 for (i = 0; i < num_found_colors; i++) {
734 if (pix == found_colors[i])
735 break;
736 }
737 if (i == num_found_colors &&
738 num_found_colors <
739 ARRAY_SIZE(found_colors)) {
740 found_colors[num_found_colors++] = pix;
741 }
742
743 if (i < num_found_colors) {
744 if (all_found_color == -1)
745 all_found_color = i;
746 else if (i != all_found_color)
747 all_found_color = ARRAY_SIZE(found_colors);
748 }
749 }
750 }
751 /* If all pixels for this chunk have a consistent
752 * value, then print a character for it. Either a
753 * fixed name (particularly common for piglit tests),
754 * or a runtime-generated number.
755 */
756 if (all_found_color >= 0 &&
757 all_found_color < ARRAY_SIZE(found_colors)) {
758 static const struct {
759 uint32_t val;
760 const char *c;
761 } named_colors[] = {
762 { 0xff000000, "█" },
763 { 0x00000000, "█" },
764 { 0xffff0000, "r" },
765 { 0xff00ff00, "g" },
766 { 0xff0000ff, "b" },
767 { 0xffffffff, "w" },
768 };
769 int i;
770 for (i = 0; i < ARRAY_SIZE(named_colors); i++) {
771 if (named_colors[i].val ==
772 found_colors[all_found_color]) {
773 fprintf(stderr, "%s",
774 named_colors[i].c);
775 break;
776 }
777 }
778 /* For unnamed colors, print a number and the
779 * numbers will have values printed at the
780 * end.
781 */
782 if (i == ARRAY_SIZE(named_colors)) {
783 fprintf(stderr, "%c",
784 '0' + all_found_color);
785 }
786 } else {
787 /* If there's no consistent color, print this.
788 */
789 fprintf(stderr, ".");
790 }
791 }
792 fprintf(stderr, "\n");
793 }
794
795 for (int i = 0; i < num_found_colors; i++) {
796 fprintf(stderr, "color %d: 0x%08x\n", i, found_colors[i]);
797 }
798 }
799
800 static uint32_t
801 vc4_surface_msaa_get_sample(struct pipe_surface *psurf,
802 uint32_t x, uint32_t y, uint32_t sample)
803 {
804 struct pipe_resource *prsc = psurf->texture;
805 struct vc4_resource *rsc = vc4_resource(prsc);
806 uint32_t tile_w = 32, tile_h = 32;
807 uint32_t tiles_w = DIV_ROUND_UP(psurf->width, 32);
808
809 uint32_t tile_x = x / tile_w;
810 uint32_t tile_y = y / tile_h;
811 uint32_t *tile = (vc4_bo_map(rsc->bo) +
812 VC4_TILE_BUFFER_SIZE * (tile_y * tiles_w + tile_x));
813 uint32_t subtile_x = x % tile_w;
814 uint32_t subtile_y = y % tile_h;
815
816 uint32_t quad_samples = VC4_MAX_SAMPLES * 4;
817 uint32_t tile_stride = quad_samples * tile_w / 2;
818
819 return *((uint32_t *)tile +
820 (subtile_y >> 1) * tile_stride +
821 (subtile_x >> 1) * quad_samples +
822 ((subtile_y & 1) << 1) +
823 (subtile_x & 1) +
824 sample);
825 }
826
827 static void
828 vc4_dump_surface_msaa_char(struct pipe_surface *psurf,
829 uint32_t start_x, uint32_t start_y,
830 uint32_t w, uint32_t h)
831 {
832 bool all_same_color = true;
833 uint32_t all_pix = 0;
834
835 for (int y = start_y; y < start_y + h; y++) {
836 for (int x = start_x; x < start_x + w; x++) {
837 for (int s = 0; s < VC4_MAX_SAMPLES; s++) {
838 uint32_t pix = vc4_surface_msaa_get_sample(psurf,
839 x, y,
840 s);
841 if (x == start_x && y == start_y)
842 all_pix = pix;
843 else if (all_pix != pix)
844 all_same_color = false;
845 }
846 }
847 }
848 if (all_same_color) {
849 static const struct {
850 uint32_t val;
851 const char *c;
852 } named_colors[] = {
853 { 0xff000000, "█" },
854 { 0x00000000, "█" },
855 { 0xffff0000, "r" },
856 { 0xff00ff00, "g" },
857 { 0xff0000ff, "b" },
858 { 0xffffffff, "w" },
859 };
860 int i;
861 for (i = 0; i < ARRAY_SIZE(named_colors); i++) {
862 if (named_colors[i].val == all_pix) {
863 fprintf(stderr, "%s",
864 named_colors[i].c);
865 return;
866 }
867 }
868 fprintf(stderr, "x");
869 } else {
870 fprintf(stderr, ".");
871 }
872 }
873
874 static void
875 vc4_dump_surface_msaa(struct pipe_surface *psurf)
876 {
877 uint32_t tile_w = 32, tile_h = 32;
878 uint32_t tiles_w = DIV_ROUND_UP(psurf->width, tile_w);
879 uint32_t tiles_h = DIV_ROUND_UP(psurf->height, tile_h);
880 uint32_t char_w = 140, char_h = 60;
881 uint32_t char_w_per_tile = char_w / tiles_w - 1;
882 uint32_t char_h_per_tile = char_h / tiles_h - 1;
883 uint32_t found_colors[10];
884 uint32_t num_found_colors = 0;
885
886 fprintf(stderr, "Surface: %dx%d (%dx MSAA)\n",
887 psurf->width, psurf->height, psurf->texture->nr_samples);
888
889 for (int x = 0; x < (char_w_per_tile + 1) * tiles_w; x++)
890 fprintf(stderr, "-");
891 fprintf(stderr, "\n");
892
893 for (int ty = 0; ty < psurf->height; ty += tile_h) {
894 for (int y = 0; y < char_h_per_tile; y++) {
895
896 for (int tx = 0; tx < psurf->width; tx += tile_w) {
897 for (int x = 0; x < char_w_per_tile; x++) {
898 uint32_t bx1 = (x * tile_w /
899 char_w_per_tile);
900 uint32_t bx2 = ((x + 1) * tile_w /
901 char_w_per_tile);
902 uint32_t by1 = (y * tile_h /
903 char_h_per_tile);
904 uint32_t by2 = ((y + 1) * tile_h /
905 char_h_per_tile);
906
907 vc4_dump_surface_msaa_char(psurf,
908 tx + bx1,
909 ty + by1,
910 bx2 - bx1,
911 by2 - by1);
912 }
913 fprintf(stderr, "|");
914 }
915 fprintf(stderr, "\n");
916 }
917
918 for (int x = 0; x < (char_w_per_tile + 1) * tiles_w; x++)
919 fprintf(stderr, "-");
920 fprintf(stderr, "\n");
921 }
922
923 for (int i = 0; i < num_found_colors; i++) {
924 fprintf(stderr, "color %d: 0x%08x\n", i, found_colors[i]);
925 }
926 }
927
928 /** Debug routine to dump the contents of an 8888 surface to the console */
929 void
930 vc4_dump_surface(struct pipe_surface *psurf)
931 {
932 if (!psurf)
933 return;
934
935 if (psurf->texture->nr_samples > 1)
936 vc4_dump_surface_msaa(psurf);
937 else
938 vc4_dump_surface_non_msaa(psurf);
939 }
940
941 static void
942 vc4_flush_resource(struct pipe_context *pctx, struct pipe_resource *resource)
943 {
944 /* All calls to flush_resource are followed by a flush of the context,
945 * so there's nothing to do.
946 */
947 }
948
949 void
950 vc4_update_shadow_baselevel_texture(struct pipe_context *pctx,
951 struct pipe_sampler_view *view)
952 {
953 struct vc4_resource *shadow = vc4_resource(view->texture);
954 struct vc4_resource *orig = vc4_resource(shadow->shadow_parent);
955 assert(orig);
956
957 if (shadow->writes == orig->writes && orig->bo->private)
958 return;
959
960 perf_debug("Updating %dx%d@%d shadow texture due to %s\n",
961 orig->base.width0, orig->base.height0,
962 view->u.tex.first_level,
963 view->u.tex.first_level ? "base level" : "raster layout");
964
965 for (int i = 0; i <= shadow->base.last_level; i++) {
966 unsigned width = u_minify(shadow->base.width0, i);
967 unsigned height = u_minify(shadow->base.height0, i);
968 struct pipe_blit_info info = {
969 .dst = {
970 .resource = &shadow->base,
971 .level = i,
972 .box = {
973 .x = 0,
974 .y = 0,
975 .z = 0,
976 .width = width,
977 .height = height,
978 .depth = 1,
979 },
980 .format = shadow->base.format,
981 },
982 .src = {
983 .resource = &orig->base,
984 .level = view->u.tex.first_level + i,
985 .box = {
986 .x = 0,
987 .y = 0,
988 .z = 0,
989 .width = width,
990 .height = height,
991 .depth = 1,
992 },
993 .format = orig->base.format,
994 },
995 .mask = ~0,
996 };
997 pctx->blit(pctx, &info);
998 }
999
1000 shadow->writes = orig->writes;
1001 }
1002
1003 /**
1004 * Converts a 4-byte index buffer to 2 bytes.
1005 *
1006 * Since GLES2 only has support for 1 and 2-byte indices, the hardware doesn't
1007 * include 4-byte index support, and we have to shrink it down.
1008 *
1009 * There's no fallback support for when indices end up being larger than 2^16,
1010 * though it will at least assertion fail. Also, if the original index data
1011 * was in user memory, it would be nice to not have uploaded it to a VBO
1012 * before translating.
1013 */
1014 struct pipe_resource *
1015 vc4_get_shadow_index_buffer(struct pipe_context *pctx,
1016 const struct pipe_draw_info *info,
1017 uint32_t offset,
1018 uint32_t count,
1019 uint32_t *shadow_offset)
1020 {
1021 struct vc4_context *vc4 = vc4_context(pctx);
1022 struct vc4_resource *orig = vc4_resource(info->index.resource);
1023 perf_debug("Fallback conversion for %d uint indices\n", count);
1024
1025 void *data;
1026 struct pipe_resource *shadow_rsc = NULL;
1027 u_upload_alloc(vc4->uploader, 0, count * 2, 4,
1028 shadow_offset, &shadow_rsc, &data);
1029 uint16_t *dst = data;
1030
1031 struct pipe_transfer *src_transfer = NULL;
1032 const uint32_t *src;
1033 if (info->has_user_indices) {
1034 src = info->index.user;
1035 } else {
1036 src = pipe_buffer_map_range(pctx, &orig->base,
1037 offset,
1038 count * 4,
1039 PIPE_TRANSFER_READ, &src_transfer);
1040 }
1041
1042 for (int i = 0; i < count; i++) {
1043 uint32_t src_index = src[i];
1044 assert(src_index <= 0xffff);
1045 dst[i] = src_index;
1046 }
1047
1048 if (src_transfer)
1049 pctx->transfer_unmap(pctx, src_transfer);
1050
1051 return shadow_rsc;
1052 }
1053
1054 void
1055 vc4_resource_screen_init(struct pipe_screen *pscreen)
1056 {
1057 pscreen->resource_create = vc4_resource_create;
1058 pscreen->resource_from_handle = vc4_resource_from_handle;
1059 pscreen->resource_destroy = u_resource_destroy_vtbl;
1060 pscreen->resource_get_handle = vc4_resource_get_handle;
1061 pscreen->resource_destroy = vc4_resource_destroy;
1062 }
1063
1064 void
1065 vc4_resource_context_init(struct pipe_context *pctx)
1066 {
1067 pctx->transfer_map = vc4_resource_transfer_map;
1068 pctx->transfer_flush_region = u_default_transfer_flush_region;
1069 pctx->transfer_unmap = vc4_resource_transfer_unmap;
1070 pctx->buffer_subdata = u_default_buffer_subdata;
1071 pctx->texture_subdata = u_default_texture_subdata;
1072 pctx->create_surface = vc4_create_surface;
1073 pctx->surface_destroy = vc4_surface_destroy;
1074 pctx->resource_copy_region = util_resource_copy_region;
1075 pctx->blit = vc4_blit;
1076 pctx->flush_resource = vc4_flush_resource;
1077 }