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