+svga_buffer_upload_gb_command(struct svga_context *svga,
+ struct svga_buffer *sbuf)
+{
+ struct svga_winsys_context *swc = svga->swc;
+ SVGA3dCmdUpdateGBImage *update_cmd;
+ struct svga_3d_update_gb_image *whole_update_cmd = NULL;
+ const uint32 numBoxes = sbuf->map.num_ranges;
+ struct pipe_resource *dummy;
+ unsigned i;
+
+ if (swc->force_coherent || sbuf->key.coherent)
+ return PIPE_OK;
+
+ assert(svga_have_gb_objects(svga));
+ assert(numBoxes);
+ assert(sbuf->dma.updates == NULL);
+
+ if (sbuf->dma.flags.discard) {
+ struct svga_3d_invalidate_gb_image *cicmd = NULL;
+ SVGA3dCmdInvalidateGBImage *invalidate_cmd;
+ const unsigned total_commands_size =
+ sizeof(*invalidate_cmd) + numBoxes * sizeof(*whole_update_cmd);
+
+ /* Allocate FIFO space for one INVALIDATE_GB_IMAGE command followed by
+ * 'numBoxes' UPDATE_GB_IMAGE commands. Allocate all at once rather
+ * than with separate commands because we need to properly deal with
+ * filling the command buffer.
+ */
+ invalidate_cmd = SVGA3D_FIFOReserve(swc,
+ SVGA_3D_CMD_INVALIDATE_GB_IMAGE,
+ total_commands_size, 1 + numBoxes);
+ if (!invalidate_cmd)
+ return PIPE_ERROR_OUT_OF_MEMORY;
+
+ cicmd = container_of(invalidate_cmd, cicmd, body);
+ cicmd->header.size = sizeof(*invalidate_cmd);
+ swc->surface_relocation(swc, &invalidate_cmd->image.sid, NULL,
+ sbuf->handle,
+ (SVGA_RELOC_WRITE |
+ SVGA_RELOC_INTERNAL |
+ SVGA_RELOC_DMA));
+ invalidate_cmd->image.face = 0;
+ invalidate_cmd->image.mipmap = 0;
+
+ /* The whole_update_command is a SVGA3dCmdHeader plus the
+ * SVGA3dCmdUpdateGBImage command.
+ */
+ whole_update_cmd = (struct svga_3d_update_gb_image *) &invalidate_cmd[1];
+ /* initialize the first UPDATE_GB_IMAGE command */
+ whole_update_cmd->header.id = SVGA_3D_CMD_UPDATE_GB_IMAGE;
+ update_cmd = &whole_update_cmd->body;
+
+ } else {
+ /* Allocate FIFO space for 'numBoxes' UPDATE_GB_IMAGE commands */
+ const unsigned total_commands_size =
+ sizeof(*update_cmd) + (numBoxes - 1) * sizeof(*whole_update_cmd);
+
+ update_cmd = SVGA3D_FIFOReserve(swc,
+ SVGA_3D_CMD_UPDATE_GB_IMAGE,
+ total_commands_size, numBoxes);
+ if (!update_cmd)
+ return PIPE_ERROR_OUT_OF_MEMORY;
+
+ /* The whole_update_command is a SVGA3dCmdHeader plus the
+ * SVGA3dCmdUpdateGBImage command.
+ */
+ whole_update_cmd = container_of(update_cmd, whole_update_cmd, body);
+ }
+
+ /* Init the first UPDATE_GB_IMAGE command */
+ whole_update_cmd->header.size = sizeof(*update_cmd);
+ swc->surface_relocation(swc, &update_cmd->image.sid, NULL, sbuf->handle,
+ SVGA_RELOC_WRITE | SVGA_RELOC_INTERNAL);
+ update_cmd->image.face = 0;
+ update_cmd->image.mipmap = 0;
+
+ /* Save pointer to the first UPDATE_GB_IMAGE command so that we can
+ * fill in the box info below.
+ */
+ sbuf->dma.updates = whole_update_cmd;
+
+ /*
+ * Copy the face, mipmap, etc. info to all subsequent commands.
+ * Also do the surface relocation for each subsequent command.
+ */
+ for (i = 1; i < numBoxes; ++i) {
+ whole_update_cmd++;
+ memcpy(whole_update_cmd, sbuf->dma.updates, sizeof(*whole_update_cmd));
+
+ swc->surface_relocation(swc, &whole_update_cmd->body.image.sid, NULL,
+ sbuf->handle,
+ SVGA_RELOC_WRITE | SVGA_RELOC_INTERNAL);
+ }
+
+ /* Increment reference count */
+ sbuf->dma.svga = svga;
+ dummy = NULL;
+ pipe_resource_reference(&dummy, &sbuf->b.b);
+ SVGA_FIFOCommitAll(swc);
+
+ swc->hints |= SVGA_HINT_FLAG_CAN_PRE_FLUSH;
+ sbuf->dma.flags.discard = FALSE;
+
+ svga->hud.num_resource_updates++;
+
+ return PIPE_OK;
+}
+
+
+/**
+ * Issue DMA commands to transfer guest memory to the host.
+ * Note that the memory segments (offset, size) will be patched in
+ * later in the svga_buffer_upload_flush() function.
+ */
+static enum pipe_error
+svga_buffer_upload_hb_command(struct svga_context *svga,
+ struct svga_buffer *sbuf)