+ if (!st->hwbuf) {
+ FREE(st);
+ return NULL;
+ }
+
+ if (st->hw_nblocksy < nblocksy) {
+ /* We couldn't allocate a hardware buffer big enough for the transfer,
+ * so allocate regular malloc memory instead */
+ if (0) {
+ debug_printf("%s: failed to allocate %u KB of DMA, "
+ "splitting into %u x %u KB DMA transfers\n",
+ __FUNCTION__,
+ (nblocksy*st->base.stride + 1023)/1024,
+ (nblocksy + st->hw_nblocksy - 1)/st->hw_nblocksy,
+ (st->hw_nblocksy*st->base.stride + 1023)/1024);
+ }
+
+ st->swbuf = MALLOC(nblocksy * st->base.stride * d);
+ if (!st->swbuf) {
+ sws->buffer_destroy(sws, st->hwbuf);
+ FREE(st);
+ return NULL;
+ }
+ }
+
+ if (usage & PIPE_TRANSFER_READ) {
+ SVGA3dSurfaceDMAFlags flags;
+ memset(&flags, 0, sizeof flags);
+ svga_transfer_dma(svga, st, SVGA3D_READ_HOST_VRAM, flags);
+ }
+ } else {
+ struct pipe_transfer *transfer = &st->base;
+ struct svga_winsys_surface *surf = tex->handle;
+
+ if (!surf) {
+ FREE(st);
+ return NULL;
+ }
+
+ if (need_tex_readback(transfer)) {
+ enum pipe_error ret;
+
+ svga_surfaces_flush(svga);
+
+ if (svga_have_vgpu10(svga)) {
+ ret = readback_image_vgpu10(svga, surf, st->slice, transfer->level,
+ tex->b.b.last_level + 1);
+ } else {
+ ret = readback_image_vgpu9(svga, surf, st->slice, transfer->level);
+ }
+
+ assert(ret == PIPE_OK);
+ (void) ret;
+
+ svga_context_flush(svga, NULL);
+
+ /*
+ * Note: if PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE were specified
+ * we could potentially clear the flag for all faces/layers/mips.
+ */
+ svga_clear_texture_rendered_to(tex, st->slice, transfer->level);
+ }
+ else {
+ assert(transfer->usage & PIPE_TRANSFER_WRITE);
+ if ((transfer->usage & PIPE_TRANSFER_UNSYNCHRONIZED) == 0) {
+ svga_surfaces_flush(svga);
+ if (!sws->surface_is_flushed(sws, surf))
+ svga_context_flush(svga, NULL);
+ }
+ }