/********************************************************** * Copyright 2008-2009 VMware, Inc. All rights reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * **********************************************************/ #include "util/u_inlines.h" #include "pipe/p_state.h" #include "svga_context.h" #include "svga_state.h" #include "svga_debug.h" #include "svga_hw_reg.h" /*********************************************************************** */ /** * Given a gallium vertex element format, return the corresponding SVGA3D * format. Return SVGA3D_DECLTYPE_MAX for unsupported gallium formats. */ static INLINE SVGA3dDeclType svga_translate_vertex_format(enum pipe_format format) { switch (format) { case PIPE_FORMAT_R32_FLOAT: return SVGA3D_DECLTYPE_FLOAT1; case PIPE_FORMAT_R32G32_FLOAT: return SVGA3D_DECLTYPE_FLOAT2; case PIPE_FORMAT_R32G32B32_FLOAT: return SVGA3D_DECLTYPE_FLOAT3; case PIPE_FORMAT_R32G32B32A32_FLOAT: return SVGA3D_DECLTYPE_FLOAT4; case PIPE_FORMAT_B8G8R8A8_UNORM: return SVGA3D_DECLTYPE_D3DCOLOR; case PIPE_FORMAT_R8G8B8A8_USCALED: return SVGA3D_DECLTYPE_UBYTE4; case PIPE_FORMAT_R16G16_SSCALED: return SVGA3D_DECLTYPE_SHORT2; case PIPE_FORMAT_R16G16B16A16_SSCALED: return SVGA3D_DECLTYPE_SHORT4; case PIPE_FORMAT_R8G8B8A8_UNORM: return SVGA3D_DECLTYPE_UBYTE4N; case PIPE_FORMAT_R16G16_SNORM: return SVGA3D_DECLTYPE_SHORT2N; case PIPE_FORMAT_R16G16B16A16_SNORM: return SVGA3D_DECLTYPE_SHORT4N; case PIPE_FORMAT_R16G16_UNORM: return SVGA3D_DECLTYPE_USHORT2N; case PIPE_FORMAT_R16G16B16A16_UNORM: return SVGA3D_DECLTYPE_USHORT4N; case PIPE_FORMAT_R10G10B10X2_USCALED: return SVGA3D_DECLTYPE_UDEC3; case PIPE_FORMAT_R10G10B10X2_SNORM: return SVGA3D_DECLTYPE_DEC3N; case PIPE_FORMAT_R16G16_FLOAT: return SVGA3D_DECLTYPE_FLOAT16_2; case PIPE_FORMAT_R16G16B16A16_FLOAT: return SVGA3D_DECLTYPE_FLOAT16_4; default: /* There are many formats without hardware support. This case * will be hit regularly, meaning we'll need swvfetch. */ return SVGA3D_DECLTYPE_MAX; } } static enum pipe_error update_need_swvfetch( struct svga_context *svga, unsigned dirty ) { unsigned i; boolean need_swvfetch = FALSE; if (!svga->curr.velems) { /* No vertex elements bound. */ return 0; } for (i = 0; i < svga->curr.velems->count; i++) { svga->state.sw.ve_format[i] = svga_translate_vertex_format(svga->curr.velems->velem[i].src_format); if (svga->state.sw.ve_format[i] == SVGA3D_DECLTYPE_MAX) { /* Unsupported format - use software fetch */ need_swvfetch = TRUE; break; } } if (need_swvfetch != svga->state.sw.need_swvfetch) { svga->state.sw.need_swvfetch = need_swvfetch; svga->dirty |= SVGA_NEW_NEED_SWVFETCH; } return 0; } struct svga_tracked_state svga_update_need_swvfetch = { "update need_swvfetch", ( SVGA_NEW_VELEMENT ), update_need_swvfetch }; /*********************************************************************** */ static enum pipe_error update_need_pipeline( struct svga_context *svga, unsigned dirty ) { boolean need_pipeline = FALSE; struct svga_vertex_shader *vs = svga->curr.vs; /* SVGA_NEW_RAST, SVGA_NEW_REDUCED_PRIMITIVE */ if (svga->curr.rast->need_pipeline & (1 << svga->curr.reduced_prim)) { SVGA_DBG(DEBUG_SWTNL, "%s: rast need_pipeline (0x%x) & prim (0x%x)\n", __FUNCTION__, svga->curr.rast->need_pipeline, (1 << svga->curr.reduced_prim) ); SVGA_DBG(DEBUG_SWTNL, "%s: rast need_pipeline tris (%s), lines (%s), points (%s)\n", __FUNCTION__, svga->curr.rast->need_pipeline_tris_str, svga->curr.rast->need_pipeline_lines_str, svga->curr.rast->need_pipeline_points_str); need_pipeline = TRUE; } /* EDGEFLAGS */ if (vs && vs->base.info.writes_edgeflag) { SVGA_DBG(DEBUG_SWTNL, "%s: edgeflags\n", __FUNCTION__); need_pipeline = TRUE; } /* SVGA_NEW_FS, SVGA_NEW_RAST, SVGA_NEW_REDUCED_PRIMITIVE */ if (svga->curr.reduced_prim == PIPE_PRIM_POINTS) { unsigned sprite_coord_gen = svga->curr.rast->templ.sprite_coord_enable; unsigned generic_inputs = svga->curr.fs ? svga->curr.fs->generic_inputs : 0; if (sprite_coord_gen && (generic_inputs & ~sprite_coord_gen)) { /* The fragment shader is using some generic inputs that are * not being replaced by auto-generated point/sprite coords (and * auto sprite coord generation is turned on). * The SVGA3D interface does not support that: if we enable * SVGA3D_RS_POINTSPRITEENABLE it gets enabled for _all_ * texture coordinate sets. * To solve this, we have to use the draw-module's wide/sprite * point stage. */ need_pipeline = TRUE; } } if (need_pipeline != svga->state.sw.need_pipeline) { svga->state.sw.need_pipeline = need_pipeline; svga->dirty |= SVGA_NEW_NEED_PIPELINE; } /* DEBUG */ if (0 && svga->state.sw.need_pipeline) debug_printf("sw.need_pipeline = %d\n", svga->state.sw.need_pipeline); return 0; } struct svga_tracked_state svga_update_need_pipeline = { "need pipeline", (SVGA_NEW_RAST | SVGA_NEW_FS | SVGA_NEW_VS | SVGA_NEW_REDUCED_PRIMITIVE), update_need_pipeline }; /*********************************************************************** */ static enum pipe_error update_need_swtnl( struct svga_context *svga, unsigned dirty ) { boolean need_swtnl; if (svga->debug.no_swtnl) { svga->state.sw.need_swvfetch = FALSE; svga->state.sw.need_pipeline = FALSE; } need_swtnl = (svga->state.sw.need_swvfetch || svga->state.sw.need_pipeline); if (svga->debug.force_swtnl) { need_swtnl = TRUE; } /* * Some state changes the draw module does makes us believe we * we don't need swtnl. This causes the vdecl code to pickup * the wrong buffers and vertex formats. Try trivial/line-wide. */ if (svga->state.sw.in_swtnl_draw) need_swtnl = TRUE; if (need_swtnl != svga->state.sw.need_swtnl) { SVGA_DBG(DEBUG_SWTNL|DEBUG_PERF, "%s: need_swvfetch %s, need_pipeline %s\n", __FUNCTION__, svga->state.sw.need_swvfetch ? "true" : "false", svga->state.sw.need_pipeline ? "true" : "false"); svga->state.sw.need_swtnl = need_swtnl; svga->dirty |= SVGA_NEW_NEED_SWTNL; svga->swtnl.new_vdecl = TRUE; } return 0; } struct svga_tracked_state svga_update_need_swtnl = { "need swtnl", (SVGA_NEW_NEED_PIPELINE | SVGA_NEW_NEED_SWVFETCH), update_need_swtnl };