/** * Copy an image between textures with the vgpu10 CopyRegion command. */ static void copy_region_vgpu10(struct svga_context *svga, struct pipe_resource *src_tex, unsigned src_x, unsigned src_y, unsigned src_z, unsigned src_level, unsigned src_layer_face, struct pipe_resource *dst_tex, unsigned dst_x, unsigned dst_y, unsigned dst_z, unsigned dst_level, unsigned dst_layer_face, unsigned width, unsigned height, unsigned depth) { uint32 srcSubResource, dstSubResource; struct svga_texture *dtex, *stex; stex = svga_texture(src_tex); dtex = svga_texture(dst_tex); svga_surfaces_flush(svga); srcSubResource = src_layer_face * (src_tex->last_level + 1) + src_level; dstSubResource = dst_layer_face * (dst_tex->last_level + 1) + dst_level; svga_texture_copy_region(svga, stex->handle, srcSubResource, src_x, src_y, src_z, dtex->handle, dstSubResource, dst_x, dst_y, dst_z, width, height, depth); /* Mark the texture subresource as defined. */ svga_define_texture_level(dtex, dst_layer_face, dst_level); /* Mark the texture subresource as rendered-to. */ svga_set_texture_rendered_to(dtex, dst_layer_face, dst_level); }
/** * Check whether we can blit using the intra_surface_copy command. */ static bool can_blit_via_intra_surface_copy(struct svga_context *svga, const struct pipe_blit_info *blit_info) { struct svga_winsys_screen *sws = svga_screen(svga->pipe.screen)->sws; struct svga_texture *dtex, *stex; if (!svga_have_vgpu10(svga)) return false; /* src surface cannot be multisample */ if (blit_info->src.resource->nr_samples > 1) return false; if (!sws->have_intra_surface_copy) return false; if (svga->render_condition && blit_info->render_condition_enable) return false; if (blit_info->src.level != blit_info->dst.level) return false; if (has_layer_face_index_in_z(blit_info->src.resource->target)){ if (blit_info->src.box.z != blit_info->dst.box.z) return false; } stex = svga_texture(blit_info->src.resource); dtex = svga_texture(blit_info->dst.resource); return (stex->handle == dtex->handle); }
static boolean svga_texture_get_handle(struct pipe_screen *screen, struct pipe_resource *texture, struct winsys_handle *whandle) { struct svga_winsys_screen *sws = svga_winsys_screen(texture->screen); unsigned stride; assert(svga_texture(texture)->key.cachable == 0); svga_texture(texture)->key.cachable = 0; stride = util_format_get_nblocksx(texture->format, texture->width0) * util_format_get_blocksize(texture->format); return sws->surface_get_handle(sws, svga_texture(texture)->handle, stride, whandle); }
static INLINE void svga_mark_surface_dirty(struct pipe_surface *surf) { struct svga_surface *s = svga_surface(surf); if (!s->dirty) { struct svga_texture *tex = svga_texture(surf->texture); s->dirty = TRUE; if (s->handle == tex->handle) { /* hmm so 3d textures always have all their slices marked ? */ if (surf->texture->target == PIPE_TEXTURE_CUBE) svga_define_texture_level(tex, surf->u.tex.first_layer, surf->u.tex.level); else svga_define_texture_level(tex, 0, surf->u.tex.level); } else { /* this will happen later in svga_propagate_surface */ } /* Increment the view_age and texture age for this surface's mipmap * level so that any sampler views into the texture are re-validated too. */ svga_age_texture_view(tex, surf->u.tex.level); } }
static void svga_texture_destroy(struct pipe_screen *screen, struct pipe_resource *pt) { struct svga_screen *ss = svga_screen(screen); struct svga_texture *tex = svga_texture(pt); ss->texture_timestamp++; svga_sampler_view_reference(&tex->cached_view, NULL); /* DBG("%s deleting %p\n", __FUNCTION__, (void *) tex); */ SVGA_DBG(DEBUG_DMA, "unref sid %p (texture)\n", tex->handle); svga_screen_surface_destroy(ss, &tex->key, &tex->handle); ss->hud.total_resource_bytes -= tex->size; FREE(tex->defined); FREE(tex->rendered_to); FREE(tex); assert(ss->hud.num_resources > 0); if (ss->hud.num_resources > 0) ss->hud.num_resources--; }
static void svga_texture_transfer_destroy(struct pipe_context *pipe, struct pipe_transfer *transfer) { struct svga_context *svga = svga_context(pipe); struct svga_texture *tex = svga_texture(transfer->resource); struct svga_screen *ss = svga_screen(pipe->screen); struct svga_winsys_screen *sws = ss->sws; struct svga_transfer *st = svga_transfer(transfer); if (st->base.usage & PIPE_TRANSFER_WRITE) { SVGA3dSurfaceDMAFlags flags; memset(&flags, 0, sizeof flags); if (transfer->usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE) { flags.discard = TRUE; } if (transfer->usage & PIPE_TRANSFER_UNSYNCHRONIZED) { flags.unsynchronized = TRUE; } svga_transfer_dma(svga, st, SVGA3D_WRITE_HOST_VRAM, flags); ss->texture_timestamp++; tex->view_age[transfer->level] = ++(tex->age); if (transfer->resource->target == PIPE_TEXTURE_CUBE) tex->defined[transfer->box.z][transfer->level] = TRUE; else tex->defined[0][transfer->level] = TRUE; } pipe_resource_reference(&st->base.resource, NULL); FREE(st->swbuf); sws->buffer_destroy(sws, st->hwbuf); FREE(st); }
/** * Determine if we need to read back a texture image before mapping it. */ static boolean need_tex_readback(struct pipe_transfer *transfer) { struct svga_texture *t = svga_texture(transfer->resource); if (transfer->usage & PIPE_TRANSFER_READ) return TRUE; if ((transfer->usage & PIPE_TRANSFER_WRITE) && ((transfer->usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE) == 0)) { unsigned face; if (transfer->resource->target == PIPE_TEXTURE_CUBE) { assert(transfer->box.depth == 1); face = transfer->box.z; } else { face = 0; } if (svga_was_texture_rendered_to(t, face, transfer->level)) { return TRUE; } } return FALSE; }
/** * Check if we should call svga_propagate_surface on the surface. */ boolean svga_surface_needs_propagation(struct pipe_surface *surf) { struct svga_surface *s = svga_surface(surf); struct svga_texture *tex = svga_texture(surf->texture); return s->dirty && s->handle != tex->handle; }
/** * unmap direct map transfer request */ static void svga_texture_transfer_unmap_direct(struct svga_context *svga, struct svga_transfer *st) { struct pipe_transfer *transfer = &st->base; struct svga_texture *tex = svga_texture(transfer->resource); svga_texture_surface_unmap(svga, transfer); /* Now send an update command to update the content in the backend. */ if (st->base.usage & PIPE_TRANSFER_WRITE) { struct svga_winsys_surface *surf = tex->handle; enum pipe_error ret; assert(svga_have_gb_objects(svga)); /* update the effected region */ SVGA3dBox box = st->box; unsigned nlayers; switch (tex->b.b.target) { case PIPE_TEXTURE_2D_ARRAY: case PIPE_TEXTURE_CUBE_ARRAY: case PIPE_TEXTURE_1D_ARRAY: nlayers = box.d; box.d = 1; break; default: nlayers = 1; break; } if (0) debug_printf("%s %d, %d, %d %d x %d x %d\n", __FUNCTION__, box.x, box.y, box.z, box.w, box.h, box.d); if (svga_have_vgpu10(svga)) { unsigned i; for (i = 0; i < nlayers; i++) { ret = update_image_vgpu10(svga, surf, &box, st->slice + i, transfer->level, tex->b.b.last_level + 1); assert(ret == PIPE_OK); } } else { assert(nlayers == 1); ret = update_image_vgpu9(svga, surf, &box, st->slice, transfer->level); assert(ret == PIPE_OK); } (void) ret; } }
/** Get resource handle for a texture or buffer */ static inline struct svga_winsys_surface * svga_resource_handle(struct pipe_resource *res) { if (res->target == PIPE_BUFFER) { return svga_buffer(res)->handle; } else { return svga_texture(res)->handle; } }
enum pipe_error SVGA3D_SurfaceDMA(struct svga_winsys_context *swc, struct svga_transfer *st, // IN SVGA3dTransferType transfer, // IN const SVGA3dCopyBox *boxes, // IN uint32 numBoxes, // IN SVGA3dSurfaceDMAFlags flags) // IN { struct svga_texture *texture = svga_texture(st->base.resource); SVGA3dCmdSurfaceDMA *cmd; SVGA3dCmdSurfaceDMASuffix *pSuffix; uint32 boxesSize = sizeof *boxes * numBoxes; unsigned region_flags; unsigned surface_flags; if(transfer == SVGA3D_WRITE_HOST_VRAM) { region_flags = SVGA_RELOC_READ; surface_flags = SVGA_RELOC_WRITE; } else if(transfer == SVGA3D_READ_HOST_VRAM) { region_flags = SVGA_RELOC_WRITE; surface_flags = SVGA_RELOC_READ; } else { assert(0); return PIPE_ERROR_BAD_INPUT; } cmd = SVGA3D_FIFOReserve(swc, SVGA_3D_CMD_SURFACE_DMA, sizeof *cmd + boxesSize + sizeof *pSuffix, 2); if(!cmd) return PIPE_ERROR_OUT_OF_MEMORY; swc->region_relocation(swc, &cmd->guest.ptr, st->hwbuf, 0, region_flags); cmd->guest.pitch = st->base.stride; swc->surface_relocation(swc, &cmd->host.sid, texture->handle, surface_flags); cmd->host.face = st->face; /* PIPE_TEX_FACE_* and SVGA3D_CUBEFACE_* match */ cmd->host.mipmap = st->base.level; cmd->transfer = transfer; memcpy(&cmd[1], boxes, boxesSize); pSuffix = (SVGA3dCmdSurfaceDMASuffix *)((uint8_t*)cmd + sizeof *cmd + boxesSize); pSuffix->suffixSize = sizeof *pSuffix; pSuffix->maximumOffset = st->hw_nblocksy*st->base.stride; pSuffix->flags = flags; swc->commit(swc); return PIPE_OK; }
/** * Check whether we can blit using the surface_copy command. */ static bool can_blit_via_surface_copy(struct svga_context *svga, const struct pipe_blit_info *blit_info) { struct svga_texture *dtex, *stex; /* Mimic the format tests in util_can_blit_via_copy_region(), but * skip the other tests that have already been performed. */ if (blit_info->src.format != blit_info->dst.format) { const struct util_format_description *src_desc, *dst_desc; src_desc = util_format_description(blit_info->src.resource->format); dst_desc = util_format_description(blit_info->dst.resource->format); if (blit_info->src.resource->format != blit_info->src.format || blit_info->dst.resource->format != blit_info->dst.format || !util_is_format_compatible(src_desc, dst_desc)) return false; } if (svga->render_condition && blit_info->render_condition_enable) return false; /* can't copy between different resource types */ if (svga_resource_type(blit_info->src.resource->target) != svga_resource_type(blit_info->dst.resource->target)) return false; stex = svga_texture(blit_info->src.resource); dtex = svga_texture(blit_info->dst.resource); if (stex->handle == dtex->handle) return false; /* * This is what we've been using before, but it can probably be * relaxed. The device checks are less stringent. */ return (stex->b.b.format == dtex->b.b.format); }
/** * Determine if we need to read back a texture image before mapping it. */ static inline boolean need_tex_readback(struct svga_transfer *st) { if (st->base.usage & PIPE_TRANSFER_READ) return TRUE; if ((st->base.usage & PIPE_TRANSFER_WRITE) && ((st->base.usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE) == 0)) { return svga_was_texture_rendered_to(svga_texture(st->base.resource), st->slice, st->base.level); } return FALSE; }
/** * The state tracker implements some resource copies with blits (for * GL_ARB_copy_image). This function checks if we should really do the blit * with a VGPU10 CopyRegion command or software fallback (for incompatible * src/dst formats). */ static bool can_blit_via_copy_region_vgpu10(struct svga_context *svga, const struct pipe_blit_info *blit_info) { struct svga_texture *dtex, *stex; /* can't copy between different resource types */ if (svga_resource_type(blit_info->src.resource->target) != svga_resource_type(blit_info->dst.resource->target)) return false; stex = svga_texture(blit_info->src.resource); dtex = svga_texture(blit_info->dst.resource); if (!svga_have_vgpu10(svga)) return false; if (stex->handle == dtex->handle) return false; return formats_compatible(svga_screen(svga->pipe.screen), stex->key.format, dtex->key.format); }
static void svga_tex_surface_destroy(struct pipe_surface *surf) { struct svga_surface *s = svga_surface(surf); struct svga_texture *t = svga_texture(surf->texture); struct svga_screen *ss = svga_screen(surf->texture->screen); if(s->handle != t->handle) { SVGA_DBG(DEBUG_DMA, "unref sid %p (tex surface)\n", s->handle); svga_screen_surface_destroy(ss, &s->key, &s->handle); } pipe_resource_reference(&surf->texture, NULL); FREE(surf); }
static INLINE void svga_transfer_dma_band(struct svga_context *svga, struct svga_transfer *st, SVGA3dTransferType transfer, unsigned y, unsigned h, unsigned srcy, SVGA3dSurfaceDMAFlags flags) { struct svga_texture *texture = svga_texture(st->base.resource); SVGA3dCopyBox box; enum pipe_error ret; box.x = st->base.box.x; box.y = y; box.z = st->base.box.z; box.w = st->base.box.width; box.h = h; box.d = 1; box.srcx = 0; box.srcy = srcy; box.srcz = 0; if (st->base.resource->target == PIPE_TEXTURE_CUBE) { st->face = st->base.box.z; box.z = 0; } else st->face = 0; SVGA_DBG(DEBUG_DMA, "dma %s sid %p, face %u, (%u, %u, %u) - (%u, %u, %u), %ubpp\n", transfer == SVGA3D_WRITE_HOST_VRAM ? "to" : "from", texture->handle, st->face, st->base.box.x, y, box.z, st->base.box.x + st->base.box.width, y + h, box.z + 1, util_format_get_blocksize(texture->b.b.format) * 8 / (util_format_get_blockwidth(texture->b.b.format)*util_format_get_blockheight(texture->b.b.format))); ret = SVGA3D_SurfaceDMA(svga->swc, st, transfer, &box, 1, flags); if(ret != PIPE_OK) { svga_context_flush(svga, NULL); ret = SVGA3D_SurfaceDMA(svga->swc, st, transfer, &box, 1, flags); assert(ret == PIPE_OK); } }
static void svga_transfer_dma_band(struct svga_context *svga, struct svga_transfer *st, SVGA3dTransferType transfer, unsigned x, unsigned y, unsigned z, unsigned w, unsigned h, unsigned d, unsigned srcx, unsigned srcy, unsigned srcz, SVGA3dSurfaceDMAFlags flags) { struct svga_texture *texture = svga_texture(st->base.resource); SVGA3dCopyBox box; enum pipe_error ret; assert(!st->use_direct_map); box.x = x; box.y = y; box.z = z; box.w = w; box.h = h; box.d = d; box.srcx = srcx; box.srcy = srcy; box.srcz = srcz; SVGA_DBG(DEBUG_DMA, "dma %s sid %p, face %u, (%u, %u, %u) - " "(%u, %u, %u), %ubpp\n", transfer == SVGA3D_WRITE_HOST_VRAM ? "to" : "from", texture->handle, st->slice, x, y, z, x + w, y + h, z + 1, util_format_get_blocksize(texture->b.b.format) * 8 / (util_format_get_blockwidth(texture->b.b.format) * util_format_get_blockheight(texture->b.b.format))); ret = SVGA3D_SurfaceDMA(svga->swc, st, transfer, &box, 1, flags); if (ret != PIPE_OK) { svga_context_flush(svga, NULL); ret = SVGA3D_SurfaceDMA(svga->swc, st, transfer, &box, 1, flags); assert(ret == PIPE_OK); } }
static INLINE void svga_mark_surface_dirty(struct pipe_surface *surf) { struct svga_surface *s = svga_surface(surf); if(!s->dirty) { struct svga_texture *tex = svga_texture(surf->texture); s->dirty = TRUE; if (s->handle == tex->handle) tex->defined[surf->face][surf->level] = TRUE; else { /* this will happen later in svga_propagate_surface */ } } }
void svga_destroy_sampler_view_priv(struct svga_sampler_view *v) { struct svga_texture *tex = svga_texture(v->texture); if (v->handle != tex->handle) { struct svga_screen *ss = svga_screen(v->texture->screen); SVGA_DBG(DEBUG_DMA, "unref sid %p (sampler view)\n", v->handle); svga_screen_surface_destroy(ss, &v->key, &v->handle); } /* Note: we're not refcounting the texture resource here to avoid * a circular dependency. */ v->texture = NULL; FREE(v); }
/** * Copy when src texture and dst texture are same with IntraSurfaceCopy * command. */ static void intra_surface_copy(struct svga_context *svga, struct pipe_resource *tex, unsigned src_x, unsigned src_y, unsigned src_z, unsigned level, unsigned layer_face, unsigned dst_x, unsigned dst_y, unsigned dst_z, unsigned width, unsigned height, unsigned depth) { enum pipe_error ret; SVGA3dCopyBox box; struct svga_texture *stex; /* * Makes sure we have flushed all buffered draw operations and also * synchronizes all surfaces with any emulated surface views. */ svga_surfaces_flush(svga); stex = svga_texture(tex); box.x = dst_x; box.y = dst_y; box.z = dst_z; box.w = width; box.h = height; box.d = depth; box.srcx = src_x; box.srcy = src_y; box.srcz = src_z; ret = SVGA3D_vgpu10_IntraSurfaceCopy(svga->swc, stex->handle, level, layer_face, &box); if (ret != PIPE_OK) { svga_context_flush(svga, NULL); ret = SVGA3D_vgpu10_IntraSurfaceCopy(svga->swc, stex->handle, level, layer_face, &box); assert(ret == PIPE_OK); } /* Mark the texture subresource as rendered-to. */ svga_set_texture_rendered_to(stex, layer_face, level); }
static void svga_texture_transfer_unmap(struct pipe_context *pipe, struct pipe_transfer *transfer) { struct svga_context *svga = svga_context(pipe); struct svga_screen *ss = svga_screen(pipe->screen); struct svga_winsys_screen *sws = ss->sws; struct svga_transfer *st = svga_transfer(transfer); struct svga_texture *tex = svga_texture(transfer->resource); SVGA_STATS_TIME_PUSH(sws, SVGA_STATS_TIME_TEXTRANSFERUNMAP); if (!st->use_direct_map) { svga_texture_transfer_unmap_dma(svga, st); } else if (st->upload.buf) { svga_texture_transfer_unmap_upload(svga, st); } else { svga_texture_transfer_unmap_direct(svga, st); } if (st->base.usage & PIPE_TRANSFER_WRITE) { svga->hud.num_resource_updates++; /* Mark the texture level as dirty */ ss->texture_timestamp++; svga_age_texture_view(tex, transfer->level); if (transfer->resource->target == PIPE_TEXTURE_CUBE) svga_define_texture_level(tex, st->slice, transfer->level); else svga_define_texture_level(tex, 0, transfer->level); } pipe_resource_reference(&st->base.resource, NULL); FREE(st); SVGA_STATS_TIME_POP(sws); (void) sws; }
static unsigned int svga_texture_is_referenced( struct pipe_context *pipe, struct pipe_resource *texture, unsigned face, unsigned level) { struct svga_texture *tex = svga_texture(texture); struct svga_screen *ss = svga_screen(pipe->screen); /** * The screen does not cache texture writes. */ if (!tex->handle || ss->sws->surface_is_flushed(ss->sws, tex->handle)) return PIPE_UNREFERENCED; /** * sws->surface_is_flushed() does not distinguish between read references * and write references. So assume a reference is both. */ return PIPE_REFERENCED_FOR_READ | PIPE_REFERENCED_FOR_WRITE; }
static void svga_texture_transfer_destroy(struct pipe_context *pipe, struct pipe_transfer *transfer) { struct svga_context *svga = svga_context(pipe); struct svga_texture *tex = svga_texture(transfer->resource); struct svga_screen *ss = svga_screen(pipe->screen); struct svga_winsys_screen *sws = ss->sws; struct svga_transfer *st = svga_transfer(transfer); if (st->base.usage & PIPE_TRANSFER_WRITE) { svga_transfer_dma(svga, st, SVGA3D_WRITE_HOST_VRAM); ss->texture_timestamp++; tex->view_age[transfer->sr.level] = ++(tex->age); tex->defined[transfer->sr.face][transfer->sr.level] = TRUE; } pipe_resource_reference(&st->base.resource, NULL); FREE(st->swbuf); sws->buffer_destroy(sws, st->hwbuf); FREE(st); }
/** * Unmap a GB texture surface. */ static void svga_texture_surface_unmap(struct svga_context *svga, struct pipe_transfer *transfer) { struct svga_winsys_surface *surf = svga_texture(transfer->resource)->handle; struct svga_winsys_context *swc = svga->swc; boolean rebind; assert(surf); swc->surface_unmap(swc, surf, &rebind); if (rebind) { enum pipe_error ret; ret = SVGA3D_BindGBSurface(swc, surf); if (ret != PIPE_OK) { /* flush and retry */ svga_context_flush(svga, NULL); ret = SVGA3D_BindGBSurface(swc, surf); assert(ret == PIPE_OK); } } }
void svga_validate_sampler_view(struct svga_context *svga, struct svga_sampler_view *v) { struct svga_texture *tex = svga_texture(v->texture); unsigned numFaces; unsigned age = 0; int i; unsigned k; assert(svga); assert(!svga_have_vgpu10(svga)); if (v->handle == tex->handle) return; age = tex->age; if (tex->b.b.target == PIPE_TEXTURE_CUBE) numFaces = 6; else numFaces = 1; for (i = v->min_lod; i <= v->max_lod; i++) { for (k = 0; k < numFaces; k++) { assert(i < ARRAY_SIZE(tex->view_age)); if (v->age < tex->view_age[i]) svga_texture_copy_handle(svga, tex->handle, 0, 0, 0, i, k, v->handle, 0, 0, 0, i - v->min_lod, k, u_minify(tex->b.b.width0, i), u_minify(tex->b.b.height0, i), u_minify(tex->b.b.depth0, i)); } } v->age = age; }
/** * Clone the surface view and its associated resource. */ static struct svga_surface * create_backed_surface_view(struct svga_context *svga, struct svga_surface *s) { struct svga_surface *bs = s->backed; if (!bs) { struct svga_texture *tex = svga_texture(s->base.texture); struct pipe_surface *backed_view; backed_view = svga_create_surface_view(&svga->pipe, &tex->b.b, &s->base, TRUE); if (!backed_view) return NULL; bs = svga_surface(backed_view); s->backed = bs; } svga_mark_surface_dirty(&bs->base); return bs; }
/** * Progagate any changes from surfaces to texture. * pipe is optional context to inline the blit command in. */ void svga_propagate_surface(struct svga_context *svga, struct pipe_surface *surf) { struct svga_surface *s = svga_surface(surf); struct svga_texture *tex = svga_texture(surf->texture); struct svga_screen *ss = svga_screen(surf->texture->screen); unsigned zslice, face; if (!s->dirty) return; if (surf->texture->target == PIPE_TEXTURE_CUBE) { zslice = 0; face = surf->u.tex.first_layer; } else { zslice = surf->u.tex.first_layer; face = 0; } s->dirty = FALSE; ss->texture_timestamp++; svga_age_texture_view(tex, surf->u.tex.level); if (s->handle != tex->handle) { SVGA_DBG(DEBUG_VIEWS, "svga: Surface propagate: tex %p, level %u, from %p\n", tex, surf->u.tex.level, surf); svga_texture_copy_handle(svga, s->handle, 0, 0, 0, s->real_level, s->real_face, tex->handle, 0, 0, zslice, surf->u.tex.level, face, u_minify(tex->b.b.width0, surf->u.tex.level), u_minify(tex->b.b.height0, surf->u.tex.level), 1); svga_define_texture_level(tex, face, surf->u.tex.level); } }
/** * Progagate any changes from surfaces to texture. * pipe is optional context to inline the blit command in. */ void svga_propagate_surface(struct pipe_context *pipe, struct pipe_surface *surf) { struct svga_surface *s = svga_surface(surf); struct svga_texture *tex = svga_texture(surf->texture); struct svga_screen *ss = svga_screen(surf->texture->screen); if (!s->dirty) return; s->dirty = FALSE; ss->texture_timestamp++; tex->view_age[surf->level] = ++(tex->age); if (s->handle != tex->handle) { SVGA_DBG(DEBUG_VIEWS, "svga: Surface propagate: tex %p, level %u, from %p\n", tex, surf->level, surf); svga_texture_copy_handle(svga_context(pipe), s->handle, 0, 0, 0, s->real_level, s->real_face, tex->handle, 0, 0, surf->zslice, surf->level, surf->face, u_minify(tex->b.b.width0, surf->level), u_minify(tex->b.b.height0, surf->level), 1); tex->defined[surf->face][surf->level] = TRUE; } }
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 void svga_texture_transfer_unmap(struct pipe_context *pipe, struct pipe_transfer *transfer) { struct svga_context *svga = svga_context(pipe); struct svga_screen *ss = svga_screen(pipe->screen); struct svga_winsys_screen *sws = ss->sws; struct svga_transfer *st = svga_transfer(transfer); struct svga_texture *tex = svga_texture(transfer->resource); if (!st->swbuf) { if (st->use_direct_map) { svga_texture_surface_unmap(svga, transfer); } else { sws->buffer_unmap(sws, st->hwbuf); } } if (!st->use_direct_map && (st->base.usage & PIPE_TRANSFER_WRITE)) { /* Use DMA to transfer texture data */ SVGA3dSurfaceDMAFlags flags; memset(&flags, 0, sizeof flags); if (transfer->usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE) { flags.discard = TRUE; } if (transfer->usage & PIPE_TRANSFER_UNSYNCHRONIZED) { flags.unsynchronized = TRUE; } svga_transfer_dma(svga, st, SVGA3D_WRITE_HOST_VRAM, flags); } else if (transfer->usage & PIPE_TRANSFER_WRITE) { struct svga_winsys_surface *surf = svga_texture(transfer->resource)->handle; SVGA3dBox box; enum pipe_error ret; assert(svga_have_gb_objects(svga)); /* update the effected region */ box.x = transfer->box.x; box.y = transfer->box.y; switch (tex->b.b.target) { case PIPE_TEXTURE_CUBE: case PIPE_TEXTURE_2D_ARRAY: box.z = 0; break; case PIPE_TEXTURE_1D_ARRAY: box.y = box.z = 0; break; default: box.z = transfer->box.z; break; } box.w = transfer->box.width; box.h = transfer->box.height; box.d = transfer->box.depth; if (0) debug_printf("%s %d, %d, %d %d x %d x %d\n", __FUNCTION__, box.x, box.y, box.z, box.w, box.h, box.d); if (svga_have_vgpu10(svga)) { ret = update_image_vgpu10(svga, surf, &box, st->slice, transfer->level, tex->b.b.last_level + 1); } else { ret = update_image_vgpu9(svga, surf, &box, st->slice, transfer->level); } assert(ret == PIPE_OK); (void) ret; } ss->texture_timestamp++; svga_age_texture_view(tex, transfer->level); if (transfer->resource->target == PIPE_TEXTURE_CUBE) svga_define_texture_level(tex, st->slice, transfer->level); else svga_define_texture_level(tex, 0, transfer->level); pipe_resource_reference(&st->base.resource, NULL); FREE(st->swbuf); if (!st->use_direct_map) { sws->buffer_destroy(sws, st->hwbuf); } FREE(st); }