gallium/util: replace pipe_mutex_lock() with mtx_lock()
[mesa.git] / src / gallium / drivers / svga / svga_resource_buffer_upload.c
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 *
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
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
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
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
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
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
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
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
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
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
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 mtx_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
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 *
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
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 }