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