draw_pt_fetch_shade_pipeline.c revision a08e348a84f57ed5e8bf5888f1ce13934d2ce8fa
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 "util/u_math.h" 29#include "util/u_memory.h" 30#include "draw/draw_context.h" 31#include "draw/draw_vbuf.h" 32#include "draw/draw_vertex.h" 33#include "draw/draw_pt.h" 34#include "draw/draw_vs.h" 35#include "translate/translate.h" 36 37 38struct fetch_pipeline_middle_end { 39 struct draw_pt_middle_end base; 40 struct draw_context *draw; 41 42 struct pt_emit *emit; 43 struct pt_fetch *fetch; 44 struct pt_post_vs *post_vs; 45 46 unsigned vertex_data_offset; 47 unsigned vertex_size; 48 unsigned prim; 49 unsigned opt; 50}; 51 52 53static void fetch_pipeline_prepare( struct draw_pt_middle_end *middle, 54 unsigned prim, 55 unsigned opt, 56 unsigned *max_vertices ) 57{ 58 struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle; 59 struct draw_context *draw = fpme->draw; 60 struct draw_vertex_shader *vs = draw->vs.vertex_shader; 61 62 /* Add one to num_outputs because the pipeline occasionally tags on 63 * an additional texcoord, eg for AA lines. 64 */ 65 unsigned nr = MAX2( vs->info.num_inputs, 66 vs->info.num_outputs + 1 ); 67 68 fpme->prim = prim; 69 fpme->opt = opt; 70 71 /* Always leave room for the vertex header whether we need it or 72 * not. It's hard to get rid of it in particular because of the 73 * viewport code in draw_pt_post_vs.c. 74 */ 75 fpme->vertex_size = sizeof(struct vertex_header) + nr * 4 * sizeof(float); 76 77 78 79 draw_pt_fetch_prepare( fpme->fetch, 80 vs->info.num_inputs, 81 fpme->vertex_size ); 82 /* XXX: it's not really gl rasterization rules we care about here, 83 * but gl vs dx9 clip spaces. 84 */ 85 draw_pt_post_vs_prepare( fpme->post_vs, 86 (boolean)draw->bypass_clipping, 87 (boolean)(draw->identity_viewport || 88 draw->rasterizer->bypass_vs_clip_and_viewport), 89 (boolean)draw->rasterizer->gl_rasterization_rules, 90 need_edgeflags ); 91 92 93 if (!(opt & PT_PIPELINE)) { 94 draw_pt_emit_prepare( fpme->emit, 95 prim, 96 max_vertices ); 97 98 *max_vertices = MAX2( *max_vertices, 99 DRAW_PIPE_MAX_VERTICES ); 100 } 101 else { 102 *max_vertices = DRAW_PIPE_MAX_VERTICES; 103 } 104 105 /* return even number */ 106 *max_vertices = *max_vertices & ~1; 107 108 /* No need to prepare the shader. 109 */ 110 vs->prepare(vs, draw); 111} 112 113 114 115static void fetch_pipeline_run( struct draw_pt_middle_end *middle, 116 const unsigned *fetch_elts, 117 unsigned fetch_count, 118 const ushort *draw_elts, 119 unsigned draw_count ) 120{ 121 struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle; 122 struct draw_context *draw = fpme->draw; 123 struct draw_vertex_shader *shader = draw->vs.vertex_shader; 124 unsigned opt = fpme->opt; 125 unsigned alloc_count = align( fetch_count, 4 ); 126 127 struct vertex_header *pipeline_verts = 128 (struct vertex_header *)MALLOC(fpme->vertex_size * alloc_count); 129 130 if (!pipeline_verts) { 131 /* Not much we can do here - just skip the rendering. 132 */ 133 assert(0); 134 return; 135 } 136 137 /* Fetch into our vertex buffer 138 */ 139 draw_pt_fetch_run( fpme->fetch, 140 fetch_elts, 141 fetch_count, 142 (char *)pipeline_verts ); 143 144 /* Run the shader, note that this overwrites the data[] parts of 145 * the pipeline verts. If there is no shader, eg if 146 * bypass_vs_clip_and_viewport, then the inputs == outputs, and are 147 * already in the correct place. 148 */ 149 if (opt & PT_SHADE) 150 { 151 shader->run_linear(shader, 152 (const float (*)[4])pipeline_verts->data, 153 ( float (*)[4])pipeline_verts->data, 154 (const float (*)[4])draw->pt.user.constants, 155 fetch_count, 156 fpme->vertex_size, 157 fpme->vertex_size); 158 } 159 160 if (draw_pt_post_vs_run( fpme->post_vs, 161 pipeline_verts, 162 fetch_count, 163 fpme->vertex_size )) 164 { 165 opt |= PT_PIPELINE; 166 } 167 168 /* Do we need to run the pipeline? 169 */ 170 if (opt & PT_PIPELINE) { 171 draw_pipeline_run( fpme->draw, 172 fpme->prim, 173 pipeline_verts, 174 fetch_count, 175 fpme->vertex_size, 176 draw_elts, 177 draw_count ); 178 } 179 else { 180 draw_pt_emit( fpme->emit, 181 (const float (*)[4])pipeline_verts->data, 182 fetch_count, 183 fpme->vertex_size, 184 draw_elts, 185 draw_count ); 186 } 187 188 189 FREE(pipeline_verts); 190} 191 192 193static void fetch_pipeline_linear_run( struct draw_pt_middle_end *middle, 194 unsigned start, 195 unsigned count) 196{ 197 struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle; 198 struct draw_context *draw = fpme->draw; 199 struct draw_vertex_shader *shader = draw->vs.vertex_shader; 200 unsigned opt = fpme->opt; 201 unsigned alloc_count = align( count, 4 ); 202 203 struct vertex_header *pipeline_verts = 204 (struct vertex_header *)MALLOC(fpme->vertex_size * alloc_count); 205 206 if (!pipeline_verts) { 207 /* Not much we can do here - just skip the rendering. 208 */ 209 assert(0); 210 return; 211 } 212 213 /* Fetch into our vertex buffer 214 */ 215 draw_pt_fetch_run_linear( fpme->fetch, 216 start, 217 count, 218 (char *)pipeline_verts ); 219 220 /* Run the shader, note that this overwrites the data[] parts of 221 * the pipeline verts. If there is no shader, ie if 222 * bypass_vs_clip_and_viewport, then the inputs == outputs, and are 223 * already in the correct place. 224 */ 225 if (opt & PT_SHADE) 226 { 227 shader->run_linear(shader, 228 (const float (*)[4])pipeline_verts->data, 229 ( float (*)[4])pipeline_verts->data, 230 (const float (*)[4])draw->pt.user.constants, 231 count, 232 fpme->vertex_size, 233 fpme->vertex_size); 234 } 235 236 if (draw_pt_post_vs_run( fpme->post_vs, 237 pipeline_verts, 238 count, 239 fpme->vertex_size )) 240 { 241 opt |= PT_PIPELINE; 242 } 243 244 /* Do we need to run the pipeline? 245 */ 246 if (opt & PT_PIPELINE) { 247 draw_pipeline_run_linear( fpme->draw, 248 fpme->prim, 249 pipeline_verts, 250 count, 251 fpme->vertex_size); 252 } 253 else { 254 draw_pt_emit_linear( fpme->emit, 255 (const float (*)[4])pipeline_verts->data, 256 fpme->vertex_size, 257 count ); 258 } 259 260 FREE(pipeline_verts); 261} 262 263 264 265static boolean fetch_pipeline_linear_run_elts( struct draw_pt_middle_end *middle, 266 unsigned start, 267 unsigned count, 268 const ushort *draw_elts, 269 unsigned draw_count ) 270{ 271 struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle; 272 struct draw_context *draw = fpme->draw; 273 struct draw_vertex_shader *shader = draw->vs.vertex_shader; 274 unsigned opt = fpme->opt; 275 unsigned alloc_count = align( count, 4 ); 276 277 struct vertex_header *pipeline_verts = 278 (struct vertex_header *)MALLOC(fpme->vertex_size * alloc_count); 279 280 if (!pipeline_verts) 281 return FALSE; 282 283 /* Fetch into our vertex buffer 284 */ 285 draw_pt_fetch_run_linear( fpme->fetch, 286 start, 287 count, 288 (char *)pipeline_verts ); 289 290 /* Run the shader, note that this overwrites the data[] parts of 291 * the pipeline verts. If there is no shader, ie if 292 * bypass_vs_clip_and_viewport, then the inputs == outputs, and are 293 * already in the correct place. 294 */ 295 if (opt & PT_SHADE) 296 { 297 shader->run_linear(shader, 298 (const float (*)[4])pipeline_verts->data, 299 ( float (*)[4])pipeline_verts->data, 300 (const float (*)[4])draw->pt.user.constants, 301 count, 302 fpme->vertex_size, 303 fpme->vertex_size); 304 } 305 306 if (draw_pt_post_vs_run( fpme->post_vs, 307 pipeline_verts, 308 count, 309 fpme->vertex_size )) 310 { 311 opt |= PT_PIPELINE; 312 } 313 314 /* Do we need to run the pipeline? 315 */ 316 if (opt & PT_PIPELINE) { 317 draw_pipeline_run( fpme->draw, 318 fpme->prim, 319 pipeline_verts, 320 count, 321 fpme->vertex_size, 322 draw_elts, 323 draw_count ); 324 } 325 else { 326 draw_pt_emit( fpme->emit, 327 (const float (*)[4])pipeline_verts->data, 328 count, 329 fpme->vertex_size, 330 draw_elts, 331 draw_count ); 332 } 333 334 FREE(pipeline_verts); 335 return TRUE; 336} 337 338 339 340static void fetch_pipeline_finish( struct draw_pt_middle_end *middle ) 341{ 342 /* nothing to do */ 343} 344 345static void fetch_pipeline_destroy( struct draw_pt_middle_end *middle ) 346{ 347 struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle; 348 349 if (fpme->fetch) 350 draw_pt_fetch_destroy( fpme->fetch ); 351 352 if (fpme->emit) 353 draw_pt_emit_destroy( fpme->emit ); 354 355 if (fpme->post_vs) 356 draw_pt_post_vs_destroy( fpme->post_vs ); 357 358 FREE(middle); 359} 360 361 362struct draw_pt_middle_end *draw_pt_fetch_pipeline_or_emit( struct draw_context *draw ) 363{ 364 struct fetch_pipeline_middle_end *fpme = CALLOC_STRUCT( fetch_pipeline_middle_end ); 365 if (!fpme) 366 goto fail; 367 368 fpme->base.prepare = fetch_pipeline_prepare; 369 fpme->base.run = fetch_pipeline_run; 370 fpme->base.run_linear = fetch_pipeline_linear_run; 371 fpme->base.run_linear_elts = fetch_pipeline_linear_run_elts; 372 fpme->base.finish = fetch_pipeline_finish; 373 fpme->base.destroy = fetch_pipeline_destroy; 374 375 fpme->draw = draw; 376 377 fpme->fetch = draw_pt_fetch_create( draw ); 378 if (!fpme->fetch) 379 goto fail; 380 381 fpme->post_vs = draw_pt_post_vs_create( draw ); 382 if (!fpme->post_vs) 383 goto fail; 384 385 fpme->emit = draw_pt_emit_create( draw ); 386 if (!fpme->emit) 387 goto fail; 388 389 return &fpme->base; 390 391 fail: 392 if (fpme) 393 fetch_pipeline_destroy( &fpme->base ); 394 395 return NULL; 396} 397