xref: /aosp_15_r20/external/mesa3d/src/gallium/drivers/svga/svga_resource_texture.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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