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); } }
/** * 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); }
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; }
/** * 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); } }
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); }
/** * Try region copy using one of the region copy commands */ static bool try_copy_region(struct svga_context *svga, const struct pipe_blit_info *blit) { unsigned src_layer_face, src_z, dst_layer_face, dst_z; if (!can_blit_via_svga_copy_region(svga, blit)) return false; adjust_z_layer(blit->src.resource->target, blit->src.box.z, &src_layer_face, &src_z); adjust_z_layer(blit->dst.resource->target, blit->dst.box.z, &dst_layer_face, &dst_z); if (can_blit_via_copy_region_vgpu10(svga, blit)) { svga_toggle_render_condition(svga, blit->render_condition_enable, FALSE); copy_region_vgpu10(svga, blit->src.resource, blit->src.box.x, blit->src.box.y, src_z, blit->src.level, src_layer_face, blit->dst.resource, blit->dst.box.x, blit->dst.box.y, dst_z, blit->dst.level, dst_layer_face, blit->src.box.width, blit->src.box.height, blit->src.box.depth); svga_toggle_render_condition(svga, blit->render_condition_enable, TRUE); return true; } if (can_blit_via_surface_copy(svga, blit)) { struct svga_texture *stex = svga_texture(blit->src.resource); struct svga_texture *dtex = svga_texture(blit->dst.resource); svga_surfaces_flush(svga); svga_texture_copy_handle(svga, stex->handle, blit->src.box.x, blit->src.box.y, src_z, blit->src.level, src_layer_face, dtex->handle, blit->dst.box.x, blit->dst.box.y, dst_z, blit->dst.level, dst_layer_face, blit->src.box.width, blit->src.box.height, blit->src.box.depth); svga_define_texture_level(dtex, dst_layer_face, blit->dst.level); svga_set_texture_rendered_to(dtex, dst_layer_face, blit->dst.level); return true; } if (can_blit_via_intra_surface_copy(svga, blit)) { intra_surface_copy(svga, blit->src.resource, blit->src.box.x, blit->src.box.y, src_z, blit->src.level, src_layer_face, blit->dst.box.x, blit->dst.box.y, dst_z, blit->src.box.width, blit->src.box.height, blit->src.box.depth); return true; } return false; }
/* XXX still have doubts about this... */ static void svga_surface_copy(struct pipe_context *pipe, struct pipe_resource* dst_tex, unsigned dst_level, unsigned dstx, unsigned dsty, unsigned dstz, struct pipe_resource* src_tex, unsigned src_level, const struct pipe_box *src_box) { struct svga_context *svga = svga_context(pipe); struct svga_texture *stex, *dtex; /* struct pipe_screen *screen = pipe->screen; SVGA3dCopyBox *box; enum pipe_error ret; struct pipe_surface *srcsurf, *dstsurf;*/ unsigned dst_face, dst_z, src_face, src_z; /* Emit buffered drawing commands, and any back copies. */ svga_surfaces_flush( svga ); /* Fallback for buffers. */ if (dst_tex->target == PIPE_BUFFER && src_tex->target == PIPE_BUFFER) { util_resource_copy_region(pipe, dst_tex, dst_level, dstx, dsty, dstz, src_tex, src_level, src_box); return; } stex = svga_texture(src_tex); dtex = svga_texture(dst_tex); #if 0 srcsurf = screen->get_tex_surface(screen, src_tex, src_level, src_box->z, src_box->z, PIPE_BIND_SAMPLER_VIEW); dstsurf = screen->get_tex_surface(screen, dst_tex, dst_level, dst_box->z, dst_box->z, PIPE_BIND_RENDER_TARGET); SVGA_DBG(DEBUG_DMA, "blit to sid %p (%d,%d), from sid %p (%d,%d) sz %dx%d\n", svga_surface(dstsurf)->handle, dstx, dsty, svga_surface(srcsurf)->handle, src_box->x, src_box->y, width, height); ret = SVGA3D_BeginSurfaceCopy(svga->swc, srcsurf, dstsurf, &box, 1); if(ret != PIPE_OK) { svga_context_flush(svga, NULL); ret = SVGA3D_BeginSurfaceCopy(svga->swc, srcsurf, dstsurf, &box, 1); assert(ret == PIPE_OK); } box->x = dstx; box->y = dsty; box->z = 0; box->w = width; box->h = height; box->d = 1; box->srcx = src_box->x; box->srcy = src_box->y; box->srcz = 0; SVGA_FIFOCommitAll(svga->swc); svga_surface(dstsurf)->dirty = TRUE; svga_propagate_surface(pipe, dstsurf); pipe_surface_reference(&srcsurf, NULL); pipe_surface_reference(&dstsurf, NULL); #else if (src_tex->target == PIPE_TEXTURE_CUBE) { src_face = src_box->z; src_z = 0; assert(src_box->depth == 1); } else { src_face = 0; src_z = src_box->z; } /* different src/dst type???*/ if (dst_tex->target == PIPE_TEXTURE_CUBE) { dst_face = dstz; dst_z = 0; assert(src_box->depth == 1); } else { dst_face = 0; dst_z = dstz; } svga_texture_copy_handle(svga, stex->handle, src_box->x, src_box->y, src_z, src_level, src_face, dtex->handle, dstx, dsty, dst_z, dst_level, dst_face, src_box->width, src_box->height, src_box->depth); #endif /* Mark the destination image as being defined */ svga_define_texture_level(dtex, dst_face, dst_level); }
static void svga_surface_destroy(struct pipe_context *pipe, struct pipe_surface *surf) { struct svga_context *svga = svga_context(pipe); struct svga_surface *s = svga_surface(surf); struct svga_texture *t = svga_texture(surf->texture); struct svga_screen *ss = svga_screen(surf->texture->screen); enum pipe_error ret = PIPE_OK; /* Destroy the backed view surface if it exists */ if (s->backed) { svga_surface_destroy(pipe, &s->backed->base); s->backed = NULL; } 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); } if (s->view_id != SVGA3D_INVALID_ID) { unsigned try; assert(svga_have_vgpu10(svga)); for (try = 0; try < 2; try++) { if (util_format_is_depth_or_stencil(s->base.format)) { ret = SVGA3D_vgpu10_DestroyDepthStencilView(svga->swc, s->view_id); } else { ret = SVGA3D_vgpu10_DestroyRenderTargetView(svga->swc, s->view_id); } if (ret == PIPE_OK) break; svga_context_flush(svga, NULL); } assert(ret == PIPE_OK); util_bitmask_clear(svga->surface_view_id_bm, s->view_id); } pipe_resource_reference(&surf->texture, NULL); FREE(surf); svga->hud.num_surface_views--; } static void svga_mark_surface_dirty(struct pipe_surface *surf) { struct svga_surface *s = svga_surface(surf); struct svga_texture *tex = svga_texture(surf->texture); if (!s->dirty) { s->dirty = TRUE; if (s->handle == tex->handle) { /* hmm so 3d textures always have all their slices marked ? */ svga_define_texture_level(tex, surf->u.tex.first_layer, 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); } void svga_mark_surfaces_dirty(struct svga_context *svga) { struct svga_screen *svgascreen = svga_screen(svga->pipe.screen); unsigned i; for (i = 0; i < svgascreen->max_color_buffers; i++) { if (svga->curr.framebuffer.cbufs[i]) svga_mark_surface_dirty(svga->curr.framebuffer.cbufs[i]); } if (svga->curr.framebuffer.zsbuf) svga_mark_surface_dirty(svga->curr.framebuffer.zsbuf); } /** * 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, layer; unsigned nlayers = 1; unsigned i; if (!s->dirty) return; if (surf->texture->target == PIPE_TEXTURE_CUBE) { zslice = 0; layer = surf->u.tex.first_layer; } else if (surf->texture->target == PIPE_TEXTURE_1D_ARRAY || surf->texture->target == PIPE_TEXTURE_2D_ARRAY) { zslice = 0; layer = surf->u.tex.first_layer; nlayers = surf->u.tex.last_layer - surf->u.tex.first_layer + 1; } else { zslice = surf->u.tex.first_layer; layer = 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); for (i = 0; i < nlayers; i++) { svga_texture_copy_handle(svga, s->handle, 0, 0, 0, s->real_level, s->real_layer + i, tex->handle, 0, 0, zslice, surf->u.tex.level, layer + i, 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, layer + i, surf->u.tex.level); } } } /** * Check if we should call svga_propagate_surface on the surface. */ boolean svga_surface_needs_propagation(const struct pipe_surface *surf) { const struct svga_surface *s = svga_surface_const(surf); struct svga_texture *tex = svga_texture(surf->texture); return s->dirty && s->handle != tex->handle; } static void svga_get_sample_position(struct pipe_context *context, unsigned sample_count, unsigned sample_index, float *pos_out) { /* We can't actually query the device to learn the sample positions. * These were grabbed from nvidia's driver. */ static const float pos1[1][2] = { { 0.5, 0.5 } }; static const float pos4[4][2] = { { 0.375000, 0.125000 }, { 0.875000, 0.375000 }, { 0.125000, 0.625000 }, { 0.625000, 0.875000 } }; static const float pos8[8][2] = { { 0.562500, 0.312500 }, { 0.437500, 0.687500 }, { 0.812500, 0.562500 }, { 0.312500, 0.187500 }, { 0.187500, 0.812500 }, { 0.062500, 0.437500 }, { 0.687500, 0.937500 }, { 0.937500, 0.062500 } }; static const float pos16[16][2] = { { 0.187500, 0.062500 }, { 0.437500, 0.187500 }, { 0.062500, 0.312500 }, { 0.312500, 0.437500 }, { 0.687500, 0.062500 }, { 0.937500, 0.187500 }, { 0.562500, 0.312500 }, { 0.812500, 0.437500 }, { 0.187500, 0.562500 }, { 0.437500, 0.687500 }, { 0.062500, 0.812500 }, { 0.312500, 0.937500 }, { 0.687500, 0.562500 }, { 0.937500, 0.687500 }, { 0.562500, 0.812500 }, { 0.812500, 0.937500 } }; const float (*positions)[2]; switch (sample_count) { case 4: positions = pos4; break; case 8: positions = pos8; break; case 16: positions = pos16; break; default: positions = pos1; } pos_out[0] = positions[sample_index][0]; pos_out[1] = positions[sample_index][1]; } void svga_init_surface_functions(struct svga_context *svga) { svga->pipe.create_surface = svga_create_surface; svga->pipe.surface_destroy = svga_surface_destroy; svga->pipe.get_sample_position = svga_get_sample_position; }