/** * 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; }
/** * 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; }
/** * Request a transfer map to the texture resource */ static void * svga_texture_transfer_map(struct pipe_context *pipe, struct pipe_resource *texture, unsigned level, unsigned usage, const struct pipe_box *box, struct pipe_transfer **ptransfer) { struct svga_context *svga = svga_context(pipe); struct svga_winsys_screen *sws = svga_screen(pipe->screen)->sws; struct svga_texture *tex = svga_texture(texture); struct svga_transfer *st; struct svga_winsys_surface *surf = tex->handle; boolean use_direct_map = svga_have_gb_objects(svga) && !svga_have_gb_dma(svga); void *map = NULL; int64_t begin = svga_get_time(svga); SVGA_STATS_TIME_PUSH(sws, SVGA_STATS_TIME_TEXTRANSFERMAP); if (!surf) goto done; /* We can't map texture storage directly unless we have GB objects */ if (usage & PIPE_TRANSFER_MAP_DIRECTLY) { if (svga_have_gb_objects(svga)) use_direct_map = TRUE; else goto done; } st = CALLOC_STRUCT(svga_transfer); if (!st) goto done; st->base.level = level; st->base.usage = usage; st->base.box = *box; /* The modified transfer map box with the array index removed from z. * The array index is specified in slice. */ st->box.x = box->x; st->box.y = box->y; st->box.z = box->z; st->box.w = box->width; st->box.h = box->height; st->box.d = box->depth; switch (tex->b.b.target) { case PIPE_TEXTURE_CUBE: st->slice = st->base.box.z; st->box.z = 0; /* so we don't apply double offsets below */ break; case PIPE_TEXTURE_1D_ARRAY: case PIPE_TEXTURE_2D_ARRAY: case PIPE_TEXTURE_CUBE_ARRAY: st->slice = st->base.box.z; st->box.z = 0; /* so we don't apply double offsets below */ /* Force direct map for transfering multiple slices */ if (st->base.box.depth > 1) use_direct_map = svga_have_gb_objects(svga); break; default: st->slice = 0; break; } /* Force direct map for multisample surface */ if (texture->nr_samples > 1) { assert(svga_have_gb_objects(svga)); assert(sws->have_sm4_1); use_direct_map = TRUE; } st->use_direct_map = use_direct_map; pipe_resource_reference(&st->base.resource, texture); /* If this is the first time mapping to the surface in this * command buffer, clear the dirty masks of this surface. */ if (sws->surface_is_flushed(sws, surf)) { svga_clear_texture_dirty(tex); } if (!use_direct_map) { /* upload to the DMA buffer */ map = svga_texture_transfer_map_dma(svga, st); } else { boolean can_use_upload = tex->can_use_upload && !(st->base.usage & PIPE_TRANSFER_READ); boolean was_rendered_to = svga_was_texture_rendered_to(svga_texture(texture), st->slice, st->base.level); /* If the texture was already rendered to and upload buffer * is supported, then we will use upload buffer to * avoid the need to read back the texture content; otherwise, * we'll first try to map directly to the GB surface, if it is blocked, * then we'll try the upload buffer. */ if (was_rendered_to && can_use_upload) { map = svga_texture_transfer_map_upload(svga, st); } else { unsigned orig_usage = st->base.usage; /* First try directly map to the GB surface */ if (can_use_upload) st->base.usage |= PIPE_TRANSFER_DONTBLOCK; map = svga_texture_transfer_map_direct(svga, st); st->base.usage = orig_usage; if (!map && can_use_upload) { /* if direct map with DONTBLOCK fails, then try upload to the * texture upload buffer. */ map = svga_texture_transfer_map_upload(svga, st); } } /* If upload fails, then try direct map again without forcing it * to DONTBLOCK. */ if (!map) { map = svga_texture_transfer_map_direct(svga, st); } } if (!map) { FREE(st); } else { *ptransfer = &st->base; svga->hud.num_textures_mapped++; if (usage & PIPE_TRANSFER_WRITE) { /* record texture upload for HUD */ svga->hud.num_bytes_uploaded += st->base.layer_stride * st->box.d; /* mark this texture level as dirty */ svga_set_texture_dirty(tex, st->slice, level); } } done: svga->hud.map_buffer_time += (svga_get_time(svga) - begin); SVGA_STATS_TIME_POP(sws); (void) sws; return map; }