1/************************************************************************** 2 * 3 * Copyright 2008 VMware, Inc. 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 VMWARE 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/** 29 * Polygon stipple stage: implement polygon stipple with texture map and 30 * fragment program. The fragment program samples the texture using the 31 * fragment window coordinate register and does a fragment kill for the 32 * stipple-failing fragments. 33 * 34 * Authors: Brian Paul 35 */ 36 37 38#include "pipe/p_context.h" 39#include "pipe/p_defines.h" 40#include "pipe/p_shader_tokens.h" 41#include "util/u_inlines.h" 42 43#include "util/format/u_format.h" 44#include "util/u_math.h" 45#include "util/u_memory.h" 46#include "util/u_pstipple.h" 47#include "util/u_sampler.h" 48 49#include "tgsi/tgsi_transform.h" 50 51#include "draw_context.h" 52#include "draw_pipe.h" 53 54#include "nir.h" 55#include "nir/nir_draw_helpers.h" 56 57/** Approx number of new tokens for instructions in pstip_transform_inst() */ 58#define NUM_NEW_TOKENS 53 59 60 61/** 62 * Subclass of pipe_shader_state to carry extra fragment shader info. 63 */ 64struct pstip_fragment_shader 65{ 66 struct pipe_shader_state state; 67 void *driver_fs; 68 void *pstip_fs; 69 uint sampler_unit; 70}; 71 72 73/** 74 * Subclass of draw_stage 75 */ 76struct pstip_stage 77{ 78 struct draw_stage stage; 79 80 void *sampler_cso; 81 struct pipe_resource *texture; 82 struct pipe_sampler_view *sampler_view; 83 uint num_samplers; 84 uint num_sampler_views; 85 86 /* 87 * Currently bound state 88 */ 89 struct pstip_fragment_shader *fs; 90 struct { 91 void *samplers[PIPE_MAX_SAMPLERS]; 92 struct pipe_sampler_view *sampler_views[PIPE_MAX_SHADER_SAMPLER_VIEWS]; 93 const struct pipe_poly_stipple *stipple; 94 } state; 95 96 /* 97 * Driver interface/override functions 98 */ 99 void * (*driver_create_fs_state)(struct pipe_context *, 100 const struct pipe_shader_state *); 101 void (*driver_bind_fs_state)(struct pipe_context *, void *); 102 void (*driver_delete_fs_state)(struct pipe_context *, void *); 103 104 void (*driver_bind_sampler_states)(struct pipe_context *, 105 enum pipe_shader_type, 106 unsigned, unsigned, void **); 107 108 void (*driver_set_sampler_views)(struct pipe_context *, 109 enum pipe_shader_type shader, 110 unsigned start, unsigned count, 111 unsigned unbind_num_trailing_slots, 112 bool take_ownership, 113 struct pipe_sampler_view **); 114 115 void (*driver_set_polygon_stipple)(struct pipe_context *, 116 const struct pipe_poly_stipple *); 117 118 struct pipe_context *pipe; 119}; 120 121 122/** 123 * Generate the frag shader we'll use for doing polygon stipple. 124 * This will be the user's shader prefixed with a TEX and KIL instruction. 125 */ 126static boolean 127generate_pstip_fs(struct pstip_stage *pstip) 128{ 129 struct pipe_context *pipe = pstip->pipe; 130 struct pipe_screen *screen = pipe->screen; 131 const struct pipe_shader_state *orig_fs = &pstip->fs->state; 132 /*struct draw_context *draw = pstip->stage.draw;*/ 133 struct pipe_shader_state pstip_fs; 134 enum tgsi_file_type wincoord_file; 135 136 wincoord_file = screen->get_param(screen, PIPE_CAP_TGSI_FS_POSITION_IS_SYSVAL) ? 137 TGSI_FILE_SYSTEM_VALUE : TGSI_FILE_INPUT; 138 139 pstip_fs = *orig_fs; /* copy to init */ 140 if (orig_fs->type == PIPE_SHADER_IR_TGSI) { 141 pstip_fs.tokens = util_pstipple_create_fragment_shader(orig_fs->tokens, 142 &pstip->fs->sampler_unit, 143 0, 144 wincoord_file); 145 if (pstip_fs.tokens == NULL) 146 return FALSE; 147 } else { 148 pstip_fs.ir.nir = nir_shader_clone(NULL, orig_fs->ir.nir); 149 nir_lower_pstipple_fs(pstip_fs.ir.nir, 150 &pstip->fs->sampler_unit, 0, wincoord_file == TGSI_FILE_SYSTEM_VALUE); 151 } 152 153 assert(pstip->fs->sampler_unit < PIPE_MAX_SAMPLERS); 154 155 pstip->fs->pstip_fs = pstip->driver_create_fs_state(pipe, &pstip_fs); 156 157 FREE((void *)pstip_fs.tokens); 158 159 if (!pstip->fs->pstip_fs) 160 return FALSE; 161 162 return TRUE; 163} 164 165 166/** 167 * When we're about to draw our first stipple polygon in a batch, this function 168 * is called to tell the driver to bind our modified fragment shader. 169 */ 170static boolean 171bind_pstip_fragment_shader(struct pstip_stage *pstip) 172{ 173 struct draw_context *draw = pstip->stage.draw; 174 if (!pstip->fs->pstip_fs && 175 !generate_pstip_fs(pstip)) 176 return FALSE; 177 178 draw->suspend_flushing = TRUE; 179 pstip->driver_bind_fs_state(pstip->pipe, pstip->fs->pstip_fs); 180 draw->suspend_flushing = FALSE; 181 return TRUE; 182} 183 184 185static inline struct pstip_stage * 186pstip_stage( struct draw_stage *stage ) 187{ 188 return (struct pstip_stage *) stage; 189} 190 191 192static void 193pstip_first_tri(struct draw_stage *stage, struct prim_header *header) 194{ 195 struct pstip_stage *pstip = pstip_stage(stage); 196 struct pipe_context *pipe = pstip->pipe; 197 struct draw_context *draw = stage->draw; 198 uint num_samplers; 199 uint num_sampler_views; 200 201 assert(stage->draw->rasterizer->poly_stipple_enable); 202 203 /* bind our fragprog */ 204 if (!bind_pstip_fragment_shader(pstip)) { 205 stage->tri = draw_pipe_passthrough_tri; 206 stage->tri(stage, header); 207 return; 208 } 209 210 /* how many samplers? */ 211 /* we'll use sampler/texture[pstip->sampler_unit] for the stipple */ 212 num_samplers = MAX2(pstip->num_samplers, pstip->fs->sampler_unit + 1); 213 num_sampler_views = MAX2(pstip->num_sampler_views, num_samplers); 214 215 /* plug in our sampler, texture */ 216 pstip->state.samplers[pstip->fs->sampler_unit] = pstip->sampler_cso; 217 pipe_sampler_view_reference(&pstip->state.sampler_views[pstip->fs->sampler_unit], 218 pstip->sampler_view); 219 220 assert(num_samplers <= PIPE_MAX_SAMPLERS); 221 222 draw->suspend_flushing = TRUE; 223 224 pstip->driver_bind_sampler_states(pipe, PIPE_SHADER_FRAGMENT, 0, 225 num_samplers, pstip->state.samplers); 226 227 pstip->driver_set_sampler_views(pipe, PIPE_SHADER_FRAGMENT, 0, 228 num_sampler_views, 0, false, 229 pstip->state.sampler_views); 230 231 draw->suspend_flushing = FALSE; 232 233 /* now really draw first triangle */ 234 stage->tri = draw_pipe_passthrough_tri; 235 stage->tri(stage, header); 236} 237 238 239static void 240pstip_flush(struct draw_stage *stage, unsigned flags) 241{ 242 struct draw_context *draw = stage->draw; 243 struct pstip_stage *pstip = pstip_stage(stage); 244 struct pipe_context *pipe = pstip->pipe; 245 246 stage->tri = pstip_first_tri; 247 stage->next->flush( stage->next, flags ); 248 249 /* restore original frag shader, texture, sampler state */ 250 draw->suspend_flushing = TRUE; 251 pstip->driver_bind_fs_state(pipe, pstip->fs ? pstip->fs->driver_fs : NULL); 252 253 pstip->driver_bind_sampler_states(pipe, PIPE_SHADER_FRAGMENT, 0, 254 pstip->num_samplers, 255 pstip->state.samplers); 256 257 pstip->driver_set_sampler_views(pipe, PIPE_SHADER_FRAGMENT, 0, 258 pstip->num_sampler_views, 0, false, 259 pstip->state.sampler_views); 260 261 draw->suspend_flushing = FALSE; 262} 263 264 265static void 266pstip_reset_stipple_counter(struct draw_stage *stage) 267{ 268 stage->next->reset_stipple_counter( stage->next ); 269} 270 271 272static void 273pstip_destroy(struct draw_stage *stage) 274{ 275 struct pstip_stage *pstip = pstip_stage(stage); 276 uint i; 277 278 for (i = 0; i < PIPE_MAX_SHADER_SAMPLER_VIEWS; i++) { 279 pipe_sampler_view_reference(&pstip->state.sampler_views[i], NULL); 280 } 281 282 pstip->pipe->delete_sampler_state(pstip->pipe, pstip->sampler_cso); 283 284 pipe_resource_reference(&pstip->texture, NULL); 285 286 if (pstip->sampler_view) { 287 pipe_sampler_view_reference(&pstip->sampler_view, NULL); 288 } 289 290 draw_free_temp_verts( stage ); 291 FREE( stage ); 292} 293 294 295/** Create a new polygon stipple drawing stage object */ 296static struct pstip_stage * 297draw_pstip_stage(struct draw_context *draw, struct pipe_context *pipe) 298{ 299 struct pstip_stage *pstip = CALLOC_STRUCT(pstip_stage); 300 if (!pstip) 301 goto fail; 302 303 pstip->pipe = pipe; 304 305 pstip->stage.draw = draw; 306 pstip->stage.name = "pstip"; 307 pstip->stage.next = NULL; 308 pstip->stage.point = draw_pipe_passthrough_point; 309 pstip->stage.line = draw_pipe_passthrough_line; 310 pstip->stage.tri = pstip_first_tri; 311 pstip->stage.flush = pstip_flush; 312 pstip->stage.reset_stipple_counter = pstip_reset_stipple_counter; 313 pstip->stage.destroy = pstip_destroy; 314 315 if (!draw_alloc_temp_verts( &pstip->stage, 8 )) 316 goto fail; 317 318 return pstip; 319 320fail: 321 if (pstip) 322 pstip->stage.destroy( &pstip->stage ); 323 324 return NULL; 325} 326 327 328static struct pstip_stage * 329pstip_stage_from_pipe(struct pipe_context *pipe) 330{ 331 struct draw_context *draw = (struct draw_context *) pipe->draw; 332 return pstip_stage(draw->pipeline.pstipple); 333} 334 335 336/** 337 * This function overrides the driver's create_fs_state() function and 338 * will typically be called by the gallium frontend. 339 */ 340static void * 341pstip_create_fs_state(struct pipe_context *pipe, 342 const struct pipe_shader_state *fs) 343{ 344 struct pstip_stage *pstip = pstip_stage_from_pipe(pipe); 345 struct pstip_fragment_shader *pstipfs = CALLOC_STRUCT(pstip_fragment_shader); 346 347 if (pstipfs) { 348 pstipfs->state.type = fs->type; 349 if (fs->type == PIPE_SHADER_IR_TGSI) 350 pstipfs->state.tokens = tgsi_dup_tokens(fs->tokens); 351 else 352 pstipfs->state.ir.nir = nir_shader_clone(NULL, fs->ir.nir); 353 354 /* pass-through */ 355 pstipfs->driver_fs = pstip->driver_create_fs_state(pstip->pipe, fs); 356 } 357 358 return pstipfs; 359} 360 361 362static void 363pstip_bind_fs_state(struct pipe_context *pipe, void *fs) 364{ 365 struct pstip_stage *pstip = pstip_stage_from_pipe(pipe); 366 struct pstip_fragment_shader *pstipfs = (struct pstip_fragment_shader *) fs; 367 /* save current */ 368 pstip->fs = pstipfs; 369 /* pass-through */ 370 pstip->driver_bind_fs_state(pstip->pipe, 371 (pstipfs ? pstipfs->driver_fs : NULL)); 372} 373 374 375static void 376pstip_delete_fs_state(struct pipe_context *pipe, void *fs) 377{ 378 struct pstip_stage *pstip = pstip_stage_from_pipe(pipe); 379 struct pstip_fragment_shader *pstipfs = (struct pstip_fragment_shader *) fs; 380 /* pass-through */ 381 pstip->driver_delete_fs_state(pstip->pipe, pstipfs->driver_fs); 382 383 if (pstipfs->pstip_fs) 384 pstip->driver_delete_fs_state(pstip->pipe, pstipfs->pstip_fs); 385 386 if (pstipfs->state.type == PIPE_SHADER_IR_TGSI) 387 FREE((void*)pstipfs->state.tokens); 388 else 389 ralloc_free(pstipfs->state.ir.nir); 390 FREE(pstipfs); 391} 392 393 394static void 395pstip_bind_sampler_states(struct pipe_context *pipe, 396 enum pipe_shader_type shader, 397 unsigned start, unsigned num, void **sampler) 398{ 399 struct pstip_stage *pstip = pstip_stage_from_pipe(pipe); 400 uint i; 401 402 assert(start == 0); 403 404 if (shader == PIPE_SHADER_FRAGMENT) { 405 /* save current */ 406 memcpy(pstip->state.samplers, sampler, num * sizeof(void *)); 407 for (i = num; i < PIPE_MAX_SAMPLERS; i++) { 408 pstip->state.samplers[i] = NULL; 409 } 410 pstip->num_samplers = num; 411 } 412 413 /* pass-through */ 414 pstip->driver_bind_sampler_states(pstip->pipe, shader, start, num, sampler); 415} 416 417 418static void 419pstip_set_sampler_views(struct pipe_context *pipe, 420 enum pipe_shader_type shader, 421 unsigned start, unsigned num, 422 unsigned unbind_num_trailing_slots, 423 bool take_ownership, 424 struct pipe_sampler_view **views) 425{ 426 struct pstip_stage *pstip = pstip_stage_from_pipe(pipe); 427 uint i; 428 429 if (shader == PIPE_SHADER_FRAGMENT) { 430 /* save current */ 431 for (i = 0; i < num; i++) { 432 pipe_sampler_view_reference(&pstip->state.sampler_views[start + i], 433 views[i]); 434 } 435 for (; i < num + unbind_num_trailing_slots; i++) { 436 pipe_sampler_view_reference(&pstip->state.sampler_views[start + i], 437 NULL); 438 } 439 pstip->num_sampler_views = num; 440 } 441 442 /* pass-through */ 443 pstip->driver_set_sampler_views(pstip->pipe, shader, start, num, 444 unbind_num_trailing_slots, take_ownership, views); 445} 446 447 448static void 449pstip_set_polygon_stipple(struct pipe_context *pipe, 450 const struct pipe_poly_stipple *stipple) 451{ 452 struct pstip_stage *pstip = pstip_stage_from_pipe(pipe); 453 454 /* save current */ 455 pstip->state.stipple = stipple; 456 457 /* pass-through */ 458 pstip->driver_set_polygon_stipple(pstip->pipe, stipple); 459 460 util_pstipple_update_stipple_texture(pstip->pipe, pstip->texture, 461 pstip->state.stipple->stipple); 462} 463 464 465/** 466 * Called by drivers that want to install this polygon stipple stage 467 * into the draw module's pipeline. This will not be used if the 468 * hardware has native support for polygon stipple. 469 */ 470boolean 471draw_install_pstipple_stage(struct draw_context *draw, 472 struct pipe_context *pipe) 473{ 474 struct pstip_stage *pstip; 475 476 pipe->draw = (void *) draw; 477 478 /* 479 * Create / install pgon stipple drawing / prim stage 480 */ 481 pstip = draw_pstip_stage( draw, pipe ); 482 if (!pstip) 483 goto fail; 484 485 draw->pipeline.pstipple = &pstip->stage; 486 487 /* save original driver functions */ 488 pstip->driver_create_fs_state = pipe->create_fs_state; 489 pstip->driver_bind_fs_state = pipe->bind_fs_state; 490 pstip->driver_delete_fs_state = pipe->delete_fs_state; 491 492 pstip->driver_bind_sampler_states = pipe->bind_sampler_states; 493 pstip->driver_set_sampler_views = pipe->set_sampler_views; 494 pstip->driver_set_polygon_stipple = pipe->set_polygon_stipple; 495 496 /* create special texture, sampler state */ 497 pstip->texture = util_pstipple_create_stipple_texture(pipe, NULL); 498 if (!pstip->texture) 499 goto fail; 500 501 pstip->sampler_view = util_pstipple_create_sampler_view(pipe, 502 pstip->texture); 503 if (!pstip->sampler_view) 504 goto fail; 505 506 pstip->sampler_cso = util_pstipple_create_sampler(pipe); 507 if (!pstip->sampler_cso) 508 goto fail; 509 510 /* override the driver's functions */ 511 pipe->create_fs_state = pstip_create_fs_state; 512 pipe->bind_fs_state = pstip_bind_fs_state; 513 pipe->delete_fs_state = pstip_delete_fs_state; 514 515 pipe->bind_sampler_states = pstip_bind_sampler_states; 516 pipe->set_sampler_views = pstip_set_sampler_views; 517 pipe->set_polygon_stipple = pstip_set_polygon_stipple; 518 519 return TRUE; 520 521 fail: 522 if (pstip) 523 pstip->stage.destroy( &pstip->stage ); 524 525 return FALSE; 526} 527