xref: /aosp_15_r20/external/mesa3d/src/gallium/drivers/svga/svga_resource_buffer_upload.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 
9 #include "util/u_thread.h"
10 #include "pipe/p_state.h"
11 #include "pipe/p_defines.h"
12 #include "util/u_inlines.h"
13 #include "util/u_math.h"
14 #include "util/u_memory.h"
15 
16 #include "svga_cmd.h"
17 #include "svga_context.h"
18 #include "svga_debug.h"
19 #include "svga_resource_buffer.h"
20 #include "svga_resource_buffer_upload.h"
21 #include "svga_screen.h"
22 #include "svga_winsys.h"
23 
24 /**
25  * Describes a complete SVGA_3D_CMD_UPDATE_GB_IMAGE command
26  *
27  */
28 struct svga_3d_update_gb_image {
29    SVGA3dCmdHeader header;
30    SVGA3dCmdUpdateGBImage body;
31 };
32 
33 static void
34 svga_buffer_upload_ranges(struct svga_context *, struct svga_buffer *);
35 
36 
37 /**
38  * Allocate a winsys_buffer (ie. DMA, aka GMR memory).
39  *
40  * It will flush and retry in case the first attempt to create a DMA buffer
41  * fails, so it should not be called from any function involved in flushing
42  * to avoid recursion.
43  */
44 struct svga_winsys_buffer *
svga_winsys_buffer_create(struct svga_context * svga,unsigned alignment,unsigned usage,unsigned size)45 svga_winsys_buffer_create( struct svga_context *svga,
46                            unsigned alignment,
47                            unsigned usage,
48                            unsigned size )
49 {
50    struct svga_screen *svgascreen = svga_screen(svga->pipe.screen);
51    struct svga_winsys_screen *sws = svgascreen->sws;
52    struct svga_winsys_buffer *buf;
53 
54    /* Just try */
55    buf = SVGA_TRY_PTR(sws->buffer_create(sws, alignment, usage, size));
56    if (!buf) {
57       SVGA_DBG(DEBUG_DMA|DEBUG_PERF, "flushing context to find %d bytes GMR\n",
58                size);
59 
60       /* Try flushing all pending DMAs */
61       svga_retry_enter(svga);
62       svga_context_flush(svga, NULL);
63       buf = sws->buffer_create(sws, alignment, usage, size);
64       svga_retry_exit(svga);
65    }
66 
67    return buf;
68 }
69 
70 
71 /**
72  * Destroy HW storage if separate from the host surface.
73  * In the GB case, the HW storage is associated with the host surface
74  * and is therefore a No-op.
75  */
76 void
svga_buffer_destroy_hw_storage(struct svga_screen * ss,struct svga_buffer * sbuf)77 svga_buffer_destroy_hw_storage(struct svga_screen *ss, struct svga_buffer *sbuf)
78 {
79    struct svga_winsys_screen *sws = ss->sws;
80 
81    assert(sbuf->map.count == 0);
82    assert(sbuf->hwbuf);
83    if (sbuf->hwbuf) {
84       sws->buffer_destroy(sws, sbuf->hwbuf);
85       sbuf->hwbuf = NULL;
86    }
87 }
88 
89 
90 
91 /**
92  * Allocate DMA'ble or Updatable storage for the buffer.
93  *
94  * Called before mapping a buffer.
95  */
96 enum pipe_error
svga_buffer_create_hw_storage(struct svga_screen * ss,struct svga_buffer * sbuf,unsigned bind_flags)97 svga_buffer_create_hw_storage(struct svga_screen *ss,
98                               struct svga_buffer *sbuf,
99                               unsigned bind_flags)
100 {
101    assert(!sbuf->user);
102 
103    if (ss->sws->have_gb_objects) {
104       assert(sbuf->handle || !sbuf->dma.pending);
105       return svga_buffer_create_host_surface(ss, sbuf, bind_flags);
106    }
107    if (!sbuf->hwbuf) {
108       struct svga_winsys_screen *sws = ss->sws;
109       unsigned alignment = 16;
110       unsigned usage = 0;
111       unsigned size = sbuf->b.width0;
112 
113       sbuf->hwbuf = sws->buffer_create(sws, alignment, usage, size);
114       if (!sbuf->hwbuf)
115          return PIPE_ERROR_OUT_OF_MEMORY;
116 
117       assert(!sbuf->dma.pending);
118    }
119 
120    return PIPE_OK;
121 }
122 
123 
124 /**
125  * Allocate graphics memory for vertex/index/constant/texture buffer.
126  */
127 enum pipe_error
svga_buffer_create_host_surface(struct svga_screen * ss,struct svga_buffer * sbuf,unsigned bind_flags)128 svga_buffer_create_host_surface(struct svga_screen *ss,
129                                 struct svga_buffer *sbuf,
130                                 unsigned bind_flags)
131 {
132    enum pipe_error ret = PIPE_OK;
133 
134    assert(!sbuf->user);
135 
136    if (!sbuf->handle) {
137       bool invalidated;
138 
139       sbuf->key.flags = 0;
140 
141       sbuf->key.format = SVGA3D_BUFFER;
142       if (bind_flags & PIPE_BIND_VERTEX_BUFFER) {
143          sbuf->key.flags |= SVGA3D_SURFACE_HINT_VERTEXBUFFER;
144          sbuf->key.flags |= SVGA3D_SURFACE_BIND_VERTEX_BUFFER;
145       }
146       if (bind_flags & PIPE_BIND_INDEX_BUFFER) {
147          sbuf->key.flags |= SVGA3D_SURFACE_HINT_INDEXBUFFER;
148          sbuf->key.flags |= SVGA3D_SURFACE_BIND_INDEX_BUFFER;
149       }
150       if (bind_flags & PIPE_BIND_CONSTANT_BUFFER)
151          sbuf->key.flags |= SVGA3D_SURFACE_BIND_CONSTANT_BUFFER;
152 
153       if (bind_flags & PIPE_BIND_STREAM_OUTPUT)
154          sbuf->key.flags |= SVGA3D_SURFACE_BIND_STREAM_OUTPUT;
155 
156       if (bind_flags & PIPE_BIND_SAMPLER_VIEW)
157          sbuf->key.flags |= SVGA3D_SURFACE_BIND_SHADER_RESOURCE;
158 
159       if (bind_flags & PIPE_BIND_COMMAND_ARGS_BUFFER) {
160          assert(ss->sws->have_sm5);
161          sbuf->key.flags |= SVGA3D_SURFACE_DRAWINDIRECT_ARGS;
162       }
163 
164       if (!bind_flags && sbuf->b.usage == PIPE_USAGE_STAGING) {
165          /* This surface is to be used with the
166           * SVGA3D_CMD_DX_TRANSFER_FROM_BUFFER command, and no other
167           * bind flags are allowed to be set for this surface.
168           */
169          sbuf->key.flags = SVGA3D_SURFACE_TRANSFER_FROM_BUFFER;
170       }
171 
172       if (ss->sws->have_gl43 &&
173           (bind_flags & (PIPE_BIND_SHADER_BUFFER | PIPE_BIND_SHADER_IMAGE)) &&
174           (!(bind_flags & (PIPE_BIND_STREAM_OUTPUT)))) {
175          /* This surface can be bound to a uav. */
176          assert((bind_flags & PIPE_BIND_CONSTANT_BUFFER) == 0);
177          sbuf->key.flags |= SVGA3D_SURFACE_BIND_UAVIEW |
178                             SVGA3D_SURFACE_BIND_RAW_VIEWS;
179       }
180 
181       if (sbuf->b.flags & PIPE_RESOURCE_FLAG_MAP_PERSISTENT) {
182          /* This surface can be mapped persistently. We use
183           * coherent memory if available to avoid implementing memory barriers
184           * for persistent non-coherent memory for now.
185           */
186          sbuf->key.coherent = ss->sws->have_coherent;
187 
188          if (ss->sws->have_gl43) {
189             /* Set the persistent bit so if the buffer is to be bound
190              * as constant buffer, we'll access it as raw buffer
191              * instead of copying the content back and forth between the
192              * mapped buffer surface and the constant buffer surface.
193              */
194             sbuf->key.persistent = 1;
195 
196             /* Set the raw views bind flag only if the mapped buffer surface
197              * is not already bound as constant buffer since constant buffer
198              * surface cannot have other bind flags.
199              */
200             if ((bind_flags & PIPE_BIND_CONSTANT_BUFFER) == 0) {
201 	       sbuf->key.flags |= SVGA3D_SURFACE_BIND_UAVIEW |
202                                   SVGA3D_SURFACE_BIND_RAW_VIEWS;
203                bind_flags = bind_flags | PIPE_BIND_SHADER_BUFFER;
204                //sbuf->key.flags |= SVGA3D_SURFACE_BIND_RAW_VIEWS;
205             }
206          }
207       }
208 
209       sbuf->key.size.width = sbuf->b.width0;
210       sbuf->key.size.height = 1;
211       sbuf->key.size.depth = 1;
212 
213       sbuf->key.numFaces = 1;
214       sbuf->key.numMipLevels = 1;
215       sbuf->key.cachable = 1;
216       sbuf->key.arraySize = 1;
217       sbuf->key.sampleCount = 0;
218 
219       SVGA_DBG(DEBUG_DMA, "surface_create for buffer sz %d\n",
220                sbuf->b.width0);
221 
222       sbuf->handle = svga_screen_surface_create(ss, bind_flags,
223                                                 sbuf->b.usage,
224                                                 &invalidated, &sbuf->key);
225       if (!sbuf->handle)
226          return PIPE_ERROR_OUT_OF_MEMORY;
227 
228       /* Set the discard flag on the first time the buffer is written
229        * as svga_screen_surface_create might have passed a recycled host
230        * buffer. This is only needed for host-backed mode. As in guest-backed
231        * mode, the recycled buffer would have been invalidated.
232        */
233       if (!ss->sws->have_gb_objects)
234          sbuf->dma.flags.discard = true;
235 
236       SVGA_DBG(DEBUG_DMA, "   --> got sid %p sz %d (buffer)\n",
237                sbuf->handle, sbuf->b.width0);
238 
239       /* Add the new surface to the buffer surface list */
240       sbuf->bufsurf = svga_buffer_add_host_surface(sbuf, sbuf->handle,
241 		                                   &sbuf->key,
242                                                    bind_flags);
243       if (sbuf->bufsurf == NULL)
244          return PIPE_ERROR_OUT_OF_MEMORY;
245 
246       sbuf->bufsurf->surface_state =
247 	 invalidated ? SVGA_SURFACE_STATE_INVALIDATED :
248 	               SVGA_SURFACE_STATE_CREATED;
249 
250       if (ss->sws->have_gb_objects) {
251          /* Initialize the surface with zero */
252          ss->sws->surface_init(ss->sws, sbuf->handle, svga_surface_size(&sbuf->key),
253                                sbuf->key.flags);
254       }
255    }
256 
257    return ret;
258 }
259 
260 
261 /**
262  * Recreates a host surface with the new bind flags.
263  */
264 enum pipe_error
svga_buffer_recreate_host_surface(struct svga_context * svga,struct svga_buffer * sbuf,unsigned bind_flags)265 svga_buffer_recreate_host_surface(struct svga_context *svga,
266                                   struct svga_buffer *sbuf,
267                                   unsigned bind_flags)
268 {
269    enum pipe_error ret = PIPE_OK;
270    struct svga_winsys_surface *old_handle = sbuf->handle;
271 
272    assert(sbuf->bind_flags != bind_flags);
273    assert(old_handle);
274 
275    sbuf->handle = NULL;
276 
277    /* Create a new resource with the requested bind_flags */
278    ret = svga_buffer_create_host_surface(svga_screen(svga->pipe.screen),
279                                          sbuf, bind_flags);
280    if (ret == PIPE_OK) {
281       /* Copy the surface data */
282       assert(sbuf->handle);
283       assert(sbuf->bufsurf);
284       SVGA_RETRY(svga, SVGA3D_vgpu10_BufferCopy(svga->swc, old_handle,
285                                                 sbuf->handle,
286                                                 0, 0, sbuf->b.width0));
287 
288       /* Mark this surface as RENDERED */
289       sbuf->bufsurf->surface_state = SVGA_SURFACE_STATE_RENDERED;
290    }
291 
292    /* Set the new bind flags for this buffer resource */
293    sbuf->bind_flags = bind_flags;
294 
295    /* Set the dirty bit to signal a read back is needed before the data copied
296     * to this new surface can be referenced.
297     */
298    sbuf->dirty = true;
299 
300    return ret;
301 }
302 
303 
304 /**
305  * Returns TRUE if the surface bind flags is compatible with the new bind flags.
306  */
307 static bool
compatible_bind_flags(unsigned bind_flags,unsigned tobind_flags)308 compatible_bind_flags(unsigned bind_flags,
309                       unsigned tobind_flags)
310 {
311    if ((bind_flags & tobind_flags) == tobind_flags)
312       return true;
313    else if ((bind_flags|tobind_flags) & PIPE_BIND_CONSTANT_BUFFER)
314       return false;
315    else if ((bind_flags & PIPE_BIND_STREAM_OUTPUT) &&
316             (tobind_flags & (PIPE_BIND_SHADER_IMAGE | PIPE_BIND_SHADER_BUFFER)))
317       /* Stream out cannot be mixed with UAV */
318       return false;
319    else
320       return true;
321 }
322 
323 
324 /**
325  * Returns a buffer surface from the surface list
326  * that has the requested bind flags or its existing bind flags
327  * can be promoted to include the new bind flags.
328  */
329 static struct svga_buffer_surface *
svga_buffer_get_host_surface(struct svga_buffer * sbuf,unsigned bind_flags)330 svga_buffer_get_host_surface(struct svga_buffer *sbuf,
331                              unsigned bind_flags)
332 {
333    struct svga_buffer_surface *bufsurf;
334 
335    LIST_FOR_EACH_ENTRY(bufsurf, &sbuf->surfaces, list) {
336       if (compatible_bind_flags(bufsurf->bind_flags, bind_flags))
337          return bufsurf;
338    }
339    return NULL;
340 }
341 
342 
343 /**
344  * Adds the host surface to the buffer surface list.
345  */
346 struct svga_buffer_surface *
svga_buffer_add_host_surface(struct svga_buffer * sbuf,struct svga_winsys_surface * handle,struct svga_host_surface_cache_key * key,unsigned bind_flags)347 svga_buffer_add_host_surface(struct svga_buffer *sbuf,
348                              struct svga_winsys_surface *handle,
349                              struct svga_host_surface_cache_key *key,
350                              unsigned bind_flags)
351 {
352    struct svga_buffer_surface *bufsurf;
353 
354    bufsurf = CALLOC_STRUCT(svga_buffer_surface);
355    if (!bufsurf)
356       return NULL;
357 
358    bufsurf->bind_flags = bind_flags;
359    bufsurf->handle = handle;
360    bufsurf->key = *key;
361 
362    /* add the surface to the surface list */
363    list_add(&bufsurf->list, &sbuf->surfaces);
364 
365    /* Set the new bind flags for this buffer resource */
366    sbuf->bind_flags = bind_flags;
367 
368    return bufsurf;
369 }
370 
371 
372 /**
373  * Start using the specified surface for this buffer resource.
374  */
375 void
svga_buffer_bind_host_surface(struct svga_context * svga,struct svga_buffer * sbuf,struct svga_buffer_surface * bufsurf)376 svga_buffer_bind_host_surface(struct svga_context *svga,
377                               struct svga_buffer *sbuf,
378                               struct svga_buffer_surface *bufsurf)
379 {
380    /* Update the to-bind surface */
381    assert(bufsurf->handle);
382    assert(sbuf->handle);
383 
384    /* If we are switching from stream output to other buffer,
385     * make sure to copy the buffer content.
386     */
387    if (sbuf->bind_flags & PIPE_BIND_STREAM_OUTPUT) {
388       SVGA_RETRY(svga, SVGA3D_vgpu10_BufferCopy(svga->swc, sbuf->handle,
389                                                 bufsurf->handle,
390                                                 0, 0, sbuf->b.width0));
391       bufsurf->surface_state = SVGA_SURFACE_STATE_RENDERED;
392    }
393 
394    /* Set this surface as the current one */
395    sbuf->handle = bufsurf->handle;
396    sbuf->key = bufsurf->key;
397    sbuf->bind_flags = bufsurf->bind_flags;
398    sbuf->bufsurf = bufsurf;
399 }
400 
401 
402 /**
403  * Prepare a host surface that can be used as indicated in the
404  * tobind_flags. If the existing host surface is not created
405  * with the necessary binding flags and if the new bind flags can be
406  * combined with the existing bind flags, then we will recreate a
407  * new surface with the combined bind flags. Otherwise, we will create
408  * a surface for that incompatible bind flags.
409  * For example, if a stream output buffer is reused as a constant buffer,
410  * since constant buffer surface cannot be bound as a stream output surface,
411  * two surfaces will be created, one for stream output,
412  * and another one for constant buffer.
413  */
414 enum pipe_error
svga_buffer_validate_host_surface(struct svga_context * svga,struct svga_buffer * sbuf,unsigned tobind_flags)415 svga_buffer_validate_host_surface(struct svga_context *svga,
416                                   struct svga_buffer *sbuf,
417                                   unsigned tobind_flags)
418 {
419    struct svga_buffer_surface *bufsurf;
420    enum pipe_error ret = PIPE_OK;
421 
422    /* upload any dirty ranges */
423    svga_buffer_upload_ranges(svga, sbuf);
424 
425    /* Flush any pending upload first */
426    svga_buffer_upload_flush(svga, sbuf);
427 
428    /* First check from the cached buffer surface list to see if there is
429     * already a buffer surface that has the requested bind flags, or
430     * surface with compatible bind flags that can be promoted.
431     */
432    bufsurf = svga_buffer_get_host_surface(sbuf, tobind_flags);
433 
434    if (bufsurf) {
435       if ((bufsurf->bind_flags & tobind_flags) == tobind_flags) {
436          /* there is a surface with the requested bind flags */
437          svga_buffer_bind_host_surface(svga, sbuf, bufsurf);
438       } else {
439 
440          /* Recreate a host surface with the combined bind flags */
441          ret = svga_buffer_recreate_host_surface(svga, sbuf,
442                                                  bufsurf->bind_flags |
443                                                  tobind_flags);
444 
445          /* Destroy the old surface */
446          svga_screen_surface_destroy(svga_screen(sbuf->b.screen),
447                                      &bufsurf->key,
448                                      svga_was_buffer_rendered_to(bufsurf),
449                                      &bufsurf->handle);
450 
451          list_del(&bufsurf->list);
452          FREE(bufsurf);
453       }
454    } else {
455       /* Need to create a new surface if the bind flags are incompatible,
456        * such as constant buffer surface & stream output surface.
457        */
458       ret = svga_buffer_recreate_host_surface(svga, sbuf,
459                                               tobind_flags);
460    }
461    return ret;
462 }
463 
464 
465 void
svga_buffer_destroy_host_surface(struct svga_screen * ss,struct svga_buffer * sbuf)466 svga_buffer_destroy_host_surface(struct svga_screen *ss,
467                                  struct svga_buffer *sbuf)
468 {
469    struct svga_buffer_surface *bufsurf, *next;
470 
471    LIST_FOR_EACH_ENTRY_SAFE(bufsurf, next, &sbuf->surfaces, list) {
472       SVGA_DBG(DEBUG_DMA, " ungrab sid %p sz %d\n",
473                bufsurf->handle, sbuf->b.width0);
474       svga_screen_surface_destroy(ss, &bufsurf->key,
475                                   svga_was_buffer_rendered_to(bufsurf),
476                                   &bufsurf->handle);
477       FREE(bufsurf);
478    }
479 }
480 
481 
482 /**
483  * Insert a number of preliminary UPDATE_GB_IMAGE commands in the
484  * command buffer, equal to the current number of mapped ranges.
485  * The UPDATE_GB_IMAGE commands will be patched with the
486  * actual ranges just before flush.
487  */
488 static enum pipe_error
svga_buffer_upload_gb_command(struct svga_context * svga,struct svga_buffer * sbuf)489 svga_buffer_upload_gb_command(struct svga_context *svga,
490                               struct svga_buffer *sbuf)
491 {
492    struct svga_winsys_context *swc = svga->swc;
493    SVGA3dCmdUpdateGBImage *update_cmd;
494    struct svga_3d_update_gb_image *whole_update_cmd = NULL;
495    const uint32 numBoxes = sbuf->map.num_ranges;
496    struct pipe_resource *dummy;
497    unsigned i;
498 
499    if (swc->force_coherent || sbuf->key.coherent)
500       return PIPE_OK;
501 
502    assert(svga_have_gb_objects(svga));
503    assert(numBoxes);
504    assert(sbuf->dma.updates == NULL);
505 
506    /* Allocate FIFO space for 'numBoxes' UPDATE_GB_IMAGE commands */
507    const unsigned total_commands_size =
508       sizeof(*update_cmd) + (numBoxes - 1) * sizeof(*whole_update_cmd);
509 
510    update_cmd = SVGA3D_FIFOReserve(swc,
511                                    SVGA_3D_CMD_UPDATE_GB_IMAGE,
512                                    total_commands_size, numBoxes);
513    if (!update_cmd)
514       return PIPE_ERROR_OUT_OF_MEMORY;
515 
516    /* The whole_update_command is a SVGA3dCmdHeader plus the
517     * SVGA3dCmdUpdateGBImage command.
518     */
519    whole_update_cmd = container_of(update_cmd, struct svga_3d_update_gb_image, body);
520 
521    /* Init the first UPDATE_GB_IMAGE command */
522    whole_update_cmd->header.size = sizeof(*update_cmd);
523    swc->surface_relocation(swc, &update_cmd->image.sid, NULL, sbuf->handle,
524                            SVGA_RELOC_WRITE | SVGA_RELOC_INTERNAL);
525    update_cmd->image.face = 0;
526    update_cmd->image.mipmap = 0;
527 
528    /* Save pointer to the first UPDATE_GB_IMAGE command so that we can
529     * fill in the box info below.
530     */
531    sbuf->dma.updates = whole_update_cmd;
532 
533    /*
534     * Copy the face, mipmap, etc. info to all subsequent commands.
535     * Also do the surface relocation for each subsequent command.
536     */
537    for (i = 1; i < numBoxes; ++i) {
538       whole_update_cmd++;
539       memcpy(whole_update_cmd, sbuf->dma.updates, sizeof(*whole_update_cmd));
540 
541       swc->surface_relocation(swc, &whole_update_cmd->body.image.sid, NULL,
542                               sbuf->handle,
543                               SVGA_RELOC_WRITE | SVGA_RELOC_INTERNAL);
544    }
545 
546    /* Increment reference count */
547    sbuf->dma.svga = svga;
548    dummy = NULL;
549    pipe_resource_reference(&dummy, &sbuf->b);
550    SVGA_FIFOCommitAll(swc);
551 
552    swc->hints |= SVGA_HINT_FLAG_CAN_PRE_FLUSH;
553    sbuf->dma.flags.discard = false;
554 
555    svga->hud.num_resource_updates++;
556 
557    return PIPE_OK;
558 }
559 
560 
561 /**
562  * Issue DMA commands to transfer guest memory to the host.
563  * Note that the memory segments (offset, size) will be patched in
564  * later in the svga_buffer_upload_flush() function.
565  */
566 static enum pipe_error
svga_buffer_upload_hb_command(struct svga_context * svga,struct svga_buffer * sbuf)567 svga_buffer_upload_hb_command(struct svga_context *svga,
568                               struct svga_buffer *sbuf)
569 {
570    struct svga_winsys_context *swc = svga->swc;
571    struct svga_winsys_buffer *guest = sbuf->hwbuf;
572    struct svga_winsys_surface *host = sbuf->handle;
573    const SVGA3dTransferType transfer = SVGA3D_WRITE_HOST_VRAM;
574    SVGA3dCmdSurfaceDMA *cmd;
575    const uint32 numBoxes = sbuf->map.num_ranges;
576    SVGA3dCopyBox *boxes;
577    SVGA3dCmdSurfaceDMASuffix *pSuffix;
578    unsigned region_flags;
579    unsigned surface_flags;
580    struct pipe_resource *dummy;
581 
582    assert(!svga_have_gb_objects(svga));
583 
584    if (transfer == SVGA3D_WRITE_HOST_VRAM) {
585       region_flags = SVGA_RELOC_READ;
586       surface_flags = SVGA_RELOC_WRITE;
587    }
588    else if (transfer == SVGA3D_READ_HOST_VRAM) {
589       region_flags = SVGA_RELOC_WRITE;
590       surface_flags = SVGA_RELOC_READ;
591    }
592    else {
593       assert(0);
594       return PIPE_ERROR_BAD_INPUT;
595    }
596 
597    assert(numBoxes);
598 
599    cmd = SVGA3D_FIFOReserve(swc,
600                             SVGA_3D_CMD_SURFACE_DMA,
601                             sizeof *cmd + numBoxes * sizeof *boxes + sizeof *pSuffix,
602                             2);
603    if (!cmd)
604       return PIPE_ERROR_OUT_OF_MEMORY;
605 
606    swc->region_relocation(swc, &cmd->guest.ptr, guest, 0, region_flags);
607    cmd->guest.pitch = 0;
608 
609    swc->surface_relocation(swc, &cmd->host.sid, NULL, host, surface_flags);
610    cmd->host.face = 0;
611    cmd->host.mipmap = 0;
612 
613    cmd->transfer = transfer;
614 
615    sbuf->dma.boxes = (SVGA3dCopyBox *)&cmd[1];
616    sbuf->dma.svga = svga;
617 
618    /* Increment reference count */
619    dummy = NULL;
620    pipe_resource_reference(&dummy, &sbuf->b);
621 
622    pSuffix = (SVGA3dCmdSurfaceDMASuffix *)((uint8_t*)cmd + sizeof *cmd + numBoxes * sizeof *boxes);
623    pSuffix->suffixSize = sizeof *pSuffix;
624    pSuffix->maximumOffset = sbuf->b.width0;
625    pSuffix->flags = sbuf->dma.flags;
626 
627    SVGA_FIFOCommitAll(swc);
628 
629    swc->hints |= SVGA_HINT_FLAG_CAN_PRE_FLUSH;
630    sbuf->dma.flags.discard = false;
631 
632    svga->hud.num_buffer_uploads++;
633 
634    return PIPE_OK;
635 }
636 
637 
638 /**
639  * Issue commands to transfer guest memory to the host.
640  */
641 static enum pipe_error
svga_buffer_upload_command(struct svga_context * svga,struct svga_buffer * sbuf)642 svga_buffer_upload_command(struct svga_context *svga, struct svga_buffer *sbuf)
643 {
644    if (svga_have_gb_objects(svga)) {
645       return svga_buffer_upload_gb_command(svga, sbuf);
646    } else {
647       return svga_buffer_upload_hb_command(svga, sbuf);
648    }
649 }
650 
651 
652 /**
653  * Patch up the upload DMA command reserved by svga_buffer_upload_command
654  * with the final ranges.
655  */
656 void
svga_buffer_upload_flush(struct svga_context * svga,struct svga_buffer * sbuf)657 svga_buffer_upload_flush(struct svga_context *svga, struct svga_buffer *sbuf)
658 {
659    unsigned i;
660    struct pipe_resource *dummy;
661 
662    if (!sbuf->dma.pending || svga->swc->force_coherent ||
663        sbuf->key.coherent) {
664       //debug_printf("no dma pending on buffer\n");
665       return;
666    }
667 
668    assert(sbuf->handle);
669    assert(sbuf->map.num_ranges);
670    assert(sbuf->dma.svga == svga);
671 
672    /*
673     * Patch the DMA/update command with the final copy box.
674     */
675    if (svga_have_gb_objects(svga)) {
676       struct svga_3d_update_gb_image *update = sbuf->dma.updates;
677 
678       assert(update);
679 
680       for (i = 0; i < sbuf->map.num_ranges; ++i, ++update) {
681          SVGA3dBox *box = &update->body.box;
682 
683          SVGA_DBG(DEBUG_DMA, "  bytes %u - %u\n",
684                   sbuf->map.ranges[i].start, sbuf->map.ranges[i].end);
685 
686          box->x = sbuf->map.ranges[i].start;
687          box->y = 0;
688          box->z = 0;
689          box->w = sbuf->map.ranges[i].end - sbuf->map.ranges[i].start;
690          box->h = 1;
691          box->d = 1;
692 
693          assert(box->x <= sbuf->b.width0);
694          assert(box->x + box->w <= sbuf->b.width0);
695 
696          svga->hud.num_bytes_uploaded += box->w;
697          svga->hud.num_buffer_uploads++;
698       }
699    }
700    else {
701       assert(sbuf->hwbuf);
702       assert(sbuf->dma.boxes);
703       SVGA_DBG(DEBUG_DMA, "dma to sid %p\n", sbuf->handle);
704 
705       for (i = 0; i < sbuf->map.num_ranges; ++i) {
706          SVGA3dCopyBox *box = sbuf->dma.boxes + i;
707 
708          SVGA_DBG(DEBUG_DMA, "  bytes %u - %u\n",
709                sbuf->map.ranges[i].start, sbuf->map.ranges[i].end);
710 
711          box->x = sbuf->map.ranges[i].start;
712          box->y = 0;
713          box->z = 0;
714          box->w = sbuf->map.ranges[i].end - sbuf->map.ranges[i].start;
715          box->h = 1;
716          box->d = 1;
717          box->srcx = sbuf->map.ranges[i].start;
718          box->srcy = 0;
719          box->srcz = 0;
720 
721          assert(box->x <= sbuf->b.width0);
722          assert(box->x + box->w <= sbuf->b.width0);
723 
724          svga->hud.num_bytes_uploaded += box->w;
725          svga->hud.num_buffer_uploads++;
726       }
727    }
728 
729    /* Reset sbuf for next use/upload */
730 
731    sbuf->map.num_ranges = 0;
732 
733    assert(sbuf->head.prev && sbuf->head.next);
734    list_del(&sbuf->head);  /* remove from svga->dirty_buffers list */
735    sbuf->dma.pending = false;
736    sbuf->dma.flags.discard = false;
737    sbuf->dma.flags.unsynchronized = false;
738 
739    sbuf->dma.svga = NULL;
740    sbuf->dma.boxes = NULL;
741    sbuf->dma.updates = NULL;
742 
743    /* Decrement reference count (and potentially destroy) */
744    dummy = &sbuf->b;
745    pipe_resource_reference(&dummy, NULL);
746 }
747 
748 
749 /**
750  * Note a dirty range.
751  *
752  * This function only notes the range down. It doesn't actually emit a DMA
753  * upload command. That only happens when a context tries to refer to this
754  * buffer, and the DMA upload command is added to that context's command
755  * buffer.
756  *
757  * We try to lump as many contiguous DMA transfers together as possible.
758  */
759 void
svga_buffer_add_range(struct svga_buffer * sbuf,unsigned start,unsigned end)760 svga_buffer_add_range(struct svga_buffer *sbuf, unsigned start, unsigned end)
761 {
762    unsigned i;
763    unsigned nearest_range;
764    unsigned nearest_dist;
765 
766    assert(end > start);
767 
768    if (sbuf->map.num_ranges < SVGA_BUFFER_MAX_RANGES) {
769       nearest_range = sbuf->map.num_ranges;
770       nearest_dist = ~0;
771    } else {
772       nearest_range = SVGA_BUFFER_MAX_RANGES - 1;
773       nearest_dist = 0;
774    }
775 
776    /*
777     * Try to grow one of the ranges.
778     */
779    for (i = 0; i < sbuf->map.num_ranges; ++i) {
780       const int left_dist = start - sbuf->map.ranges[i].end;
781       const int right_dist = sbuf->map.ranges[i].start - end;
782       const int dist = MAX2(left_dist, right_dist);
783 
784       if (dist <= 0) {
785          /*
786           * Ranges are contiguous or overlapping -- extend this one and return.
787           *
788           * Note that it is not this function's task to prevent overlapping
789           * ranges, as the GMR was already given so it is too late to do
790           * anything.  If the ranges overlap here it must surely be because
791           * PIPE_MAP_UNSYNCHRONIZED was set.
792           */
793          sbuf->map.ranges[i].start = MIN2(sbuf->map.ranges[i].start, start);
794          sbuf->map.ranges[i].end   = MAX2(sbuf->map.ranges[i].end,   end);
795          return;
796       }
797       else {
798          /*
799           * Discontiguous ranges -- keep track of the nearest range.
800           */
801          if (dist < nearest_dist) {
802             nearest_range = i;
803             nearest_dist = dist;
804          }
805       }
806    }
807 
808    /*
809     * We cannot add a new range to an existing DMA command, so patch-up the
810     * pending DMA upload and start clean.
811     */
812 
813    svga_buffer_upload_flush(sbuf->dma.svga, sbuf);
814 
815    assert(!sbuf->dma.pending);
816    assert(!sbuf->dma.svga);
817    assert(!sbuf->dma.boxes);
818 
819    if (sbuf->map.num_ranges < SVGA_BUFFER_MAX_RANGES) {
820       /*
821        * Add a new range.
822        */
823 
824       sbuf->map.ranges[sbuf->map.num_ranges].start = start;
825       sbuf->map.ranges[sbuf->map.num_ranges].end = end;
826       ++sbuf->map.num_ranges;
827    } else {
828       /*
829        * Everything else failed, so just extend the nearest range.
830        *
831        * It is OK to do this because we always keep a local copy of the
832        * host buffer data, for SW TNL, and the host never modifies the buffer.
833        */
834 
835       assert(nearest_range < SVGA_BUFFER_MAX_RANGES);
836       assert(nearest_range < sbuf->map.num_ranges);
837       sbuf->map.ranges[nearest_range].start =
838          MIN2(sbuf->map.ranges[nearest_range].start, start);
839       sbuf->map.ranges[nearest_range].end =
840          MAX2(sbuf->map.ranges[nearest_range].end, end);
841    }
842 }
843 
844 
845 /**
846  * Copy the contents of the malloc buffer to a hardware buffer.
847  */
848 static enum pipe_error
svga_buffer_update_hw(struct svga_context * svga,struct svga_buffer * sbuf,unsigned bind_flags)849 svga_buffer_update_hw(struct svga_context *svga, struct svga_buffer *sbuf,
850                       unsigned bind_flags)
851 {
852    assert(!sbuf->user);
853    if (!svga_buffer_has_hw_storage(sbuf)) {
854       struct svga_screen *ss = svga_screen(sbuf->b.screen);
855       enum pipe_error ret;
856       bool retry;
857       void *map;
858       unsigned i;
859 
860       assert(sbuf->swbuf);
861       if (!sbuf->swbuf)
862          return PIPE_ERROR;
863 
864       ret = svga_buffer_create_hw_storage(svga_screen(sbuf->b.screen), sbuf,
865                                           bind_flags);
866       if (ret != PIPE_OK)
867          return ret;
868 
869       mtx_lock(&ss->swc_mutex);
870       map = svga_buffer_hw_storage_map(svga, sbuf, PIPE_MAP_WRITE, &retry);
871       assert(map);
872       assert(!retry);
873       if (!map) {
874          mtx_unlock(&ss->swc_mutex);
875          svga_buffer_destroy_hw_storage(ss, sbuf);
876          return PIPE_ERROR;
877       }
878 
879       /* Copy data from malloc'd swbuf to the new hardware buffer */
880       for (i = 0; i < sbuf->map.num_ranges; i++) {
881          unsigned start = sbuf->map.ranges[i].start;
882          unsigned len = sbuf->map.ranges[i].end - start;
883          memcpy((uint8_t *) map + start, (uint8_t *) sbuf->swbuf + start, len);
884       }
885 
886       if (svga->swc->force_coherent || sbuf->key.coherent)
887          sbuf->map.num_ranges = 0;
888 
889       svga_buffer_hw_storage_unmap(svga, sbuf);
890 
891       /* This user/malloc buffer is now indistinguishable from a gpu buffer */
892       assert(sbuf->map.count == 0);
893       if (sbuf->map.count == 0) {
894          if (sbuf->user)
895             sbuf->user = false;
896          else
897             align_free(sbuf->swbuf);
898          sbuf->swbuf = NULL;
899       }
900 
901       mtx_unlock(&ss->swc_mutex);
902    }
903 
904    return PIPE_OK;
905 }
906 
907 
908 /**
909  * Upload the buffer to the host in a piecewise fashion.
910  *
911  * Used when the buffer is too big to fit in the GMR aperture.
912  * This function should never get called in the guest-backed case
913  * since we always have a full-sized hardware storage backing the
914  * host surface.
915  */
916 static enum pipe_error
svga_buffer_upload_piecewise(struct svga_screen * ss,struct svga_context * svga,struct svga_buffer * sbuf)917 svga_buffer_upload_piecewise(struct svga_screen *ss,
918                              struct svga_context *svga,
919                              struct svga_buffer *sbuf)
920 {
921    struct svga_winsys_screen *sws = ss->sws;
922    const unsigned alignment = sizeof(void *);
923    const unsigned usage = 0;
924    unsigned i;
925 
926    assert(sbuf->map.num_ranges);
927    assert(!sbuf->dma.pending);
928    assert(!svga_have_gb_objects(svga));
929 
930    SVGA_DBG(DEBUG_DMA, "dma to sid %p\n", sbuf->handle);
931 
932    for (i = 0; i < sbuf->map.num_ranges; ++i) {
933       const struct svga_buffer_range *range = &sbuf->map.ranges[i];
934       unsigned offset = range->start;
935       unsigned size = range->end - range->start;
936 
937       while (offset < range->end) {
938          struct svga_winsys_buffer *hwbuf;
939          uint8_t *map;
940 
941          if (offset + size > range->end)
942             size = range->end - offset;
943 
944          hwbuf = sws->buffer_create(sws, alignment, usage, size);
945          while (!hwbuf) {
946             size /= 2;
947             if (!size)
948                return PIPE_ERROR_OUT_OF_MEMORY;
949             hwbuf = sws->buffer_create(sws, alignment, usage, size);
950          }
951 
952          SVGA_DBG(DEBUG_DMA, "  bytes %u - %u\n",
953                   offset, offset + size);
954 
955          map = sws->buffer_map(sws, hwbuf,
956                                PIPE_MAP_WRITE |
957                                PIPE_MAP_DISCARD_RANGE);
958          assert(map);
959          if (map) {
960             memcpy(map, (const char *) sbuf->swbuf + offset, size);
961             sws->buffer_unmap(sws, hwbuf);
962          }
963 
964          SVGA_RETRY(svga, SVGA3D_BufferDMA(svga->swc,
965                                            hwbuf, sbuf->handle,
966                                            SVGA3D_WRITE_HOST_VRAM,
967                                            size, 0, offset, sbuf->dma.flags));
968          sbuf->dma.flags.discard = false;
969 
970          sws->buffer_destroy(sws, hwbuf);
971 
972          offset += size;
973       }
974    }
975 
976    sbuf->map.num_ranges = 0;
977 
978    return PIPE_OK;
979 }
980 
981 
982 /**
983  * A helper function to add an update command for the dirty ranges if there
984  * isn't already one.
985  */
986 static void
svga_buffer_upload_ranges(struct svga_context * svga,struct svga_buffer * sbuf)987 svga_buffer_upload_ranges(struct svga_context *svga,
988                           struct svga_buffer *sbuf)
989 {
990    struct pipe_screen *screen = svga->pipe.screen;
991    struct svga_screen *ss = svga_screen(screen);
992    enum pipe_error ret = PIPE_OK;
993 
994    if (sbuf->map.num_ranges) {
995       if (!sbuf->dma.pending) {
996          /* No pending DMA/update commands yet. */
997 
998          /* Migrate the data from swbuf -> hwbuf if necessary */
999          ret = svga_buffer_update_hw(svga, sbuf, sbuf->bind_flags);
1000          if (ret == PIPE_OK) {
1001             /* Emit DMA or UpdateGBImage commands */
1002             SVGA_RETRY_OOM(svga, ret, svga_buffer_upload_command(svga, sbuf));
1003             if (ret == PIPE_OK) {
1004                sbuf->dma.pending = true;
1005                assert(!sbuf->head.prev && !sbuf->head.next);
1006                list_addtail(&sbuf->head, &svga->dirty_buffers);
1007             }
1008          }
1009          else if (ret == PIPE_ERROR_OUT_OF_MEMORY) {
1010             /*
1011              * The buffer is too big to fit in the GMR aperture, so break it in
1012              * smaller pieces.
1013              */
1014             ret = svga_buffer_upload_piecewise(ss, svga, sbuf);
1015          }
1016 
1017          if (ret != PIPE_OK) {
1018             /*
1019              * Something unexpected happened above. There is very little that
1020              * we can do other than proceeding while ignoring the dirty ranges.
1021              */
1022             assert(0);
1023             sbuf->map.num_ranges = 0;
1024          }
1025       }
1026       else {
1027          /*
1028           * There a pending dma already. Make sure it is from this context.
1029           */
1030          assert(sbuf->dma.svga == svga);
1031       }
1032    }
1033    return;
1034 }
1035 
1036 
1037 /**
1038  * Get (or create/upload) the winsys surface handle so that we can
1039  * refer to this buffer in fifo commands.
1040  * This function will create the host surface, and in the GB case also the
1041  * hardware storage. In the non-GB case, the hardware storage will be created
1042  * if there are mapped ranges and the data is currently in a malloc'ed buffer.
1043  */
1044 struct svga_winsys_surface *
svga_buffer_handle(struct svga_context * svga,struct pipe_resource * buf,unsigned tobind_flags)1045 svga_buffer_handle(struct svga_context *svga, struct pipe_resource *buf,
1046                    unsigned tobind_flags)
1047 {
1048    struct pipe_screen *screen = svga->pipe.screen;
1049    struct svga_screen *ss = svga_screen(screen);
1050    struct svga_buffer *sbuf;
1051    enum pipe_error ret;
1052 
1053    if (!buf)
1054       return NULL;
1055 
1056    sbuf = svga_buffer(buf);
1057 
1058    assert(!sbuf->user);
1059 
1060    if (sbuf->handle) {
1061       if ((sbuf->bind_flags & tobind_flags) != tobind_flags) {
1062          /* If the allocated resource's bind flags do not include the
1063           * requested bind flags, validate the host surface.
1064           */
1065          ret = svga_buffer_validate_host_surface(svga, sbuf, tobind_flags);
1066          if (ret != PIPE_OK)
1067             return NULL;
1068       }
1069    } else {
1070       /* If there is no resource handle yet, then combine the buffer bind
1071        * flags and the tobind_flags if they are compatible.
1072        * If not, just use the tobind_flags for creating the resource handle.
1073        */
1074       if (compatible_bind_flags(sbuf->bind_flags, tobind_flags))
1075          sbuf->bind_flags = sbuf->bind_flags | tobind_flags;
1076       else
1077          sbuf->bind_flags = tobind_flags;
1078 
1079       assert((sbuf->bind_flags & tobind_flags) == tobind_flags);
1080 
1081       /* This call will set sbuf->handle */
1082       if (svga_have_gb_objects(svga)) {
1083          ret = svga_buffer_update_hw(svga, sbuf, sbuf->bind_flags);
1084       } else {
1085          ret = svga_buffer_create_host_surface(ss, sbuf, sbuf->bind_flags);
1086       }
1087       if (ret != PIPE_OK)
1088          return NULL;
1089    }
1090 
1091    assert(sbuf->handle);
1092    assert(sbuf->bufsurf);
1093    if (svga->swc->force_coherent || sbuf->key.coherent)
1094       return sbuf->handle;
1095 
1096    /* upload any dirty ranges */
1097    svga_buffer_upload_ranges(svga, sbuf);
1098 
1099    assert(sbuf->map.num_ranges == 0 || sbuf->dma.pending);
1100 
1101    return sbuf->handle;
1102 }
1103 
1104 
1105 void
svga_context_flush_buffers(struct svga_context * svga)1106 svga_context_flush_buffers(struct svga_context *svga)
1107 {
1108    struct list_head *curr, *next;
1109 
1110    SVGA_STATS_TIME_PUSH(svga_sws(svga), SVGA_STATS_TIME_BUFFERSFLUSH);
1111 
1112    curr = svga->dirty_buffers.next;
1113    next = curr->next;
1114    while (curr != &svga->dirty_buffers) {
1115       struct svga_buffer *sbuf = list_entry(curr, struct svga_buffer, head);
1116 
1117       assert(p_atomic_read(&sbuf->b.reference.count) != 0);
1118       assert(sbuf->dma.pending);
1119 
1120       svga_buffer_upload_flush(svga, sbuf);
1121 
1122       curr = next;
1123       next = curr->next;
1124    }
1125 
1126    SVGA_STATS_TIME_POP(svga_sws(svga));
1127 }
1128