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