draw_pt_fetch_shade_pipeline.c revision 683e7091a953204c9aee1410ac44be3b69bae9fc
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 fpme->vertex_size ); 81 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 91 92 if (!(opt & PT_PIPELINE)) { 93 draw_pt_emit_prepare( fpme->emit, 94 prim, 95 max_vertices ); 96 97 *max_vertices = MAX2( *max_vertices, 98 DRAW_PIPE_MAX_VERTICES ); 99 } 100 else { 101 *max_vertices = DRAW_PIPE_MAX_VERTICES; 102 } 103 104 /* return even number */ 105 *max_vertices = *max_vertices & ~1; 106 107 /* No need to prepare the shader. 108 */ 109 vs->prepare(vs, draw); 110} 111 112 113 114static void fetch_pipeline_run( struct draw_pt_middle_end *middle, 115 const unsigned *fetch_elts, 116 unsigned fetch_count, 117 const ushort *draw_elts, 118 unsigned draw_count ) 119{ 120 struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle; 121 struct draw_context *draw = fpme->draw; 122 struct draw_vertex_shader *shader = draw->vs.vertex_shader; 123 unsigned opt = fpme->opt; 124 unsigned alloc_count = align( fetch_count, 4 ); 125 126 struct vertex_header *pipeline_verts = 127 (struct vertex_header *)MALLOC(fpme->vertex_size * alloc_count); 128 129 if (!pipeline_verts) { 130 /* Not much we can do here - just skip the rendering. 131 */ 132 assert(0); 133 return; 134 } 135 136 /* Fetch into our vertex buffer 137 */ 138 draw_pt_fetch_run( fpme->fetch, 139 fetch_elts, 140 fetch_count, 141 (char *)pipeline_verts ); 142 143 /* Run the shader, note that this overwrites the data[] parts of 144 * the pipeline verts. If there is no shader, eg if 145 * bypass_vs_clip_and_viewport, then the inputs == outputs, and are 146 * already in the correct place. 147 */ 148 if (opt & PT_SHADE) 149 { 150 shader->run_linear(shader, 151 (const float (*)[4])pipeline_verts->data, 152 ( float (*)[4])pipeline_verts->data, 153 (const float (*)[4])draw->pt.user.constants, 154 fetch_count, 155 fpme->vertex_size, 156 fpme->vertex_size); 157 } 158 159 if (draw_pt_post_vs_run( fpme->post_vs, 160 pipeline_verts, 161 fetch_count, 162 fpme->vertex_size )) 163 { 164 opt |= PT_PIPELINE; 165 } 166 167 /* Do we need to run the pipeline? 168 */ 169 if (opt & PT_PIPELINE) { 170 draw_pipeline_run( fpme->draw, 171 fpme->prim, 172 pipeline_verts, 173 fetch_count, 174 fpme->vertex_size, 175 draw_elts, 176 draw_count ); 177 } 178 else { 179 draw_pt_emit( fpme->emit, 180 (const float (*)[4])pipeline_verts->data, 181 fetch_count, 182 fpme->vertex_size, 183 draw_elts, 184 draw_count ); 185 } 186 187 188 FREE(pipeline_verts); 189} 190 191 192static void fetch_pipeline_linear_run( struct draw_pt_middle_end *middle, 193 unsigned start, 194 unsigned count) 195{ 196 struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle; 197 struct draw_context *draw = fpme->draw; 198 struct draw_vertex_shader *shader = draw->vs.vertex_shader; 199 unsigned opt = fpme->opt; 200 unsigned alloc_count = align( count, 4 ); 201 202 struct vertex_header *pipeline_verts = 203 (struct vertex_header *)MALLOC(fpme->vertex_size * alloc_count); 204 205 if (!pipeline_verts) { 206 /* Not much we can do here - just skip the rendering. 207 */ 208 assert(0); 209 return; 210 } 211 212 /* Fetch into our vertex buffer 213 */ 214 draw_pt_fetch_run_linear( fpme->fetch, 215 start, 216 count, 217 (char *)pipeline_verts ); 218 219 /* Run the shader, note that this overwrites the data[] parts of 220 * the pipeline verts. If there is no shader, ie if 221 * bypass_vs_clip_and_viewport, then the inputs == outputs, and are 222 * already in the correct place. 223 */ 224 if (opt & PT_SHADE) 225 { 226 shader->run_linear(shader, 227 (const float (*)[4])pipeline_verts->data, 228 ( float (*)[4])pipeline_verts->data, 229 (const float (*)[4])draw->pt.user.constants, 230 count, 231 fpme->vertex_size, 232 fpme->vertex_size); 233 } 234 235 if (draw_pt_post_vs_run( fpme->post_vs, 236 pipeline_verts, 237 count, 238 fpme->vertex_size )) 239 { 240 opt |= PT_PIPELINE; 241 } 242 243 /* Do we need to run the pipeline? 244 */ 245 if (opt & PT_PIPELINE) { 246 draw_pipeline_run_linear( fpme->draw, 247 fpme->prim, 248 pipeline_verts, 249 count, 250 fpme->vertex_size); 251 } 252 else { 253 draw_pt_emit_linear( fpme->emit, 254 (const float (*)[4])pipeline_verts->data, 255 fpme->vertex_size, 256 count ); 257 } 258 259 FREE(pipeline_verts); 260} 261 262 263 264static boolean fetch_pipeline_linear_run_elts( struct draw_pt_middle_end *middle, 265 unsigned start, 266 unsigned count, 267 const ushort *draw_elts, 268 unsigned draw_count ) 269{ 270 struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle; 271 struct draw_context *draw = fpme->draw; 272 struct draw_vertex_shader *shader = draw->vs.vertex_shader; 273 unsigned opt = fpme->opt; 274 unsigned alloc_count = align( count, 4 ); 275 276 struct vertex_header *pipeline_verts = 277 (struct vertex_header *)MALLOC(fpme->vertex_size * alloc_count); 278 279 if (!pipeline_verts) 280 return FALSE; 281 282 /* Fetch into our vertex buffer 283 */ 284 draw_pt_fetch_run_linear( fpme->fetch, 285 start, 286 count, 287 (char *)pipeline_verts ); 288 289 /* Run the shader, note that this overwrites the data[] parts of 290 * the pipeline verts. If there is no shader, ie if 291 * bypass_vs_clip_and_viewport, then the inputs == outputs, and are 292 * already in the correct place. 293 */ 294 if (opt & PT_SHADE) 295 { 296 shader->run_linear(shader, 297 (const float (*)[4])pipeline_verts->data, 298 ( float (*)[4])pipeline_verts->data, 299 (const float (*)[4])draw->pt.user.constants, 300 count, 301 fpme->vertex_size, 302 fpme->vertex_size); 303 } 304 305 if (draw_pt_post_vs_run( fpme->post_vs, 306 pipeline_verts, 307 count, 308 fpme->vertex_size )) 309 { 310 opt |= PT_PIPELINE; 311 } 312 313 /* Do we need to run the pipeline? 314 */ 315 if (opt & PT_PIPELINE) { 316 draw_pipeline_run( fpme->draw, 317 fpme->prim, 318 pipeline_verts, 319 count, 320 fpme->vertex_size, 321 draw_elts, 322 draw_count ); 323 } 324 else { 325 draw_pt_emit( fpme->emit, 326 (const float (*)[4])pipeline_verts->data, 327 count, 328 fpme->vertex_size, 329 draw_elts, 330 draw_count ); 331 } 332 333 FREE(pipeline_verts); 334 return TRUE; 335} 336 337 338 339static void fetch_pipeline_finish( struct draw_pt_middle_end *middle ) 340{ 341 /* nothing to do */ 342} 343 344static void fetch_pipeline_destroy( struct draw_pt_middle_end *middle ) 345{ 346 struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle; 347 348 if (fpme->fetch) 349 draw_pt_fetch_destroy( fpme->fetch ); 350 351 if (fpme->emit) 352 draw_pt_emit_destroy( fpme->emit ); 353 354 if (fpme->post_vs) 355 draw_pt_post_vs_destroy( fpme->post_vs ); 356 357 FREE(middle); 358} 359 360 361struct draw_pt_middle_end *draw_pt_fetch_pipeline_or_emit( struct draw_context *draw ) 362{ 363 struct fetch_pipeline_middle_end *fpme = CALLOC_STRUCT( fetch_pipeline_middle_end ); 364 if (!fpme) 365 goto fail; 366 367 fpme->base.prepare = fetch_pipeline_prepare; 368 fpme->base.run = fetch_pipeline_run; 369 fpme->base.run_linear = fetch_pipeline_linear_run; 370 fpme->base.run_linear_elts = fetch_pipeline_linear_run_elts; 371 fpme->base.finish = fetch_pipeline_finish; 372 fpme->base.destroy = fetch_pipeline_destroy; 373 374 fpme->draw = draw; 375 376 fpme->fetch = draw_pt_fetch_create( draw ); 377 if (!fpme->fetch) 378 goto fail; 379 380 fpme->post_vs = draw_pt_post_vs_create( draw ); 381 if (!fpme->post_vs) 382 goto fail; 383 384 fpme->emit = draw_pt_emit_create( draw ); 385 if (!fpme->emit) 386 goto fail; 387 388 return &fpme->base; 389 390 fail: 391 if (fpme) 392 fetch_pipeline_destroy( &fpme->base ); 393 394 return NULL; 395} 396