1 /*
2 * Copyright (c) 2012-2015 Etnaviv Project
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 * the rights to use, copy, modify, merge, publish, distribute, sub license,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the
12 * next paragraph) shall be included in all copies or substantial portions
13 * of the 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 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 *
23 * Authors:
24 * Wladimir J. van der Laan <laanwj@gmail.com>
25 */
26
27 #include "etnaviv_resource.h"
28
29 #include "hw/common.xml.h"
30
31 #include "etnaviv_context.h"
32 #include "etnaviv_debug.h"
33 #include "etnaviv_screen.h"
34 #include "etnaviv_translate.h"
35
36 #include "util/hash_table.h"
37 #include "util/u_inlines.h"
38 #include "util/u_memory.h"
39
40 #include "drm-uapi/drm_fourcc.h"
41
modifier_to_layout(uint64_t modifier)42 static enum etna_surface_layout modifier_to_layout(uint64_t modifier)
43 {
44 switch (modifier) {
45 case DRM_FORMAT_MOD_VIVANTE_TILED:
46 return ETNA_LAYOUT_TILED;
47 case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
48 return ETNA_LAYOUT_SUPER_TILED;
49 case DRM_FORMAT_MOD_VIVANTE_SPLIT_TILED:
50 return ETNA_LAYOUT_MULTI_TILED;
51 case DRM_FORMAT_MOD_VIVANTE_SPLIT_SUPER_TILED:
52 return ETNA_LAYOUT_MULTI_SUPERTILED;
53 case DRM_FORMAT_MOD_LINEAR:
54 default:
55 return ETNA_LAYOUT_LINEAR;
56 }
57 }
58
layout_to_modifier(enum etna_surface_layout layout)59 static uint64_t layout_to_modifier(enum etna_surface_layout layout)
60 {
61 switch (layout) {
62 case ETNA_LAYOUT_TILED:
63 return DRM_FORMAT_MOD_VIVANTE_TILED;
64 case ETNA_LAYOUT_SUPER_TILED:
65 return DRM_FORMAT_MOD_VIVANTE_SUPER_TILED;
66 case ETNA_LAYOUT_MULTI_TILED:
67 return DRM_FORMAT_MOD_VIVANTE_SPLIT_TILED;
68 case ETNA_LAYOUT_MULTI_SUPERTILED:
69 return DRM_FORMAT_MOD_VIVANTE_SPLIT_SUPER_TILED;
70 case ETNA_LAYOUT_LINEAR:
71 return DRM_FORMAT_MOD_LINEAR;
72 default:
73 return DRM_FORMAT_MOD_INVALID;
74 }
75 }
76
77 /* A tile is 4x4 pixels, having 'screen->specs.bits_per_tile' of tile status.
78 * So, in a buffer of N pixels, there are N / (4 * 4) tiles.
79 * We need N * screen->specs.bits_per_tile / (4 * 4) bits of tile status, or
80 * N * screen->specs.bits_per_tile / (4 * 4 * 8) bytes.
81 */
82 bool
etna_screen_resource_alloc_ts(struct pipe_screen * pscreen,struct etna_resource * rsc)83 etna_screen_resource_alloc_ts(struct pipe_screen *pscreen,
84 struct etna_resource *rsc)
85 {
86 struct etna_screen *screen = etna_screen(pscreen);
87 size_t rt_ts_size, ts_layer_stride;
88 uint8_t ts_mode = TS_MODE_128B;
89 int8_t ts_compress_fmt;
90
91 assert(!rsc->ts_bo);
92
93 /* pre-v4 compression is largely useless, so disable it when not wanted for MSAA
94 * v4 compression can be enabled everywhere without any known drawback,
95 * except that in-place resolve must go through a slower path
96 */
97 ts_compress_fmt = (screen->specs.v4_compression || rsc->base.nr_samples > 1) ?
98 translate_ts_format(rsc->base.format) : -1;
99
100 /* enable 256B ts mode with compression, as it improves performance
101 * the size of the resource might also determine if we want to use it or not
102 */
103 if (VIV_FEATURE(screen, chipMinorFeatures6, CACHE128B256BPERLINE) &&
104 ts_compress_fmt >= 0 &&
105 (rsc->layout != ETNA_LAYOUT_LINEAR ||
106 rsc->levels[0].stride % 256 == 0) )
107 ts_mode = TS_MODE_256B;
108
109 ts_layer_stride = align(DIV_ROUND_UP(rsc->levels[0].layer_stride,
110 etna_screen_get_tile_size(screen, ts_mode) *
111 8 / screen->specs.bits_per_tile),
112 0x100 * screen->specs.pixel_pipes);
113 rt_ts_size = ts_layer_stride * rsc->base.array_size;
114 if (rt_ts_size == 0)
115 return true;
116
117 DBG_F(ETNA_DBG_RESOURCE_MSGS, "%p: Allocating tile status of size %zu",
118 rsc, rt_ts_size);
119
120 struct etna_bo *rt_ts;
121 rt_ts = etna_bo_new(screen->dev, rt_ts_size, DRM_ETNA_GEM_CACHE_WC);
122
123 if (unlikely(!rt_ts)) {
124 BUG("Problem allocating tile status for resource");
125 return false;
126 }
127
128 rsc->ts_bo = rt_ts;
129 rsc->levels[0].ts_offset = 0;
130 rsc->levels[0].ts_layer_stride = ts_layer_stride;
131 rsc->levels[0].ts_size = rt_ts_size;
132 rsc->levels[0].ts_mode = ts_mode;
133 rsc->levels[0].ts_compress_fmt = ts_compress_fmt;
134
135 return true;
136 }
137
138 static bool
etna_screen_can_create_resource(struct pipe_screen * pscreen,const struct pipe_resource * templat)139 etna_screen_can_create_resource(struct pipe_screen *pscreen,
140 const struct pipe_resource *templat)
141 {
142 struct etna_screen *screen = etna_screen(pscreen);
143 if (!translate_samples_to_xyscale(templat->nr_samples, NULL, NULL))
144 return false;
145
146 /* templat->bind is not set here, so we must use the minimum sizes */
147 uint max_size =
148 MIN2(screen->specs.max_rendertarget_size, screen->specs.max_texture_size);
149
150 if (templat->width0 > max_size || templat->height0 > max_size)
151 return false;
152
153 return true;
154 }
155
156 static unsigned
setup_miptree(struct etna_resource * rsc,unsigned paddingX,unsigned paddingY,unsigned msaa_xscale,unsigned msaa_yscale)157 setup_miptree(struct etna_resource *rsc, unsigned paddingX, unsigned paddingY,
158 unsigned msaa_xscale, unsigned msaa_yscale)
159 {
160 struct pipe_resource *prsc = &rsc->base;
161 unsigned level, size = 0;
162 unsigned width = prsc->width0;
163 unsigned height = prsc->height0;
164 unsigned depth = prsc->depth0;
165
166 for (level = 0; level <= prsc->last_level; level++) {
167 struct etna_resource_level *mip = &rsc->levels[level];
168
169 mip->width = width;
170 mip->height = height;
171 mip->depth = depth;
172 mip->padded_width = align(width * msaa_xscale, paddingX);
173 mip->padded_height = align(height * msaa_yscale, paddingY);
174 mip->stride = util_format_get_stride(prsc->format, mip->padded_width);
175 mip->offset = size;
176 mip->layer_stride = mip->stride * util_format_get_nblocksy(prsc->format, mip->padded_height);
177 mip->size = prsc->array_size * mip->layer_stride;
178
179 /* align levels to 64 bytes to be able to render to them */
180 size += align(mip->size, ETNA_PE_ALIGNMENT) * depth;
181
182 width = u_minify(width, 1);
183 height = u_minify(height, 1);
184 depth = u_minify(depth, 1);
185 }
186
187 return size;
188 }
189
190 /* Is rs alignment needed? */
is_rs_align(struct etna_screen * screen,const struct pipe_resource * tmpl)191 static bool is_rs_align(struct etna_screen *screen,
192 const struct pipe_resource *tmpl)
193 {
194 return screen->specs.use_blt ? false : (
195 VIV_FEATURE(screen, chipMinorFeatures1, TEXTURE_HALIGN) ||
196 !etna_resource_sampler_only(tmpl));
197 }
198
199 /* Create a new resource object, using the given template info */
200 struct pipe_resource *
etna_resource_alloc(struct pipe_screen * pscreen,unsigned layout,uint64_t modifier,const struct pipe_resource * templat)201 etna_resource_alloc(struct pipe_screen *pscreen, unsigned layout,
202 uint64_t modifier, const struct pipe_resource *templat)
203 {
204 struct etna_screen *screen = etna_screen(pscreen);
205 struct etna_resource *rsc;
206 unsigned size;
207
208 DBG_F(ETNA_DBG_RESOURCE_MSGS,
209 "target=%d, format=%s, %ux%ux%u, array_size=%u, "
210 "last_level=%u, nr_samples=%u, usage=%u, bind=%x, flags=%x",
211 templat->target, util_format_name(templat->format), templat->width0,
212 templat->height0, templat->depth0, templat->array_size,
213 templat->last_level, templat->nr_samples, templat->usage,
214 templat->bind, templat->flags);
215
216 /* Determine scaling for antialiasing, allow override using debug flag */
217 int nr_samples = templat->nr_samples;
218 if ((templat->bind & (PIPE_BIND_RENDER_TARGET | PIPE_BIND_DEPTH_STENCIL)) &&
219 !(templat->bind & PIPE_BIND_SAMPLER_VIEW)) {
220 if (DBG_ENABLED(ETNA_DBG_MSAA_2X))
221 nr_samples = 2;
222 if (DBG_ENABLED(ETNA_DBG_MSAA_4X))
223 nr_samples = 4;
224 }
225
226 int msaa_xscale = 1, msaa_yscale = 1;
227 if (!translate_samples_to_xyscale(nr_samples, &msaa_xscale, &msaa_yscale)) {
228 /* Number of samples not supported */
229 return NULL;
230 }
231
232 /* Determine needed padding (alignment of height/width) */
233 unsigned paddingX = 0, paddingY = 0;
234 unsigned halign = TEXTURE_HALIGN_FOUR;
235 if (!util_format_is_compressed(templat->format)) {
236 /* If we have the TEXTURE_HALIGN feature, we can always align to the
237 * resolve engine's width. If not, we must not align resources used
238 * only for textures. If this GPU uses the BLT engine, never do RS align.
239 */
240 etna_layout_multiple(layout, screen->specs.pixel_pipes,
241 is_rs_align (screen, templat),
242 &paddingX, &paddingY, &halign);
243 assert(paddingX && paddingY);
244 } else {
245 /* Compressed textures are padded to their block size, but we don't have
246 * to do anything special for that. */
247 paddingX = 1;
248 paddingY = 1;
249 }
250
251 if (!screen->specs.use_blt && templat->target != PIPE_BUFFER && layout == ETNA_LAYOUT_LINEAR)
252 paddingY = align(paddingY, ETNA_RS_HEIGHT_MASK + 1);
253
254 rsc = CALLOC_STRUCT(etna_resource);
255 if (!rsc)
256 return NULL;
257
258 rsc->base = *templat;
259 rsc->base.screen = pscreen;
260 rsc->base.nr_samples = nr_samples;
261 rsc->layout = layout;
262 rsc->halign = halign;
263 rsc->explicit_flush = true;
264
265 pipe_reference_init(&rsc->base.reference, 1);
266 util_range_init(&rsc->valid_buffer_range);
267
268 size = setup_miptree(rsc, paddingX, paddingY, msaa_xscale, msaa_yscale);
269
270 if (unlikely(templat->bind & PIPE_BIND_SCANOUT) && screen->ro) {
271 struct pipe_resource scanout_templat = *templat;
272 struct winsys_handle handle;
273
274 scanout_templat.width0 = align(scanout_templat.width0, paddingX);
275 scanout_templat.height0 = align(scanout_templat.height0, paddingY);
276
277 rsc->scanout = renderonly_scanout_for_resource(&scanout_templat,
278 screen->ro, &handle);
279 if (!rsc->scanout) {
280 BUG("Problem allocating kms memory for resource");
281 goto free_rsc;
282 }
283
284 assert(handle.type == WINSYS_HANDLE_TYPE_FD);
285 rsc->levels[0].stride = handle.stride;
286 rsc->bo = etna_screen_bo_from_handle(pscreen, &handle);
287 close(handle.handle);
288 if (unlikely(!rsc->bo))
289 goto free_rsc;
290 } else {
291 uint32_t flags = DRM_ETNA_GEM_CACHE_WC;
292
293 if (templat->bind & PIPE_BIND_VERTEX_BUFFER)
294 flags |= DRM_ETNA_GEM_FORCE_MMU;
295
296 rsc->bo = etna_bo_new(screen->dev, size, flags);
297 if (unlikely(!rsc->bo)) {
298 BUG("Problem allocating video memory for resource");
299 goto free_rsc;
300 }
301 }
302
303 if (DBG_ENABLED(ETNA_DBG_ZERO)) {
304 void *map = etna_bo_map(rsc->bo);
305 etna_bo_cpu_prep(rsc->bo, DRM_ETNA_PREP_WRITE);
306 memset(map, 0, size);
307 etna_bo_cpu_fini(rsc->bo);
308 }
309
310 return &rsc->base;
311
312 free_rsc:
313 FREE(rsc);
314 return NULL;
315 }
316
317 static struct pipe_resource *
etna_resource_create(struct pipe_screen * pscreen,const struct pipe_resource * templat)318 etna_resource_create(struct pipe_screen *pscreen,
319 const struct pipe_resource *templat)
320 {
321 struct etna_screen *screen = etna_screen(pscreen);
322 unsigned layout = ETNA_LAYOUT_TILED;
323
324 /* At this point we don't know if the resource will be used as a texture,
325 * render target, or both, because gallium sets the bits whenever possible
326 * This matters because on some GPUs (GC2000) there is no tiling that is
327 * compatible with both TE and PE.
328 *
329 * We expect that depth/stencil buffers will always be used by PE (rendering),
330 * and any other non-scanout resource will be used as a texture at some point,
331 * So allocate a render-compatible base buffer for scanout/depthstencil buffers,
332 * and a texture-compatible base buffer in other cases
333 *
334 */
335 if (templat->bind & PIPE_BIND_DEPTH_STENCIL) {
336 if (screen->specs.pixel_pipes > 1 && !screen->specs.single_buffer)
337 layout |= ETNA_LAYOUT_BIT_MULTI;
338 if (screen->specs.can_supertile)
339 layout |= ETNA_LAYOUT_BIT_SUPER;
340 } else if (screen->specs.can_supertile &&
341 VIV_FEATURE(screen, chipMinorFeatures2, SUPERTILED_TEXTURE) &&
342 etna_resource_hw_tileable(screen->specs.use_blt, templat)) {
343 layout |= ETNA_LAYOUT_BIT_SUPER;
344 }
345
346 if (/* linear base or scanout without modifier requested */
347 (templat->bind & (PIPE_BIND_LINEAR | PIPE_BIND_SCANOUT)) ||
348 templat->target == PIPE_BUFFER || /* buffer always linear */
349 /* compressed textures don't use tiling, they have their own "tiles" */
350 util_format_is_compressed(templat->format)) {
351 layout = ETNA_LAYOUT_LINEAR;
352 }
353
354 /* modifier is only used for scanout surfaces, so safe to use LINEAR here */
355 return etna_resource_alloc(pscreen, layout, DRM_FORMAT_MOD_LINEAR, templat);
356 }
357
358 enum modifier_priority {
359 MODIFIER_PRIORITY_INVALID = 0,
360 MODIFIER_PRIORITY_LINEAR,
361 MODIFIER_PRIORITY_SPLIT_TILED,
362 MODIFIER_PRIORITY_SPLIT_SUPER_TILED,
363 MODIFIER_PRIORITY_TILED,
364 MODIFIER_PRIORITY_SUPER_TILED,
365 };
366
367 static const uint64_t priority_to_modifier[] = {
368 [MODIFIER_PRIORITY_INVALID] = DRM_FORMAT_MOD_INVALID,
369 [MODIFIER_PRIORITY_LINEAR] = DRM_FORMAT_MOD_LINEAR,
370 [MODIFIER_PRIORITY_SPLIT_TILED] = DRM_FORMAT_MOD_VIVANTE_SPLIT_TILED,
371 [MODIFIER_PRIORITY_SPLIT_SUPER_TILED] = DRM_FORMAT_MOD_VIVANTE_SPLIT_SUPER_TILED,
372 [MODIFIER_PRIORITY_TILED] = DRM_FORMAT_MOD_VIVANTE_TILED,
373 [MODIFIER_PRIORITY_SUPER_TILED] = DRM_FORMAT_MOD_VIVANTE_SUPER_TILED,
374 };
375
376 static uint64_t
select_best_modifier(const struct etna_screen * screen,const uint64_t * modifiers,const unsigned count)377 select_best_modifier(const struct etna_screen * screen,
378 const uint64_t *modifiers, const unsigned count)
379 {
380 enum modifier_priority prio = MODIFIER_PRIORITY_INVALID;
381
382 for (int i = 0; i < count; i++) {
383 switch (modifiers[i]) {
384 case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
385 if ((screen->specs.pixel_pipes > 1 && !screen->specs.single_buffer) ||
386 !screen->specs.can_supertile)
387 break;
388 prio = MAX2(prio, MODIFIER_PRIORITY_SUPER_TILED);
389 break;
390 case DRM_FORMAT_MOD_VIVANTE_TILED:
391 if (screen->specs.pixel_pipes > 1 && !screen->specs.single_buffer)
392 break;
393 prio = MAX2(prio, MODIFIER_PRIORITY_TILED);
394 break;
395 case DRM_FORMAT_MOD_VIVANTE_SPLIT_SUPER_TILED:
396 if ((screen->specs.pixel_pipes < 2) || !screen->specs.can_supertile)
397 break;
398 prio = MAX2(prio, MODIFIER_PRIORITY_SPLIT_SUPER_TILED);
399 break;
400 case DRM_FORMAT_MOD_VIVANTE_SPLIT_TILED:
401 if (screen->specs.pixel_pipes < 2)
402 break;
403 prio = MAX2(prio, MODIFIER_PRIORITY_SPLIT_TILED);
404 break;
405 case DRM_FORMAT_MOD_LINEAR:
406 prio = MAX2(prio, MODIFIER_PRIORITY_LINEAR);
407 break;
408 case DRM_FORMAT_MOD_INVALID:
409 default:
410 break;
411 }
412 }
413
414 return priority_to_modifier[prio];
415 }
416
417 static struct pipe_resource *
etna_resource_create_modifiers(struct pipe_screen * pscreen,const struct pipe_resource * templat,const uint64_t * modifiers,int count)418 etna_resource_create_modifiers(struct pipe_screen *pscreen,
419 const struct pipe_resource *templat,
420 const uint64_t *modifiers, int count)
421 {
422 struct etna_screen *screen = etna_screen(pscreen);
423 struct pipe_resource tmpl = *templat;
424 uint64_t modifier = select_best_modifier(screen, modifiers, count);
425
426 if (modifier == DRM_FORMAT_MOD_INVALID)
427 return NULL;
428
429 return etna_resource_alloc(pscreen, modifier_to_layout(modifier), modifier, &tmpl);
430 }
431
432 static void
etna_resource_changed(struct pipe_screen * pscreen,struct pipe_resource * prsc)433 etna_resource_changed(struct pipe_screen *pscreen, struct pipe_resource *prsc)
434 {
435 etna_resource(prsc)->seqno++;
436 }
437
438 static void
etna_resource_destroy(struct pipe_screen * pscreen,struct pipe_resource * prsc)439 etna_resource_destroy(struct pipe_screen *pscreen, struct pipe_resource *prsc)
440 {
441 struct etna_resource *rsc = etna_resource(prsc);
442
443 if (rsc->bo)
444 etna_bo_del(rsc->bo);
445
446 if (rsc->ts_bo)
447 etna_bo_del(rsc->ts_bo);
448
449 if (rsc->scanout)
450 renderonly_scanout_destroy(rsc->scanout, etna_screen(pscreen)->ro);
451
452 util_range_destroy(&rsc->valid_buffer_range);
453
454 pipe_resource_reference(&rsc->texture, NULL);
455 pipe_resource_reference(&rsc->render, NULL);
456
457 for (unsigned i = 0; i < ETNA_NUM_LOD; i++)
458 FREE(rsc->levels[i].patch_offsets);
459
460 FREE(rsc);
461 }
462
463 static struct pipe_resource *
etna_resource_from_handle(struct pipe_screen * pscreen,const struct pipe_resource * tmpl,struct winsys_handle * handle,unsigned usage)464 etna_resource_from_handle(struct pipe_screen *pscreen,
465 const struct pipe_resource *tmpl,
466 struct winsys_handle *handle, unsigned usage)
467 {
468 struct etna_screen *screen = etna_screen(pscreen);
469 struct etna_resource *rsc;
470 struct etna_resource_level *level;
471 struct pipe_resource *prsc;
472
473 DBG("target=%d, format=%s, %ux%ux%u, array_size=%u, last_level=%u, "
474 "nr_samples=%u, usage=%u, bind=%x, flags=%x",
475 tmpl->target, util_format_name(tmpl->format), tmpl->width0,
476 tmpl->height0, tmpl->depth0, tmpl->array_size, tmpl->last_level,
477 tmpl->nr_samples, tmpl->usage, tmpl->bind, tmpl->flags);
478
479 rsc = CALLOC_STRUCT(etna_resource);
480 if (!rsc)
481 return NULL;
482
483 level = &rsc->levels[0];
484 prsc = &rsc->base;
485
486 *prsc = *tmpl;
487
488 pipe_reference_init(&prsc->reference, 1);
489 util_range_init(&rsc->valid_buffer_range);
490 prsc->screen = pscreen;
491
492 rsc->bo = etna_screen_bo_from_handle(pscreen, handle);
493 if (!rsc->bo)
494 goto fail;
495
496 rsc->seqno = 1;
497 rsc->layout = modifier_to_layout(handle->modifier);
498 rsc->halign = TEXTURE_HALIGN_FOUR;
499
500 if (usage & PIPE_HANDLE_USAGE_EXPLICIT_FLUSH)
501 rsc->explicit_flush = true;
502
503 level->width = tmpl->width0;
504 level->height = tmpl->height0;
505 level->depth = tmpl->depth0;
506 level->stride = handle->stride;
507 level->offset = handle->offset;
508
509 /* Determine padding of the imported resource. */
510 unsigned paddingX = 0, paddingY = 0;
511 etna_layout_multiple(rsc->layout, screen->specs.pixel_pipes,
512 is_rs_align(screen, tmpl),
513 &paddingX, &paddingY, &rsc->halign);
514
515 if (!screen->specs.use_blt && rsc->layout == ETNA_LAYOUT_LINEAR)
516 paddingY = align(paddingY, ETNA_RS_HEIGHT_MASK + 1);
517 level->padded_width = align(level->width, paddingX);
518 level->padded_height = align(level->height, paddingY);
519
520 level->layer_stride = level->stride * util_format_get_nblocksy(prsc->format,
521 level->padded_height);
522 level->size = level->layer_stride;
523
524 /* The DDX must give us a BO which conforms to our padding size.
525 * The stride of the BO must be greater or equal to our padded
526 * stride. The size of the BO must accomodate the padded height. */
527 if (level->stride < util_format_get_stride(tmpl->format, level->padded_width)) {
528 BUG("BO stride %u is too small for RS engine width padding (%zu, format %s)",
529 level->stride, util_format_get_stride(tmpl->format, level->padded_width),
530 util_format_name(tmpl->format));
531 goto fail;
532 }
533 if (etna_bo_size(rsc->bo) < level->stride * level->padded_height) {
534 BUG("BO size %u is too small for RS engine height padding (%u, format %s)",
535 etna_bo_size(rsc->bo), level->stride * level->padded_height,
536 util_format_name(tmpl->format));
537 goto fail;
538 }
539
540 if (screen->ro) {
541 struct pipe_resource *imp_prsc = prsc;
542 do {
543 etna_resource(imp_prsc)->scanout =
544 renderonly_create_gpu_import_for_resource(imp_prsc, screen->ro,
545 NULL);
546 /* failure is expected for scanout incompatible buffers */
547 } while ((imp_prsc = imp_prsc->next));
548 }
549
550 return prsc;
551
552 fail:
553 etna_resource_destroy(pscreen, prsc);
554
555 return NULL;
556 }
557
558 static bool
etna_resource_get_handle(struct pipe_screen * pscreen,struct pipe_context * pctx,struct pipe_resource * prsc,struct winsys_handle * handle,unsigned usage)559 etna_resource_get_handle(struct pipe_screen *pscreen,
560 struct pipe_context *pctx,
561 struct pipe_resource *prsc,
562 struct winsys_handle *handle, unsigned usage)
563 {
564 struct etna_screen *screen = etna_screen(pscreen);
565 struct etna_resource *rsc = etna_resource(prsc);
566 struct renderonly_scanout *scanout;
567
568 if (handle->plane) {
569 struct pipe_resource *cur = prsc;
570
571 for (int i = 0; i < handle->plane; i++) {
572 cur = cur->next;
573 if (!cur)
574 return false;
575 }
576 rsc = etna_resource(cur);
577 }
578
579 /* Scanout is always attached to the base resource */
580 scanout = rsc->scanout;
581
582 handle->stride = rsc->levels[0].stride;
583 handle->offset = rsc->levels[0].offset;
584 handle->modifier = layout_to_modifier(rsc->layout);
585
586 if (!(usage & PIPE_HANDLE_USAGE_EXPLICIT_FLUSH))
587 rsc->explicit_flush = false;
588
589 if (handle->type == WINSYS_HANDLE_TYPE_SHARED) {
590 return etna_bo_get_name(rsc->bo, &handle->handle) == 0;
591 } else if (handle->type == WINSYS_HANDLE_TYPE_KMS) {
592 if (screen->ro) {
593 return renderonly_get_handle(scanout, handle);
594 } else {
595 handle->handle = etna_bo_handle(rsc->bo);
596 return true;
597 }
598 } else if (handle->type == WINSYS_HANDLE_TYPE_FD) {
599 handle->handle = etna_bo_dmabuf(rsc->bo);
600 return true;
601 } else {
602 return false;
603 }
604 }
605
606 static bool
etna_resource_get_param(struct pipe_screen * pscreen,struct pipe_context * pctx,struct pipe_resource * prsc,unsigned plane,unsigned layer,unsigned level,enum pipe_resource_param param,unsigned usage,uint64_t * value)607 etna_resource_get_param(struct pipe_screen *pscreen,
608 struct pipe_context *pctx, struct pipe_resource *prsc,
609 unsigned plane, unsigned layer, unsigned level,
610 enum pipe_resource_param param,
611 unsigned usage, uint64_t *value)
612 {
613 if (param == PIPE_RESOURCE_PARAM_NPLANES) {
614 unsigned count = 0;
615
616 for (struct pipe_resource *cur = prsc; cur; cur = cur->next)
617 count++;
618 *value = count;
619 return true;
620 }
621
622 struct pipe_resource *cur = prsc;
623 for (int i = 0; i < plane; i++) {
624 cur = cur->next;
625 if (!cur)
626 return false;
627 }
628 struct etna_resource *rsc = etna_resource(cur);
629
630 switch (param) {
631 case PIPE_RESOURCE_PARAM_STRIDE:
632 *value = rsc->levels[level].stride;
633 return true;
634 case PIPE_RESOURCE_PARAM_OFFSET:
635 *value = rsc->levels[level].offset;
636 return true;
637 case PIPE_RESOURCE_PARAM_MODIFIER:
638 *value = layout_to_modifier(rsc->layout);
639 return true;
640 default:
641 return false;
642 }
643 }
644
645 void
etna_resource_used(struct etna_context * ctx,struct pipe_resource * prsc,enum etna_resource_status status)646 etna_resource_used(struct etna_context *ctx, struct pipe_resource *prsc,
647 enum etna_resource_status status)
648 {
649 struct etna_resource *rsc;
650 struct hash_entry *entry;
651 uint32_t hash;
652
653 if (!prsc)
654 return;
655
656 rsc = etna_resource(prsc);
657 hash = _mesa_hash_pointer(rsc);
658 entry = _mesa_hash_table_search_pre_hashed(ctx->pending_resources,
659 hash, rsc);
660
661 if (entry) {
662 enum etna_resource_status tmp = (uintptr_t)entry->data;
663 tmp |= status;
664 entry->data = (void *)(uintptr_t)tmp;
665 } else {
666 _mesa_hash_table_insert_pre_hashed(ctx->pending_resources, hash, rsc,
667 (void *)(uintptr_t)status);
668 }
669 }
670
671 enum etna_resource_status
etna_resource_status(struct etna_context * ctx,struct etna_resource * res)672 etna_resource_status(struct etna_context *ctx, struct etna_resource *res)
673 {
674 struct hash_entry *entry = _mesa_hash_table_search(ctx->pending_resources, res);
675
676 if (entry)
677 return (enum etna_resource_status)(uintptr_t)entry->data;
678 else
679 return 0;
680 }
681
682 bool
etna_resource_has_valid_ts(struct etna_resource * rsc)683 etna_resource_has_valid_ts(struct etna_resource *rsc)
684 {
685 if (!rsc->ts_bo)
686 return false;
687
688 for (int level = 0; level <= rsc->base.last_level; level++)
689 if (rsc->levels[level].ts_valid)
690 return true;
691
692 return false;
693 }
694
695 void
etna_resource_screen_init(struct pipe_screen * pscreen)696 etna_resource_screen_init(struct pipe_screen *pscreen)
697 {
698 pscreen->can_create_resource = etna_screen_can_create_resource;
699 pscreen->resource_create = etna_resource_create;
700 pscreen->resource_create_with_modifiers = etna_resource_create_modifiers;
701 pscreen->resource_from_handle = etna_resource_from_handle;
702 pscreen->resource_get_handle = etna_resource_get_handle;
703 pscreen->resource_get_param = etna_resource_get_param;
704 pscreen->resource_changed = etna_resource_changed;
705 pscreen->resource_destroy = etna_resource_destroy;
706 }
707