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 * This file implements the st_draw_vbo() function which is called from 30 * Mesa's VBO module. All point/line/triangle rendering is done through 31 * this function whether the user called glBegin/End, glDrawArrays, 32 * glDrawElements, glEvalMesh, or glCalList, etc. 33 * 34 * Authors: 35 * Keith Whitwell <keithw (at) vmware.com> 36 */ 37 38 39 #include "main/imports.h" 40 #include "main/image.h" 41 #include "main/bufferobj.h" 42 #include "main/macros.h" 43 #include "main/varray.h" 44 45 #include "compiler/glsl/ir_uniform.h" 46 47 #include "vbo/vbo.h" 48 49 #include "st_context.h" 50 #include "st_atom.h" 51 #include "st_cb_bitmap.h" 52 #include "st_cb_bufferobjects.h" 53 #include "st_cb_xformfb.h" 54 #include "st_debug.h" 55 #include "st_draw.h" 56 #include "st_program.h" 57 58 #include "pipe/p_context.h" 59 #include "pipe/p_defines.h" 60 #include "util/u_inlines.h" 61 #include "util/u_format.h" 62 #include "util/u_prim.h" 63 #include "util/u_draw.h" 64 #include "util/u_upload_mgr.h" 65 #include "draw/draw_context.h" 66 #include "cso_cache/cso_context.h" 67 68 69 /** 70 * This is very similar to vbo_all_varyings_in_vbos() but we are 71 * only interested in per-vertex data. See bug 38626. 72 */ 73 static GLboolean 74 all_varyings_in_vbos(const struct gl_vertex_array *arrays[]) 75 { 76 GLuint i; 77 78 for (i = 0; i < VERT_ATTRIB_MAX; i++) 79 if (arrays[i]->StrideB && 80 !arrays[i]->InstanceDivisor && 81 !_mesa_is_bufferobj(arrays[i]->BufferObj)) 82 return GL_FALSE; 83 84 return GL_TRUE; 85 } 86 87 88 /** 89 * Basically, translate Mesa's index buffer information into 90 * a pipe_index_buffer object. 91 * \return TRUE or FALSE for success/failure 92 */ 93 static boolean 94 setup_index_buffer(struct st_context *st, 95 const struct _mesa_index_buffer *ib, 96 struct pipe_index_buffer *ibuffer) 97 { 98 struct gl_buffer_object *bufobj = ib->obj; 99 100 ibuffer->index_size = vbo_sizeof_ib_type(ib->type); 101 102 /* get/create the index buffer object */ 103 if (_mesa_is_bufferobj(bufobj)) { 104 /* indices are in a real VBO */ 105 ibuffer->buffer = st_buffer_object(bufobj)->buffer; 106 ibuffer->offset = pointer_to_offset(ib->ptr); 107 } 108 else if (st->indexbuf_uploader) { 109 /* upload indexes from user memory into a real buffer */ 110 u_upload_data(st->indexbuf_uploader, 0, 111 ib->count * ibuffer->index_size, 4, ib->ptr, 112 &ibuffer->offset, &ibuffer->buffer); 113 if (!ibuffer->buffer) { 114 /* out of memory */ 115 return FALSE; 116 } 117 u_upload_unmap(st->indexbuf_uploader); 118 } 119 else { 120 /* indices are in user space memory */ 121 ibuffer->user_buffer = ib->ptr; 122 } 123 124 cso_set_index_buffer(st->cso_context, ibuffer); 125 return TRUE; 126 } 127 128 129 /** 130 * Set the restart index. 131 */ 132 static void 133 setup_primitive_restart(struct gl_context *ctx, 134 const struct _mesa_index_buffer *ib, 135 struct pipe_draw_info *info) 136 { 137 if (ctx->Array._PrimitiveRestart) { 138 info->restart_index = _mesa_primitive_restart_index(ctx, ib->type); 139 140 /* Enable primitive restart only when the restart index can have an 141 * effect. This is required for correctness in radeonsi VI support. 142 * Other hardware may also benefit from taking a faster, non-restart path 143 * when possible. 144 */ 145 if ((ib->type == GL_UNSIGNED_INT) || 146 (ib->type == GL_UNSIGNED_SHORT && info->restart_index <= 0xffff) || 147 (ib->type == GL_UNSIGNED_BYTE && info->restart_index <= 0xff)) 148 info->primitive_restart = true; 149 } 150 } 151 152 153 /** 154 * Translate OpenGL primtive type (GL_POINTS, GL_TRIANGLE_STRIP, etc) to 155 * the corresponding Gallium type. 156 */ 157 static unsigned 158 translate_prim(const struct gl_context *ctx, unsigned prim) 159 { 160 /* GL prims should match Gallium prims, spot-check a few */ 161 STATIC_ASSERT(GL_POINTS == PIPE_PRIM_POINTS); 162 STATIC_ASSERT(GL_QUADS == PIPE_PRIM_QUADS); 163 STATIC_ASSERT(GL_TRIANGLE_STRIP_ADJACENCY == PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY); 164 STATIC_ASSERT(GL_PATCHES == PIPE_PRIM_PATCHES); 165 166 return prim; 167 } 168 169 170 /** 171 * This function gets plugged into the VBO module and is called when 172 * we have something to render. 173 * Basically, translate the information into the format expected by gallium. 174 */ 175 void 176 st_draw_vbo(struct gl_context *ctx, 177 const struct _mesa_prim *prims, 178 GLuint nr_prims, 179 const struct _mesa_index_buffer *ib, 180 GLboolean index_bounds_valid, 181 GLuint min_index, 182 GLuint max_index, 183 struct gl_transform_feedback_object *tfb_vertcount, 184 unsigned stream, 185 struct gl_buffer_object *indirect) 186 { 187 struct st_context *st = st_context(ctx); 188 struct pipe_index_buffer ibuffer = {0}; 189 struct pipe_draw_info info; 190 const struct gl_vertex_array **arrays = ctx->Array._DrawArrays; 191 unsigned i; 192 193 /* Mesa core state should have been validated already */ 194 assert(ctx->NewState == 0x0); 195 196 st_flush_bitmap_cache(st); 197 st_invalidate_readpix_cache(st); 198 199 /* Validate state. */ 200 if ((st->dirty | ctx->NewDriverState) & ST_PIPELINE_RENDER_STATE_MASK || 201 st->gfx_shaders_may_be_dirty) { 202 st_validate_state(st, ST_PIPELINE_RENDER); 203 } 204 205 if (st->vertex_array_out_of_memory) { 206 return; 207 } 208 209 util_draw_init_info(&info); 210 211 if (ib) { 212 /* Get index bounds for user buffers. */ 213 if (!index_bounds_valid) 214 if (!all_varyings_in_vbos(arrays)) 215 vbo_get_minmax_indices(ctx, prims, ib, &min_index, &max_index, 216 nr_prims); 217 218 if (!setup_index_buffer(st, ib, &ibuffer)) { 219 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBegin/DrawElements/DrawArray"); 220 return; 221 } 222 223 info.indexed = TRUE; 224 if (min_index != ~0U && max_index != ~0U) { 225 info.min_index = min_index; 226 info.max_index = max_index; 227 } 228 229 /* The VBO module handles restart for the non-indexed GLDrawArrays 230 * so we only set these fields for indexed drawing: 231 */ 232 setup_primitive_restart(ctx, ib, &info); 233 } 234 else { 235 /* Transform feedback drawing is always non-indexed. */ 236 /* Set info.count_from_stream_output. */ 237 if (tfb_vertcount) { 238 if (!st_transform_feedback_draw_init(tfb_vertcount, stream, &info)) 239 return; 240 } 241 } 242 243 assert(!indirect); 244 245 /* do actual drawing */ 246 for (i = 0; i < nr_prims; i++) { 247 info.mode = translate_prim(ctx, prims[i].mode); 248 info.start = prims[i].start; 249 info.count = prims[i].count; 250 info.start_instance = prims[i].base_instance; 251 info.instance_count = prims[i].num_instances; 252 info.vertices_per_patch = ctx->TessCtrlProgram.patch_vertices; 253 info.index_bias = prims[i].basevertex; 254 info.drawid = prims[i].draw_id; 255 if (!ib) { 256 info.min_index = info.start; 257 info.max_index = info.start + info.count - 1; 258 } 259 260 if (ST_DEBUG & DEBUG_DRAW) { 261 debug_printf("st/draw: mode %s start %u count %u indexed %d\n", 262 u_prim_name(info.mode), 263 info.start, 264 info.count, 265 info.indexed); 266 } 267 268 if (info.count_from_stream_output) { 269 cso_draw_vbo(st->cso_context, &info); 270 } 271 else if (info.primitive_restart) { 272 /* don't trim, restarts might be inside index list */ 273 cso_draw_vbo(st->cso_context, &info); 274 } 275 else if (u_trim_pipe_prim(prims[i].mode, &info.count)) { 276 cso_draw_vbo(st->cso_context, &info); 277 } 278 } 279 280 if (ib && st->indexbuf_uploader && !_mesa_is_bufferobj(ib->obj)) { 281 pipe_resource_reference(&ibuffer.buffer, NULL); 282 } 283 } 284 285 static void 286 st_indirect_draw_vbo(struct gl_context *ctx, 287 GLuint mode, 288 struct gl_buffer_object *indirect_data, 289 GLsizeiptr indirect_offset, 290 unsigned draw_count, 291 unsigned stride, 292 struct gl_buffer_object *indirect_params, 293 GLsizeiptr indirect_params_offset, 294 const struct _mesa_index_buffer *ib) 295 { 296 struct st_context *st = st_context(ctx); 297 struct pipe_index_buffer ibuffer = {0}; 298 struct pipe_draw_info info; 299 300 /* Mesa core state should have been validated already */ 301 assert(ctx->NewState == 0x0); 302 assert(stride); 303 304 /* Validate state. */ 305 if ((st->dirty | ctx->NewDriverState) & ST_PIPELINE_RENDER_STATE_MASK || 306 st->gfx_shaders_may_be_dirty) { 307 st_validate_state(st, ST_PIPELINE_RENDER); 308 } 309 310 if (st->vertex_array_out_of_memory) { 311 return; 312 } 313 314 util_draw_init_info(&info); 315 316 if (ib) { 317 if (!setup_index_buffer(st, ib, &ibuffer)) { 318 _mesa_error(ctx, GL_OUT_OF_MEMORY, "gl%sDrawElementsIndirect%s", 319 (draw_count > 1) ? "Multi" : "", 320 indirect_params ? "CountARB" : ""); 321 return; 322 } 323 324 info.indexed = TRUE; 325 326 /* Primitive restart is not handled by the VBO module in this case. */ 327 setup_primitive_restart(ctx, ib, &info); 328 } 329 330 info.mode = translate_prim(ctx, mode); 331 info.vertices_per_patch = ctx->TessCtrlProgram.patch_vertices; 332 info.indirect = st_buffer_object(indirect_data)->buffer; 333 info.indirect_offset = indirect_offset; 334 335 if (ST_DEBUG & DEBUG_DRAW) { 336 debug_printf("st/draw indirect: mode %s drawcount %d indexed %d\n", 337 u_prim_name(info.mode), 338 draw_count, 339 info.indexed); 340 } 341 342 if (!st->has_multi_draw_indirect) { 343 int i; 344 345 assert(!indirect_params); 346 info.indirect_count = 1; 347 for (i = 0; i < draw_count; i++) { 348 info.drawid = i; 349 cso_draw_vbo(st->cso_context, &info); 350 info.indirect_offset += stride; 351 } 352 } else { 353 info.indirect_count = draw_count; 354 info.indirect_stride = stride; 355 if (indirect_params) { 356 info.indirect_params = st_buffer_object(indirect_params)->buffer; 357 info.indirect_params_offset = indirect_params_offset; 358 } 359 cso_draw_vbo(st->cso_context, &info); 360 } 361 } 362 363 364 void 365 st_init_draw(struct st_context *st) 366 { 367 struct gl_context *ctx = st->ctx; 368 369 vbo_set_draw_func(ctx, st_draw_vbo); 370 vbo_set_indirect_draw_func(ctx, st_indirect_draw_vbo); 371 } 372 373 374 void 375 st_destroy_draw(struct st_context *st) 376 { 377 draw_destroy(st->draw); 378 } 379 380 /** 381 * Getter for the draw_context, so that initialization of it can happen only 382 * when needed (the TGSI exec machines take up quite a bit of memory). 383 */ 384 struct draw_context * 385 st_get_draw_context(struct st_context *st) 386 { 387 if (!st->draw) { 388 st->draw = draw_create(st->pipe); 389 if (!st->draw) { 390 _mesa_error(st->ctx, GL_OUT_OF_MEMORY, "feedback fallback allocation"); 391 return NULL; 392 } 393 } 394 395 /* Disable draw options that might convert points/lines to tris, etc. 396 * as that would foul-up feedback/selection mode. 397 */ 398 draw_wide_line_threshold(st->draw, 1000.0f); 399 draw_wide_point_threshold(st->draw, 1000.0f); 400 draw_enable_line_stipple(st->draw, FALSE); 401 draw_enable_point_sprites(st->draw, FALSE); 402 403 return st->draw; 404 } 405 406 /** 407 * Draw a quad with given position, texcoords and color. 408 */ 409 bool 410 st_draw_quad(struct st_context *st, 411 float x0, float y0, float x1, float y1, float z, 412 float s0, float t0, float s1, float t1, 413 const float *color, 414 unsigned num_instances) 415 { 416 struct pipe_vertex_buffer vb = {0}; 417 struct st_util_vertex *verts; 418 419 vb.stride = sizeof(struct st_util_vertex); 420 421 u_upload_alloc(st->uploader, 0, 4 * sizeof(struct st_util_vertex), 4, 422 &vb.buffer_offset, &vb.buffer, (void **) &verts); 423 if (!vb.buffer) { 424 return false; 425 } 426 427 /* lower-left */ 428 verts[0].x = x0; 429 verts[0].y = y1; 430 verts[0].z = z; 431 verts[0].r = color[0]; 432 verts[0].g = color[1]; 433 verts[0].b = color[2]; 434 verts[0].a = color[3]; 435 verts[0].s = s0; 436 verts[0].t = t0; 437 438 /* lower-right */ 439 verts[1].x = x1; 440 verts[1].y = y1; 441 verts[1].z = z; 442 verts[1].r = color[0]; 443 verts[1].g = color[1]; 444 verts[1].b = color[2]; 445 verts[1].a = color[3]; 446 verts[1].s = s1; 447 verts[1].t = t0; 448 449 /* upper-right */ 450 verts[2].x = x1; 451 verts[2].y = y0; 452 verts[2].z = z; 453 verts[2].r = color[0]; 454 verts[2].g = color[1]; 455 verts[2].b = color[2]; 456 verts[2].a = color[3]; 457 verts[2].s = s1; 458 verts[2].t = t1; 459 460 /* upper-left */ 461 verts[3].x = x0; 462 verts[3].y = y0; 463 verts[3].z = z; 464 verts[3].r = color[0]; 465 verts[3].g = color[1]; 466 verts[3].b = color[2]; 467 verts[3].a = color[3]; 468 verts[3].s = s0; 469 verts[3].t = t1; 470 471 u_upload_unmap(st->uploader); 472 473 /* At the time of writing, cso_get_aux_vertex_buffer_slot() always returns 474 * zero. If that ever changes we need to audit the calls to that function 475 * and make sure the slot number is used consistently everywhere. 476 */ 477 assert(cso_get_aux_vertex_buffer_slot(st->cso_context) == 0); 478 479 cso_set_vertex_buffers(st->cso_context, 480 cso_get_aux_vertex_buffer_slot(st->cso_context), 481 1, &vb); 482 483 if (num_instances > 1) { 484 cso_draw_arrays_instanced(st->cso_context, PIPE_PRIM_TRIANGLE_FAN, 0, 4, 485 0, num_instances); 486 } else { 487 cso_draw_arrays(st->cso_context, PIPE_PRIM_TRIANGLE_FAN, 0, 4); 488 } 489 490 pipe_resource_reference(&vb.buffer, NULL); 491 492 return true; 493 } 494