1/************************************************************************** 2 * 3 * Copyright 2007 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 * Authors: 30 * Keith Whitwell <keithw@vmware.com> 31 */ 32 33#include "util/u_memory.h" 34#include "util/u_math.h" 35#include "draw/draw_context.h" 36#include "draw/draw_private.h" 37#include "draw/draw_vbuf.h" 38#include "draw/draw_vertex.h" 39#include "draw/draw_vs.h" 40#include "translate/translate.h" 41 42/* A first pass at incorporating vertex fetch/emit functionality into 43 */ 44struct draw_vs_variant_generic { 45 struct draw_vs_variant base; 46 47 struct draw_vertex_shader *shader; 48 struct draw_context *draw; 49 50 /* Basic plan is to run these two translate functions before/after 51 * the vertex shader's existing run_linear() routine to simulate 52 * the inclusion of this functionality into the shader... 53 * 54 * Next will look at actually including it. 55 */ 56 struct translate *fetch; 57 struct translate *emit; 58 59 unsigned temp_vertex_stride; 60}; 61 62 63 64 65 66static void vsvg_set_buffer( struct draw_vs_variant *variant, 67 unsigned buffer, 68 const void *ptr, 69 unsigned stride, 70 unsigned max_index ) 71{ 72 struct draw_vs_variant_generic *vsvg = (struct draw_vs_variant_generic *)variant; 73 74 vsvg->fetch->set_buffer(vsvg->fetch, 75 buffer, 76 ptr, 77 stride, 78 max_index ); 79} 80 81static const struct pipe_viewport_state * 82find_viewport(struct draw_context *draw, 83 char *buffer, 84 unsigned vertex_idx, 85 unsigned stride) 86{ 87 int viewport_index_output = 88 draw_current_shader_viewport_index_output(draw); 89 char *ptr = buffer + vertex_idx * stride; 90 unsigned *data = (unsigned *)ptr; 91 int viewport_index = 92 draw_current_shader_uses_viewport_index(draw) ? 93 data[viewport_index_output * 4] : 0; 94 95 viewport_index = draw_clamp_viewport_idx(viewport_index); 96 97 return &draw->viewports[viewport_index]; 98} 99 100 101/* Mainly for debug at this stage: 102 */ 103static void do_rhw_viewport( struct draw_vs_variant_generic *vsvg, 104 unsigned count, 105 void *output_buffer ) 106{ 107 char *ptr = (char *)output_buffer; 108 unsigned stride = vsvg->temp_vertex_stride; 109 unsigned j; 110 111 ptr += vsvg->base.vs->position_output * 4 * sizeof(float); 112 113 for (j = 0; j < count; j++, ptr += stride) { 114 const struct pipe_viewport_state *viewport = 115 find_viewport(vsvg->base.vs->draw, (char*)output_buffer, 116 j, stride); 117 const float *scale = viewport->scale; 118 const float *trans = viewport->translate; 119 float *data = (float *)ptr; 120 float w = 1.0f / data[3]; 121 122 data[0] = data[0] * w * scale[0] + trans[0]; 123 data[1] = data[1] * w * scale[1] + trans[1]; 124 data[2] = data[2] * w * scale[2] + trans[2]; 125 data[3] = w; 126 } 127} 128 129static void do_viewport( struct draw_vs_variant_generic *vsvg, 130 unsigned count, 131 void *output_buffer ) 132{ 133 char *ptr = (char *)output_buffer; 134 unsigned stride = vsvg->temp_vertex_stride; 135 unsigned j; 136 137 ptr += vsvg->base.vs->position_output * 4 * sizeof(float); 138 139 for (j = 0; j < count; j++, ptr += stride) { 140 const struct pipe_viewport_state *viewport = 141 find_viewport(vsvg->base.vs->draw, (char*)output_buffer, 142 j, stride); 143 const float *scale = viewport->scale; 144 const float *trans = viewport->translate; 145 float *data = (float *)ptr; 146 147 data[0] = data[0] * scale[0] + trans[0]; 148 data[1] = data[1] * scale[1] + trans[1]; 149 data[2] = data[2] * scale[2] + trans[2]; 150 } 151} 152 153 154static void PIPE_CDECL vsvg_run_elts( struct draw_vs_variant *variant, 155 const unsigned *elts, 156 unsigned count, 157 void *output_buffer) 158{ 159 struct draw_vs_variant_generic *vsvg = (struct draw_vs_variant_generic *)variant; 160 unsigned temp_vertex_stride = vsvg->temp_vertex_stride; 161 void *temp_buffer = MALLOC( align(count,4) * temp_vertex_stride ); 162 163 if (0) debug_printf("%s %d \n", __FUNCTION__, count); 164 165 /* Want to do this in small batches for cache locality? 166 */ 167 168 vsvg->fetch->run_elts( vsvg->fetch, 169 elts, 170 count, 171 vsvg->draw->start_instance, 172 vsvg->draw->instance_id, 173 temp_buffer ); 174 175 vsvg->base.vs->run_linear( vsvg->base.vs, 176 temp_buffer, 177 temp_buffer, 178 vsvg->base.vs->draw->pt.user.vs_constants, 179 vsvg->base.vs->draw->pt.user.vs_constants_size, 180 count, 181 temp_vertex_stride, 182 temp_vertex_stride); 183 184 /* FIXME: geometry shading? */ 185 186 if (vsvg->base.key.clip) { 187 /* not really handling clipping, just do the rhw so we can 188 * see the results... 189 */ 190 do_rhw_viewport( vsvg, 191 count, 192 temp_buffer ); 193 } 194 else if (vsvg->base.key.viewport) { 195 do_viewport( vsvg, 196 count, 197 temp_buffer ); 198 } 199 200 201 vsvg->emit->set_buffer( vsvg->emit, 202 0, 203 temp_buffer, 204 temp_vertex_stride, 205 ~0 ); 206 207 vsvg->emit->set_buffer( vsvg->emit, 208 1, 209 &vsvg->draw->rasterizer->point_size, 210 0, 211 ~0 ); 212 213 vsvg->emit->run( vsvg->emit, 214 0, count, 215 vsvg->draw->start_instance, 216 vsvg->draw->instance_id, 217 output_buffer ); 218 219 FREE(temp_buffer); 220} 221 222 223static void PIPE_CDECL vsvg_run_linear( struct draw_vs_variant *variant, 224 unsigned start, 225 unsigned count, 226 void *output_buffer ) 227{ 228 struct draw_vs_variant_generic *vsvg = (struct draw_vs_variant_generic *)variant; 229 unsigned temp_vertex_stride = vsvg->temp_vertex_stride; 230 void *temp_buffer = MALLOC( align(count,4) * temp_vertex_stride ); 231 232 if (0) debug_printf("%s %d %d (sz %d, %d)\n", __FUNCTION__, start, count, 233 vsvg->base.key.output_stride, 234 temp_vertex_stride); 235 236 vsvg->fetch->run( vsvg->fetch, 237 start, 238 count, 239 vsvg->draw->start_instance, 240 vsvg->draw->instance_id, 241 temp_buffer ); 242 243 vsvg->base.vs->run_linear( vsvg->base.vs, 244 temp_buffer, 245 temp_buffer, 246 vsvg->base.vs->draw->pt.user.vs_constants, 247 vsvg->base.vs->draw->pt.user.vs_constants_size, 248 count, 249 temp_vertex_stride, 250 temp_vertex_stride); 251 252 if (vsvg->base.key.clip) { 253 /* not really handling clipping, just do the rhw so we can 254 * see the results... 255 */ 256 do_rhw_viewport( vsvg, 257 count, 258 temp_buffer ); 259 } 260 else if (vsvg->base.key.viewport) { 261 do_viewport( vsvg, 262 count, 263 temp_buffer ); 264 } 265 266 vsvg->emit->set_buffer( vsvg->emit, 267 0, 268 temp_buffer, 269 temp_vertex_stride, 270 ~0 ); 271 272 vsvg->emit->set_buffer( vsvg->emit, 273 1, 274 &vsvg->draw->rasterizer->point_size, 275 0, 276 ~0 ); 277 278 vsvg->emit->run( vsvg->emit, 279 0, count, 280 vsvg->draw->start_instance, 281 vsvg->draw->instance_id, 282 output_buffer ); 283 284 FREE(temp_buffer); 285} 286 287 288 289 290 291static void vsvg_destroy( struct draw_vs_variant *variant ) 292{ 293 FREE(variant); 294} 295 296 297struct draw_vs_variant * 298draw_vs_create_variant_generic( struct draw_vertex_shader *vs, 299 const struct draw_vs_variant_key *key ) 300{ 301 unsigned i; 302 struct translate_key fetch, emit; 303 304 struct draw_vs_variant_generic *vsvg = CALLOC_STRUCT( draw_vs_variant_generic ); 305 if (!vsvg) 306 return NULL; 307 308 vsvg->base.key = *key; 309 vsvg->base.vs = vs; 310 vsvg->base.set_buffer = vsvg_set_buffer; 311 vsvg->base.run_elts = vsvg_run_elts; 312 vsvg->base.run_linear = vsvg_run_linear; 313 vsvg->base.destroy = vsvg_destroy; 314 315 vsvg->draw = vs->draw; 316 317 vsvg->temp_vertex_stride = MAX2(key->nr_inputs, 318 draw_total_vs_outputs(vs->draw)) * 4 * sizeof(float); 319 320 /* Build free-standing fetch and emit functions: 321 */ 322 fetch.nr_elements = key->nr_inputs; 323 fetch.output_stride = vsvg->temp_vertex_stride; 324 for (i = 0; i < key->nr_inputs; i++) { 325 fetch.element[i].type = TRANSLATE_ELEMENT_NORMAL; 326 fetch.element[i].input_format = key->element[i].in.format; 327 fetch.element[i].input_buffer = key->element[i].in.buffer; 328 fetch.element[i].input_offset = key->element[i].in.offset; 329 fetch.element[i].instance_divisor = 0; 330 fetch.element[i].output_format = PIPE_FORMAT_R32G32B32A32_FLOAT; 331 fetch.element[i].output_offset = i * 4 * sizeof(float); 332 assert(fetch.element[i].output_offset < fetch.output_stride); 333 } 334 335 336 emit.nr_elements = key->nr_outputs; 337 emit.output_stride = key->output_stride; 338 for (i = 0; i < key->nr_outputs; i++) { 339 if (key->element[i].out.format != EMIT_1F_PSIZE) 340 { 341 emit.element[i].type = TRANSLATE_ELEMENT_NORMAL; 342 emit.element[i].input_format = PIPE_FORMAT_R32G32B32A32_FLOAT; 343 emit.element[i].input_buffer = 0; 344 emit.element[i].input_offset = key->element[i].out.vs_output * 4 * sizeof(float); 345 emit.element[i].instance_divisor = 0; 346 emit.element[i].output_format = draw_translate_vinfo_format(key->element[i].out.format); 347 emit.element[i].output_offset = key->element[i].out.offset; 348 assert(emit.element[i].input_offset <= fetch.output_stride); 349 } 350 else { 351 emit.element[i].type = TRANSLATE_ELEMENT_NORMAL; 352 emit.element[i].input_format = PIPE_FORMAT_R32_FLOAT; 353 emit.element[i].input_buffer = 1; 354 emit.element[i].input_offset = 0; 355 emit.element[i].instance_divisor = 0; 356 emit.element[i].output_format = PIPE_FORMAT_R32_FLOAT; 357 emit.element[i].output_offset = key->element[i].out.offset; 358 } 359 } 360 361 vsvg->fetch = draw_vs_get_fetch( vs->draw, &fetch ); 362 vsvg->emit = draw_vs_get_emit( vs->draw, &emit ); 363 364 return &vsvg->base; 365} 366 367 368 369 370 371