enum pipe_error SVGA3D_vgpu10_SetRenderTargets(struct svga_winsys_context *swc, unsigned color_count, struct pipe_surface **color_surfs, struct pipe_surface *depth_stencil_surf) { const unsigned surf_count = color_count + 1; SVGA3dCmdDXSetRenderTargets *cmd; SVGA3dRenderTargetViewId *ctarget; struct svga_surface *ss; unsigned i; assert(surf_count > 0); cmd = SVGA3D_FIFOReserve(swc, SVGA_3D_CMD_DX_SET_RENDERTARGETS, sizeof(SVGA3dCmdDXSetRenderTargets) + color_count * sizeof(SVGA3dRenderTargetViewId), surf_count); /* 'surf_count' relocations */ if (!cmd) return PIPE_ERROR_OUT_OF_MEMORY; /* NOTE: See earlier comment about the tricky handling of the ViewIds. */ /* Depth / Stencil buffer */ if (depth_stencil_surf) { ss = svga_surface(depth_stencil_surf); view_relocation(swc, depth_stencil_surf, &cmd->depthStencilViewId, SVGA_RELOC_WRITE); cmd->depthStencilViewId = ss->view_id; } else { /* no depth/stencil buffer - still need a relocation */ view_relocation(swc, NULL, &cmd->depthStencilViewId, SVGA_RELOC_WRITE); cmd->depthStencilViewId = SVGA3D_INVALID_ID; } /* Color buffers */ ctarget = (SVGA3dRenderTargetViewId *) &cmd[1]; for (i = 0; i < color_count; i++) { if (color_surfs[i]) { ss = svga_surface(color_surfs[i]); view_relocation(swc, color_surfs[i], ctarget + i, SVGA_RELOC_WRITE); ctarget[i] = ss->view_id; } else { view_relocation(swc, NULL, ctarget + i, SVGA_RELOC_WRITE); ctarget[i] = SVGA3D_INVALID_ID; } } swc->commit(swc); return PIPE_OK; }
/** * Clear the given surface to the specified value. * No masking, no scissor (clear entire buffer). */ void svga_clear(struct pipe_context *pipe, unsigned buffers, const float *rgba, double depth, unsigned stencil) { struct svga_context *svga = svga_context( pipe ); int ret; if (buffers & PIPE_CLEAR_COLOR) SVGA_DBG(DEBUG_DMA, "clear sid %p\n", svga_surface(svga->curr.framebuffer.cbufs[0])->handle); ret = try_clear( svga, buffers, rgba, depth, stencil ); if (ret == PIPE_ERROR_OUT_OF_MEMORY) { /* Flush command buffer and retry: */ svga_context_flush( svga, NULL ); ret = try_clear( svga, buffers, rgba, depth, stencil ); } /* * Mark target surfaces as dirty * TODO Mark only cleared surfaces. */ svga_mark_surfaces_dirty(svga); assert (ret == PIPE_OK); }
/** * Clear the given surface to the specified value. * No masking, no scissor (clear entire buffer). */ void svga_clear(struct pipe_context *pipe, unsigned buffers, const union pipe_color_union *color, double depth, unsigned stencil) { struct svga_context *svga = svga_context( pipe ); enum pipe_error ret; if (buffers & PIPE_CLEAR_COLOR) SVGA_DBG(DEBUG_DMA, "clear sid %p\n", svga_surface(svga->curr.framebuffer.cbufs[0])->handle); /* flush any queued prims (don't want them to appear after the clear!) */ svga_hwtnl_flush_retry(svga); ret = try_clear( svga, buffers, color, depth, stencil ); if (ret == PIPE_ERROR_OUT_OF_MEMORY) { /* Flush command buffer and retry: */ svga_context_flush( svga, NULL ); ret = try_clear( svga, buffers, color, depth, stencil ); } /* * Mark target surfaces as dirty * TODO Mark only cleared surfaces. */ svga_mark_surfaces_dirty(svga); assert (ret == PIPE_OK); }
enum pipe_error SVGA3D_vgpu10_ClearDepthStencilView(struct svga_winsys_context *swc, struct pipe_surface *ds_surf, uint16 flags, uint16 stencil, float depth) { SVGA3dCmdDXClearDepthStencilView *cmd; struct svga_surface *ss = svga_surface(ds_surf); cmd = SVGA3D_FIFOReserve(swc, SVGA_3D_CMD_DX_CLEAR_DEPTHSTENCIL_VIEW, sizeof(SVGA3dCmdDXClearDepthStencilView), 1); /* one relocation */ if (!cmd) return PIPE_ERROR_OUT_OF_MEMORY; /* NOTE: The following is pretty tricky. We need to emit a view/surface * relocation and we have to provide a pointer to an ID which lies in * the bounds of the command space which we just allocated. However, * we then need to overwrite it with the original DepthStencilViewId. */ view_relocation(swc, ds_surf, &cmd->depthStencilViewId, SVGA_RELOC_WRITE); cmd->depthStencilViewId = ss->view_id; cmd->flags = flags; cmd->stencil = stencil; cmd->depth = depth; swc->commit(swc); return 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) { /* 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); } }
enum pipe_error SVGA3D_vgpu10_ClearRenderTargetView(struct svga_winsys_context *swc, struct pipe_surface *color_surf, const float *rgba) { SVGA3dCmdDXClearRenderTargetView *cmd; struct svga_surface *ss = svga_surface(color_surf); cmd = SVGA3D_FIFOReserve(swc, SVGA_3D_CMD_DX_CLEAR_RENDERTARGET_VIEW, sizeof(SVGA3dCmdDXClearRenderTargetView), 1); /* one relocation */ if (!cmd) return PIPE_ERROR_OUT_OF_MEMORY; /* NOTE: The following is pretty tricky. We need to emit a view/surface * relocation and we have to provide a pointer to an ID which lies in * the bounds of the command space which we just allocated. However, * we then need to overwrite it with the original RenderTargetViewId. */ view_relocation(swc, color_surf, &cmd->renderTargetViewId, SVGA_RELOC_WRITE); cmd->renderTargetViewId = ss->view_id; COPY_4V(cmd->rgba.value, rgba); swc->commit(swc); return PIPE_OK; }
/** * 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; }
/** * \brief Clear the whole render target using vgpu10 functionality * * \param svga[in] The svga context * \param dst[in] The surface to clear * \param color[in] Clear color * \return PIPE_OK if all well, PIPE_ERROR_OUT_OF_MEMORY if ran out of * command submission resources. */ static enum pipe_error svga_try_clear_render_target(struct svga_context *svga, struct pipe_surface *dst, const union pipe_color_union *color) { struct pipe_surface *rtv = svga_validate_surface_view(svga, svga_surface(dst)); if (!rtv) return PIPE_ERROR_OUT_OF_MEMORY; return SVGA3D_vgpu10_ClearRenderTargetView(svga->swc, rtv, color->f); }
/* * Send a private allocation command to page in rendertargets resource. */ enum pipe_error svga_rebind_framebuffer_bindings(struct svga_context *svga) { const struct svga_screen *ss = svga_screen(svga->pipe.screen); struct pipe_framebuffer_state *hw = &svga->state.hw_clear.framebuffer; unsigned i; enum pipe_error ret; assert(svga_have_vgpu10(svga)); if (!svga->rebind.flags.rendertargets) return PIPE_OK; for (i = 0; i < ss->max_color_buffers; i++) { if (hw->cbufs[i]) { ret = svga->swc->resource_rebind(svga->swc, svga_surface(hw->cbufs[i])->handle, NULL, SVGA_RELOC_WRITE); if (ret != PIPE_OK) return ret; } } if (hw->zsbuf) { ret = svga->swc->resource_rebind(svga->swc, svga_surface(hw->zsbuf)->handle, NULL, SVGA_RELOC_WRITE); if (ret != PIPE_OK) return ret; } svga->rebind.flags.rendertargets = 0; return PIPE_OK; }
/** * Check if there are any resources that are both bound to a render target * and bound as a shader resource for the given type of shader. */ boolean svga_check_sampler_framebuffer_resource_collision(struct svga_context *svga, enum pipe_shader_type shader) { struct svga_surface *surf; unsigned i; for (i = 0; i < svga->curr.framebuffer.nr_cbufs; i++) { surf = svga_surface(svga->curr.framebuffer.cbufs[i]); if (surf && svga_check_sampler_view_resource_collision(svga, surf->handle, shader)) { return TRUE; } } surf = svga_surface(svga->curr.framebuffer.zsbuf); if (surf && svga_check_sampler_view_resource_collision(svga, surf->handle, shader)) { return TRUE; } return FALSE; }
/* * Send a private allocation command to page in rendertargets resource. */ enum pipe_error svga_rebind_framebuffer_bindings(struct svga_context *svga) { struct svga_hw_draw_state *hw = &svga->state.hw_draw; unsigned i; enum pipe_error ret; assert(svga_have_vgpu10(svga)); if (!svga->rebind.flags.rendertargets) return PIPE_OK; for (i = 0; i < hw->num_rendertargets; i++) { if (hw->rtv[i]) { ret = svga->swc->resource_rebind(svga->swc, svga_surface(hw->rtv[i])->handle, NULL, SVGA_RELOC_WRITE); if (ret != PIPE_OK) return ret; } } if (hw->dsv) { ret = svga->swc->resource_rebind(svga->swc, svga_surface(hw->dsv)->handle, NULL, SVGA_RELOC_WRITE); if (ret != PIPE_OK) return ret; } svga->rebind.flags.rendertargets = 0; return PIPE_OK; }
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); }
/** * Emit a surface relocation for RenderTargetViewId */ static void view_relocation(struct svga_winsys_context *swc, // IN struct pipe_surface *surface, // IN SVGA3dRenderTargetViewId *id, // OUT unsigned flags) { if (surface) { struct svga_surface *s = svga_surface(surface); assert(s->handle); swc->surface_relocation(swc, id, NULL, s->handle, flags); } else { swc->surface_relocation(swc, id, NULL, NULL, flags); } }
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 */ } } }
static INLINE void surface_to_surfaceid(struct svga_winsys_context *swc, // IN struct pipe_surface *surface, // IN SVGA3dSurfaceImageId *id, // OUT unsigned flags) // IN { if(surface) { struct svga_surface *s = svga_surface(surface); swc->surface_relocation(swc, &id->sid, s->handle, flags); id->face = s->real_face; /* faces have the same order */ id->mipmap = s->real_level; } else { id->sid = SVGA3D_INVALID_ID; id->face = 0; id->mipmap = 0; } }
/** * 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; } }
/** * 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; }
static enum pipe_error emit_fb_vgpu10(struct svga_context *svga) { const struct svga_screen *ss = svga_screen(svga->pipe.screen); struct pipe_surface *rtv[SVGA3D_MAX_RENDER_TARGETS]; struct pipe_surface *dsv; struct pipe_framebuffer_state *curr = &svga->curr.framebuffer; struct pipe_framebuffer_state *hw = &svga->state.hw_clear.framebuffer; const unsigned num_color = MAX2(curr->nr_cbufs, hw->nr_cbufs); unsigned i; enum pipe_error ret; assert(svga_have_vgpu10(svga)); /* Setup render targets array. Note that we loop over the max of the * number of previously bound buffers and the new buffers to unbind * any previously bound buffers when the new number of buffers is less * than the old number of buffers. */ for (i = 0; i < num_color; i++) { if (curr->cbufs[i]) { rtv[i] = svga_validate_surface_view(svga, svga_surface(curr->cbufs[i])); if (rtv[i] == NULL) { return PIPE_ERROR_OUT_OF_MEMORY; } assert(svga_surface(rtv[i])->view_id != SVGA3D_INVALID_ID); } else { rtv[i] = NULL; } } /* Setup depth stencil view */ if (curr->zsbuf) { dsv = svga_validate_surface_view(svga, svga_surface(curr->zsbuf)); if (!dsv) { return PIPE_ERROR_OUT_OF_MEMORY; } } else { dsv = NULL; } ret = SVGA3D_vgpu10_SetRenderTargets(svga->swc, num_color, rtv, dsv); if (ret != PIPE_OK) return ret; for (i = 0; i < ss->max_color_buffers; i++) { if (hw->cbufs[i] != curr->cbufs[i]) { /* propagate the backed view surface before unbinding it */ if (hw->cbufs[i] && svga_surface(hw->cbufs[i])->backed) { svga_propagate_surface(svga, &svga_surface(hw->cbufs[i])->backed->base); } pipe_surface_reference(&hw->cbufs[i], curr->cbufs[i]); } } hw->nr_cbufs = curr->nr_cbufs; if (hw->zsbuf != curr->zsbuf) { /* propagate the backed view surface before unbinding it */ if (hw->zsbuf && svga_surface(hw->zsbuf)->backed) { svga_propagate_surface(svga, &svga_surface(hw->zsbuf)->backed->base); } pipe_surface_reference(&hw->zsbuf, curr->zsbuf); } return ret; }
static enum pipe_error draw_vgpu9(struct svga_hwtnl *hwtnl) { struct svga_winsys_context *swc = hwtnl->cmd.swc; struct svga_context *svga = hwtnl->svga; enum pipe_error ret; struct svga_winsys_surface *vb_handle[SVGA3D_INPUTREG_MAX]; struct svga_winsys_surface *ib_handle[QSZ]; struct svga_winsys_surface *handle; SVGA3dVertexDecl *vdecl; SVGA3dPrimitiveRange *prim; unsigned i; for (i = 0; i < hwtnl->cmd.vdecl_count; i++) { unsigned j = hwtnl->cmd.vdecl_buffer_index[i]; handle = svga_buffer_handle(svga, hwtnl->cmd.vbufs[j].buffer); if (handle == NULL) return PIPE_ERROR_OUT_OF_MEMORY; vb_handle[i] = handle; } for (i = 0; i < hwtnl->cmd.prim_count; i++) { if (hwtnl->cmd.prim_ib[i]) { handle = svga_buffer_handle(svga, hwtnl->cmd.prim_ib[i]); if (handle == NULL) return PIPE_ERROR_OUT_OF_MEMORY; } else handle = NULL; ib_handle[i] = handle; } if (svga->rebind.flags.rendertargets) { ret = svga_reemit_framebuffer_bindings(svga); if (ret != PIPE_OK) { return ret; } } if (svga->rebind.flags.texture_samplers) { ret = svga_reemit_tss_bindings(svga); if (ret != PIPE_OK) { return ret; } } if (svga->rebind.flags.vs) { ret = svga_reemit_vs_bindings(svga); if (ret != PIPE_OK) { return ret; } } if (svga->rebind.flags.fs) { ret = svga_reemit_fs_bindings(svga); if (ret != PIPE_OK) { return ret; } } SVGA_DBG(DEBUG_DMA, "draw to sid %p, %d prims\n", svga->curr.framebuffer.cbufs[0] ? svga_surface(svga->curr.framebuffer.cbufs[0])->handle : NULL, hwtnl->cmd.prim_count); ret = SVGA3D_BeginDrawPrimitives(swc, &vdecl, hwtnl->cmd.vdecl_count, &prim, hwtnl->cmd.prim_count); if (ret != PIPE_OK) return ret; memcpy(vdecl, hwtnl->cmd.vdecl, hwtnl->cmd.vdecl_count * sizeof hwtnl->cmd.vdecl[0]); for (i = 0; i < hwtnl->cmd.vdecl_count; i++) { /* check for 4-byte alignment */ assert(vdecl[i].array.offset % 4 == 0); assert(vdecl[i].array.stride % 4 == 0); /* Given rangeHint is considered to be relative to indexBias, and * indexBias varies per primitive, we cannot accurately supply an * rangeHint when emitting more than one primitive per draw command. */ if (hwtnl->cmd.prim_count == 1) { vdecl[i].rangeHint.first = hwtnl->cmd.min_index[0]; vdecl[i].rangeHint.last = hwtnl->cmd.max_index[0] + 1; } else { vdecl[i].rangeHint.first = 0; vdecl[i].rangeHint.last = 0; } swc->surface_relocation(swc, &vdecl[i].array.surfaceId, NULL, vb_handle[i], SVGA_RELOC_READ); } memcpy(prim, hwtnl->cmd.prim, hwtnl->cmd.prim_count * sizeof hwtnl->cmd.prim[0]); for (i = 0; i < hwtnl->cmd.prim_count; i++) { swc->surface_relocation(swc, &prim[i].indexArray.surfaceId, NULL, ib_handle[i], SVGA_RELOC_READ); pipe_resource_reference(&hwtnl->cmd.prim_ib[i], NULL); } SVGA_FIFOCommitAll(swc); hwtnl->cmd.prim_count = 0; return PIPE_OK; }
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; }
static void svga_clear_texture(struct pipe_context *pipe, struct pipe_resource *res, unsigned level, const struct pipe_box *box, const void *data) { struct svga_context *svga = svga_context(pipe); struct svga_surface *svga_surface_dst; enum pipe_error ret; struct pipe_surface tmpl; struct pipe_surface *surface; memset(&tmpl, 0, sizeof(tmpl)); tmpl.format = res->format; tmpl.u.tex.first_layer = box->z; tmpl.u.tex.last_layer = box->z + box->depth - 1; tmpl.u.tex.level = level; surface = pipe->create_surface(pipe, res, &tmpl); if (surface == NULL) { debug_printf("failed to create surface\n"); return; } svga_surface_dst = svga_surface(surface); union pipe_color_union color; const struct util_format_description *desc = util_format_description(surface->format); if (util_format_is_depth_or_stencil(surface->format)) { float depth; uint8_t stencil; unsigned clear_flags = 0; /* If data is NULL, then set depthValue and stencilValue to zeros */ if (data == NULL) { depth = 0.0; stencil = 0; } else { desc->unpack_z_float(&depth, 0, data, 0, 1, 1); desc->unpack_s_8uint(&stencil, 0, data, 0, 1, 1); } if (util_format_has_depth(desc)) { clear_flags |= PIPE_CLEAR_DEPTH; } if (util_format_has_stencil(desc)) { clear_flags |= PIPE_CLEAR_STENCIL; } /* Setup depth stencil view */ struct pipe_surface *dsv = svga_validate_surface_view(svga, svga_surface_dst); if (!dsv) { pipe_surface_reference(&surface, NULL); return; } if (box->x == 0 && box->y == 0 && box->width == surface->width && box->height == surface->height) { /* clearing whole surface, use direct VGPU10 command */ ret = SVGA3D_vgpu10_ClearDepthStencilView(svga->swc, dsv, clear_flags, stencil, depth); if (ret != PIPE_OK) { /* flush and try again */ svga_context_flush(svga, NULL); ret = SVGA3D_vgpu10_ClearDepthStencilView(svga->swc, dsv, clear_flags, stencil, depth); assert(ret == PIPE_OK); } } else { /* To clear subtexture use software fallback */ util_blitter_save_framebuffer(svga->blitter, &svga->curr.framebuffer); begin_blit(svga); util_blitter_clear_depth_stencil(svga->blitter, dsv, clear_flags, depth,stencil, box->x, box->y, box->width, box->height); } } else { /* non depth-stencil formats */ if (data == NULL) { /* If data is NULL, the texture image is filled with zeros */ color.f[0] = color.f[1] = color.f[2] = color.f[3] = 0; } else { if (util_format_is_pure_sint(surface->format)) { /* signed integer */ desc->unpack_rgba_sint(color.i, 0, data, 0, 1, 1); } else if (util_format_is_pure_uint(surface->format)) { /* unsigned integer */ desc->unpack_rgba_uint(color.ui, 0, data, 0, 1, 1); } else { /* floating point */ desc->unpack_rgba_float(color.f, 0, data, 0, 1, 1); } } /* Setup render target view */ struct pipe_surface *rtv = svga_validate_surface_view(svga, svga_surface_dst); if (!rtv) { pipe_surface_reference(&surface, NULL); return; } if (box->x == 0 && box->y == 0 && box->width == surface->width && box->height == surface->height) { struct pipe_framebuffer_state *curr = &svga->curr.framebuffer; if (is_integer_target(curr, PIPE_CLEAR_COLOR) && !ints_fit_in_floats(&color)) { /* To clear full texture with integer format */ clear_buffers_with_quad(svga, PIPE_CLEAR_COLOR, &color, 0.0, 0); } else { /* clearing whole surface using VGPU10 command */ ret = SVGA3D_vgpu10_ClearRenderTargetView(svga->swc, rtv, color.f); if (ret != PIPE_OK) { svga_context_flush(svga,NULL); ret = SVGA3D_vgpu10_ClearRenderTargetView(svga->swc, rtv, color.f); assert(ret == PIPE_OK); } } } else { /* To clear subtexture use software fallback */ /** * util_blitter_clear_render_target doesn't support PIPE_TEXTURE_3D * It tries to draw quad with depth 0 for PIPE_TEXTURE_3D so use * util_clear_render_target() for PIPE_TEXTURE_3D. */ if (rtv->texture->target != PIPE_TEXTURE_3D && pipe->screen->is_format_supported(pipe->screen, rtv->format, rtv->texture->target, rtv->texture->nr_samples, PIPE_BIND_RENDER_TARGET)) { /* clear with quad drawing */ util_blitter_save_framebuffer(svga->blitter, &svga->curr.framebuffer); begin_blit(svga); util_blitter_clear_render_target(svga->blitter, rtv, &color, box->x, box->y, box->width, box->height); } else { /* clear with map/write/unmap */ /* store layer values */ unsigned first_layer = rtv->u.tex.first_layer; unsigned last_layer = rtv->u.tex.last_layer; unsigned box_depth = last_layer - first_layer + 1; for (unsigned i = 0; i < box_depth; i++) { rtv->u.tex.first_layer = rtv->u.tex.last_layer = first_layer + i; util_clear_render_target(pipe, rtv, &color, box->x, box->y, box->width, box->height); } /* restore layer values */ rtv->u.tex.first_layer = first_layer; rtv->u.tex.last_layer = last_layer; } } } pipe_surface_reference(&surface, NULL); }
enum pipe_error svga_hwtnl_flush( struct svga_hwtnl *hwtnl ) { struct svga_winsys_context *swc = hwtnl->cmd.swc; struct svga_context *svga = hwtnl->svga; enum pipe_error ret; if (hwtnl->cmd.prim_count) { struct svga_winsys_surface *vb_handle[SVGA3D_INPUTREG_MAX]; struct svga_winsys_surface *ib_handle[QSZ]; struct svga_winsys_surface *handle; SVGA3dVertexDecl *vdecl; SVGA3dPrimitiveRange *prim; unsigned i; for (i = 0; i < hwtnl->cmd.vdecl_count; i++) { handle = svga_buffer_handle(svga, hwtnl->cmd.vdecl_vb[i]); if (handle == NULL) return PIPE_ERROR_OUT_OF_MEMORY; vb_handle[i] = handle; } for (i = 0; i < hwtnl->cmd.prim_count; i++) { if (hwtnl->cmd.prim_ib[i]) { handle = svga_buffer_handle(svga, hwtnl->cmd.prim_ib[i]); if (handle == NULL) return PIPE_ERROR_OUT_OF_MEMORY; } else handle = NULL; ib_handle[i] = handle; } SVGA_DBG(DEBUG_DMA, "draw to sid %p, %d prims\n", svga->curr.framebuffer.cbufs[0] ? svga_surface(svga->curr.framebuffer.cbufs[0])->handle : NULL, hwtnl->cmd.prim_count); ret = SVGA3D_BeginDrawPrimitives(swc, &vdecl, hwtnl->cmd.vdecl_count, &prim, hwtnl->cmd.prim_count); if (ret != PIPE_OK) return ret; memcpy( vdecl, hwtnl->cmd.vdecl, hwtnl->cmd.vdecl_count * sizeof hwtnl->cmd.vdecl[0]); for (i = 0; i < hwtnl->cmd.vdecl_count; i++) { /* Given rangeHint is considered to be relative to indexBias, and * indexBias varies per primitive, we cannot accurately supply an * rangeHint when emitting more than one primitive per draw command. */ if (hwtnl->cmd.prim_count == 1) { vdecl[i].rangeHint.first = hwtnl->cmd.min_index[0]; vdecl[i].rangeHint.last = hwtnl->cmd.max_index[0] + 1; } else { vdecl[i].rangeHint.first = 0; vdecl[i].rangeHint.last = 0; } swc->surface_relocation(swc, &vdecl[i].array.surfaceId, vb_handle[i], PIPE_BUFFER_USAGE_GPU_READ); } memcpy( prim, hwtnl->cmd.prim, hwtnl->cmd.prim_count * sizeof hwtnl->cmd.prim[0]); for (i = 0; i < hwtnl->cmd.prim_count; i++) { swc->surface_relocation(swc, &prim[i].indexArray.surfaceId, ib_handle[i], PIPE_BUFFER_USAGE_GPU_READ); pipe_buffer_reference(&hwtnl->cmd.prim_ib[i], NULL); } SVGA_FIFOCommitAll( swc ); hwtnl->cmd.prim_count = 0; } return PIPE_OK; }
/* 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 }
static enum pipe_error try_clear(struct svga_context *svga, unsigned buffers, const union pipe_color_union *color, double depth, unsigned stencil) { enum pipe_error ret = PIPE_OK; SVGA3dRect rect = { 0, 0, 0, 0 }; boolean restore_viewport = FALSE; SVGA3dClearFlag flags = 0; struct pipe_framebuffer_state *fb = &svga->curr.framebuffer; union util_color uc = {0}; ret = svga_update_state(svga, SVGA_STATE_HW_CLEAR); if (ret != PIPE_OK) return ret; if (svga->rebind.flags.rendertargets) { ret = svga_reemit_framebuffer_bindings(svga); if (ret != PIPE_OK) { return ret; } } if (buffers & PIPE_CLEAR_COLOR) { flags |= SVGA3D_CLEAR_COLOR; util_pack_color(color->f, PIPE_FORMAT_B8G8R8A8_UNORM, &uc); rect.w = fb->width; rect.h = fb->height; } if ((buffers & PIPE_CLEAR_DEPTHSTENCIL) && fb->zsbuf) { if (buffers & PIPE_CLEAR_DEPTH) flags |= SVGA3D_CLEAR_DEPTH; if (buffers & PIPE_CLEAR_STENCIL) flags |= SVGA3D_CLEAR_STENCIL; rect.w = MAX2(rect.w, fb->zsbuf->width); rect.h = MAX2(rect.h, fb->zsbuf->height); } if (!svga_have_vgpu10(svga) && !svga_rects_equal(&rect, &svga->state.hw_clear.viewport)) { restore_viewport = TRUE; ret = SVGA3D_SetViewport(svga->swc, &rect); if (ret != PIPE_OK) return ret; } if (svga_have_vgpu10(svga)) { if (flags & SVGA3D_CLEAR_COLOR) { unsigned i; if (is_integer_target(fb, buffers) && !ints_fit_in_floats(color)) { clear_buffers_with_quad(svga, buffers, color, depth, stencil); /* We also cleared depth/stencil, so that's done */ flags &= ~(SVGA3D_CLEAR_DEPTH | SVGA3D_CLEAR_STENCIL); } else { struct pipe_surface *rtv; /* Issue VGPU10 Clear commands */ for (i = 0; i < fb->nr_cbufs; i++) { if ((fb->cbufs[i] == NULL) || !(buffers & (PIPE_CLEAR_COLOR0 << i))) continue; rtv = svga_validate_surface_view(svga, svga_surface(fb->cbufs[i])); if (!rtv) return PIPE_ERROR_OUT_OF_MEMORY; ret = SVGA3D_vgpu10_ClearRenderTargetView(svga->swc, rtv, color->f); if (ret != PIPE_OK) return ret; } } } if (flags & (SVGA3D_CLEAR_DEPTH | SVGA3D_CLEAR_STENCIL)) { struct pipe_surface *dsv = svga_validate_surface_view(svga, svga_surface(fb->zsbuf)); if (!dsv) return PIPE_ERROR_OUT_OF_MEMORY; ret = SVGA3D_vgpu10_ClearDepthStencilView(svga->swc, dsv, flags, stencil, (float) depth); if (ret != PIPE_OK) return ret; } } else { ret = SVGA3D_ClearRect(svga->swc, flags, uc.ui[0], (float) depth, stencil, rect.x, rect.y, rect.w, rect.h); if (ret != PIPE_OK) return ret; } if (restore_viewport) { ret = SVGA3D_SetViewport(svga->swc, &svga->state.hw_clear.viewport); } return ret; }