1/********************************************************** 2 * Copyright 2008-2009 VMware, Inc. All rights reserved. 3 * 4 * Permission is hereby granted, free of charge, to any person 5 * obtaining a copy of this software and associated documentation 6 * files (the "Software"), to deal in the Software without 7 * restriction, including without limitation the rights to use, copy, 8 * modify, merge, publish, distribute, sublicense, and/or sell copies 9 * of the Software, and to permit persons to whom the Software is 10 * furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be 13 * included in all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 * SOFTWARE. 23 * 24 **********************************************************/ 25 26#include "util/u_inlines.h" 27#include "pipe/p_defines.h" 28#include "util/u_format.h" 29#include "util/u_math.h" 30#include "util/u_memory.h" 31#include "util/u_bitmask.h" 32#include "translate/translate.h" 33#include "tgsi/tgsi_ureg.h" 34 35#include "svga_context.h" 36#include "svga_state.h" 37#include "svga_cmd.h" 38#include "svga_tgsi.h" 39 40#include "svga_hw_reg.h" 41 42/*********************************************************************** 43 */ 44 45 46static INLINE int compare_vs_keys( const struct svga_vs_compile_key *a, 47 const struct svga_vs_compile_key *b ) 48{ 49 unsigned keysize = svga_vs_key_size( a ); 50 return memcmp( a, b, keysize ); 51} 52 53 54static struct svga_shader_result *search_vs_key( struct svga_vertex_shader *vs, 55 const struct svga_vs_compile_key *key ) 56{ 57 struct svga_shader_result *result = vs->base.results; 58 59 assert(key); 60 61 for ( ; result; result = result->next) { 62 if (compare_vs_keys( key, &result->key.vkey ) == 0) 63 return result; 64 } 65 66 return NULL; 67} 68 69 70/** 71 * If we fail to compile a vertex shader we'll use a dummy/fallback shader 72 * that simply emits a (0,0,0,1) vertex position. 73 */ 74static const struct tgsi_token * 75get_dummy_vertex_shader(void) 76{ 77 static const float zero[4] = { 0.0, 0.0, 0.0, 1.0 }; 78 struct ureg_program *ureg; 79 const struct tgsi_token *tokens; 80 struct ureg_src src; 81 struct ureg_dst dst; 82 unsigned num_tokens; 83 84 ureg = ureg_create(TGSI_PROCESSOR_VERTEX); 85 if (!ureg) 86 return NULL; 87 88 dst = ureg_DECL_output(ureg, TGSI_SEMANTIC_POSITION, 0); 89 src = ureg_DECL_immediate(ureg, zero, 4); 90 ureg_MOV(ureg, dst, src); 91 ureg_END(ureg); 92 93 tokens = ureg_get_tokens(ureg, &num_tokens); 94 95 ureg_destroy(ureg); 96 97 return tokens; 98} 99 100 101static enum pipe_error compile_vs( struct svga_context *svga, 102 struct svga_vertex_shader *vs, 103 const struct svga_vs_compile_key *key, 104 struct svga_shader_result **out_result ) 105{ 106 struct svga_shader_result *result; 107 enum pipe_error ret = PIPE_ERROR; 108 109 result = svga_translate_vertex_program( vs, key ); 110 if (result == NULL) { 111 /* some problem during translation, try the dummy shader */ 112 const struct tgsi_token *dummy = get_dummy_vertex_shader(); 113 if (!dummy) { 114 ret = PIPE_ERROR_OUT_OF_MEMORY; 115 goto fail; 116 } 117 debug_printf("Failed to compile vertex shader, using dummy shader instead.\n"); 118 FREE((void *) vs->base.tokens); 119 vs->base.tokens = dummy; 120 result = svga_translate_vertex_program(vs, key); 121 if (result == NULL) { 122 ret = PIPE_ERROR; 123 goto fail; 124 } 125 } 126 127 result->id = util_bitmask_add(svga->vs_bm); 128 if(result->id == UTIL_BITMASK_INVALID_INDEX) { 129 ret = PIPE_ERROR_OUT_OF_MEMORY; 130 goto fail; 131 } 132 133 ret = SVGA3D_DefineShader(svga->swc, 134 result->id, 135 SVGA3D_SHADERTYPE_VS, 136 result->tokens, 137 result->nr_tokens * sizeof result->tokens[0]); 138 if (ret != PIPE_OK) 139 goto fail; 140 141 *out_result = result; 142 result->next = vs->base.results; 143 vs->base.results = result; 144 return PIPE_OK; 145 146fail: 147 if (result) { 148 if (result->id != UTIL_BITMASK_INVALID_INDEX) 149 util_bitmask_clear( svga->vs_bm, result->id ); 150 svga_destroy_shader_result( result ); 151 } 152 return ret; 153} 154 155/* SVGA_NEW_PRESCALE, SVGA_NEW_RAST, SVGA_NEW_FS 156 */ 157static void 158make_vs_key(struct svga_context *svga, struct svga_vs_compile_key *key) 159{ 160 memset(key, 0, sizeof *key); 161 key->need_prescale = svga->state.hw_clear.prescale.enabled; 162 key->allow_psiz = svga->curr.rast->templ.point_size_per_vertex; 163 164 /* SVGA_NEW_FS */ 165 key->fs_generic_inputs = svga->curr.fs->generic_inputs; 166} 167 168 169 170static enum pipe_error 171emit_hw_vs(struct svga_context *svga, unsigned dirty) 172{ 173 struct svga_shader_result *result = NULL; 174 unsigned id = SVGA3D_INVALID_ID; 175 enum pipe_error ret = PIPE_OK; 176 177 /* SVGA_NEW_NEED_SWTNL */ 178 if (!svga->state.sw.need_swtnl) { 179 struct svga_vertex_shader *vs = svga->curr.vs; 180 struct svga_vs_compile_key key; 181 182 make_vs_key( svga, &key ); 183 184 result = search_vs_key( vs, &key ); 185 if (!result) { 186 ret = compile_vs( svga, vs, &key, &result ); 187 if (ret != PIPE_OK) 188 return ret; 189 } 190 191 assert (result); 192 id = result->id; 193 } 194 195 if (result != svga->state.hw_draw.vs) { 196 ret = SVGA3D_SetShader(svga->swc, 197 SVGA3D_SHADERTYPE_VS, 198 id ); 199 if (ret != PIPE_OK) 200 return ret; 201 202 svga->dirty |= SVGA_NEW_VS_RESULT; 203 svga->state.hw_draw.vs = result; 204 } 205 206 return PIPE_OK; 207} 208 209struct svga_tracked_state svga_hw_vs = 210{ 211 "vertex shader (hwtnl)", 212 (SVGA_NEW_VS | 213 SVGA_NEW_FS | 214 SVGA_NEW_PRESCALE | 215 SVGA_NEW_NEED_SWTNL), 216 emit_hw_vs 217}; 218