static void svga_transfer_dma(struct svga_context *svga, struct svga_transfer *st, SVGA3dTransferType transfer, SVGA3dSurfaceDMAFlags flags) { struct svga_texture *texture = svga_texture(st->base.resource); struct svga_screen *screen = svga_screen(texture->b.b.screen); struct svga_winsys_screen *sws = screen->sws; struct pipe_fence_handle *fence = NULL; assert(!st->use_direct_map); if (transfer == SVGA3D_READ_HOST_VRAM) { SVGA_DBG(DEBUG_PERF, "%s: readback transfer\n", __FUNCTION__); } /* Ensure any pending operations on host surfaces are queued on the command * buffer first. */ svga_surfaces_flush( svga ); if (!st->swbuf) { /* Do the DMA transfer in a single go */ svga_transfer_dma_band(svga, st, transfer, st->base.box.y, st->base.box.height, 0, flags); if (transfer == SVGA3D_READ_HOST_VRAM) { svga_context_flush(svga, &fence); sws->fence_finish(sws, fence, 0); sws->fence_reference(sws, &fence, NULL); } } else { int y, h, srcy; unsigned blockheight = util_format_get_blockheight(st->base.resource->format); h = st->hw_nblocksy * blockheight; srcy = 0; for (y = 0; y < st->base.box.height; y += h) { unsigned offset, length; void *hw, *sw; if (y + h > st->base.box.height) h = st->base.box.height - y; /* Transfer band must be aligned to pixel block boundaries */ assert(y % blockheight == 0); assert(h % blockheight == 0); offset = y * st->base.stride / blockheight; length = h * st->base.stride / blockheight; sw = (uint8_t *) st->swbuf + offset; if (transfer == SVGA3D_WRITE_HOST_VRAM) { unsigned usage = PIPE_TRANSFER_WRITE; /* Wait for the previous DMAs to complete */ /* TODO: keep one DMA (at half the size) in the background */ if (y) { svga_context_flush(svga, NULL); usage |= PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE; } hw = sws->buffer_map(sws, st->hwbuf, usage); assert(hw); if (hw) { memcpy(hw, sw, length); sws->buffer_unmap(sws, st->hwbuf); } } svga_transfer_dma_band(svga, st, transfer, y, h, srcy, flags); /* * Prevent the texture contents to be discarded on the next band * upload. */ flags.discard = FALSE; if (transfer == SVGA3D_READ_HOST_VRAM) { svga_context_flush(svga, &fence); sws->fence_finish(sws, fence, 0); hw = sws->buffer_map(sws, st->hwbuf, PIPE_TRANSFER_READ); assert(hw); if (hw) { memcpy(sw, hw, length); sws->buffer_unmap(sws, st->hwbuf); } } } } }
static INLINE void svga_transfer_dma(struct svga_context *svga, struct svga_transfer *st, SVGA3dTransferType transfer) { struct svga_texture *texture = svga_texture(st->base.resource); struct svga_screen *screen = svga_screen(texture->b.b.screen); struct svga_winsys_screen *sws = screen->sws; struct pipe_fence_handle *fence = NULL; if (transfer == SVGA3D_READ_HOST_VRAM) { SVGA_DBG(DEBUG_PERF, "%s: readback transfer\n", __FUNCTION__); } if(!st->swbuf) { /* Do the DMA transfer in a single go */ svga_transfer_dma_band(svga, st, transfer, st->base.box.y, st->base.box.height, 0); if(transfer == SVGA3D_READ_HOST_VRAM) { svga_context_flush(svga, &fence); sws->fence_finish(sws, fence, 0); sws->fence_reference(sws, &fence, NULL); } } else { unsigned y, h, srcy; unsigned blockheight = util_format_get_blockheight(st->base.resource->format); h = st->hw_nblocksy * blockheight; srcy = 0; for(y = 0; y < st->base.box.height; y += h) { unsigned offset, length; void *hw, *sw; if (y + h > st->base.box.height) h = st->base.box.height - y; /* Transfer band must be aligned to pixel block boundaries */ assert(y % blockheight == 0); assert(h % blockheight == 0); offset = y * st->base.stride / blockheight; length = h * st->base.stride / blockheight; sw = (uint8_t *)st->swbuf + offset; if(transfer == SVGA3D_WRITE_HOST_VRAM) { /* Wait for the previous DMAs to complete */ /* TODO: keep one DMA (at half the size) in the background */ if(y) { svga_context_flush(svga, &fence); sws->fence_finish(sws, fence, 0); sws->fence_reference(sws, &fence, NULL); } hw = sws->buffer_map(sws, st->hwbuf, PIPE_TRANSFER_WRITE); assert(hw); if(hw) { memcpy(hw, sw, length); sws->buffer_unmap(sws, st->hwbuf); } } svga_transfer_dma_band(svga, st, transfer, y, h, srcy); if(transfer == SVGA3D_READ_HOST_VRAM) { svga_context_flush(svga, &fence); sws->fence_finish(sws, fence, 0); hw = sws->buffer_map(sws, st->hwbuf, PIPE_TRANSFER_READ); assert(hw); if(hw) { memcpy(sw, hw, length); sws->buffer_unmap(sws, st->hwbuf); } } } } }