st_draw.c revision bfa50f88cea2ba9f4dc4b825828d2c8f02866fc3
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@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 */ 73static GLboolean 74all_varyings_in_vbos(const struct gl_client_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 */ 93static boolean 94setup_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 * Translate OpenGL primtive type (GL_POINTS, GL_TRIANGLE_STRIP, etc) to 131 * the corresponding Gallium type. 132 */ 133static unsigned 134translate_prim(const struct gl_context *ctx, unsigned prim) 135{ 136 /* GL prims should match Gallium prims, spot-check a few */ 137 STATIC_ASSERT(GL_POINTS == PIPE_PRIM_POINTS); 138 STATIC_ASSERT(GL_QUADS == PIPE_PRIM_QUADS); 139 STATIC_ASSERT(GL_TRIANGLE_STRIP_ADJACENCY == PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY); 140 STATIC_ASSERT(GL_PATCHES == PIPE_PRIM_PATCHES); 141 142 return prim; 143} 144 145 146/** 147 * This function gets plugged into the VBO module and is called when 148 * we have something to render. 149 * Basically, translate the information into the format expected by gallium. 150 */ 151void 152st_draw_vbo(struct gl_context *ctx, 153 const struct _mesa_prim *prims, 154 GLuint nr_prims, 155 const struct _mesa_index_buffer *ib, 156 GLboolean index_bounds_valid, 157 GLuint min_index, 158 GLuint max_index, 159 struct gl_transform_feedback_object *tfb_vertcount, 160 unsigned stream, 161 struct gl_buffer_object *indirect) 162{ 163 struct st_context *st = st_context(ctx); 164 struct pipe_index_buffer ibuffer = {0}; 165 struct pipe_draw_info info; 166 const struct gl_client_array **arrays = ctx->Array._DrawArrays; 167 unsigned i; 168 169 /* Mesa core state should have been validated already */ 170 assert(ctx->NewState == 0x0); 171 172 st_flush_bitmap_cache(st); 173 st_invalidate_readpix_cache(st); 174 175 /* Validate state. */ 176 if ((st->dirty | ctx->NewDriverState) & ST_PIPELINE_RENDER_STATE_MASK || 177 st->gfx_shaders_may_be_dirty) { 178 st_validate_state(st, ST_PIPELINE_RENDER); 179 } 180 181 if (st->vertex_array_out_of_memory) { 182 return; 183 } 184 185 util_draw_init_info(&info); 186 187 if (ib) { 188 /* Get index bounds for user buffers. */ 189 if (!index_bounds_valid) 190 if (!all_varyings_in_vbos(arrays)) 191 vbo_get_minmax_indices(ctx, prims, ib, &min_index, &max_index, 192 nr_prims); 193 194 if (!setup_index_buffer(st, ib, &ibuffer)) { 195 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBegin/DrawElements/DrawArray"); 196 return; 197 } 198 199 info.indexed = TRUE; 200 if (min_index != ~0U && max_index != ~0U) { 201 info.min_index = min_index; 202 info.max_index = max_index; 203 } 204 205 /* The VBO module handles restart for the non-indexed GLDrawArrays 206 * so we only set these fields for indexed drawing: 207 */ 208 if (ctx->Array._PrimitiveRestart) { 209 info.restart_index = _mesa_primitive_restart_index(ctx, ib->type); 210 211 /* Enable primitive restart only when the restart index can have an 212 * effect. This is required for correctness in radeonsi VI support, 213 * though other hardware may also benefit from taking a faster, 214 * non-restart path when possible. 215 */ 216 if ((ibuffer.index_size >= 4) || 217 (ibuffer.index_size >= 2 && info.restart_index <= 0xffff) || 218 (info.restart_index <= 0xff)) 219 info.primitive_restart = true; 220 } 221 } 222 else { 223 /* Transform feedback drawing is always non-indexed. */ 224 /* Set info.count_from_stream_output. */ 225 if (tfb_vertcount) { 226 if (!st_transform_feedback_draw_init(tfb_vertcount, stream, &info)) 227 return; 228 } 229 } 230 231 assert(!indirect); 232 233 /* do actual drawing */ 234 for (i = 0; i < nr_prims; i++) { 235 info.mode = translate_prim(ctx, prims[i].mode); 236 info.start = prims[i].start; 237 info.count = prims[i].count; 238 info.start_instance = prims[i].base_instance; 239 info.instance_count = prims[i].num_instances; 240 info.vertices_per_patch = ctx->TessCtrlProgram.patch_vertices; 241 info.index_bias = prims[i].basevertex; 242 info.drawid = prims[i].draw_id; 243 if (!ib) { 244 info.min_index = info.start; 245 info.max_index = info.start + info.count - 1; 246 } 247 248 if (ST_DEBUG & DEBUG_DRAW) { 249 debug_printf("st/draw: mode %s start %u count %u indexed %d\n", 250 u_prim_name(info.mode), 251 info.start, 252 info.count, 253 info.indexed); 254 } 255 256 if (info.count_from_stream_output) { 257 cso_draw_vbo(st->cso_context, &info); 258 } 259 else if (info.primitive_restart) { 260 /* don't trim, restarts might be inside index list */ 261 cso_draw_vbo(st->cso_context, &info); 262 } 263 else if (u_trim_pipe_prim(prims[i].mode, &info.count)) { 264 cso_draw_vbo(st->cso_context, &info); 265 } 266 } 267 268 if (ib && st->indexbuf_uploader && !_mesa_is_bufferobj(ib->obj)) { 269 pipe_resource_reference(&ibuffer.buffer, NULL); 270 } 271} 272 273static void 274st_indirect_draw_vbo(struct gl_context *ctx, 275 GLuint mode, 276 struct gl_buffer_object *indirect_data, 277 GLsizeiptr indirect_offset, 278 unsigned draw_count, 279 unsigned stride, 280 struct gl_buffer_object *indirect_params, 281 GLsizeiptr indirect_params_offset, 282 const struct _mesa_index_buffer *ib) 283{ 284 struct st_context *st = st_context(ctx); 285 struct pipe_index_buffer ibuffer = {0}; 286 struct pipe_draw_info info; 287 288 /* Mesa core state should have been validated already */ 289 assert(ctx->NewState == 0x0); 290 assert(stride); 291 292 /* Validate state. */ 293 if ((st->dirty | ctx->NewDriverState) & ST_PIPELINE_RENDER_STATE_MASK || 294 st->gfx_shaders_may_be_dirty) { 295 st_validate_state(st, ST_PIPELINE_RENDER); 296 } 297 298 if (st->vertex_array_out_of_memory) { 299 return; 300 } 301 302 util_draw_init_info(&info); 303 304 if (ib) { 305 if (!setup_index_buffer(st, ib, &ibuffer)) { 306 _mesa_error(ctx, GL_OUT_OF_MEMORY, "gl%sDrawElementsIndirect%s", 307 (draw_count > 1) ? "Multi" : "", 308 indirect_params ? "CountARB" : ""); 309 return; 310 } 311 312 info.indexed = TRUE; 313 } 314 315 info.mode = translate_prim(ctx, mode); 316 info.vertices_per_patch = ctx->TessCtrlProgram.patch_vertices; 317 info.indirect = st_buffer_object(indirect_data)->buffer; 318 info.indirect_offset = indirect_offset; 319 320 /* Primitive restart is not handled by the VBO module in this case. */ 321 info.primitive_restart = ctx->Array._PrimitiveRestart; 322 info.restart_index = ctx->Array.RestartIndex; 323 324 if (ST_DEBUG & DEBUG_DRAW) { 325 debug_printf("st/draw indirect: mode %s drawcount %d indexed %d\n", 326 u_prim_name(info.mode), 327 draw_count, 328 info.indexed); 329 } 330 331 if (!st->has_multi_draw_indirect) { 332 int i; 333 334 assert(!indirect_params); 335 info.indirect_count = 1; 336 for (i = 0; i < draw_count; i++) { 337 info.drawid = i; 338 cso_draw_vbo(st->cso_context, &info); 339 info.indirect_offset += stride; 340 } 341 } else { 342 info.indirect_count = draw_count; 343 info.indirect_stride = stride; 344 if (indirect_params) { 345 info.indirect_params = st_buffer_object(indirect_params)->buffer; 346 info.indirect_params_offset = indirect_params_offset; 347 } 348 cso_draw_vbo(st->cso_context, &info); 349 } 350} 351 352 353void 354st_init_draw(struct st_context *st) 355{ 356 struct gl_context *ctx = st->ctx; 357 358 vbo_set_draw_func(ctx, st_draw_vbo); 359 vbo_set_indirect_draw_func(ctx, st_indirect_draw_vbo); 360} 361 362 363void 364st_destroy_draw(struct st_context *st) 365{ 366 draw_destroy(st->draw); 367} 368 369/** 370 * Getter for the draw_context, so that initialization of it can happen only 371 * when needed (the TGSI exec machines take up quite a bit of memory). 372 */ 373struct draw_context * 374st_get_draw_context(struct st_context *st) 375{ 376 if (!st->draw) { 377 st->draw = draw_create(st->pipe); 378 if (!st->draw) { 379 _mesa_error(st->ctx, GL_OUT_OF_MEMORY, "feedback fallback allocation"); 380 return NULL; 381 } 382 } 383 384 /* Disable draw options that might convert points/lines to tris, etc. 385 * as that would foul-up feedback/selection mode. 386 */ 387 draw_wide_line_threshold(st->draw, 1000.0f); 388 draw_wide_point_threshold(st->draw, 1000.0f); 389 draw_enable_line_stipple(st->draw, FALSE); 390 draw_enable_point_sprites(st->draw, FALSE); 391 392 return st->draw; 393} 394 395/** 396 * Draw a quad with given position, texcoords and color. 397 */ 398bool 399st_draw_quad(struct st_context *st, 400 float x0, float y0, float x1, float y1, float z, 401 float s0, float t0, float s1, float t1, 402 const float *color, 403 unsigned num_instances) 404{ 405 struct pipe_vertex_buffer vb = {0}; 406 struct st_util_vertex *verts; 407 408 vb.stride = sizeof(struct st_util_vertex); 409 410 u_upload_alloc(st->uploader, 0, 4 * sizeof(struct st_util_vertex), 4, 411 &vb.buffer_offset, &vb.buffer, (void **) &verts); 412 if (!vb.buffer) { 413 return false; 414 } 415 416 /* lower-left */ 417 verts[0].x = x0; 418 verts[0].y = y1; 419 verts[0].z = z; 420 verts[0].r = color[0]; 421 verts[0].g = color[1]; 422 verts[0].b = color[2]; 423 verts[0].a = color[3]; 424 verts[0].s = s0; 425 verts[0].t = t0; 426 427 /* lower-right */ 428 verts[1].x = x1; 429 verts[1].y = y1; 430 verts[1].z = z; 431 verts[1].r = color[0]; 432 verts[1].g = color[1]; 433 verts[1].b = color[2]; 434 verts[1].a = color[3]; 435 verts[1].s = s1; 436 verts[1].t = t0; 437 438 /* upper-right */ 439 verts[2].x = x1; 440 verts[2].y = y0; 441 verts[2].z = z; 442 verts[2].r = color[0]; 443 verts[2].g = color[1]; 444 verts[2].b = color[2]; 445 verts[2].a = color[3]; 446 verts[2].s = s1; 447 verts[2].t = t1; 448 449 /* upper-left */ 450 verts[3].x = x0; 451 verts[3].y = y0; 452 verts[3].z = z; 453 verts[3].r = color[0]; 454 verts[3].g = color[1]; 455 verts[3].b = color[2]; 456 verts[3].a = color[3]; 457 verts[3].s = s0; 458 verts[3].t = t1; 459 460 u_upload_unmap(st->uploader); 461 462 /* At the time of writing, cso_get_aux_vertex_buffer_slot() always returns 463 * zero. If that ever changes we need to audit the calls to that function 464 * and make sure the slot number is used consistently everywhere. 465 */ 466 assert(cso_get_aux_vertex_buffer_slot(st->cso_context) == 0); 467 468 cso_set_vertex_buffers(st->cso_context, 469 cso_get_aux_vertex_buffer_slot(st->cso_context), 470 1, &vb); 471 472 if (num_instances > 1) { 473 cso_draw_arrays_instanced(st->cso_context, PIPE_PRIM_TRIANGLE_FAN, 0, 4, 474 0, num_instances); 475 } else { 476 cso_draw_arrays(st->cso_context, PIPE_PRIM_TRIANGLE_FAN, 0, 4); 477 } 478 479 pipe_resource_reference(&vb.buffer, NULL); 480 481 return true; 482} 483