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