1 /*
2 * Copyright (c) 2008-2024 Broadcom. All Rights Reserved.
3 * The term “Broadcom” refers to Broadcom Inc.
4 * and/or its subsidiaries.
5 * SPDX-License-Identifier: MIT
6 */
7
8 #include "svga3d_reg.h"
9 #include "svga3d_surfacedefs.h"
10
11 #include "pipe/p_state.h"
12 #include "pipe/p_defines.h"
13 #include "util/u_thread.h"
14 #include "util/format/u_format.h"
15 #include "util/u_inlines.h"
16 #include "util/u_math.h"
17 #include "util/u_memory.h"
18 #include "util/u_resource.h"
19 #include "util/u_upload_mgr.h"
20
21 #include "svga_cmd.h"
22 #include "svga_format.h"
23 #include "svga_screen.h"
24 #include "svga_context.h"
25 #include "svga_resource_texture.h"
26 #include "svga_resource_buffer.h"
27 #include "svga_sampler_view.h"
28 #include "svga_surface.h"
29 #include "svga_winsys.h"
30 #include "svga_debug.h"
31
32
33 static void
svga_transfer_dma_band(struct svga_context * svga,struct svga_transfer * st,SVGA3dTransferType transfer,unsigned x,unsigned y,unsigned z,unsigned w,unsigned h,unsigned d,unsigned srcx,unsigned srcy,unsigned srcz,SVGA3dSurfaceDMAFlags flags)34 svga_transfer_dma_band(struct svga_context *svga,
35 struct svga_transfer *st,
36 SVGA3dTransferType transfer,
37 unsigned x, unsigned y, unsigned z,
38 unsigned w, unsigned h, unsigned d,
39 unsigned srcx, unsigned srcy, unsigned srcz,
40 SVGA3dSurfaceDMAFlags flags)
41 {
42 struct svga_texture *texture = svga_texture(st->base.resource);
43 SVGA3dCopyBox box;
44
45 assert(!st->use_direct_map);
46
47 box.x = x;
48 box.y = y;
49 box.z = z;
50 box.w = w;
51 box.h = h;
52 box.d = d;
53 box.srcx = srcx;
54 box.srcy = srcy;
55 box.srcz = srcz;
56
57 SVGA_DBG(DEBUG_DMA, "dma %s sid %p, face %u, (%u, %u, %u) - "
58 "(%u, %u, %u), %ubpp\n",
59 transfer == SVGA3D_WRITE_HOST_VRAM ? "to" : "from",
60 texture->handle,
61 st->slice,
62 x,
63 y,
64 z,
65 x + w,
66 y + h,
67 z + 1,
68 util_format_get_blocksize(texture->b.format) * 8 /
69 (util_format_get_blockwidth(texture->b.format)
70 * util_format_get_blockheight(texture->b.format)));
71
72 SVGA_RETRY(svga, SVGA3D_SurfaceDMA(svga->swc, st, transfer, &box, 1, flags));
73 }
74
75
76 static void
svga_transfer_dma(struct svga_context * svga,struct svga_transfer * st,SVGA3dTransferType transfer,SVGA3dSurfaceDMAFlags flags)77 svga_transfer_dma(struct svga_context *svga,
78 struct svga_transfer *st,
79 SVGA3dTransferType transfer,
80 SVGA3dSurfaceDMAFlags flags)
81 {
82 struct svga_texture *texture = svga_texture(st->base.resource);
83 struct svga_screen *screen = svga_screen(texture->b.screen);
84 struct svga_winsys_screen *sws = screen->sws;
85 struct pipe_fence_handle *fence = NULL;
86
87 assert(!st->use_direct_map);
88
89 if (transfer == SVGA3D_READ_HOST_VRAM) {
90 SVGA_DBG(DEBUG_PERF, "%s: readback transfer\n", __func__);
91 }
92
93 /* Ensure any pending operations on host surfaces are queued on the command
94 * buffer first.
95 */
96 svga_surfaces_flush(svga);
97
98 if (!st->swbuf) {
99 /* Do the DMA transfer in a single go */
100 svga_transfer_dma_band(svga, st, transfer,
101 st->box.x, st->box.y, st->box.z,
102 st->box.w, st->box.h, st->box.d,
103 0, 0, 0,
104 flags);
105
106 if (transfer == SVGA3D_READ_HOST_VRAM) {
107 svga_context_flush(svga, &fence);
108 sws->fence_finish(sws, fence, OS_TIMEOUT_INFINITE, 0);
109 sws->fence_reference(sws, &fence, NULL);
110 }
111 }
112 else {
113 int y, h, srcy;
114 unsigned blockheight =
115 util_format_get_blockheight(st->base.resource->format);
116
117 h = st->hw_nblocksy * blockheight;
118 srcy = 0;
119
120 for (y = 0; y < st->box.h; y += h) {
121 unsigned offset, length;
122 void *hw, *sw;
123
124 if (y + h > st->box.h)
125 h = st->box.h - y;
126
127 /* Transfer band must be aligned to pixel block boundaries */
128 assert(y % blockheight == 0);
129 assert(h % blockheight == 0);
130
131 offset = y * st->base.stride / blockheight;
132 length = h * st->base.stride / blockheight;
133
134 sw = (uint8_t *) st->swbuf + offset;
135
136 if (transfer == SVGA3D_WRITE_HOST_VRAM) {
137 unsigned usage = PIPE_MAP_WRITE;
138
139 /* Wait for the previous DMAs to complete */
140 /* TODO: keep one DMA (at half the size) in the background */
141 if (y) {
142 svga_context_flush(svga, NULL);
143 usage |= PIPE_MAP_DISCARD_WHOLE_RESOURCE;
144 }
145
146 hw = sws->buffer_map(sws, st->hwbuf, usage);
147 assert(hw);
148 if (hw) {
149 memcpy(hw, sw, length);
150 sws->buffer_unmap(sws, st->hwbuf);
151 }
152 }
153
154 svga_transfer_dma_band(svga, st, transfer,
155 st->box.x, y, st->box.z,
156 st->box.w, h, st->box.d,
157 0, srcy, 0, flags);
158
159 /*
160 * Prevent the texture contents to be discarded on the next band
161 * upload.
162 */
163 flags.discard = false;
164
165 if (transfer == SVGA3D_READ_HOST_VRAM) {
166 svga_context_flush(svga, &fence);
167 sws->fence_finish(sws, fence, OS_TIMEOUT_INFINITE, 0);
168
169 hw = sws->buffer_map(sws, st->hwbuf, PIPE_MAP_READ);
170 assert(hw);
171 if (hw) {
172 memcpy(sw, hw, length);
173 sws->buffer_unmap(sws, st->hwbuf);
174 }
175 }
176 }
177 }
178 }
179
180
181
182 bool
svga_resource_get_handle(struct pipe_screen * screen,struct pipe_context * context,struct pipe_resource * texture,struct winsys_handle * whandle,unsigned usage)183 svga_resource_get_handle(struct pipe_screen *screen,
184 struct pipe_context *context,
185 struct pipe_resource *texture,
186 struct winsys_handle *whandle,
187 unsigned usage)
188 {
189 struct svga_winsys_screen *sws = svga_winsys_screen(texture->screen);
190 unsigned stride;
191
192 if (texture->target == PIPE_BUFFER)
193 return false;
194
195 SVGA_DBG(DEBUG_DMA, "%s: texture=%p cachable=%d\n", __FUNCTION__,
196 texture, svga_texture(texture)->key.cachable);
197
198 svga_texture(texture)->key.cachable = 0;
199
200 stride = util_format_get_nblocksx(texture->format, texture->width0) *
201 util_format_get_blocksize(texture->format);
202
203 return sws->surface_get_handle(sws, svga_texture(texture)->handle,
204 stride, whandle);
205 }
206
207
208 /**
209 * Determine if we need to read back a texture image before mapping it.
210 */
211 static inline bool
need_tex_readback(struct svga_transfer * st)212 need_tex_readback(struct svga_transfer *st)
213 {
214 if (st->base.usage & PIPE_MAP_READ)
215 return true;
216
217 if ((st->base.usage & PIPE_MAP_WRITE) &&
218 ((st->base.usage & PIPE_MAP_DISCARD_WHOLE_RESOURCE) == 0)) {
219 return svga_was_texture_rendered_to(svga_texture(st->base.resource));
220 }
221
222 return false;
223 }
224
225
226 static void
readback_texture_surface(struct svga_context * svga,struct svga_texture * tex,struct svga_winsys_surface * surf)227 readback_texture_surface(struct svga_context *svga,
228 struct svga_texture *tex,
229 struct svga_winsys_surface *surf)
230 {
231 SVGA_RETRY(svga, SVGA3D_ReadbackGBSurface(svga->swc, surf));
232
233 /* Mark the texture surface as UPDATED */
234 tex->surface_state = SVGA_SURFACE_STATE_UPDATED;
235
236 svga->hud.num_readbacks++;
237 SVGA_STATS_COUNT_INC(svga_sws(svga), SVGA_STATS_COUNT_TEXREADBACK);
238 }
239
240 /**
241 * Use DMA for the transfer request
242 */
243 static void *
svga_texture_transfer_map_dma(struct svga_context * svga,struct svga_transfer * st)244 svga_texture_transfer_map_dma(struct svga_context *svga,
245 struct svga_transfer *st)
246 {
247 struct svga_winsys_screen *sws = svga_screen(svga->pipe.screen)->sws;
248 struct pipe_resource *texture = st->base.resource;
249 unsigned nblocksx, nblocksy;
250 unsigned d;
251 unsigned usage = st->base.usage;
252
253 /* we'll put the data into a tightly packed buffer */
254 nblocksx = util_format_get_nblocksx(texture->format, st->box.w);
255 nblocksy = util_format_get_nblocksy(texture->format, st->box.h);
256 d = st->box.d;
257
258 st->base.stride = nblocksx*util_format_get_blocksize(texture->format);
259 st->base.layer_stride = st->base.stride * nblocksy;
260 st->hw_nblocksy = nblocksy;
261
262 st->hwbuf = svga_winsys_buffer_create(svga, 1, 0,
263 st->hw_nblocksy * st->base.stride * d);
264
265 while (!st->hwbuf && (st->hw_nblocksy /= 2)) {
266 st->hwbuf =
267 svga_winsys_buffer_create(svga, 1, 0,
268 st->hw_nblocksy * st->base.stride * d);
269 }
270
271 if (!st->hwbuf)
272 return NULL;
273
274 if (st->hw_nblocksy < nblocksy) {
275 /* We couldn't allocate a hardware buffer big enough for the transfer,
276 * so allocate regular malloc memory instead
277 */
278 if (0) {
279 debug_printf("%s: failed to allocate %u KB of DMA, "
280 "splitting into %u x %u KB DMA transfers\n",
281 __func__,
282 (nblocksy * st->base.stride + 1023) / 1024,
283 (nblocksy + st->hw_nblocksy - 1) / st->hw_nblocksy,
284 (st->hw_nblocksy * st->base.stride + 1023) / 1024);
285 }
286
287 st->swbuf = MALLOC(nblocksy * st->base.stride * d);
288 if (!st->swbuf) {
289 sws->buffer_destroy(sws, st->hwbuf);
290 return NULL;
291 }
292 }
293
294 if (usage & PIPE_MAP_READ) {
295 SVGA3dSurfaceDMAFlags flags;
296 memset(&flags, 0, sizeof flags);
297 svga_transfer_dma(svga, st, SVGA3D_READ_HOST_VRAM, flags);
298 }
299
300 if (st->swbuf) {
301 return st->swbuf;
302 }
303 else {
304 return sws->buffer_map(sws, st->hwbuf, usage);
305 }
306 }
307
308
309 /**
310 * Use direct map for the transfer request
311 */
312 static void *
svga_texture_transfer_map_direct(struct svga_context * svga,struct svga_transfer * st)313 svga_texture_transfer_map_direct(struct svga_context *svga,
314 struct svga_transfer *st)
315 {
316 struct svga_winsys_screen *sws = svga_screen(svga->pipe.screen)->sws;
317 struct pipe_transfer *transfer = &st->base;
318 struct pipe_resource *texture = transfer->resource;
319 struct svga_texture *tex = svga_texture(texture);
320 struct svga_winsys_surface *surf = tex->handle;
321 unsigned level = st->base.level;
322 unsigned w, h, nblocksx, nblocksy;
323 unsigned usage = st->base.usage;
324
325 if (need_tex_readback(st)) {
326 svga_surfaces_flush(svga);
327
328 if (!svga->swc->force_coherent || tex->imported) {
329 /* Readback the whole surface */
330 readback_texture_surface(svga, tex, surf);
331
332 svga_context_finish(svga);
333 }
334 /*
335 * Note: if PIPE_MAP_DISCARD_WHOLE_RESOURCE were specified
336 * we could potentially clear the flag for all faces/layers/mips.
337 */
338 svga_clear_texture_rendered_to(tex);
339 }
340 else {
341 assert(usage & PIPE_MAP_WRITE);
342 if ((usage & PIPE_MAP_UNSYNCHRONIZED) == 0) {
343 if (svga_is_texture_level_dirty(tex, st->slice, level)) {
344 /*
345 * do a surface flush if the subresource has been modified
346 * in this command buffer.
347 */
348 svga_surfaces_flush(svga);
349 if (!sws->surface_is_flushed(sws, surf)) {
350 svga->hud.surface_write_flushes++;
351 SVGA_STATS_COUNT_INC(sws, SVGA_STATS_COUNT_SURFACEWRITEFLUSH);
352 svga_context_flush(svga, NULL);
353 }
354 }
355 }
356 }
357
358 /* we'll directly access the guest-backed surface */
359 w = u_minify(texture->width0, level);
360 h = u_minify(texture->height0, level);
361 nblocksx = util_format_get_nblocksx(texture->format, w);
362 nblocksy = util_format_get_nblocksy(texture->format, h);
363 st->hw_nblocksy = nblocksy;
364 st->base.stride = nblocksx*util_format_get_blocksize(texture->format);
365 st->base.layer_stride = st->base.stride * nblocksy;
366
367 /*
368 * Begin mapping code
369 */
370 {
371 SVGA3dSize baseLevelSize;
372 uint8_t *map;
373 bool retry, rebind;
374 unsigned offset, mip_width, mip_height;
375 struct svga_winsys_context *swc = svga->swc;
376
377 if (swc->force_coherent) {
378 usage |= PIPE_MAP_PERSISTENT | PIPE_MAP_COHERENT;
379 }
380
381 map = SVGA_TRY_MAP(svga->swc->surface_map
382 (svga->swc, surf, usage, &retry, &rebind), retry);
383
384 if (map == NULL && retry) {
385 /*
386 * At this point, the svga_surfaces_flush() should already have
387 * called in svga_texture_get_transfer().
388 */
389 svga->hud.surface_write_flushes++;
390 svga_retry_enter(svga);
391 svga_context_flush(svga, NULL);
392 map = svga->swc->surface_map(svga->swc, surf, usage, &retry, &rebind);
393 svga_retry_exit(svga);
394 }
395 if (map && rebind) {
396 enum pipe_error ret;
397
398 ret = SVGA3D_BindGBSurface(swc, surf);
399 if (ret != PIPE_OK) {
400 svga_context_flush(svga, NULL);
401 ret = SVGA3D_BindGBSurface(swc, surf);
402 assert(ret == PIPE_OK);
403 }
404 svga_context_flush(svga, NULL);
405 }
406
407 /*
408 * Make sure we return NULL if the map fails
409 */
410 if (!map) {
411 return NULL;
412 }
413
414 /**
415 * Compute the offset to the specific texture slice in the buffer.
416 */
417 baseLevelSize.width = tex->b.width0;
418 baseLevelSize.height = tex->b.height0;
419 baseLevelSize.depth = tex->b.depth0;
420
421 if ((tex->b.target == PIPE_TEXTURE_1D_ARRAY) ||
422 (tex->b.target == PIPE_TEXTURE_2D_ARRAY) ||
423 (tex->b.target == PIPE_TEXTURE_CUBE_ARRAY)) {
424 st->base.layer_stride =
425 svga3dsurface_get_image_offset(tex->key.format, baseLevelSize,
426 tex->b.last_level + 1, 1, 0);
427 }
428
429 offset = svga3dsurface_get_image_offset(tex->key.format, baseLevelSize,
430 tex->b.last_level + 1, /* numMips */
431 st->slice, level);
432 if (level > 0) {
433 assert(offset > 0);
434 }
435
436 mip_width = u_minify(tex->b.width0, level);
437 mip_height = u_minify(tex->b.height0, level);
438
439 offset += svga3dsurface_get_pixel_offset(tex->key.format,
440 mip_width, mip_height,
441 st->box.x,
442 st->box.y,
443 st->box.z);
444
445 return (void *) (map + offset);
446 }
447 }
448
449
450 /**
451 * Request a transfer map to the texture resource
452 */
453 void *
svga_texture_transfer_map(struct pipe_context * pipe,struct pipe_resource * texture,unsigned level,unsigned usage,const struct pipe_box * box,struct pipe_transfer ** ptransfer)454 svga_texture_transfer_map(struct pipe_context *pipe,
455 struct pipe_resource *texture,
456 unsigned level,
457 unsigned usage,
458 const struct pipe_box *box,
459 struct pipe_transfer **ptransfer)
460 {
461 struct svga_context *svga = svga_context(pipe);
462 struct svga_winsys_screen *sws = svga_screen(pipe->screen)->sws;
463 struct svga_texture *tex = svga_texture(texture);
464 struct svga_transfer *st;
465 struct svga_winsys_surface *surf = tex->handle;
466 bool use_direct_map = svga_have_gb_objects(svga) &&
467 (!svga_have_gb_dma(svga) || (usage & PIPE_MAP_WRITE));
468 void *map = NULL;
469 int64_t begin = svga_get_time(svga);
470
471 SVGA_STATS_TIME_PUSH(sws, SVGA_STATS_TIME_TEXTRANSFERMAP);
472
473 if (!surf)
474 goto done;
475
476 /* We can't map texture storage directly unless we have GB objects */
477 if (usage & PIPE_MAP_DIRECTLY) {
478 if (svga_have_gb_objects(svga))
479 use_direct_map = true;
480 else
481 goto done;
482 }
483
484 st = CALLOC_STRUCT(svga_transfer);
485 if (!st)
486 goto done;
487
488 st->base.level = level;
489 st->base.usage = usage;
490 st->base.box = *box;
491
492 /* The modified transfer map box with the array index removed from z.
493 * The array index is specified in slice.
494 */
495 st->box.x = box->x;
496 st->box.y = box->y;
497 st->box.z = box->z;
498 st->box.w = box->width;
499 st->box.h = box->height;
500 st->box.d = box->depth;
501
502 switch (tex->b.target) {
503 case PIPE_TEXTURE_CUBE:
504 st->slice = st->base.box.z;
505 st->box.z = 0; /* so we don't apply double offsets below */
506 break;
507 case PIPE_TEXTURE_1D_ARRAY:
508 case PIPE_TEXTURE_2D_ARRAY:
509 case PIPE_TEXTURE_CUBE_ARRAY:
510 st->slice = st->base.box.z;
511 st->box.z = 0; /* so we don't apply double offsets below */
512
513 /* Force direct map for transfering multiple slices */
514 if (st->base.box.depth > 1)
515 use_direct_map = svga_have_gb_objects(svga);
516
517 break;
518 default:
519 st->slice = 0;
520 break;
521 }
522
523 /* We never want to use DMA transfers on systems with GBObjects because
524 * it causes serialization issues and in SVGAv3 vram is gone which
525 * makes it impossible to support both at the same time.
526 */
527 if (svga_have_gb_objects(svga)) {
528 use_direct_map = true;
529 }
530
531 st->use_direct_map = use_direct_map;
532 pipe_resource_reference(&st->base.resource, texture);
533
534 /* If this is the first time mapping to the surface in this
535 * command buffer and there is no pending primitives, clear
536 * the dirty masks of this surface.
537 */
538 if (sws->surface_is_flushed(sws, surf) &&
539 (svga_have_vgpu10(svga) ||
540 !svga_hwtnl_has_pending_prim(svga->hwtnl))) {
541 svga_clear_texture_dirty(tex);
542 }
543
544 if (!use_direct_map) {
545 /* upload to the DMA buffer */
546 map = svga_texture_transfer_map_dma(svga, st);
547 }
548 else {
549 bool can_use_upload = tex->can_use_upload &&
550 !(st->base.usage & PIPE_MAP_READ);
551 bool was_rendered_to =
552 svga_was_texture_rendered_to(svga_texture(texture));
553 bool is_dirty = svga_is_texture_dirty(svga_texture(texture));
554
555 /* If the texture was already rendered to or has pending changes and
556 * upload buffer is supported, then we will use upload buffer to
557 * avoid the need to read back the texture content; otherwise,
558 * we'll first try to map directly to the GB surface, if it is blocked,
559 * then we'll try the upload buffer.
560 */
561 if ((was_rendered_to || is_dirty) && can_use_upload) {
562 map = svga_texture_transfer_map_upload(svga, st);
563 }
564 else {
565 unsigned orig_usage = st->base.usage;
566
567 /* First try directly map to the GB surface */
568 if (can_use_upload)
569 st->base.usage |= PIPE_MAP_DONTBLOCK;
570 map = svga_texture_transfer_map_direct(svga, st);
571 st->base.usage = orig_usage;
572
573 if (!map && can_use_upload) {
574 /* if direct map with DONTBLOCK fails, then try upload to the
575 * texture upload buffer.
576 */
577 map = svga_texture_transfer_map_upload(svga, st);
578 }
579 }
580
581 /* If upload fails, then try direct map again without forcing it
582 * to DONTBLOCK.
583 */
584 if (!map) {
585 map = svga_texture_transfer_map_direct(svga, st);
586 }
587 }
588
589 if (!map) {
590 FREE(st);
591 }
592 else {
593 *ptransfer = &st->base;
594 svga->hud.num_textures_mapped++;
595 if (usage & PIPE_MAP_WRITE) {
596 /* record texture upload for HUD */
597 svga->hud.num_bytes_uploaded +=
598 st->base.layer_stride * st->box.d;
599
600 /* mark this texture level as dirty */
601 svga_set_texture_dirty(tex, st->slice, level);
602 }
603 }
604
605 done:
606 svga->hud.map_buffer_time += (svga_get_time(svga) - begin);
607 SVGA_STATS_TIME_POP(sws);
608 (void) sws;
609
610 return map;
611 }
612
613 /**
614 * Unmap a GB texture surface.
615 */
616 static void
svga_texture_surface_unmap(struct svga_context * svga,struct pipe_transfer * transfer)617 svga_texture_surface_unmap(struct svga_context *svga,
618 struct pipe_transfer *transfer)
619 {
620 struct svga_winsys_surface *surf = svga_texture(transfer->resource)->handle;
621 struct svga_winsys_context *swc = svga->swc;
622 bool rebind;
623
624 assert(surf);
625
626 swc->surface_unmap(swc, surf, &rebind);
627 if (rebind) {
628 SVGA_RETRY(svga, SVGA3D_BindGBSurface(swc, surf));
629 }
630 }
631
632
633 static void
update_image_vgpu9(struct svga_context * svga,struct svga_winsys_surface * surf,const SVGA3dBox * box,unsigned slice,unsigned level)634 update_image_vgpu9(struct svga_context *svga,
635 struct svga_winsys_surface *surf,
636 const SVGA3dBox *box,
637 unsigned slice,
638 unsigned level)
639 {
640 SVGA_RETRY(svga, SVGA3D_UpdateGBImage(svga->swc, surf, box, slice, level));
641 }
642
643
644 static void
update_image_vgpu10(struct svga_context * svga,struct svga_winsys_surface * surf,const SVGA3dBox * box,unsigned slice,unsigned level,unsigned numMipLevels)645 update_image_vgpu10(struct svga_context *svga,
646 struct svga_winsys_surface *surf,
647 const SVGA3dBox *box,
648 unsigned slice,
649 unsigned level,
650 unsigned numMipLevels)
651 {
652 unsigned subResource;
653
654 subResource = slice * numMipLevels + level;
655
656 SVGA_RETRY(svga, SVGA3D_vgpu10_UpdateSubResource(svga->swc, surf, box,
657 subResource));
658 }
659
660
661 /**
662 * unmap DMA transfer request
663 */
664 static void
svga_texture_transfer_unmap_dma(struct svga_context * svga,struct svga_transfer * st)665 svga_texture_transfer_unmap_dma(struct svga_context *svga,
666 struct svga_transfer *st)
667 {
668 struct svga_winsys_screen *sws = svga_screen(svga->pipe.screen)->sws;
669
670 if (!st->swbuf)
671 sws->buffer_unmap(sws, st->hwbuf);
672
673 if (st->base.usage & PIPE_MAP_WRITE) {
674 /* Use DMA to transfer texture data */
675 SVGA3dSurfaceDMAFlags flags;
676 struct pipe_resource *texture = st->base.resource;
677 struct svga_texture *tex = svga_texture(texture);
678
679
680 memset(&flags, 0, sizeof flags);
681 if (st->base.usage & PIPE_MAP_DISCARD_WHOLE_RESOURCE) {
682 flags.discard = true;
683 }
684 if (st->base.usage & PIPE_MAP_UNSYNCHRONIZED) {
685 flags.unsynchronized = true;
686 }
687
688 svga_transfer_dma(svga, st, SVGA3D_WRITE_HOST_VRAM, flags);
689 svga_set_texture_rendered_to(tex);
690 }
691
692 FREE(st->swbuf);
693 sws->buffer_destroy(sws, st->hwbuf);
694 }
695
696
697 /**
698 * unmap direct map transfer request
699 */
700 static void
svga_texture_transfer_unmap_direct(struct svga_context * svga,struct svga_transfer * st)701 svga_texture_transfer_unmap_direct(struct svga_context *svga,
702 struct svga_transfer *st)
703 {
704 struct pipe_transfer *transfer = &st->base;
705 struct svga_texture *tex = svga_texture(transfer->resource);
706
707 svga_texture_surface_unmap(svga, transfer);
708
709 /* Now send an update command to update the content in the backend. */
710 if (st->base.usage & PIPE_MAP_WRITE) {
711 struct svga_winsys_surface *surf = tex->handle;
712
713 assert(svga_have_gb_objects(svga));
714
715 /* update the effected region */
716 SVGA3dBox box = st->box;
717 unsigned nlayers;
718
719 switch (tex->b.target) {
720 case PIPE_TEXTURE_2D_ARRAY:
721 case PIPE_TEXTURE_CUBE_ARRAY:
722 case PIPE_TEXTURE_1D_ARRAY:
723 nlayers = box.d;
724 box.d = 1;
725 break;
726 default:
727 nlayers = 1;
728 break;
729 }
730
731
732 if (0)
733 debug_printf("%s %d, %d, %d %d x %d x %d\n",
734 __func__,
735 box.x, box.y, box.z,
736 box.w, box.h, box.d);
737
738 if (!svga->swc->force_coherent || tex->imported) {
739 if (svga_have_vgpu10(svga)) {
740 unsigned i;
741
742 for (i = 0; i < nlayers; i++) {
743 update_image_vgpu10(svga, surf, &box,
744 st->slice + i, transfer->level,
745 tex->b.last_level + 1);
746 }
747 } else {
748 assert(nlayers == 1);
749 update_image_vgpu9(svga, surf, &box, st->slice,
750 transfer->level);
751 }
752 }
753
754 /* Mark the texture surface state as UPDATED */
755 tex->surface_state = SVGA_SURFACE_STATE_UPDATED;
756 }
757 }
758
759
760 void
svga_texture_transfer_unmap(struct pipe_context * pipe,struct pipe_transfer * transfer)761 svga_texture_transfer_unmap(struct pipe_context *pipe,
762 struct pipe_transfer *transfer)
763 {
764 struct svga_context *svga = svga_context(pipe);
765 struct svga_screen *ss = svga_screen(pipe->screen);
766 struct svga_winsys_screen *sws = ss->sws;
767 struct svga_transfer *st = svga_transfer(transfer);
768 struct svga_texture *tex = svga_texture(transfer->resource);
769
770 SVGA_STATS_TIME_PUSH(sws, SVGA_STATS_TIME_TEXTRANSFERUNMAP);
771
772 if (!st->use_direct_map) {
773 svga_texture_transfer_unmap_dma(svga, st);
774 }
775 else if (st->upload.buf) {
776 svga_texture_transfer_unmap_upload(svga, st);
777 }
778 else {
779 svga_texture_transfer_unmap_direct(svga, st);
780 }
781
782 if (st->base.usage & PIPE_MAP_WRITE) {
783 svga->hud.num_resource_updates++;
784
785 /* Mark the texture level as dirty */
786 ss->texture_timestamp++;
787 svga_age_texture_view(tex, transfer->level);
788 if (transfer->resource->target == PIPE_TEXTURE_CUBE)
789 svga_define_texture_level(tex, st->slice, transfer->level);
790 else
791 svga_define_texture_level(tex, 0, transfer->level);
792 }
793
794 pipe_resource_reference(&st->base.resource, NULL);
795 FREE(st);
796 SVGA_STATS_TIME_POP(sws);
797 (void) sws;
798 }
799
800
801 /**
802 * Does format store depth values?
803 */
804 static inline bool
format_has_depth(enum pipe_format format)805 format_has_depth(enum pipe_format format)
806 {
807 const struct util_format_description *desc = util_format_description(format);
808 return util_format_has_depth(desc);
809 }
810
811 struct pipe_resource *
svga_texture_create(struct pipe_screen * screen,const struct pipe_resource * template)812 svga_texture_create(struct pipe_screen *screen,
813 const struct pipe_resource *template)
814 {
815 struct svga_screen *svgascreen = svga_screen(screen);
816 struct svga_texture *tex;
817 unsigned bindings = template->bind;
818
819 SVGA_STATS_TIME_PUSH(svgascreen->sws,
820 SVGA_STATS_TIME_CREATETEXTURE);
821
822 assert(template->last_level < SVGA_MAX_TEXTURE_LEVELS);
823 if (template->last_level >= SVGA_MAX_TEXTURE_LEVELS) {
824 goto fail_notex;
825 }
826
827 /* Verify the number of mipmap levels isn't impossibly large. For example,
828 * if the base 2D image is 16x16, we can't have 8 mipmap levels.
829 * the gallium frontend should never ask us to create a resource with invalid
830 * parameters.
831 */
832 {
833 unsigned max_dim = template->width0;
834
835 switch (template->target) {
836 case PIPE_TEXTURE_1D:
837 case PIPE_TEXTURE_1D_ARRAY:
838 // nothing
839 break;
840 case PIPE_TEXTURE_2D:
841 case PIPE_TEXTURE_CUBE:
842 case PIPE_TEXTURE_CUBE_ARRAY:
843 case PIPE_TEXTURE_2D_ARRAY:
844 max_dim = MAX2(max_dim, template->height0);
845 break;
846 case PIPE_TEXTURE_3D:
847 max_dim = MAX3(max_dim, template->height0, template->depth0);
848 break;
849 case PIPE_TEXTURE_RECT:
850 case PIPE_BUFFER:
851 assert(template->last_level == 0);
852 /* the assertion below should always pass */
853 break;
854 default:
855 debug_printf("Unexpected texture target type\n");
856 }
857 assert(1 << template->last_level <= max_dim);
858 }
859
860 tex = CALLOC_STRUCT(svga_texture);
861 if (!tex) {
862 goto fail_notex;
863 }
864
865 tex->defined = CALLOC(template->depth0 * template->array_size,
866 sizeof(tex->defined[0]));
867 if (!tex->defined) {
868 FREE(tex);
869 goto fail_notex;
870 }
871
872 tex->dirty = CALLOC(template->depth0 * template->array_size,
873 sizeof(tex->dirty[0]));
874 if (!tex->dirty) {
875 goto fail;
876 }
877
878 tex->b = *template;
879 pipe_reference_init(&tex->b.reference, 1);
880 tex->b.screen = screen;
881
882 tex->key.flags = 0;
883 tex->key.size.width = template->width0;
884 tex->key.size.height = template->height0;
885 tex->key.size.depth = template->depth0;
886 tex->key.arraySize = 1;
887 tex->key.numFaces = 1;
888
889 /* nr_samples=1 must be treated as a non-multisample texture */
890 if (tex->b.nr_samples == 1) {
891 tex->b.nr_samples = 0;
892 }
893 else if (tex->b.nr_samples > 1) {
894 assert(svgascreen->sws->have_sm4_1);
895 tex->key.flags |= SVGA3D_SURFACE_MULTISAMPLE;
896 }
897
898 tex->key.sampleCount = tex->b.nr_samples;
899
900 if (svgascreen->sws->have_vgpu10) {
901 switch (template->target) {
902 case PIPE_TEXTURE_1D:
903 tex->key.flags |= SVGA3D_SURFACE_1D;
904 break;
905 case PIPE_TEXTURE_1D_ARRAY:
906 tex->key.flags |= SVGA3D_SURFACE_1D;
907 FALLTHROUGH;
908 case PIPE_TEXTURE_2D_ARRAY:
909 tex->key.flags |= SVGA3D_SURFACE_ARRAY;
910 tex->key.arraySize = template->array_size;
911 break;
912 case PIPE_TEXTURE_3D:
913 tex->key.flags |= SVGA3D_SURFACE_VOLUME;
914 break;
915 case PIPE_TEXTURE_CUBE:
916 tex->key.flags |= (SVGA3D_SURFACE_CUBEMAP | SVGA3D_SURFACE_ARRAY);
917 tex->key.numFaces = 6;
918 break;
919 case PIPE_TEXTURE_CUBE_ARRAY:
920 assert(svgascreen->sws->have_sm4_1);
921 tex->key.flags |= (SVGA3D_SURFACE_CUBEMAP | SVGA3D_SURFACE_ARRAY);
922 tex->key.numFaces = 1; // arraySize already includes the 6 faces
923 tex->key.arraySize = template->array_size;
924 break;
925 default:
926 break;
927 }
928 }
929 else {
930 switch (template->target) {
931 case PIPE_TEXTURE_3D:
932 tex->key.flags |= SVGA3D_SURFACE_VOLUME;
933 break;
934 case PIPE_TEXTURE_CUBE:
935 tex->key.flags |= SVGA3D_SURFACE_CUBEMAP;
936 tex->key.numFaces = 6;
937 break;
938 default:
939 break;
940 }
941 }
942
943 tex->key.cachable = 1;
944
945 if ((bindings & (PIPE_BIND_RENDER_TARGET | PIPE_BIND_DEPTH_STENCIL)) &&
946 !(bindings & PIPE_BIND_SAMPLER_VIEW)) {
947 /* Also check if the format can be sampled from */
948 if (screen->is_format_supported(screen, template->format,
949 template->target,
950 template->nr_samples,
951 template->nr_storage_samples,
952 PIPE_BIND_SAMPLER_VIEW)) {
953 bindings |= PIPE_BIND_SAMPLER_VIEW;
954 }
955 }
956
957 if (bindings & PIPE_BIND_SAMPLER_VIEW) {
958 tex->key.flags |= SVGA3D_SURFACE_HINT_TEXTURE;
959 tex->key.flags |= SVGA3D_SURFACE_BIND_SHADER_RESOURCE;
960
961 if (!(bindings & PIPE_BIND_RENDER_TARGET)) {
962 /* Also check if the format is color renderable */
963 if (screen->is_format_supported(screen, template->format,
964 template->target,
965 template->nr_samples,
966 template->nr_storage_samples,
967 PIPE_BIND_RENDER_TARGET)) {
968 bindings |= PIPE_BIND_RENDER_TARGET;
969 }
970 }
971
972 if (!(bindings & PIPE_BIND_DEPTH_STENCIL)) {
973 /* Also check if the format is depth/stencil renderable */
974 if (screen->is_format_supported(screen, template->format,
975 template->target,
976 template->nr_samples,
977 template->nr_storage_samples,
978 PIPE_BIND_DEPTH_STENCIL)) {
979 bindings |= PIPE_BIND_DEPTH_STENCIL;
980 }
981 }
982 }
983
984 if (bindings & PIPE_BIND_DISPLAY_TARGET) {
985 tex->key.cachable = 0;
986 }
987
988 if (bindings & PIPE_BIND_SHARED) {
989 tex->key.cachable = 0;
990 }
991
992 if (bindings & (PIPE_BIND_SCANOUT | PIPE_BIND_CURSOR)) {
993 tex->key.scanout = 1;
994 tex->key.cachable = 0;
995 }
996
997 /*
998 * Note: Previously we never passed the
999 * SVGA3D_SURFACE_HINT_RENDERTARGET hint. Mesa cannot
1000 * know beforehand whether a texture will be used as a rendertarget or not
1001 * and it always requests PIPE_BIND_RENDER_TARGET, therefore
1002 * passing the SVGA3D_SURFACE_HINT_RENDERTARGET here defeats its purpose.
1003 *
1004 * However, this was changed since other gallium frontends
1005 * (XA for example) uses it accurately and certain device versions
1006 * relies on it in certain situations to render correctly.
1007 */
1008 if ((bindings & PIPE_BIND_RENDER_TARGET) &&
1009 !util_format_is_s3tc(template->format)) {
1010 tex->key.flags |= SVGA3D_SURFACE_HINT_RENDERTARGET;
1011 tex->key.flags |= SVGA3D_SURFACE_BIND_RENDER_TARGET;
1012 }
1013
1014 if (bindings & PIPE_BIND_DEPTH_STENCIL) {
1015 tex->key.flags |= SVGA3D_SURFACE_HINT_DEPTHSTENCIL;
1016 tex->key.flags |= SVGA3D_SURFACE_BIND_DEPTH_STENCIL;
1017 }
1018
1019 tex->key.numMipLevels = template->last_level + 1;
1020
1021 tex->key.format = svga_translate_format(svgascreen, template->format,
1022 bindings);
1023 if (tex->key.format == SVGA3D_FORMAT_INVALID) {
1024 goto fail;
1025 }
1026
1027 bool use_typeless = false;
1028 if (svgascreen->sws->have_gl43) {
1029 /* Do not use typeless for SHARED, SCANOUT or DISPLAY_TARGET surfaces. */
1030 use_typeless = !(bindings & (PIPE_BIND_SHARED | PIPE_BIND_SCANOUT |
1031 PIPE_BIND_DISPLAY_TARGET));
1032 } else if (svgascreen->sws->have_vgpu10) {
1033 /* For VGPU10 device, use typeless formats only for sRGB and depth resources
1034 * if they do not have SHARED, SCANOUT or DISPLAY_TARGET bind flags
1035 */
1036 use_typeless = (util_format_is_srgb(template->format) ||
1037 format_has_depth(template->format)) &&
1038 !(bindings & (PIPE_BIND_SHARED | PIPE_BIND_SCANOUT |
1039 PIPE_BIND_DISPLAY_TARGET));
1040 }
1041
1042 if (use_typeless) {
1043 SVGA3dSurfaceFormat typeless = svga_typeless_format(tex->key.format);
1044 if (0) {
1045 debug_printf("Convert resource type %s -> %s (bind 0x%x)\n",
1046 svga_format_name(tex->key.format),
1047 svga_format_name(typeless),
1048 bindings);
1049 }
1050
1051 if (svga_format_is_uncompressed_snorm(tex->key.format)) {
1052 /* We can't normally render to snorm surfaces, but once we
1053 * substitute a typeless format, we can if the rendertarget view
1054 * is unorm. This can happen with GL_ARB_copy_image.
1055 */
1056 tex->key.flags |= SVGA3D_SURFACE_HINT_RENDERTARGET;
1057 tex->key.flags |= SVGA3D_SURFACE_BIND_RENDER_TARGET;
1058 }
1059
1060 tex->key.format = typeless;
1061 }
1062
1063 if (svgascreen->sws->have_sm5 &&
1064 bindings & (PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET)) {
1065 if (template->nr_samples < 2 &&
1066 screen->is_format_supported(screen, template->format,
1067 template->target,
1068 template->nr_samples,
1069 template->nr_storage_samples,
1070 PIPE_BIND_SHADER_IMAGE)) {
1071 /* Any non multi-samples texture that can be used as a render target
1072 * or sampler view can be bound to an image unit.
1073 * So make sure to set the UAV flag here.
1074 */
1075 tex->key.flags |= SVGA3D_SURFACE_BIND_UAVIEW;
1076 }
1077 }
1078
1079 SVGA_DBG(DEBUG_DMA, "surface_create for texture\n");
1080 bool invalidated;
1081 tex->handle = svga_screen_surface_create(svgascreen, bindings,
1082 tex->b.usage,
1083 &invalidated, &tex->key);
1084 if (!tex->handle) {
1085 goto fail;
1086 }
1087 if (invalidated) {
1088 tex->surface_state = SVGA_SURFACE_STATE_INVALIDATED;
1089 } else {
1090 tex->surface_state = SVGA_SURFACE_STATE_CREATED;
1091 }
1092
1093 SVGA_DBG(DEBUG_DMA, " --> got sid %p (texture)\n", tex->handle);
1094
1095 debug_reference(&tex->b.reference,
1096 (debug_reference_descriptor)debug_describe_resource, 0);
1097
1098 tex->size = util_resource_size(template);
1099
1100 /* Determine if texture upload buffer can be used to upload this texture */
1101 tex->can_use_upload = svga_texture_transfer_map_can_upload(svgascreen,
1102 &tex->b);
1103
1104 /* Initialize the backing resource cache */
1105 tex->backed_handle = NULL;
1106
1107 svgascreen->hud.total_resource_bytes += tex->size;
1108 svgascreen->hud.num_resources++;
1109
1110 SVGA_STATS_TIME_POP(svgascreen->sws);
1111
1112 return &tex->b;
1113
1114 fail:
1115 if (tex->dirty)
1116 FREE(tex->dirty);
1117 if (tex->defined)
1118 FREE(tex->defined);
1119 FREE(tex);
1120 fail_notex:
1121 SVGA_STATS_TIME_POP(svgascreen->sws);
1122 return NULL;
1123 }
1124
1125
1126 struct pipe_resource *
svga_texture_from_handle(struct pipe_screen * screen,const struct pipe_resource * template,struct winsys_handle * whandle)1127 svga_texture_from_handle(struct pipe_screen *screen,
1128 const struct pipe_resource *template,
1129 struct winsys_handle *whandle)
1130 {
1131 struct svga_winsys_screen *sws = svga_winsys_screen(screen);
1132 struct svga_screen *ss = svga_screen(screen);
1133 struct svga_winsys_surface *srf;
1134 struct svga_texture *tex;
1135 enum SVGA3dSurfaceFormat format = 0;
1136 assert(screen);
1137
1138 /* Only supports one type */
1139 if ((template->target != PIPE_TEXTURE_2D &&
1140 template->target != PIPE_TEXTURE_RECT) ||
1141 template->last_level != 0 ||
1142 template->depth0 != 1) {
1143 return NULL;
1144 }
1145
1146 srf = sws->surface_from_handle(sws, whandle, &format);
1147
1148 if (!srf)
1149 return NULL;
1150
1151 if (!svga_format_is_shareable(ss, template->format, format,
1152 template->bind, true))
1153 goto out_unref;
1154
1155 tex = CALLOC_STRUCT(svga_texture);
1156 if (!tex)
1157 goto out_unref;
1158
1159 tex->defined = CALLOC(template->depth0 * template->array_size,
1160 sizeof(tex->defined[0]));
1161 if (!tex->defined)
1162 goto out_no_defined;
1163
1164 tex->b = *template;
1165 pipe_reference_init(&tex->b.reference, 1);
1166 tex->b.screen = screen;
1167
1168 SVGA_DBG(DEBUG_DMA, "wrap surface sid %p\n", srf);
1169
1170 tex->key.cachable = 0;
1171 tex->key.format = format;
1172 tex->handle = srf;
1173
1174
1175 /* set bind flags for the imported texture handle according to the bind
1176 * flags in the template
1177 */
1178 if (template->bind & PIPE_BIND_RENDER_TARGET){
1179 tex->key.flags |= SVGA3D_SURFACE_HINT_RENDERTARGET;
1180 tex->key.flags |= SVGA3D_SURFACE_BIND_RENDER_TARGET;
1181 }
1182
1183 if (template->bind & PIPE_BIND_DEPTH_STENCIL) {
1184 tex->key.flags |= SVGA3D_SURFACE_HINT_DEPTHSTENCIL;
1185 tex->key.flags |= SVGA3D_SURFACE_BIND_DEPTH_STENCIL;
1186 }
1187
1188 if (template->bind & PIPE_BIND_SAMPLER_VIEW) {
1189 tex->key.flags |= SVGA3D_SURFACE_HINT_TEXTURE;
1190 tex->key.flags |= SVGA3D_SURFACE_BIND_SHADER_RESOURCE;
1191 }
1192
1193 tex->dirty = CALLOC(1, sizeof(tex->dirty[0]));
1194 if (!tex->dirty)
1195 goto out_no_dirty;
1196
1197 tex->imported = true;
1198
1199 ss->hud.num_resources++;
1200
1201 return &tex->b;
1202
1203 out_no_dirty:
1204 FREE(tex->defined);
1205 out_no_defined:
1206 FREE(tex);
1207 out_unref:
1208 sws->surface_reference(sws, &srf, NULL);
1209 return NULL;
1210 }
1211
1212 bool
svga_texture_generate_mipmap(struct pipe_context * pipe,struct pipe_resource * pt,enum pipe_format format,unsigned base_level,unsigned last_level,unsigned first_layer,unsigned last_layer)1213 svga_texture_generate_mipmap(struct pipe_context *pipe,
1214 struct pipe_resource *pt,
1215 enum pipe_format format,
1216 unsigned base_level,
1217 unsigned last_level,
1218 unsigned first_layer,
1219 unsigned last_layer)
1220 {
1221 struct pipe_sampler_view templ, *psv;
1222 struct svga_pipe_sampler_view *sv;
1223 struct svga_context *svga = svga_context(pipe);
1224 struct svga_texture *tex = svga_texture(pt);
1225
1226 assert(svga_have_vgpu10(svga));
1227
1228 /* Fallback to the mipmap generation utility for those formats that
1229 * do not support hw generate mipmap
1230 */
1231 if (!svga_format_support_gen_mips(format))
1232 return false;
1233
1234 /* Make sure the texture surface was created with
1235 * SVGA3D_SURFACE_BIND_RENDER_TARGET
1236 */
1237 if (!tex->handle || !(tex->key.flags & SVGA3D_SURFACE_BIND_RENDER_TARGET))
1238 return false;
1239
1240 templ.format = format;
1241 templ.target = pt->target;
1242 templ.u.tex.first_layer = first_layer;
1243 templ.u.tex.last_layer = last_layer;
1244 templ.u.tex.first_level = base_level;
1245 templ.u.tex.last_level = last_level;
1246
1247 if (pt->target == PIPE_TEXTURE_CUBE) {
1248 /**
1249 * state tracker generates mipmap one face at a time.
1250 * But SVGA generates mipmap for the entire cubemap.
1251 */
1252 templ.u.tex.first_layer = 0;
1253 templ.u.tex.last_layer = 5;
1254 }
1255
1256 psv = pipe->create_sampler_view(pipe, pt, &templ);
1257 if (psv == NULL)
1258 return false;
1259
1260 sv = svga_pipe_sampler_view(psv);
1261 SVGA_RETRY(svga, svga_validate_pipe_sampler_view(svga, sv));
1262
1263 SVGA_RETRY(svga, SVGA3D_vgpu10_GenMips(svga->swc, sv->id, tex->handle));
1264 pipe_sampler_view_reference(&psv, NULL);
1265
1266 /* Mark the texture surface as RENDERED */
1267 svga_set_texture_rendered_to(tex);
1268
1269 svga->hud.num_generate_mipmap++;
1270
1271 return true;
1272 }
1273
1274
1275 /* texture upload buffer default size in bytes */
1276 #define TEX_UPLOAD_DEFAULT_SIZE (1024 * 1024)
1277
1278 /**
1279 * Create a texture upload buffer
1280 */
1281 bool
svga_texture_transfer_map_upload_create(struct svga_context * svga)1282 svga_texture_transfer_map_upload_create(struct svga_context *svga)
1283 {
1284 svga->tex_upload = u_upload_create(&svga->pipe, TEX_UPLOAD_DEFAULT_SIZE,
1285 PIPE_BIND_CUSTOM, PIPE_USAGE_STAGING, 0);
1286 if (svga->tex_upload)
1287 u_upload_disable_persistent(svga->tex_upload);
1288
1289 return svga->tex_upload != NULL;
1290 }
1291
1292
1293 /**
1294 * Destroy the texture upload buffer
1295 */
1296 void
svga_texture_transfer_map_upload_destroy(struct svga_context * svga)1297 svga_texture_transfer_map_upload_destroy(struct svga_context *svga)
1298 {
1299 u_upload_destroy(svga->tex_upload);
1300 }
1301
1302
1303 /**
1304 * Returns true if this transfer map request can use the upload buffer.
1305 */
1306 bool
svga_texture_transfer_map_can_upload(const struct svga_screen * svgascreen,const struct pipe_resource * texture)1307 svga_texture_transfer_map_can_upload(const struct svga_screen *svgascreen,
1308 const struct pipe_resource *texture)
1309 {
1310 if (svgascreen->sws->have_transfer_from_buffer_cmd == false)
1311 return false;
1312
1313 /* TransferFromBuffer command is not well supported with multi-samples surface */
1314 if (texture->nr_samples > 1)
1315 return false;
1316
1317 if (util_format_is_compressed(texture->format)) {
1318 /* XXX Need to take a closer look to see why texture upload
1319 * with 3D texture with compressed format fails
1320 */
1321 if (texture->target == PIPE_TEXTURE_3D)
1322 return false;
1323 }
1324 else if (texture->format == PIPE_FORMAT_R9G9B9E5_FLOAT) {
1325 return false;
1326 }
1327
1328 return true;
1329 }
1330
1331
1332 /**
1333 * Return TRUE if the same texture is bound to the specified
1334 * surface view and a backing resource is created for the surface view.
1335 */
1336 static bool
need_update_texture_resource(struct pipe_surface * surf,struct svga_texture * tex)1337 need_update_texture_resource(struct pipe_surface *surf,
1338 struct svga_texture *tex)
1339 {
1340 struct svga_texture *stex = svga_texture(surf->texture);
1341 struct svga_surface *s = svga_surface(surf);
1342
1343 return (stex == tex && s->handle != tex->handle);
1344 }
1345
1346
1347 /**
1348 * Make sure the texture resource is up-to-date. If the texture is
1349 * currently bound to a render target view and a backing resource is
1350 * created, we will need to update the original resource with the
1351 * changes in the backing resource.
1352 */
1353 static void
svga_validate_texture_resource(struct svga_context * svga,struct svga_texture * tex)1354 svga_validate_texture_resource(struct svga_context *svga,
1355 struct svga_texture *tex)
1356 {
1357 if (svga_was_texture_rendered_to(tex) == false)
1358 return;
1359
1360 if ((svga->state.hw_draw.has_backed_views == false) ||
1361 (tex->backed_handle == NULL))
1362 return;
1363
1364 struct pipe_surface *s;
1365 for (unsigned i = 0; i < svga->state.hw_clear.num_rendertargets; i++) {
1366 s = svga->state.hw_clear.rtv[i];
1367 if (s && need_update_texture_resource(s, tex))
1368 svga_propagate_surface(svga, s, true);
1369 }
1370
1371 s = svga->state.hw_clear.dsv;
1372 if (s && need_update_texture_resource(s, tex))
1373 svga_propagate_surface(svga, s, true);
1374 }
1375
1376
1377 /**
1378 * Use upload buffer for the transfer map request.
1379 */
1380 void *
svga_texture_transfer_map_upload(struct svga_context * svga,struct svga_transfer * st)1381 svga_texture_transfer_map_upload(struct svga_context *svga,
1382 struct svga_transfer *st)
1383 {
1384 struct pipe_resource *texture = st->base.resource;
1385 struct pipe_resource *tex_buffer = NULL;
1386 struct svga_texture *tex = svga_texture(texture);
1387 void *tex_map;
1388 unsigned nblocksx, nblocksy;
1389 unsigned offset;
1390 unsigned upload_size;
1391
1392 assert(svga->tex_upload);
1393
1394 /* Validate the texture resource in case there is any changes
1395 * in the backing resource that needs to be updated to the original
1396 * texture resource first before the transfer upload occurs, otherwise,
1397 * the later update from backing resource to original will overwrite the
1398 * changes in this transfer map update.
1399 */
1400 svga_validate_texture_resource(svga, tex);
1401
1402 st->upload.box.x = st->base.box.x;
1403 st->upload.box.y = st->base.box.y;
1404 st->upload.box.z = st->base.box.z;
1405 st->upload.box.w = st->base.box.width;
1406 st->upload.box.h = st->base.box.height;
1407 st->upload.box.d = st->base.box.depth;
1408 st->upload.nlayers = 1;
1409
1410 switch (texture->target) {
1411 case PIPE_TEXTURE_CUBE:
1412 st->upload.box.z = 0;
1413 break;
1414 case PIPE_TEXTURE_2D_ARRAY:
1415 case PIPE_TEXTURE_CUBE_ARRAY:
1416 st->upload.nlayers = st->base.box.depth;
1417 st->upload.box.z = 0;
1418 st->upload.box.d = 1;
1419 break;
1420 case PIPE_TEXTURE_1D_ARRAY:
1421 st->upload.nlayers = st->base.box.depth;
1422 st->upload.box.y = st->upload.box.z = 0;
1423 st->upload.box.d = 1;
1424 break;
1425 default:
1426 break;
1427 }
1428
1429 nblocksx = util_format_get_nblocksx(texture->format, st->base.box.width);
1430 nblocksy = util_format_get_nblocksy(texture->format, st->base.box.height);
1431
1432 st->base.stride = nblocksx * util_format_get_blocksize(texture->format);
1433 st->base.layer_stride = st->base.stride * nblocksy;
1434
1435 /* In order to use the TransferFromBuffer command to update the
1436 * texture content from the buffer, the layer stride for a multi-layers
1437 * surface needs to be in multiples of 16 bytes.
1438 */
1439 if (st->upload.nlayers > 1 && st->base.layer_stride & 15)
1440 return NULL;
1441
1442 upload_size = st->base.layer_stride * st->base.box.depth;
1443 upload_size = align(upload_size, 16);
1444
1445 #if MESA_DEBUG
1446 if (util_format_is_compressed(texture->format)) {
1447 unsigned blockw, blockh, bytesPerBlock;
1448
1449 svga_format_size(tex->key.format, &blockw, &blockh, &bytesPerBlock);
1450
1451 /* dest box must start on block boundary */
1452 assert((st->base.box.x % blockw) == 0);
1453 assert((st->base.box.y % blockh) == 0);
1454 }
1455 #endif
1456
1457 /* If the upload size exceeds the default buffer size, the
1458 * upload buffer manager code will try to allocate a new buffer
1459 * with the new buffer size.
1460 */
1461 u_upload_alloc(svga->tex_upload, 0, upload_size, 16,
1462 &offset, &tex_buffer, &tex_map);
1463
1464 if (!tex_map) {
1465 return NULL;
1466 }
1467
1468 st->upload.buf = tex_buffer;
1469 st->upload.map = tex_map;
1470 st->upload.offset = offset;
1471
1472 return tex_map;
1473 }
1474
1475
1476 /**
1477 * Unmap upload map transfer request
1478 */
1479 void
svga_texture_transfer_unmap_upload(struct svga_context * svga,struct svga_transfer * st)1480 svga_texture_transfer_unmap_upload(struct svga_context *svga,
1481 struct svga_transfer *st)
1482 {
1483 struct svga_winsys_surface *srcsurf;
1484 struct svga_winsys_surface *dstsurf;
1485 struct pipe_resource *texture = st->base.resource;
1486 struct svga_texture *tex = svga_texture(texture);
1487 unsigned subResource;
1488 unsigned numMipLevels;
1489 unsigned i, layer;
1490 unsigned offset = st->upload.offset;
1491
1492 assert(svga->tex_upload);
1493 assert(st->upload.buf);
1494
1495 /* unmap the texture upload buffer */
1496 u_upload_unmap(svga->tex_upload);
1497
1498 srcsurf = svga_buffer_handle(svga, st->upload.buf, 0);
1499 dstsurf = svga_texture(texture)->handle;
1500 assert(dstsurf);
1501
1502 numMipLevels = texture->last_level + 1;
1503
1504 for (i = 0, layer = st->slice; i < st->upload.nlayers; i++, layer++) {
1505 subResource = layer * numMipLevels + st->base.level;
1506
1507 /* send a transferFromBuffer command to update the host texture surface */
1508 assert((offset & 15) == 0);
1509
1510 SVGA_RETRY(svga, SVGA3D_vgpu10_TransferFromBuffer(svga->swc, srcsurf,
1511 offset,
1512 st->base.stride,
1513 st->base.layer_stride,
1514 dstsurf, subResource,
1515 &st->upload.box));
1516 offset += st->base.layer_stride;
1517 }
1518
1519 /* Mark the texture surface state as RENDERED */
1520 svga_set_texture_rendered_to(tex);
1521
1522 pipe_resource_reference(&st->upload.buf, NULL);
1523 }
1524
1525 /**
1526 * Does the device format backing this surface have an
1527 * alpha channel?
1528 *
1529 * \param texture[in] The texture whose format we're querying
1530 * \return TRUE if the format has an alpha channel, FALSE otherwise
1531 *
1532 * For locally created textures, the device (svga) format is typically
1533 * identical to svga_format(texture->format), and we can use the gallium
1534 * format tests to determine whether the device format has an alpha channel
1535 * or not. However, for textures backed by imported svga surfaces that is
1536 * not always true, and we have to look at the SVGA3D utilities.
1537 */
1538 bool
svga_texture_device_format_has_alpha(struct pipe_resource * texture)1539 svga_texture_device_format_has_alpha(struct pipe_resource *texture)
1540 {
1541 /* the svga_texture() call below is invalid for PIPE_BUFFER resources */
1542 assert(texture->target != PIPE_BUFFER);
1543
1544 const struct svga3d_surface_desc *surf_desc =
1545 svga3dsurface_get_desc(svga_texture(texture)->key.format);
1546
1547 enum svga3d_block_desc block_desc = surf_desc->block_desc;
1548
1549 return !!((block_desc & SVGA3DBLOCKDESC_ALPHA) ||
1550 ((block_desc == SVGA3DBLOCKDESC_TYPELESS) &&
1551 (surf_desc->bitDepth.alpha > 0)));
1552 }
1553