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/errors.h" 40 41#include "main/image.h" 42#include "main/bufferobj.h" 43#include "main/macros.h" 44#include "main/varray.h" 45 46#include "compiler/glsl/ir_uniform.h" 47 48#include "vbo/vbo.h" 49 50#include "st_context.h" 51#include "st_atom.h" 52#include "st_cb_bitmap.h" 53#include "st_debug.h" 54#include "st_draw.h" 55#include "st_program.h" 56#include "st_util.h" 57 58#include "pipe/p_context.h" 59#include "pipe/p_defines.h" 60#include "util/u_cpu_detect.h" 61#include "util/u_inlines.h" 62#include "util/format/u_format.h" 63#include "util/u_prim.h" 64#include "util/u_draw.h" 65#include "util/u_upload_mgr.h" 66#include "util/u_threaded_context.h" 67#include "draw/draw_context.h" 68#include "cso_cache/cso_context.h" 69 70 71/** 72 * Translate OpenGL primtive type (GL_POINTS, GL_TRIANGLE_STRIP, etc) to 73 * the corresponding Gallium type. 74 */ 75static unsigned 76translate_prim(const struct gl_context *ctx, unsigned prim) 77{ 78 /* GL prims should match Gallium prims, spot-check a few */ 79 STATIC_ASSERT(GL_POINTS == PIPE_PRIM_POINTS); 80 STATIC_ASSERT(GL_QUADS == PIPE_PRIM_QUADS); 81 STATIC_ASSERT(GL_TRIANGLE_STRIP_ADJACENCY == PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY); 82 STATIC_ASSERT(GL_PATCHES == PIPE_PRIM_PATCHES); 83 84 return prim; 85} 86 87static inline void 88prepare_draw(struct st_context *st, struct gl_context *ctx, uint64_t state_mask, 89 enum st_pipeline pipeline) 90{ 91 /* Mesa core state should have been validated already */ 92 assert(ctx->NewState == 0x0); 93 94 if (unlikely(!st->bitmap.cache.empty)) 95 st_flush_bitmap_cache(st); 96 97 st_invalidate_readpix_cache(st); 98 99 /* Validate state. */ 100 if ((st->dirty | ctx->NewDriverState) & st->active_states & state_mask || 101 st->gfx_shaders_may_be_dirty) { 102 st_validate_state(st, pipeline); 103 } 104 105 /* Pin threads regularly to the same Zen CCX that the main thread is 106 * running on. The main thread can move between CCXs. 107 */ 108 if (unlikely(st->pin_thread_counter != ST_L3_PINNING_DISABLED && 109 /* no glthread */ 110 !ctx->GLThread.enabled && 111 /* do it occasionally */ 112 ++st->pin_thread_counter % 512 == 0)) { 113 st->pin_thread_counter = 0; 114 115 int cpu = util_get_current_cpu(); 116 if (cpu >= 0) { 117 struct pipe_context *pipe = st->pipe; 118 uint16_t L3_cache = util_get_cpu_caps()->cpu_to_L3[cpu]; 119 120 if (L3_cache != U_CPU_INVALID_L3) { 121 pipe->set_context_param(pipe, 122 PIPE_CONTEXT_PARAM_PIN_THREADS_TO_L3_CACHE, 123 L3_cache); 124 } 125 } 126 } 127} 128 129static bool ALWAYS_INLINE 130prepare_indexed_draw(/* pass both st and ctx to reduce dereferences */ 131 struct st_context *st, 132 struct gl_context *ctx, 133 struct pipe_draw_info *info, 134 const struct pipe_draw_start_count_bias *draws, 135 unsigned num_draws) 136{ 137 if (info->index_size) { 138 /* Get index bounds for user buffers. */ 139 if (!info->index_bounds_valid && 140 st->draw_needs_minmax_index) { 141 /* Return if this fails, which means all draws have count == 0. */ 142 if (!vbo_get_minmax_indices_gallium(ctx, info, draws, num_draws)) 143 return false; 144 145 info->index_bounds_valid = true; 146 } 147 148 if (!info->has_user_indices) { 149 if (st->pipe->draw_vbo == tc_draw_vbo) { 150 /* Fast path for u_threaded_context. This eliminates the atomic 151 * increment for the index buffer refcount when adding it into 152 * the threaded batch buffer. 153 */ 154 info->index.resource = 155 _mesa_get_bufferobj_reference(ctx, info->index.gl_bo); 156 info->take_index_buffer_ownership = true; 157 } else { 158 info->index.resource = info->index.gl_bo->buffer; 159 } 160 161 /* Return if the bound element array buffer doesn't have any backing 162 * storage. (nothing to do) 163 */ 164 if (unlikely(!info->index.resource)) 165 return false; 166 } 167 } 168 return true; 169} 170 171static void 172st_draw_gallium(struct gl_context *ctx, 173 struct pipe_draw_info *info, 174 unsigned drawid_offset, 175 const struct pipe_draw_start_count_bias *draws, 176 unsigned num_draws) 177{ 178 struct st_context *st = st_context(ctx); 179 180 prepare_draw(st, ctx, ST_PIPELINE_RENDER_STATE_MASK, ST_PIPELINE_RENDER); 181 182 if (!prepare_indexed_draw(st, ctx, info, draws, num_draws)) 183 return; 184 185 cso_multi_draw(st->cso_context, info, drawid_offset, draws, num_draws); 186} 187 188static void 189st_draw_gallium_multimode(struct gl_context *ctx, 190 struct pipe_draw_info *info, 191 const struct pipe_draw_start_count_bias *draws, 192 const unsigned char *mode, 193 unsigned num_draws) 194{ 195 struct st_context *st = st_context(ctx); 196 197 prepare_draw(st, ctx, ST_PIPELINE_RENDER_STATE_MASK, ST_PIPELINE_RENDER); 198 199 if (!prepare_indexed_draw(st, ctx, info, draws, num_draws)) 200 return; 201 202 unsigned i, first; 203 struct cso_context *cso = st->cso_context; 204 205 /* Find consecutive draws where mode doesn't vary. */ 206 for (i = 0, first = 0; i <= num_draws; i++) { 207 if (i == num_draws || mode[i] != mode[first]) { 208 info->mode = mode[first]; 209 cso_multi_draw(cso, info, 0, &draws[first], i - first); 210 first = i; 211 212 /* We can pass the reference only once. st_buffer_object keeps 213 * the reference alive for later draws. 214 */ 215 info->take_index_buffer_ownership = false; 216 } 217 } 218} 219 220static void 221rewrite_partial_stride_indirect(struct st_context *st, 222 const struct pipe_draw_info *info, 223 const struct pipe_draw_indirect_info *indirect, 224 const struct pipe_draw_start_count_bias draw) 225{ 226 unsigned draw_count = 0; 227 struct u_indirect_params *new_draws = util_draw_indirect_read(st->pipe, info, indirect, &draw_count); 228 if (!new_draws) 229 return; 230 for (unsigned i = 0; i < draw_count; i++) 231 cso_draw_vbo(st->cso_context, &new_draws[i].info, i, NULL, new_draws[i].draw); 232 free(new_draws); 233} 234 235void 236st_indirect_draw_vbo(struct gl_context *ctx, 237 GLuint mode, 238 struct gl_buffer_object *indirect_data, 239 GLsizeiptr indirect_offset, 240 unsigned draw_count, 241 unsigned stride, 242 struct gl_buffer_object *indirect_draw_count, 243 GLsizeiptr indirect_draw_count_offset, 244 const struct _mesa_index_buffer *ib, 245 bool primitive_restart, 246 unsigned restart_index) 247{ 248 struct st_context *st = st_context(ctx); 249 struct pipe_draw_info info; 250 struct pipe_draw_indirect_info indirect; 251 struct pipe_draw_start_count_bias draw = {0}; 252 253 assert(stride); 254 prepare_draw(st, ctx, ST_PIPELINE_RENDER_STATE_MASK, ST_PIPELINE_RENDER); 255 256 memset(&indirect, 0, sizeof(indirect)); 257 util_draw_init_info(&info); 258 info.max_index = ~0u; /* so that u_vbuf can tell that it's unknown */ 259 260 if (ib) { 261 struct gl_buffer_object *bufobj = ib->obj; 262 263 /* indices are always in a real VBO */ 264 assert(bufobj); 265 266 info.index_size = 1 << ib->index_size_shift; 267 info.index.resource = bufobj->buffer; 268 draw.start = pointer_to_offset(ib->ptr) >> ib->index_size_shift; 269 270 info.restart_index = restart_index; 271 info.primitive_restart = primitive_restart; 272 } 273 274 info.mode = translate_prim(ctx, mode); 275 indirect.buffer = indirect_data->buffer; 276 indirect.offset = indirect_offset; 277 278 /* Viewperf2020/Maya draws with a buffer that has no storage. */ 279 if (!indirect.buffer) 280 return; 281 282 if (!st->has_multi_draw_indirect) { 283 int i; 284 285 assert(!indirect_draw_count); 286 indirect.draw_count = 1; 287 for (i = 0; i < draw_count; i++) { 288 cso_draw_vbo(st->cso_context, &info, i, &indirect, draw); 289 indirect.offset += stride; 290 } 291 } else { 292 indirect.draw_count = draw_count; 293 indirect.stride = stride; 294 if (!st->has_indirect_partial_stride && stride && 295 (draw_count > 1 || indirect_draw_count)) { 296 /* DrawElementsIndirectCommand or DrawArraysIndirectCommand */ 297 const size_t struct_size = info.index_size ? sizeof(uint32_t) * 5 : sizeof(uint32_t) * 4; 298 if (indirect.stride && indirect.stride < struct_size) { 299 rewrite_partial_stride_indirect(st, &info, &indirect, draw); 300 return; 301 } 302 } 303 if (indirect_draw_count) { 304 indirect.indirect_draw_count = 305 indirect_draw_count->buffer; 306 indirect.indirect_draw_count_offset = indirect_draw_count_offset; 307 } 308 cso_draw_vbo(st->cso_context, &info, 0, &indirect, draw); 309 } 310} 311 312void 313st_draw_transform_feedback(struct gl_context *ctx, GLenum mode, 314 unsigned num_instances, unsigned stream, 315 struct gl_transform_feedback_object *tfb_vertcount) 316{ 317 struct st_context *st = st_context(ctx); 318 struct pipe_draw_info info; 319 struct pipe_draw_indirect_info indirect; 320 struct pipe_draw_start_count_bias draw = {0}; 321 322 prepare_draw(st, ctx, ST_PIPELINE_RENDER_STATE_MASK, ST_PIPELINE_RENDER); 323 324 memset(&indirect, 0, sizeof(indirect)); 325 util_draw_init_info(&info); 326 info.max_index = ~0u; /* so that u_vbuf can tell that it's unknown */ 327 info.mode = translate_prim(ctx, mode); 328 info.instance_count = num_instances; 329 330 /* Transform feedback drawing is always non-indexed. */ 331 /* Set info.count_from_stream_output. */ 332 indirect.count_from_stream_output = tfb_vertcount->draw_count[stream]; 333 if (indirect.count_from_stream_output == NULL) 334 return; 335 336 cso_draw_vbo(st->cso_context, &info, 0, &indirect, draw); 337} 338 339static void 340st_draw_gallium_vertex_state(struct gl_context *ctx, 341 struct pipe_vertex_state *state, 342 struct pipe_draw_vertex_state_info info, 343 const struct pipe_draw_start_count_bias *draws, 344 const uint8_t *mode, 345 unsigned num_draws, 346 bool per_vertex_edgeflags) 347{ 348 struct st_context *st = st_context(ctx); 349 bool old_vertdata_edgeflags = st->vertdata_edgeflags; 350 351 /* We don't flag any other states to make st_validate state update edge 352 * flags, so we need to update them here. 353 */ 354 st_update_edgeflags(st, per_vertex_edgeflags); 355 356 prepare_draw(st, ctx, ST_PIPELINE_RENDER_STATE_MASK_NO_VARRAYS, 357 ST_PIPELINE_RENDER_NO_VARRAYS); 358 359 struct pipe_context *pipe = st->pipe; 360 uint32_t velem_mask = ctx->VertexProgram._Current->info.inputs_read; 361 362 if (!mode) { 363 pipe->draw_vertex_state(pipe, state, velem_mask, info, draws, num_draws); 364 } else { 365 /* Find consecutive draws where mode doesn't vary. */ 366 for (unsigned i = 0, first = 0; i <= num_draws; i++) { 367 if (i == num_draws || mode[i] != mode[first]) { 368 unsigned current_num_draws = i - first; 369 370 /* Increase refcount to be able to use take_vertex_state_ownership 371 * with all draws. 372 */ 373 if (i != num_draws && info.take_vertex_state_ownership) 374 p_atomic_inc(&state->reference.count); 375 376 info.mode = mode[first]; 377 pipe->draw_vertex_state(pipe, state, velem_mask, info, &draws[first], 378 current_num_draws); 379 first = i; 380 } 381 } 382 } 383 384 /* If per-vertex edge flags are different than the non-display-list state, 385 * just flag ST_NEW_VERTEX_ARRAY, which will also completely revalidate 386 * edge flags in st_validate_state. 387 */ 388 if (st->vertdata_edgeflags != old_vertdata_edgeflags) { 389 ctx->Array.NewVertexElements = true; 390 st->dirty |= ST_NEW_VERTEX_ARRAYS; 391 } 392} 393 394void 395st_init_draw_functions(struct pipe_screen *screen, 396 struct dd_function_table *functions) 397{ 398 functions->DrawGallium = st_draw_gallium; 399 functions->DrawGalliumMultiMode = st_draw_gallium_multimode; 400 401 if (screen->get_param(screen, PIPE_CAP_DRAW_VERTEX_STATE)) { 402 functions->DrawGalliumVertexState = st_draw_gallium_vertex_state; 403 functions->CreateGalliumVertexState = st_create_gallium_vertex_state; 404 } 405} 406 407 408void 409st_destroy_draw(struct st_context *st) 410{ 411 draw_destroy(st->draw); 412} 413 414/** 415 * Getter for the draw_context, so that initialization of it can happen only 416 * when needed (the TGSI exec machines take up quite a bit of memory). 417 */ 418struct draw_context * 419st_get_draw_context(struct st_context *st) 420{ 421 if (!st->draw) { 422 st->draw = draw_create(st->pipe); 423 if (!st->draw) { 424 _mesa_error(st->ctx, GL_OUT_OF_MEMORY, "feedback fallback allocation"); 425 return NULL; 426 } 427 } 428 429 /* Disable draw options that might convert points/lines to tris, etc. 430 * as that would foul-up feedback/selection mode. 431 */ 432 draw_wide_line_threshold(st->draw, 1000.0f); 433 draw_wide_point_threshold(st->draw, 1000.0f); 434 draw_enable_line_stipple(st->draw, FALSE); 435 draw_enable_point_sprites(st->draw, FALSE); 436 437 return st->draw; 438} 439 440/** 441 * Draw a quad with given position, texcoords and color. 442 */ 443bool 444st_draw_quad(struct st_context *st, 445 float x0, float y0, float x1, float y1, float z, 446 float s0, float t0, float s1, float t1, 447 const float *color, 448 unsigned num_instances) 449{ 450 struct pipe_vertex_buffer vb = {0}; 451 struct st_util_vertex *verts; 452 453 vb.stride = sizeof(struct st_util_vertex); 454 455 u_upload_alloc(st->pipe->stream_uploader, 0, 456 4 * sizeof(struct st_util_vertex), 4, 457 &vb.buffer_offset, &vb.buffer.resource, (void **) &verts); 458 if (!vb.buffer.resource) { 459 return false; 460 } 461 462 /* lower-left */ 463 verts[0].x = x0; 464 verts[0].y = y1; 465 verts[0].z = z; 466 verts[0].r = color[0]; 467 verts[0].g = color[1]; 468 verts[0].b = color[2]; 469 verts[0].a = color[3]; 470 verts[0].s = s0; 471 verts[0].t = t0; 472 473 /* lower-right */ 474 verts[1].x = x1; 475 verts[1].y = y1; 476 verts[1].z = z; 477 verts[1].r = color[0]; 478 verts[1].g = color[1]; 479 verts[1].b = color[2]; 480 verts[1].a = color[3]; 481 verts[1].s = s1; 482 verts[1].t = t0; 483 484 /* upper-right */ 485 verts[2].x = x1; 486 verts[2].y = y0; 487 verts[2].z = z; 488 verts[2].r = color[0]; 489 verts[2].g = color[1]; 490 verts[2].b = color[2]; 491 verts[2].a = color[3]; 492 verts[2].s = s1; 493 verts[2].t = t1; 494 495 /* upper-left */ 496 verts[3].x = x0; 497 verts[3].y = y0; 498 verts[3].z = z; 499 verts[3].r = color[0]; 500 verts[3].g = color[1]; 501 verts[3].b = color[2]; 502 verts[3].a = color[3]; 503 verts[3].s = s0; 504 verts[3].t = t1; 505 506 u_upload_unmap(st->pipe->stream_uploader); 507 508 cso_set_vertex_buffers(st->cso_context, 0, 1, 0, false, &vb); 509 st->last_num_vbuffers = MAX2(st->last_num_vbuffers, 1); 510 511 if (num_instances > 1) { 512 cso_draw_arrays_instanced(st->cso_context, PIPE_PRIM_TRIANGLE_FAN, 0, 4, 513 0, num_instances); 514 } else { 515 cso_draw_arrays(st->cso_context, PIPE_PRIM_TRIANGLE_FAN, 0, 4); 516 } 517 518 pipe_resource_reference(&vb.buffer.resource, NULL); 519 520 return true; 521} 522 523static void 524st_hw_select_draw_gallium(struct gl_context *ctx, 525 struct pipe_draw_info *info, 526 unsigned drawid_offset, 527 const struct pipe_draw_start_count_bias *draws, 528 unsigned num_draws) 529{ 530 struct st_context *st = st_context(ctx); 531 532 prepare_draw(st, ctx, ST_PIPELINE_RENDER_STATE_MASK, ST_PIPELINE_RENDER); 533 534 if (!prepare_indexed_draw(st, ctx, info, draws, num_draws)) 535 return; 536 537 if (!st_draw_hw_select_prepare_common(ctx) || 538 !st_draw_hw_select_prepare_mode(ctx, info)) 539 return; 540 541 cso_multi_draw(st->cso_context, info, drawid_offset, draws, num_draws); 542} 543 544static void 545st_hw_select_draw_gallium_multimode(struct gl_context *ctx, 546 struct pipe_draw_info *info, 547 const struct pipe_draw_start_count_bias *draws, 548 const unsigned char *mode, 549 unsigned num_draws) 550{ 551 struct st_context *st = st_context(ctx); 552 553 prepare_draw(st, ctx, ST_PIPELINE_RENDER_STATE_MASK, ST_PIPELINE_RENDER); 554 555 if (!prepare_indexed_draw(st, ctx, info, draws, num_draws)) 556 return; 557 558 if (!st_draw_hw_select_prepare_common(ctx)) 559 return; 560 561 unsigned i, first; 562 struct cso_context *cso = st->cso_context; 563 564 /* Find consecutive draws where mode doesn't vary. */ 565 for (i = 0, first = 0; i <= num_draws; i++) { 566 if (i == num_draws || mode[i] != mode[first]) { 567 info->mode = mode[first]; 568 569 if (st_draw_hw_select_prepare_mode(ctx, info)) 570 cso_multi_draw(cso, info, 0, &draws[first], i - first); 571 572 first = i; 573 574 /* We can pass the reference only once. st_buffer_object keeps 575 * the reference alive for later draws. 576 */ 577 info->take_index_buffer_ownership = false; 578 } 579 } 580} 581 582void 583st_init_hw_select_draw_functions(struct pipe_screen *screen, 584 struct dd_function_table *functions) 585{ 586 functions->DrawGallium = st_hw_select_draw_gallium; 587 functions->DrawGalliumMultiMode = st_hw_select_draw_gallium_multimode; 588} 589