• 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 /**
58  * Allocate a winsys_buffer (ie. DMA, aka GMR memory).
59  *
60  * It will flush and retry in case the first attempt to create a DMA buffer
61  * fails, so it should not be called from any function involved in flushing
62  * to avoid recursion.
63  */
64 struct svga_winsys_buffer *
svga_winsys_buffer_create(struct svga_context * svga,unsigned alignment,unsigned usage,unsigned size)65 svga_winsys_buffer_create( struct svga_context *svga,
66                            unsigned alignment,
67                            unsigned usage,
68                            unsigned size )
69 {
70    struct svga_screen *svgascreen = svga_screen(svga->pipe.screen);
71    struct svga_winsys_screen *sws = svgascreen->sws;
72    struct svga_winsys_buffer *buf;
73 
74    /* Just try */
75    buf = sws->buffer_create(sws, alignment, usage, size);
76    if (!buf) {
77       SVGA_DBG(DEBUG_DMA|DEBUG_PERF, "flushing context to find %d bytes GMR\n",
78                size);
79 
80       /* Try flushing all pending DMAs */
81       svga_context_flush(svga, NULL);
82       buf = sws->buffer_create(sws, alignment, usage, size);
83    }
84 
85    return buf;
86 }
87 
88 
89 /**
90  * Destroy HW storage if separate from the host surface.
91  * In the GB case, the HW storage is associated with the host surface
92  * and is therefore a No-op.
93  */
94 void
svga_buffer_destroy_hw_storage(struct svga_screen * ss,struct svga_buffer * sbuf)95 svga_buffer_destroy_hw_storage(struct svga_screen *ss, struct svga_buffer *sbuf)
96 {
97    struct svga_winsys_screen *sws = ss->sws;
98 
99    assert(sbuf->map.count == 0);
100    assert(sbuf->hwbuf);
101    if (sbuf->hwbuf) {
102       sws->buffer_destroy(sws, sbuf->hwbuf);
103       sbuf->hwbuf = NULL;
104    }
105 }
106 
107 
108 
109 /**
110  * Allocate DMA'ble or Updatable storage for the buffer.
111  *
112  * Called before mapping a buffer.
113  */
114 enum pipe_error
svga_buffer_create_hw_storage(struct svga_screen * ss,struct svga_buffer * sbuf)115 svga_buffer_create_hw_storage(struct svga_screen *ss,
116                               struct svga_buffer *sbuf)
117 {
118    assert(!sbuf->user);
119 
120    if (ss->sws->have_gb_objects) {
121       assert(sbuf->handle || !sbuf->dma.pending);
122       return svga_buffer_create_host_surface(ss, sbuf);
123    }
124    if (!sbuf->hwbuf) {
125       struct svga_winsys_screen *sws = ss->sws;
126       unsigned alignment = 16;
127       unsigned usage = 0;
128       unsigned size = sbuf->b.b.width0;
129 
130       sbuf->hwbuf = sws->buffer_create(sws, alignment, usage, size);
131       if (!sbuf->hwbuf)
132          return PIPE_ERROR_OUT_OF_MEMORY;
133 
134       assert(!sbuf->dma.pending);
135    }
136 
137    return PIPE_OK;
138 }
139 
140 
141 
142 enum pipe_error
svga_buffer_create_host_surface(struct svga_screen * ss,struct svga_buffer * sbuf)143 svga_buffer_create_host_surface(struct svga_screen *ss,
144                                 struct svga_buffer *sbuf)
145 {
146    assert(!sbuf->user);
147 
148    if (!sbuf->handle) {
149       boolean validated;
150 
151       sbuf->key.flags = 0;
152 
153       sbuf->key.format = SVGA3D_BUFFER;
154       if (sbuf->bind_flags & PIPE_BIND_VERTEX_BUFFER) {
155          sbuf->key.flags |= SVGA3D_SURFACE_HINT_VERTEXBUFFER;
156          sbuf->key.flags |= SVGA3D_SURFACE_BIND_VERTEX_BUFFER;
157       }
158       if (sbuf->bind_flags & PIPE_BIND_INDEX_BUFFER) {
159          sbuf->key.flags |= SVGA3D_SURFACE_HINT_INDEXBUFFER;
160          sbuf->key.flags |= SVGA3D_SURFACE_BIND_INDEX_BUFFER;
161       }
162       if (sbuf->bind_flags & PIPE_BIND_CONSTANT_BUFFER)
163          sbuf->key.flags |= SVGA3D_SURFACE_BIND_CONSTANT_BUFFER;
164 
165       if (sbuf->bind_flags & PIPE_BIND_STREAM_OUTPUT)
166          sbuf->key.flags |= SVGA3D_SURFACE_BIND_STREAM_OUTPUT;
167 
168       if (sbuf->bind_flags & PIPE_BIND_SAMPLER_VIEW)
169          sbuf->key.flags |= SVGA3D_SURFACE_BIND_SHADER_RESOURCE;
170 
171       if (!sbuf->bind_flags && sbuf->b.b.usage == PIPE_USAGE_STAGING) {
172          /* This surface is to be used with the
173           * SVGA3D_CMD_DX_TRANSFER_FROM_BUFFER command, and no other
174           * bind flags are allowed to be set for this surface.
175           */
176          sbuf->key.flags = SVGA3D_SURFACE_TRANSFER_FROM_BUFFER;
177       }
178 
179       sbuf->key.size.width = sbuf->b.b.width0;
180       sbuf->key.size.height = 1;
181       sbuf->key.size.depth = 1;
182 
183       sbuf->key.numFaces = 1;
184       sbuf->key.numMipLevels = 1;
185       sbuf->key.cachable = 1;
186       sbuf->key.arraySize = 1;
187 
188       SVGA_DBG(DEBUG_DMA, "surface_create for buffer sz %d\n",
189                sbuf->b.b.width0);
190 
191       sbuf->handle = svga_screen_surface_create(ss, sbuf->b.b.bind,
192                                                 sbuf->b.b.usage,
193                                                 &validated, &sbuf->key);
194       if (!sbuf->handle)
195          return PIPE_ERROR_OUT_OF_MEMORY;
196 
197       /* Always set the discard flag on the first time the buffer is written
198        * as svga_screen_surface_create might have passed a recycled host
199        * buffer.
200        */
201       sbuf->dma.flags.discard = TRUE;
202 
203       SVGA_DBG(DEBUG_DMA, "   --> got sid %p sz %d (buffer)\n",
204                sbuf->handle, sbuf->b.b.width0);
205    }
206 
207    return PIPE_OK;
208 }
209 
210 
211 void
svga_buffer_destroy_host_surface(struct svga_screen * ss,struct svga_buffer * sbuf)212 svga_buffer_destroy_host_surface(struct svga_screen *ss,
213                                  struct svga_buffer *sbuf)
214 {
215    if (sbuf->handle) {
216       SVGA_DBG(DEBUG_DMA, " ungrab sid %p sz %d\n",
217                sbuf->handle, sbuf->b.b.width0);
218       svga_screen_surface_destroy(ss, &sbuf->key, &sbuf->handle);
219    }
220 }
221 
222 
223 /**
224  * Insert a number of preliminary UPDATE_GB_IMAGE commands in the
225  * command buffer, equal to the current number of mapped ranges.
226  * The UPDATE_GB_IMAGE commands will be patched with the
227  * actual ranges just before flush.
228  */
229 static enum pipe_error
svga_buffer_upload_gb_command(struct svga_context * svga,struct svga_buffer * sbuf)230 svga_buffer_upload_gb_command(struct svga_context *svga,
231 			      struct svga_buffer *sbuf)
232 {
233    struct svga_winsys_context *swc = svga->swc;
234    SVGA3dCmdUpdateGBImage *update_cmd;
235    struct svga_3d_update_gb_image *whole_update_cmd = NULL;
236    const uint32 numBoxes = sbuf->map.num_ranges;
237    struct pipe_resource *dummy;
238    unsigned i;
239 
240    assert(svga_have_gb_objects(svga));
241    assert(numBoxes);
242    assert(sbuf->dma.updates == NULL);
243 
244    if (sbuf->dma.flags.discard) {
245       struct svga_3d_invalidate_gb_image *cicmd = NULL;
246       SVGA3dCmdInvalidateGBImage *invalidate_cmd;
247       const unsigned total_commands_size =
248          sizeof(*invalidate_cmd) + numBoxes * sizeof(*whole_update_cmd);
249 
250       /* Allocate FIFO space for one INVALIDATE_GB_IMAGE command followed by
251        * 'numBoxes' UPDATE_GB_IMAGE commands.  Allocate all at once rather
252        * than with separate commands because we need to properly deal with
253        * filling the command buffer.
254        */
255       invalidate_cmd = SVGA3D_FIFOReserve(swc,
256                                           SVGA_3D_CMD_INVALIDATE_GB_IMAGE,
257                                           total_commands_size, 1 + numBoxes);
258       if (!invalidate_cmd)
259 	 return PIPE_ERROR_OUT_OF_MEMORY;
260 
261       cicmd = container_of(invalidate_cmd, cicmd, body);
262       cicmd->header.size = sizeof(*invalidate_cmd);
263       swc->surface_relocation(swc, &invalidate_cmd->image.sid, NULL, sbuf->handle,
264                               (SVGA_RELOC_WRITE |
265                                SVGA_RELOC_INTERNAL |
266                                SVGA_RELOC_DMA));
267       invalidate_cmd->image.face = 0;
268       invalidate_cmd->image.mipmap = 0;
269 
270       /* The whole_update_command is a SVGA3dCmdHeader plus the
271        * SVGA3dCmdUpdateGBImage command.
272        */
273       whole_update_cmd = (struct svga_3d_update_gb_image *) &invalidate_cmd[1];
274       /* initialize the first UPDATE_GB_IMAGE command */
275       whole_update_cmd->header.id = SVGA_3D_CMD_UPDATE_GB_IMAGE;
276       update_cmd = &whole_update_cmd->body;
277 
278    } else {
279       /* Allocate FIFO space for 'numBoxes' UPDATE_GB_IMAGE commands */
280       const unsigned total_commands_size =
281          sizeof(*update_cmd) + (numBoxes - 1) * sizeof(*whole_update_cmd);
282 
283       update_cmd = SVGA3D_FIFOReserve(swc,
284                                       SVGA_3D_CMD_UPDATE_GB_IMAGE,
285                                       total_commands_size, numBoxes);
286       if (!update_cmd)
287 	 return PIPE_ERROR_OUT_OF_MEMORY;
288 
289       /* The whole_update_command is a SVGA3dCmdHeader plus the
290        * SVGA3dCmdUpdateGBImage command.
291        */
292       whole_update_cmd = container_of(update_cmd, whole_update_cmd, body);
293    }
294 
295    /* Init the first UPDATE_GB_IMAGE command */
296    whole_update_cmd->header.size = sizeof(*update_cmd);
297    swc->surface_relocation(swc, &update_cmd->image.sid, NULL, sbuf->handle,
298 			   SVGA_RELOC_WRITE | SVGA_RELOC_INTERNAL);
299    update_cmd->image.face = 0;
300    update_cmd->image.mipmap = 0;
301 
302    /* Save pointer to the first UPDATE_GB_IMAGE command so that we can
303     * fill in the box info below.
304     */
305    sbuf->dma.updates = whole_update_cmd;
306 
307    /*
308     * Copy the face, mipmap, etc. info to all subsequent commands.
309     * Also do the surface relocation for each subsequent command.
310     */
311    for (i = 1; i < numBoxes; ++i) {
312       whole_update_cmd++;
313       memcpy(whole_update_cmd, sbuf->dma.updates, sizeof(*whole_update_cmd));
314 
315       swc->surface_relocation(swc, &whole_update_cmd->body.image.sid, NULL,
316                               sbuf->handle,
317                               SVGA_RELOC_WRITE | SVGA_RELOC_INTERNAL);
318    }
319 
320    /* Increment reference count */
321    sbuf->dma.svga = svga;
322    dummy = NULL;
323    pipe_resource_reference(&dummy, &sbuf->b.b);
324    SVGA_FIFOCommitAll(swc);
325 
326    swc->hints |= SVGA_HINT_FLAG_CAN_PRE_FLUSH;
327    sbuf->dma.flags.discard = FALSE;
328 
329    svga->hud.num_resource_updates++;
330 
331    return PIPE_OK;
332 }
333 
334 
335 /**
336  * Issue DMA commands to transfer guest memory to the host.
337  * Note that the memory segments (offset, size) will be patched in
338  * later in the svga_buffer_upload_flush() function.
339  */
340 static enum pipe_error
svga_buffer_upload_hb_command(struct svga_context * svga,struct svga_buffer * sbuf)341 svga_buffer_upload_hb_command(struct svga_context *svga,
342                               struct svga_buffer *sbuf)
343 {
344    struct svga_winsys_context *swc = svga->swc;
345    struct svga_winsys_buffer *guest = sbuf->hwbuf;
346    struct svga_winsys_surface *host = sbuf->handle;
347    const SVGA3dTransferType transfer = SVGA3D_WRITE_HOST_VRAM;
348    SVGA3dCmdSurfaceDMA *cmd;
349    const uint32 numBoxes = sbuf->map.num_ranges;
350    SVGA3dCopyBox *boxes;
351    SVGA3dCmdSurfaceDMASuffix *pSuffix;
352    unsigned region_flags;
353    unsigned surface_flags;
354    struct pipe_resource *dummy;
355 
356    assert(!svga_have_gb_objects(svga));
357 
358    if (transfer == SVGA3D_WRITE_HOST_VRAM) {
359       region_flags = SVGA_RELOC_READ;
360       surface_flags = SVGA_RELOC_WRITE;
361    }
362    else if (transfer == SVGA3D_READ_HOST_VRAM) {
363       region_flags = SVGA_RELOC_WRITE;
364       surface_flags = SVGA_RELOC_READ;
365    }
366    else {
367       assert(0);
368       return PIPE_ERROR_BAD_INPUT;
369    }
370 
371    assert(numBoxes);
372 
373    cmd = SVGA3D_FIFOReserve(swc,
374                             SVGA_3D_CMD_SURFACE_DMA,
375                             sizeof *cmd + numBoxes * sizeof *boxes + sizeof *pSuffix,
376                             2);
377    if (!cmd)
378       return PIPE_ERROR_OUT_OF_MEMORY;
379 
380    swc->region_relocation(swc, &cmd->guest.ptr, guest, 0, region_flags);
381    cmd->guest.pitch = 0;
382 
383    swc->surface_relocation(swc, &cmd->host.sid, NULL, host, surface_flags);
384    cmd->host.face = 0;
385    cmd->host.mipmap = 0;
386 
387    cmd->transfer = transfer;
388 
389    sbuf->dma.boxes = (SVGA3dCopyBox *)&cmd[1];
390    sbuf->dma.svga = svga;
391 
392    /* Increment reference count */
393    dummy = NULL;
394    pipe_resource_reference(&dummy, &sbuf->b.b);
395 
396    pSuffix = (SVGA3dCmdSurfaceDMASuffix *)((uint8_t*)cmd + sizeof *cmd + numBoxes * sizeof *boxes);
397    pSuffix->suffixSize = sizeof *pSuffix;
398    pSuffix->maximumOffset = sbuf->b.b.width0;
399    pSuffix->flags = sbuf->dma.flags;
400 
401    SVGA_FIFOCommitAll(swc);
402 
403    swc->hints |= SVGA_HINT_FLAG_CAN_PRE_FLUSH;
404    sbuf->dma.flags.discard = FALSE;
405 
406    svga->hud.num_buffer_uploads++;
407 
408    return PIPE_OK;
409 }
410 
411 
412 /**
413  * Issue commands to transfer guest memory to the host.
414  */
415 static enum pipe_error
svga_buffer_upload_command(struct svga_context * svga,struct svga_buffer * sbuf)416 svga_buffer_upload_command(struct svga_context *svga, struct svga_buffer *sbuf)
417 {
418    if (svga_have_gb_objects(svga)) {
419       return svga_buffer_upload_gb_command(svga, sbuf);
420    } else {
421       return svga_buffer_upload_hb_command(svga, sbuf);
422    }
423 }
424 
425 
426 /**
427  * Patch up the upload DMA command reserved by svga_buffer_upload_command
428  * with the final ranges.
429  */
430 void
svga_buffer_upload_flush(struct svga_context * svga,struct svga_buffer * sbuf)431 svga_buffer_upload_flush(struct svga_context *svga,
432 			 struct svga_buffer *sbuf)
433 {
434    unsigned i;
435    struct pipe_resource *dummy;
436 
437    if (!sbuf->dma.pending) {
438       //debug_printf("no dma pending on buffer\n");
439       return;
440    }
441 
442    assert(sbuf->handle);
443    assert(sbuf->map.num_ranges);
444    assert(sbuf->dma.svga == svga);
445 
446    /*
447     * Patch the DMA/update command with the final copy box.
448     */
449    if (svga_have_gb_objects(svga)) {
450       struct svga_3d_update_gb_image *update = sbuf->dma.updates;
451       assert(update);
452 
453       for (i = 0; i < sbuf->map.num_ranges; ++i, ++update) {
454          SVGA3dBox *box = &update->body.box;
455 
456          SVGA_DBG(DEBUG_DMA, "  bytes %u - %u\n",
457                   sbuf->map.ranges[i].start, sbuf->map.ranges[i].end);
458 
459          box->x = sbuf->map.ranges[i].start;
460          box->y = 0;
461          box->z = 0;
462          box->w = sbuf->map.ranges[i].end - sbuf->map.ranges[i].start;
463          box->h = 1;
464          box->d = 1;
465 
466          assert(box->x <= sbuf->b.b.width0);
467          assert(box->x + box->w <= sbuf->b.b.width0);
468 
469          svga->hud.num_bytes_uploaded += box->w;
470          svga->hud.num_buffer_uploads++;
471       }
472    }
473    else {
474       assert(sbuf->hwbuf);
475       assert(sbuf->dma.boxes);
476       SVGA_DBG(DEBUG_DMA, "dma to sid %p\n", sbuf->handle);
477 
478       for (i = 0; i < sbuf->map.num_ranges; ++i) {
479          SVGA3dCopyBox *box = sbuf->dma.boxes + i;
480 
481          SVGA_DBG(DEBUG_DMA, "  bytes %u - %u\n",
482                sbuf->map.ranges[i].start, sbuf->map.ranges[i].end);
483 
484          box->x = sbuf->map.ranges[i].start;
485          box->y = 0;
486          box->z = 0;
487          box->w = sbuf->map.ranges[i].end - sbuf->map.ranges[i].start;
488          box->h = 1;
489          box->d = 1;
490          box->srcx = sbuf->map.ranges[i].start;
491          box->srcy = 0;
492          box->srcz = 0;
493 
494          assert(box->x <= sbuf->b.b.width0);
495          assert(box->x + box->w <= sbuf->b.b.width0);
496 
497          svga->hud.num_bytes_uploaded += box->w;
498          svga->hud.num_buffer_uploads++;
499       }
500    }
501 
502    /* Reset sbuf for next use/upload */
503 
504    sbuf->map.num_ranges = 0;
505 
506    assert(sbuf->head.prev && sbuf->head.next);
507    LIST_DEL(&sbuf->head);  /* remove from svga->dirty_buffers list */
508 #ifdef DEBUG
509    sbuf->head.next = sbuf->head.prev = NULL;
510 #endif
511    sbuf->dma.pending = FALSE;
512    sbuf->dma.flags.discard = FALSE;
513    sbuf->dma.flags.unsynchronized = FALSE;
514 
515    sbuf->dma.svga = NULL;
516    sbuf->dma.boxes = NULL;
517    sbuf->dma.updates = NULL;
518 
519    /* Decrement reference count (and potentially destroy) */
520    dummy = &sbuf->b.b;
521    pipe_resource_reference(&dummy, NULL);
522 }
523 
524 
525 /**
526  * Note a dirty range.
527  *
528  * This function only notes the range down. It doesn't actually emit a DMA
529  * upload command. That only happens when a context tries to refer to this
530  * buffer, and the DMA upload command is added to that context's command
531  * buffer.
532  *
533  * We try to lump as many contiguous DMA transfers together as possible.
534  */
535 void
svga_buffer_add_range(struct svga_buffer * sbuf,unsigned start,unsigned end)536 svga_buffer_add_range(struct svga_buffer *sbuf, unsigned start, unsigned end)
537 {
538    unsigned i;
539    unsigned nearest_range;
540    unsigned nearest_dist;
541 
542    assert(end > start);
543 
544    if (sbuf->map.num_ranges < SVGA_BUFFER_MAX_RANGES) {
545       nearest_range = sbuf->map.num_ranges;
546       nearest_dist = ~0;
547    } else {
548       nearest_range = SVGA_BUFFER_MAX_RANGES - 1;
549       nearest_dist = 0;
550    }
551 
552    /*
553     * Try to grow one of the ranges.
554     */
555    for (i = 0; i < sbuf->map.num_ranges; ++i) {
556       const int left_dist = start - sbuf->map.ranges[i].end;
557       const int right_dist = sbuf->map.ranges[i].start - end;
558       const int dist = MAX2(left_dist, right_dist);
559 
560       if (dist <= 0) {
561          /*
562           * Ranges are contiguous or overlapping -- extend this one and return.
563           *
564           * Note that it is not this function's task to prevent overlapping
565           * ranges, as the GMR was already given so it is too late to do
566           * anything.  If the ranges overlap here it must surely be because
567           * PIPE_TRANSFER_UNSYNCHRONIZED was set.
568           */
569          sbuf->map.ranges[i].start = MIN2(sbuf->map.ranges[i].start, start);
570          sbuf->map.ranges[i].end   = MAX2(sbuf->map.ranges[i].end,   end);
571          return;
572       }
573       else {
574          /*
575           * Discontiguous ranges -- keep track of the nearest range.
576           */
577          if (dist < nearest_dist) {
578             nearest_range = i;
579             nearest_dist = dist;
580          }
581       }
582    }
583 
584    /*
585     * We cannot add a new range to an existing DMA command, so patch-up the
586     * pending DMA upload and start clean.
587     */
588 
589    svga_buffer_upload_flush(sbuf->dma.svga, sbuf);
590 
591    assert(!sbuf->dma.pending);
592    assert(!sbuf->dma.svga);
593    assert(!sbuf->dma.boxes);
594 
595    if (sbuf->map.num_ranges < SVGA_BUFFER_MAX_RANGES) {
596       /*
597        * Add a new range.
598        */
599 
600       sbuf->map.ranges[sbuf->map.num_ranges].start = start;
601       sbuf->map.ranges[sbuf->map.num_ranges].end = end;
602       ++sbuf->map.num_ranges;
603    } else {
604       /*
605        * Everything else failed, so just extend the nearest range.
606        *
607        * It is OK to do this because we always keep a local copy of the
608        * host buffer data, for SW TNL, and the host never modifies the buffer.
609        */
610 
611       assert(nearest_range < SVGA_BUFFER_MAX_RANGES);
612       assert(nearest_range < sbuf->map.num_ranges);
613       sbuf->map.ranges[nearest_range].start =
614          MIN2(sbuf->map.ranges[nearest_range].start, start);
615       sbuf->map.ranges[nearest_range].end =
616          MAX2(sbuf->map.ranges[nearest_range].end, end);
617    }
618 }
619 
620 
621 
622 /**
623  * Copy the contents of the malloc buffer to a hardware buffer.
624  */
625 static enum pipe_error
svga_buffer_update_hw(struct svga_context * svga,struct svga_buffer * sbuf)626 svga_buffer_update_hw(struct svga_context *svga, struct svga_buffer *sbuf)
627 {
628    assert(!sbuf->user);
629    if (!svga_buffer_has_hw_storage(sbuf)) {
630       struct svga_screen *ss = svga_screen(sbuf->b.b.screen);
631       enum pipe_error ret;
632       boolean retry;
633       void *map;
634       unsigned i;
635 
636       assert(sbuf->swbuf);
637       if (!sbuf->swbuf)
638          return PIPE_ERROR;
639 
640       ret = svga_buffer_create_hw_storage(svga_screen(sbuf->b.b.screen), sbuf);
641       if (ret != PIPE_OK)
642          return ret;
643 
644       pipe_mutex_lock(ss->swc_mutex);
645       map = svga_buffer_hw_storage_map(svga, sbuf, PIPE_TRANSFER_WRITE, &retry);
646       assert(map);
647       assert(!retry);
648       if (!map) {
649 	 pipe_mutex_unlock(ss->swc_mutex);
650          svga_buffer_destroy_hw_storage(ss, sbuf);
651          return PIPE_ERROR;
652       }
653 
654       /* Copy data from malloc'd swbuf to the new hardware buffer */
655       for (i = 0; i < sbuf->map.num_ranges; i++) {
656          unsigned start = sbuf->map.ranges[i].start;
657          unsigned len = sbuf->map.ranges[i].end - start;
658          memcpy((uint8_t *) map + start, (uint8_t *) sbuf->swbuf + start, len);
659       }
660 
661       svga_buffer_hw_storage_unmap(svga, sbuf);
662 
663       /* This user/malloc buffer is now indistinguishable from a gpu buffer */
664       assert(sbuf->map.count == 0);
665       if (sbuf->map.count == 0) {
666          if (sbuf->user)
667             sbuf->user = FALSE;
668          else
669             align_free(sbuf->swbuf);
670          sbuf->swbuf = NULL;
671       }
672 
673       pipe_mutex_unlock(ss->swc_mutex);
674    }
675 
676    return PIPE_OK;
677 }
678 
679 
680 /**
681  * Upload the buffer to the host in a piecewise fashion.
682  *
683  * Used when the buffer is too big to fit in the GMR aperture.
684  * This function should never get called in the guest-backed case
685  * since we always have a full-sized hardware storage backing the
686  * host surface.
687  */
688 static enum pipe_error
svga_buffer_upload_piecewise(struct svga_screen * ss,struct svga_context * svga,struct svga_buffer * sbuf)689 svga_buffer_upload_piecewise(struct svga_screen *ss,
690                              struct svga_context *svga,
691                              struct svga_buffer *sbuf)
692 {
693    struct svga_winsys_screen *sws = ss->sws;
694    const unsigned alignment = sizeof(void *);
695    const unsigned usage = 0;
696    unsigned i;
697 
698    assert(sbuf->map.num_ranges);
699    assert(!sbuf->dma.pending);
700    assert(!svga_have_gb_objects(svga));
701 
702    SVGA_DBG(DEBUG_DMA, "dma to sid %p\n", sbuf->handle);
703 
704    for (i = 0; i < sbuf->map.num_ranges; ++i) {
705       const struct svga_buffer_range *range = &sbuf->map.ranges[i];
706       unsigned offset = range->start;
707       unsigned size = range->end - range->start;
708 
709       while (offset < range->end) {
710          struct svga_winsys_buffer *hwbuf;
711          uint8_t *map;
712          enum pipe_error ret;
713 
714          if (offset + size > range->end)
715             size = range->end - offset;
716 
717          hwbuf = sws->buffer_create(sws, alignment, usage, size);
718          while (!hwbuf) {
719             size /= 2;
720             if (!size)
721                return PIPE_ERROR_OUT_OF_MEMORY;
722             hwbuf = sws->buffer_create(sws, alignment, usage, size);
723          }
724 
725          SVGA_DBG(DEBUG_DMA, "  bytes %u - %u\n",
726                   offset, offset + size);
727 
728          map = sws->buffer_map(sws, hwbuf,
729                                PIPE_TRANSFER_WRITE |
730                                PIPE_TRANSFER_DISCARD_RANGE);
731          assert(map);
732          if (map) {
733             memcpy(map, (const char *) sbuf->swbuf + offset, size);
734             sws->buffer_unmap(sws, hwbuf);
735          }
736 
737          ret = SVGA3D_BufferDMA(svga->swc,
738                                 hwbuf, sbuf->handle,
739                                 SVGA3D_WRITE_HOST_VRAM,
740                                 size, 0, offset, sbuf->dma.flags);
741          if (ret != PIPE_OK) {
742             svga_context_flush(svga, NULL);
743             ret =  SVGA3D_BufferDMA(svga->swc,
744                                     hwbuf, sbuf->handle,
745                                     SVGA3D_WRITE_HOST_VRAM,
746                                     size, 0, offset, sbuf->dma.flags);
747             assert(ret == PIPE_OK);
748          }
749 
750          sbuf->dma.flags.discard = FALSE;
751 
752          sws->buffer_destroy(sws, hwbuf);
753 
754          offset += size;
755       }
756    }
757 
758    sbuf->map.num_ranges = 0;
759 
760    return PIPE_OK;
761 }
762 
763 
764 /**
765  * Get (or create/upload) the winsys surface handle so that we can
766  * refer to this buffer in fifo commands.
767  * This function will create the host surface, and in the GB case also the
768  * hardware storage. In the non-GB case, the hardware storage will be created
769  * if there are mapped ranges and the data is currently in a malloc'ed buffer.
770  */
771 struct svga_winsys_surface *
svga_buffer_handle(struct svga_context * svga,struct pipe_resource * buf)772 svga_buffer_handle(struct svga_context *svga, struct pipe_resource *buf)
773 {
774    struct pipe_screen *screen = svga->pipe.screen;
775    struct svga_screen *ss = svga_screen(screen);
776    struct svga_buffer *sbuf;
777    enum pipe_error ret;
778 
779    if (!buf)
780       return NULL;
781 
782    sbuf = svga_buffer(buf);
783 
784    assert(!sbuf->user);
785 
786    if (!sbuf->handle) {
787       /* This call will set sbuf->handle */
788       if (svga_have_gb_objects(svga)) {
789 	 ret = svga_buffer_update_hw(svga, sbuf);
790       } else {
791 	 ret = svga_buffer_create_host_surface(ss, sbuf);
792       }
793       if (ret != PIPE_OK)
794 	 return NULL;
795    }
796 
797    assert(sbuf->handle);
798 
799    if (sbuf->map.num_ranges) {
800       if (!sbuf->dma.pending) {
801          /* No pending DMA/update commands yet. */
802 
803          /* Migrate the data from swbuf -> hwbuf if necessary */
804          ret = svga_buffer_update_hw(svga, sbuf);
805          if (ret == PIPE_OK) {
806             /* Emit DMA or UpdateGBImage commands */
807             ret = svga_buffer_upload_command(svga, sbuf);
808             if (ret == PIPE_ERROR_OUT_OF_MEMORY) {
809                svga_context_flush(svga, NULL);
810                ret = svga_buffer_upload_command(svga, sbuf);
811                assert(ret == PIPE_OK);
812             }
813             if (ret == PIPE_OK) {
814                sbuf->dma.pending = TRUE;
815                assert(!sbuf->head.prev && !sbuf->head.next);
816                LIST_ADDTAIL(&sbuf->head, &svga->dirty_buffers);
817             }
818          }
819          else if (ret == PIPE_ERROR_OUT_OF_MEMORY) {
820             /*
821              * The buffer is too big to fit in the GMR aperture, so break it in
822              * smaller pieces.
823              */
824             ret = svga_buffer_upload_piecewise(ss, svga, sbuf);
825          }
826 
827          if (ret != PIPE_OK) {
828             /*
829              * Something unexpected happened above. There is very little that
830              * we can do other than proceeding while ignoring the dirty ranges.
831              */
832             assert(0);
833             sbuf->map.num_ranges = 0;
834          }
835       }
836       else {
837          /*
838           * There a pending dma already. Make sure it is from this context.
839           */
840          assert(sbuf->dma.svga == svga);
841       }
842    }
843 
844    assert(sbuf->map.num_ranges == 0 || sbuf->dma.pending);
845 
846    return sbuf->handle;
847 }
848 
849 
850 
851 void
svga_context_flush_buffers(struct svga_context * svga)852 svga_context_flush_buffers(struct svga_context *svga)
853 {
854    struct list_head *curr, *next;
855 
856    SVGA_STATS_TIME_PUSH(svga_sws(svga), SVGA_STATS_TIME_BUFFERSFLUSH);
857 
858    curr = svga->dirty_buffers.next;
859    next = curr->next;
860    while (curr != &svga->dirty_buffers) {
861       struct svga_buffer *sbuf = LIST_ENTRY(struct svga_buffer, curr, head);
862 
863       assert(p_atomic_read(&sbuf->b.b.reference.count) != 0);
864       assert(sbuf->dma.pending);
865 
866       svga_buffer_upload_flush(svga, sbuf);
867 
868       curr = next;
869       next = curr->next;
870    }
871 
872    SVGA_STATS_TIME_POP(svga_sws(svga));
873 }
874