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