1/************************************************************************** 2 * 3 * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR 22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 **************************************************************************/ 27 28#include "sp_context.h" 29#include "sp_state.h" 30#include "sp_fs.h" 31#include "sp_texture.h" 32 33#include "pipe/p_defines.h" 34#include "util/u_memory.h" 35#include "util/u_inlines.h" 36#include "util/u_pstipple.h" 37#include "draw/draw_context.h" 38#include "draw/draw_vs.h" 39#include "draw/draw_gs.h" 40#include "tgsi/tgsi_dump.h" 41#include "tgsi/tgsi_scan.h" 42#include "tgsi/tgsi_parse.h" 43 44 45/** 46 * Create a new fragment shader variant. 47 */ 48static struct sp_fragment_shader_variant * 49create_fs_variant(struct softpipe_context *softpipe, 50 struct sp_fragment_shader *fs, 51 const struct sp_fragment_shader_variant_key *key) 52{ 53 struct sp_fragment_shader_variant *var; 54 struct pipe_shader_state *stipple_fs = NULL, *curfs = &fs->shader; 55 unsigned unit = 0; 56 57#if DO_PSTIPPLE_IN_HELPER_MODULE 58 if (key->polygon_stipple) { 59 /* get new shader that implements polygon stippling */ 60 stipple_fs = util_pstipple_create_fragment_shader(&softpipe->pipe, 61 curfs, &unit); 62 curfs = stipple_fs; 63 } 64#endif 65 66 /* codegen, create variant object */ 67 var = softpipe_create_fs_variant_exec(softpipe, curfs); 68 69 if (var) { 70 var->key = *key; 71 var->tokens = tgsi_dup_tokens(curfs->tokens); 72 var->stipple_sampler_unit = unit; 73 74 tgsi_scan_shader(var->tokens, &var->info); 75 76 /* See comments elsewhere about draw fragment shaders */ 77#if 0 78 /* draw's fs state */ 79 var->draw_shader = draw_create_fragment_shader(softpipe->draw, 80 &fs->shader); 81 if (!var->draw_shader) { 82 var->delete(var); 83 FREE((void *) var->tokens); 84 return NULL; 85 } 86#endif 87 88 /* insert variant into linked list */ 89 var->next = fs->variants; 90 fs->variants = var; 91 } 92 93 if (stipple_fs) { 94 FREE((void *) stipple_fs->tokens); 95 FREE(stipple_fs); 96 } 97 98 return var; 99} 100 101 102struct sp_fragment_shader_variant * 103softpipe_find_fs_variant(struct softpipe_context *sp, 104 struct sp_fragment_shader *fs, 105 const struct sp_fragment_shader_variant_key *key) 106{ 107 struct sp_fragment_shader_variant *var; 108 109 for (var = fs->variants; var; var = var->next) { 110 if (memcmp(&var->key, key, sizeof(*key)) == 0) { 111 /* found it */ 112 return var; 113 } 114 } 115 116 return create_fs_variant(sp, fs, key); 117} 118 119 120static void * 121softpipe_create_fs_state(struct pipe_context *pipe, 122 const struct pipe_shader_state *templ) 123{ 124 struct softpipe_context *softpipe = softpipe_context(pipe); 125 struct sp_fragment_shader *state = CALLOC_STRUCT(sp_fragment_shader); 126 127 /* debug */ 128 if (softpipe->dump_fs) 129 tgsi_dump(templ->tokens, 0); 130 131 /* we need to keep a local copy of the tokens */ 132 state->shader.tokens = tgsi_dup_tokens(templ->tokens); 133 134 /* draw's fs state */ 135 state->draw_shader = draw_create_fragment_shader(softpipe->draw, 136 &state->shader); 137 if (!state->draw_shader) { 138 FREE((void *) state->shader.tokens); 139 FREE(state); 140 return NULL; 141 } 142 143 return state; 144} 145 146 147static void 148softpipe_bind_fs_state(struct pipe_context *pipe, void *fs) 149{ 150 struct softpipe_context *softpipe = softpipe_context(pipe); 151 struct sp_fragment_shader *state = (struct sp_fragment_shader *) fs; 152 153 if (softpipe->fs == fs) 154 return; 155 156 draw_flush(softpipe->draw); 157 158 softpipe->fs = fs; 159 160 /* This depends on the current fragment shader and must always be 161 * re-validated before use. 162 */ 163 softpipe->fs_variant = NULL; 164 165 if (state) 166 draw_bind_fragment_shader(softpipe->draw, 167 state->draw_shader); 168 else 169 draw_bind_fragment_shader(softpipe->draw, NULL); 170 171 softpipe->dirty |= SP_NEW_FS; 172} 173 174 175static void 176softpipe_delete_fs_state(struct pipe_context *pipe, void *fs) 177{ 178 struct softpipe_context *softpipe = softpipe_context(pipe); 179 struct sp_fragment_shader *state = fs; 180 struct sp_fragment_shader_variant *var, *next_var; 181 182 assert(fs != softpipe->fs); 183 184 /* delete variants */ 185 for (var = state->variants; var; var = next_var) { 186 next_var = var->next; 187 188 assert(var != softpipe->fs_variant); 189 190 /* See comments elsewhere about draw fragment shaders */ 191#if 0 192 draw_delete_fragment_shader(softpipe->draw, var->draw_shader); 193#endif 194 195 var->delete(var, softpipe->fs_machine); 196 } 197 198 draw_delete_fragment_shader(softpipe->draw, state->draw_shader); 199 200 FREE((void *) state->shader.tokens); 201 FREE(state); 202} 203 204 205static void * 206softpipe_create_vs_state(struct pipe_context *pipe, 207 const struct pipe_shader_state *templ) 208{ 209 struct softpipe_context *softpipe = softpipe_context(pipe); 210 struct sp_vertex_shader *state; 211 212 state = CALLOC_STRUCT(sp_vertex_shader); 213 if (state == NULL ) 214 goto fail; 215 216 /* copy shader tokens, the ones passed in will go away. 217 */ 218 state->shader.tokens = tgsi_dup_tokens(templ->tokens); 219 if (state->shader.tokens == NULL) 220 goto fail; 221 222 state->draw_data = draw_create_vertex_shader(softpipe->draw, templ); 223 if (state->draw_data == NULL) 224 goto fail; 225 226 state->max_sampler = state->draw_data->info.file_max[TGSI_FILE_SAMPLER]; 227 228 return state; 229 230fail: 231 if (state) { 232 FREE( (void *)state->shader.tokens ); 233 FREE( state->draw_data ); 234 FREE( state ); 235 } 236 return NULL; 237} 238 239 240static void 241softpipe_bind_vs_state(struct pipe_context *pipe, void *vs) 242{ 243 struct softpipe_context *softpipe = softpipe_context(pipe); 244 245 softpipe->vs = (struct sp_vertex_shader *) vs; 246 247 draw_bind_vertex_shader(softpipe->draw, 248 (softpipe->vs ? softpipe->vs->draw_data : NULL)); 249 250 softpipe->dirty |= SP_NEW_VS; 251} 252 253 254static void 255softpipe_delete_vs_state(struct pipe_context *pipe, void *vs) 256{ 257 struct softpipe_context *softpipe = softpipe_context(pipe); 258 259 struct sp_vertex_shader *state = (struct sp_vertex_shader *) vs; 260 261 draw_delete_vertex_shader(softpipe->draw, state->draw_data); 262 FREE( (void *)state->shader.tokens ); 263 FREE( state ); 264} 265 266 267static void * 268softpipe_create_gs_state(struct pipe_context *pipe, 269 const struct pipe_shader_state *templ) 270{ 271 struct softpipe_context *softpipe = softpipe_context(pipe); 272 struct sp_geometry_shader *state; 273 274 state = CALLOC_STRUCT(sp_geometry_shader); 275 if (state == NULL ) 276 goto fail; 277 278 /* debug */ 279 if (softpipe->dump_gs) 280 tgsi_dump(templ->tokens, 0); 281 282 /* copy shader tokens, the ones passed in will go away. 283 */ 284 state->shader.tokens = tgsi_dup_tokens(templ->tokens); 285 if (state->shader.tokens == NULL) 286 goto fail; 287 288 state->draw_data = draw_create_geometry_shader(softpipe->draw, templ); 289 if (state->draw_data == NULL) 290 goto fail; 291 292 state->max_sampler = state->draw_data->info.file_max[TGSI_FILE_SAMPLER]; 293 294 return state; 295 296fail: 297 if (state) { 298 FREE( (void *)state->shader.tokens ); 299 FREE( state->draw_data ); 300 FREE( state ); 301 } 302 return NULL; 303} 304 305 306static void 307softpipe_bind_gs_state(struct pipe_context *pipe, void *gs) 308{ 309 struct softpipe_context *softpipe = softpipe_context(pipe); 310 311 softpipe->gs = (struct sp_geometry_shader *)gs; 312 313 draw_bind_geometry_shader(softpipe->draw, 314 (softpipe->gs ? softpipe->gs->draw_data : NULL)); 315 316 softpipe->dirty |= SP_NEW_GS; 317} 318 319 320static void 321softpipe_delete_gs_state(struct pipe_context *pipe, void *gs) 322{ 323 struct softpipe_context *softpipe = softpipe_context(pipe); 324 325 struct sp_geometry_shader *state = 326 (struct sp_geometry_shader *)gs; 327 328 draw_delete_geometry_shader(softpipe->draw, 329 (state) ? state->draw_data : 0); 330 331 FREE((void *) state->shader.tokens); 332 FREE(state); 333} 334 335 336static void 337softpipe_set_constant_buffer(struct pipe_context *pipe, 338 uint shader, uint index, 339 struct pipe_constant_buffer *cb) 340{ 341 struct softpipe_context *softpipe = softpipe_context(pipe); 342 struct pipe_resource *constants = cb ? cb->buffer : NULL; 343 unsigned size; 344 const void *data; 345 346 if (cb && cb->user_buffer) { 347 constants = softpipe_user_buffer_create(pipe->screen, 348 (void *) cb->user_buffer, 349 cb->buffer_size, 350 PIPE_BIND_CONSTANT_BUFFER); 351 } 352 353 size = constants ? constants->width0 : 0; 354 data = constants ? softpipe_resource(constants)->data : NULL; 355 356 assert(shader < PIPE_SHADER_TYPES); 357 358 draw_flush(softpipe->draw); 359 360 /* note: reference counting */ 361 pipe_resource_reference(&softpipe->constants[shader][index], constants); 362 363 if (shader == PIPE_SHADER_VERTEX || shader == PIPE_SHADER_GEOMETRY) { 364 draw_set_mapped_constant_buffer(softpipe->draw, shader, index, data, size); 365 } 366 367 softpipe->mapped_constants[shader][index] = data; 368 softpipe->const_buffer_size[shader][index] = size; 369 370 softpipe->dirty |= SP_NEW_CONSTANTS; 371 372 if (cb && cb->user_buffer) { 373 pipe_resource_reference(&constants, NULL); 374 } 375} 376 377 378void 379softpipe_init_shader_funcs(struct pipe_context *pipe) 380{ 381 pipe->create_fs_state = softpipe_create_fs_state; 382 pipe->bind_fs_state = softpipe_bind_fs_state; 383 pipe->delete_fs_state = softpipe_delete_fs_state; 384 385 pipe->create_vs_state = softpipe_create_vs_state; 386 pipe->bind_vs_state = softpipe_bind_vs_state; 387 pipe->delete_vs_state = softpipe_delete_vs_state; 388 389 pipe->create_gs_state = softpipe_create_gs_state; 390 pipe->bind_gs_state = softpipe_bind_gs_state; 391 pipe->delete_gs_state = softpipe_delete_gs_state; 392 393 pipe->set_constant_buffer = softpipe_set_constant_buffer; 394} 395