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