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 29 #include "svga_screen.h" 30 #include "svga_context.h" 31 #include "svga_state.h" 32 #include "svga_cmd.h" 33 #include "svga_tgsi.h" 34 #include "svga_debug.h" 35 36 #include "svga_hw_reg.h" 37 38 39 /* 40 * Don't try to send more than 4kb of successive constants. 41 */ 42 #define MAX_CONST_REG_COUNT 256 /**< number of float[4] constants */ 43 44 45 46 /** 47 * Convert from PIPE_SHADER_* to SVGA3D_SHADERTYPE_* 48 */ 49 static int 50 svga_shader_type(unsigned shader) 51 { 52 assert(PIPE_SHADER_VERTEX + 1 == SVGA3D_SHADERTYPE_VS); 53 assert(PIPE_SHADER_FRAGMENT + 1 == SVGA3D_SHADERTYPE_PS); 54 assert(shader <= PIPE_SHADER_FRAGMENT); 55 return shader + 1; 56 } 57 58 59 /** 60 * Check and emit one shader constant register. 61 * \param shader PIPE_SHADER_FRAGMENT or PIPE_SHADER_VERTEX 62 * \param i which float[4] constant to change 63 * \param value the new float[4] value 64 */ 65 static enum pipe_error 66 emit_const(struct svga_context *svga, unsigned shader, unsigned i, 67 const float *value) 68 { 69 enum pipe_error ret = PIPE_OK; 70 71 assert(shader < PIPE_SHADER_TYPES); 72 assert(i < SVGA3D_CONSTREG_MAX); 73 74 if (memcmp(svga->state.hw_draw.cb[shader][i], value, 75 4 * sizeof(float)) != 0) { 76 if (SVGA_DEBUG & DEBUG_CONSTS) 77 debug_printf("%s %s %u: %f %f %f %f\n", 78 __FUNCTION__, 79 shader == PIPE_SHADER_VERTEX ? "VERT" : "FRAG", 80 i, 81 value[0], 82 value[1], 83 value[2], 84 value[3]); 85 86 ret = SVGA3D_SetShaderConst( svga->swc, 87 i, 88 svga_shader_type(shader), 89 SVGA3D_CONST_TYPE_FLOAT, 90 value ); 91 if (ret != PIPE_OK) 92 return ret; 93 94 memcpy(svga->state.hw_draw.cb[shader][i], value, 4 * sizeof(float)); 95 } 96 97 return ret; 98 } 99 100 101 /* 102 * Check and emit a range of shader constant registers, trying to coalesce 103 * successive shader constant updates in a single command in order to save 104 * space on the command buffer. This is a HWv8 feature. 105 */ 106 static enum pipe_error 107 emit_const_range(struct svga_context *svga, 108 unsigned shader, 109 unsigned offset, 110 unsigned count, 111 const float (*values)[4]) 112 { 113 unsigned i, j; 114 enum pipe_error ret; 115 116 #ifdef DEBUG 117 if (offset + count > SVGA3D_CONSTREG_MAX) { 118 debug_printf("svga: too many constants (offset + count = %u)\n", 119 offset + count); 120 } 121 #endif 122 123 if (offset > SVGA3D_CONSTREG_MAX) { 124 /* This isn't OK, but if we propagate an error all the way up we'll 125 * just get into more trouble. 126 * XXX note that offset is always zero at this time so this is moot. 127 */ 128 return PIPE_OK; 129 } 130 131 if (offset + count > SVGA3D_CONSTREG_MAX) { 132 /* Just drop the extra constants for now. 133 * Ideally we should not have allowed the app to create a shader 134 * that exceeds our constant buffer size but there's no way to 135 * express that in gallium at this time. 136 */ 137 count = SVGA3D_CONSTREG_MAX - offset; 138 } 139 140 i = 0; 141 while (i < count) { 142 if (memcmp(svga->state.hw_draw.cb[shader][offset + i], 143 values[i], 144 4 * sizeof(float)) != 0) { 145 /* Found one dirty constant 146 */ 147 if (SVGA_DEBUG & DEBUG_CONSTS) 148 debug_printf("%s %s %d: %f %f %f %f\n", 149 __FUNCTION__, 150 shader == PIPE_SHADER_VERTEX ? "VERT" : "FRAG", 151 offset + i, 152 values[i][0], 153 values[i][1], 154 values[i][2], 155 values[i][3]); 156 157 /* Look for more consecutive dirty constants. 158 */ 159 j = i + 1; 160 while (j < count && 161 j < i + MAX_CONST_REG_COUNT && 162 memcmp(svga->state.hw_draw.cb[shader][offset + j], 163 values[j], 164 4 * sizeof(float)) != 0) { 165 166 if (SVGA_DEBUG & DEBUG_CONSTS) 167 debug_printf("%s %s %d: %f %f %f %f\n", 168 __FUNCTION__, 169 shader == PIPE_SHADER_VERTEX ? "VERT" : "FRAG", 170 offset + j, 171 values[j][0], 172 values[j][1], 173 values[j][2], 174 values[j][3]); 175 176 ++j; 177 } 178 179 assert(j >= i + 1); 180 181 /* Send them all together. 182 */ 183 ret = SVGA3D_SetShaderConsts(svga->swc, 184 offset + i, j - i, 185 svga_shader_type(shader), 186 SVGA3D_CONST_TYPE_FLOAT, 187 values + i); 188 if (ret != PIPE_OK) { 189 return ret; 190 } 191 192 /* 193 * Local copy of the hardware state. 194 */ 195 memcpy(svga->state.hw_draw.cb[shader][offset + i], 196 values[i], 197 (j - i) * 4 * sizeof(float)); 198 199 i = j + 1; 200 } else { 201 ++i; 202 } 203 } 204 205 return PIPE_OK; 206 } 207 208 209 /** 210 * Emit all the constants in a constant buffer for a shader stage. 211 */ 212 static enum pipe_error 213 emit_consts(struct svga_context *svga, unsigned shader) 214 { 215 struct svga_screen *ss = svga_screen(svga->pipe.screen); 216 struct pipe_transfer *transfer = NULL; 217 unsigned count; 218 const float (*data)[4] = NULL; 219 unsigned i; 220 enum pipe_error ret = PIPE_OK; 221 const unsigned offset = 0; 222 223 assert(shader < PIPE_SHADER_TYPES); 224 225 if (svga->curr.cb[shader] == NULL) 226 goto done; 227 228 count = svga->curr.cb[shader]->width0 / (4 * sizeof(float)); 229 230 data = (const float (*)[4])pipe_buffer_map(&svga->pipe, 231 svga->curr.cb[shader], 232 PIPE_TRANSFER_READ, 233 &transfer); 234 if (data == NULL) { 235 ret = PIPE_ERROR_OUT_OF_MEMORY; 236 goto done; 237 } 238 239 if (ss->hw_version >= SVGA3D_HWVERSION_WS8_B1) { 240 ret = emit_const_range( svga, shader, offset, count, data ); 241 if (ret != PIPE_OK) { 242 goto done; 243 } 244 } else { 245 for (i = 0; i < count; i++) { 246 ret = emit_const( svga, shader, offset + i, data[i] ); 247 if (ret != PIPE_OK) { 248 goto done; 249 } 250 } 251 } 252 253 done: 254 if (data) 255 pipe_buffer_unmap(&svga->pipe, transfer); 256 257 return ret; 258 } 259 260 261 static enum pipe_error 262 emit_fs_consts(struct svga_context *svga, unsigned dirty) 263 { 264 const struct svga_shader_result *result = svga->state.hw_draw.fs; 265 enum pipe_error ret = PIPE_OK; 266 267 ret = emit_consts( svga, PIPE_SHADER_FRAGMENT ); 268 if (ret != PIPE_OK) 269 return ret; 270 271 /* The internally generated fragment shader for xor blending 272 * doesn't have a 'result' struct. It should be fixed to avoid 273 * this special case, but work around it with a NULL check: 274 */ 275 if (result) { 276 const struct svga_fs_compile_key *key = &result->key.fkey; 277 if (key->num_unnormalized_coords) { 278 const unsigned offset = 279 result->shader->info.file_max[TGSI_FILE_CONSTANT] + 1; 280 unsigned i; 281 282 for (i = 0; i < key->num_textures; i++) { 283 if (key->tex[i].unnormalized) { 284 struct pipe_resource *tex = svga->curr.sampler_views[i]->texture; 285 float data[4]; 286 287 data[0] = 1.0f / (float) tex->width0; 288 data[1] = 1.0f / (float) tex->height0; 289 data[2] = 1.0f; 290 data[3] = 1.0f; 291 292 ret = emit_const(svga, 293 PIPE_SHADER_FRAGMENT, 294 key->tex[i].width_height_idx + offset, 295 data); 296 if (ret != PIPE_OK) { 297 return ret; 298 } 299 } 300 } 301 } 302 } 303 304 return PIPE_OK; 305 } 306 307 308 struct svga_tracked_state svga_hw_fs_constants = 309 { 310 "hw fs params", 311 (SVGA_NEW_FS_CONST_BUFFER | 312 SVGA_NEW_FS_RESULT | 313 SVGA_NEW_TEXTURE_BINDING), 314 emit_fs_consts 315 }; 316 317 318 319 static enum pipe_error 320 emit_vs_consts(struct svga_context *svga, unsigned dirty) 321 { 322 const struct svga_shader_result *result = svga->state.hw_draw.vs; 323 const struct svga_vs_compile_key *key; 324 enum pipe_error ret = PIPE_OK; 325 unsigned offset; 326 327 /* SVGA_NEW_VS_RESULT 328 */ 329 if (result == NULL) 330 return PIPE_OK; 331 332 key = &result->key.vkey; 333 334 /* SVGA_NEW_VS_CONST_BUFFER 335 */ 336 ret = emit_consts( svga, PIPE_SHADER_VERTEX ); 337 if (ret != PIPE_OK) 338 return ret; 339 340 /* offset = number of constants in the VS const buffer */ 341 offset = result->shader->info.file_max[TGSI_FILE_CONSTANT] + 1; 342 343 /* SVGA_NEW_VS_PRESCALE 344 * Put the viewport pre-scale/translate values into the const buffer. 345 */ 346 if (key->need_prescale) { 347 ret = emit_const( svga, PIPE_SHADER_VERTEX, offset++, 348 svga->state.hw_clear.prescale.scale ); 349 if (ret != PIPE_OK) 350 return ret; 351 352 ret = emit_const( svga, PIPE_SHADER_VERTEX, offset++, 353 svga->state.hw_clear.prescale.translate ); 354 if (ret != PIPE_OK) 355 return ret; 356 } 357 358 return PIPE_OK; 359 } 360 361 362 struct svga_tracked_state svga_hw_vs_constants = 363 { 364 "hw vs params", 365 (SVGA_NEW_PRESCALE | 366 SVGA_NEW_VS_CONST_BUFFER | 367 SVGA_NEW_VS_RESULT), 368 emit_vs_consts 369 }; 370