+ struct svga_context *svga = svga_context(pipe);
+ struct svga_screen *ss = svga_screen(pipe->screen);
+ struct svga_buffer *sbuf = svga_buffer(resource);
+ struct pipe_transfer *transfer;
+ uint8_t *map = NULL;
+ int64_t begin = svga_get_time(svga);
+
+ SVGA_STATS_TIME_PUSH(svga_sws(svga), SVGA_STATS_TIME_BUFFERTRANSFERMAP);
+
+ assert(box->y == 0);
+ assert(box->z == 0);
+ assert(box->height == 1);
+ assert(box->depth == 1);
+
+ transfer = MALLOC_STRUCT(pipe_transfer);
+ if (!transfer) {
+ goto done;
+ }
+
+ transfer->resource = resource;
+ transfer->level = level;
+ transfer->usage = usage;
+ transfer->box = *box;
+ transfer->stride = 0;
+ transfer->layer_stride = 0;
+
+ if (usage & PIPE_TRANSFER_WRITE) {
+ /* If we write to the buffer for any reason, free any saved translated
+ * vertices.
+ */
+ pipe_resource_reference(&sbuf->translated_indices.buffer, NULL);
+ }
+
+ if ((usage & PIPE_TRANSFER_READ) && sbuf->dirty) {
+ enum pipe_error ret;
+
+ /* Host-side buffers can only be dirtied with vgpu10 features
+ * (streamout and buffer copy).
+ */
+ assert(svga_have_vgpu10(svga));
+
+ if (!sbuf->user) {
+ (void) svga_buffer_handle(svga, resource);
+ }
+
+ if (sbuf->dma.pending > 0) {
+ svga_buffer_upload_flush(svga, sbuf);
+ svga_context_finish(svga);
+ }
+
+ assert(sbuf->handle);
+
+ ret = SVGA3D_vgpu10_ReadbackSubResource(svga->swc, sbuf->handle, 0);
+ if (ret != PIPE_OK) {
+ svga_context_flush(svga, NULL);
+ ret = SVGA3D_vgpu10_ReadbackSubResource(svga->swc, sbuf->handle, 0);
+ assert(ret == PIPE_OK);
+ }
+
+ svga->hud.num_readbacks++;
+
+ svga_context_finish(svga);
+
+ sbuf->dirty = FALSE;
+ }
+
+ if (usage & PIPE_TRANSFER_WRITE) {
+ if (usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE) {
+ /*
+ * Flush any pending primitives, finish writing any pending DMA
+ * commands, and tell the host to discard the buffer contents on
+ * the next DMA operation.
+ */
+
+ svga_hwtnl_flush_buffer(svga, resource);
+
+ if (sbuf->dma.pending) {
+ svga_buffer_upload_flush(svga, sbuf);
+
+ /*
+ * Instead of flushing the context command buffer, simply discard
+ * the current hwbuf, and start a new one.
+ * With GB objects, the map operation takes care of this
+ * if passed the PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE flag,
+ * and the old backing store is busy.
+ */
+
+ if (!svga_have_gb_objects(svga))
+ svga_buffer_destroy_hw_storage(ss, sbuf);
+ }