- st->base.slice_stride = 0;
-
- st->hw_nblocksy = nblocksy;
-
- st->hwbuf = svga_winsys_buffer_create(svga,
- 1,
- 0,
- st->hw_nblocksy*st->base.stride);
- while(!st->hwbuf && (st->hw_nblocksy /= 2)) {
- st->hwbuf = svga_winsys_buffer_create(svga,
- 1,
- 0,
- st->hw_nblocksy*st->base.stride);
- }
-
- if(!st->hwbuf)
- goto no_hwbuf;
-
- if(st->hw_nblocksy < nblocksy) {
- /* We couldn't allocate a hardware buffer big enough for the transfer,
- * so allocate regular malloc memory instead */
- 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);
- if(!st->swbuf)
- goto no_swbuf;
- }
-
- if (usage & PIPE_TRANSFER_READ)
- svga_transfer_dma(svga, st, SVGA3D_READ_HOST_VRAM);
-
- return &st->base;
-
-no_swbuf:
- sws->buffer_destroy(sws, st->hwbuf);
-no_hwbuf:
- FREE(st);
- return NULL;
+ st->base.layer_stride = st->base.stride * nblocksy;
+
+ switch (tex->b.b.target) {
+ case PIPE_TEXTURE_CUBE:
+ case PIPE_TEXTURE_2D_ARRAY:
+ case PIPE_TEXTURE_1D_ARRAY:
+ st->slice = st->base.box.z;
+ st->base.box.z = 0; /* so we don't apply double offsets below */
+ break;
+ default:
+ st->slice = 0;
+ break;
+ }
+
+ if (usage & PIPE_TRANSFER_WRITE) {
+ /* record texture upload for HUD */
+ svga->hud.num_bytes_uploaded +=
+ nblocksx * nblocksy * d * util_format_get_blocksize(texture->format);
+ }
+
+ if (!use_direct_map) {
+ /* Use a DMA buffer */
+ st->hw_nblocksy = nblocksy;
+
+ st->hwbuf = svga_winsys_buffer_create(svga, 1, 0,
+ st->hw_nblocksy * st->base.stride * d);
+ while(!st->hwbuf && (st->hw_nblocksy /= 2)) {
+ st->hwbuf = svga_winsys_buffer_create(svga, 1, 0,
+ st->hw_nblocksy * st->base.stride * d);
+ }
+
+ 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);
+ }
+ }
+ }
+
+ st->use_direct_map = use_direct_map;
+
+ *ptransfer = &st->base;
+
+ /*
+ * Begin mapping code
+ */
+ if (st->swbuf) {
+ returnVal = st->swbuf;
+ }
+ else if (!st->use_direct_map) {
+ returnVal = sws->buffer_map(sws, st->hwbuf, usage);
+ }
+ else {
+ SVGA3dSize baseLevelSize;
+ struct svga_texture *tex = svga_texture(texture);
+ struct svga_winsys_surface *surf = tex->handle;
+ uint8_t *map;
+ boolean retry;
+ unsigned offset, mip_width, mip_height;
+ unsigned xoffset = st->base.box.x;
+ unsigned yoffset = st->base.box.y;
+ unsigned zoffset = st->base.box.z;
+
+ map = svga->swc->surface_map(svga->swc, surf, usage, &retry);
+ if (map == NULL && retry) {
+ /*
+ * At this point, the svga_surfaces_flush() should already have
+ * called in svga_texture_get_transfer().
+ */
+ svga_context_flush(svga, NULL);
+ map = svga->swc->surface_map(svga->swc, surf, usage, &retry);
+ }
+
+ /*
+ * Make sure we return NULL if the map fails
+ */
+ if (!map) {
+ FREE(st);
+ return map;
+ }
+
+ /**
+ * Compute the offset to the specific texture slice in the buffer.
+ */
+ baseLevelSize.width = tex->b.b.width0;
+ baseLevelSize.height = tex->b.b.height0;
+ baseLevelSize.depth = tex->b.b.depth0;
+
+ offset = svga3dsurface_get_image_offset(tex->key.format, baseLevelSize,
+ tex->b.b.last_level + 1, /* numMips */
+ st->slice, level);
+ if (level > 0) {
+ assert(offset > 0);
+ }
+
+ mip_width = u_minify(tex->b.b.width0, level);
+ mip_height = u_minify(tex->b.b.height0, level);
+
+ offset += svga3dsurface_get_pixel_offset(tex->key.format,
+ mip_width, mip_height,
+ xoffset, yoffset, zoffset);
+ returnVal = (void *) (map + offset);
+ }
+
+ svga->hud.map_buffer_time += (os_time_get() - begin);
+ svga->hud.num_resources_mapped++;
+
+ return returnVal;