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#include "main/imports.h" 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_cb_bufferobjects.h" 54#include "st_cb_xformfb.h" 55#include "st_debug.h" 56#include "st_draw.h" 57#include "st_program.h" 58#include "st_util.h" 59 60#include "pipe/p_context.h" 61#include "pipe/p_defines.h" 62#include "util/u_cpu_detect.h" 63#include "util/u_inlines.h" 64#include "util/u_format.h" 65#include "util/u_prim.h" 66#include "util/u_draw.h" 67#include "util/u_upload_mgr.h" 68#include "draw/draw_context.h" 69#include "cso_cache/cso_context.h" 70 71#if defined(PIPE_OS_LINUX) && !defined(ANDROID) 72#include <sched.h> 73#define HAVE_SCHED_GETCPU 1 74#else 75#define sched_getcpu() 0 76#define HAVE_SCHED_GETCPU 0 77#endif 78 79/** 80 * Set the restart index. 81 */ 82static void 83setup_primitive_restart(struct gl_context *ctx, struct pipe_draw_info *info) 84{ 85 if (ctx->Array._PrimitiveRestart) { 86 unsigned index_size = info->index_size; 87 88 info->restart_index = 89 _mesa_primitive_restart_index(ctx, index_size); 90 91 /* Enable primitive restart only when the restart index can have an 92 * effect. This is required for correctness in radeonsi VI support. 93 * Other hardware may also benefit from taking a faster, non-restart path 94 * when possible. 95 */ 96 if (index_size == 4 || info->restart_index < (1 << (index_size * 8))) 97 info->primitive_restart = true; 98 } 99} 100 101 102/** 103 * Translate OpenGL primtive type (GL_POINTS, GL_TRIANGLE_STRIP, etc) to 104 * the corresponding Gallium type. 105 */ 106static unsigned 107translate_prim(const struct gl_context *ctx, unsigned prim) 108{ 109 /* GL prims should match Gallium prims, spot-check a few */ 110 STATIC_ASSERT(GL_POINTS == PIPE_PRIM_POINTS); 111 STATIC_ASSERT(GL_QUADS == PIPE_PRIM_QUADS); 112 STATIC_ASSERT(GL_TRIANGLE_STRIP_ADJACENCY == PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY); 113 STATIC_ASSERT(GL_PATCHES == PIPE_PRIM_PATCHES); 114 115 return prim; 116} 117 118static inline void 119prepare_draw(struct st_context *st, struct gl_context *ctx) 120{ 121 /* Mesa core state should have been validated already */ 122 assert(ctx->NewState == 0x0); 123 124 if (unlikely(!st->bitmap.cache.empty)) 125 st_flush_bitmap_cache(st); 126 127 st_invalidate_readpix_cache(st); 128 129 /* Validate state. */ 130 if ((st->dirty | ctx->NewDriverState) & ST_PIPELINE_RENDER_STATE_MASK || 131 st->gfx_shaders_may_be_dirty) { 132 st_validate_state(st, ST_PIPELINE_RENDER); 133 } 134 135 struct pipe_context *pipe = st->pipe; 136 137 /* Pin threads regularly to the same Zen CCX that the main thread is 138 * running on. The main thread can move between CCXs. 139 */ 140 if (unlikely(HAVE_SCHED_GETCPU && /* Linux */ 141 /* AMD Zen */ 142 util_cpu_caps.nr_cpus != util_cpu_caps.cores_per_L3 && 143 /* no glthread */ 144 ctx->CurrentClientDispatch != ctx->MarshalExec && 145 /* driver support */ 146 pipe->set_context_param && 147 /* do it occasionally */ 148 ++st->pin_thread_counter % 512 == 0)) { 149 int cpu = sched_getcpu(); 150 if (cpu >= 0) { 151 unsigned L3_cache = cpu / util_cpu_caps.cores_per_L3; 152 153 pipe->set_context_param(pipe, 154 PIPE_CONTEXT_PARAM_PIN_THREADS_TO_L3_CACHE, 155 L3_cache); 156 } 157 } 158} 159 160/** 161 * This function gets plugged into the VBO module and is called when 162 * we have something to render. 163 * Basically, translate the information into the format expected by gallium. 164 * 165 * Try to keep this logic in sync with st_feedback_draw_vbo. 166 */ 167static void 168st_draw_vbo(struct gl_context *ctx, 169 const struct _mesa_prim *prims, 170 GLuint nr_prims, 171 const struct _mesa_index_buffer *ib, 172 GLboolean index_bounds_valid, 173 GLuint min_index, 174 GLuint max_index, 175 struct gl_transform_feedback_object *tfb_vertcount, 176 unsigned stream, 177 struct gl_buffer_object *indirect) 178{ 179 struct st_context *st = st_context(ctx); 180 struct pipe_draw_info info; 181 unsigned i; 182 unsigned start = 0; 183 184 prepare_draw(st, ctx); 185 186 /* Initialize pipe_draw_info. */ 187 info.primitive_restart = false; 188 info.vertices_per_patch = ctx->TessCtrlProgram.patch_vertices; 189 info.indirect = NULL; 190 info.count_from_stream_output = NULL; 191 info.restart_index = 0; 192 193 if (ib) { 194 struct gl_buffer_object *bufobj = ib->obj; 195 196 /* Get index bounds for user buffers. */ 197 if (!index_bounds_valid && st->draw_needs_minmax_index) { 198 vbo_get_minmax_indices(ctx, prims, ib, &min_index, &max_index, 199 nr_prims); 200 } 201 202 info.index_size = ib->index_size; 203 info.min_index = min_index; 204 info.max_index = max_index; 205 206 if (_mesa_is_bufferobj(bufobj)) { 207 /* indices are in a real VBO */ 208 info.has_user_indices = false; 209 info.index.resource = st_buffer_object(bufobj)->buffer; 210 211 /* Return if the bound element array buffer doesn't have any backing 212 * storage. (nothing to do) 213 */ 214 if (!info.index.resource) 215 return; 216 217 start = pointer_to_offset(ib->ptr) / info.index_size; 218 } else { 219 /* indices are in user space memory */ 220 info.has_user_indices = true; 221 info.index.user = ib->ptr; 222 } 223 224 setup_primitive_restart(ctx, &info); 225 } 226 else { 227 info.index_size = 0; 228 info.has_user_indices = false; 229 230 /* Transform feedback drawing is always non-indexed. */ 231 /* Set info.count_from_stream_output. */ 232 if (tfb_vertcount) { 233 if (!st_transform_feedback_draw_init(tfb_vertcount, stream, &info)) 234 return; 235 } 236 } 237 238 assert(!indirect); 239 240 /* do actual drawing */ 241 for (i = 0; i < nr_prims; i++) { 242 info.count = prims[i].count; 243 244 /* Skip no-op draw calls. */ 245 if (!info.count && !tfb_vertcount) 246 continue; 247 248 info.mode = translate_prim(ctx, prims[i].mode); 249 info.start = start + prims[i].start; 250 info.start_instance = prims[i].base_instance; 251 info.instance_count = prims[i].num_instances; 252 info.index_bias = prims[i].basevertex; 253 info.drawid = prims[i].draw_id; 254 if (!ib) { 255 info.min_index = info.start; 256 info.max_index = info.start + info.count - 1; 257 } 258 259 if (ST_DEBUG & DEBUG_DRAW) { 260 debug_printf("st/draw: mode %s start %u count %u index_size %d\n", 261 u_prim_name(info.mode), 262 info.start, 263 info.count, 264 info.index_size); 265 } 266 267 /* Don't call u_trim_pipe_prim. Drivers should do it if they need it. */ 268 cso_draw_vbo(st->cso_context, &info); 269 } 270} 271 272static void 273st_indirect_draw_vbo(struct gl_context *ctx, 274 GLuint mode, 275 struct gl_buffer_object *indirect_data, 276 GLsizeiptr indirect_offset, 277 unsigned draw_count, 278 unsigned stride, 279 struct gl_buffer_object *indirect_draw_count, 280 GLsizeiptr indirect_draw_count_offset, 281 const struct _mesa_index_buffer *ib) 282{ 283 struct st_context *st = st_context(ctx); 284 struct pipe_draw_info info; 285 struct pipe_draw_indirect_info indirect; 286 287 assert(stride); 288 prepare_draw(st, ctx); 289 290 memset(&indirect, 0, sizeof(indirect)); 291 util_draw_init_info(&info); 292 info.start = 0; /* index offset / index size */ 293 info.max_index = ~0u; /* so that u_vbuf can tell that it's unknown */ 294 295 if (ib) { 296 struct gl_buffer_object *bufobj = ib->obj; 297 298 /* indices are always in a real VBO */ 299 assert(_mesa_is_bufferobj(bufobj)); 300 301 info.index_size = ib->index_size; 302 info.index.resource = st_buffer_object(bufobj)->buffer; 303 info.start = pointer_to_offset(ib->ptr) / info.index_size; 304 305 /* Primitive restart is not handled by the VBO module in this case. */ 306 setup_primitive_restart(ctx, &info); 307 } 308 309 info.mode = translate_prim(ctx, mode); 310 info.vertices_per_patch = ctx->TessCtrlProgram.patch_vertices; 311 info.indirect = &indirect; 312 indirect.buffer = st_buffer_object(indirect_data)->buffer; 313 indirect.offset = indirect_offset; 314 315 if (ST_DEBUG & DEBUG_DRAW) { 316 debug_printf("st/draw indirect: mode %s drawcount %d index_size %d\n", 317 u_prim_name(info.mode), 318 draw_count, 319 info.index_size); 320 } 321 322 if (!st->has_multi_draw_indirect) { 323 int i; 324 325 assert(!indirect_draw_count); 326 indirect.draw_count = 1; 327 for (i = 0; i < draw_count; i++) { 328 info.drawid = i; 329 cso_draw_vbo(st->cso_context, &info); 330 indirect.offset += stride; 331 } 332 } else { 333 indirect.draw_count = draw_count; 334 indirect.stride = stride; 335 if (indirect_draw_count) { 336 indirect.indirect_draw_count = 337 st_buffer_object(indirect_draw_count)->buffer; 338 indirect.indirect_draw_count_offset = indirect_draw_count_offset; 339 } 340 cso_draw_vbo(st->cso_context, &info); 341 } 342} 343 344 345void 346st_init_draw_functions(struct dd_function_table *functions) 347{ 348 functions->Draw = st_draw_vbo; 349 functions->DrawIndirect = st_indirect_draw_vbo; 350} 351 352 353void 354st_destroy_draw(struct st_context *st) 355{ 356 draw_destroy(st->draw); 357} 358 359/** 360 * Getter for the draw_context, so that initialization of it can happen only 361 * when needed (the TGSI exec machines take up quite a bit of memory). 362 */ 363struct draw_context * 364st_get_draw_context(struct st_context *st) 365{ 366 if (!st->draw) { 367 st->draw = draw_create(st->pipe); 368 if (!st->draw) { 369 _mesa_error(st->ctx, GL_OUT_OF_MEMORY, "feedback fallback allocation"); 370 return NULL; 371 } 372 } 373 374 /* Disable draw options that might convert points/lines to tris, etc. 375 * as that would foul-up feedback/selection mode. 376 */ 377 draw_wide_line_threshold(st->draw, 1000.0f); 378 draw_wide_point_threshold(st->draw, 1000.0f); 379 draw_enable_line_stipple(st->draw, FALSE); 380 draw_enable_point_sprites(st->draw, FALSE); 381 382 return st->draw; 383} 384 385/** 386 * Draw a quad with given position, texcoords and color. 387 */ 388bool 389st_draw_quad(struct st_context *st, 390 float x0, float y0, float x1, float y1, float z, 391 float s0, float t0, float s1, float t1, 392 const float *color, 393 unsigned num_instances) 394{ 395 struct pipe_vertex_buffer vb = {0}; 396 struct st_util_vertex *verts; 397 398 vb.stride = sizeof(struct st_util_vertex); 399 400 u_upload_alloc(st->pipe->stream_uploader, 0, 401 4 * sizeof(struct st_util_vertex), 4, 402 &vb.buffer_offset, &vb.buffer.resource, (void **) &verts); 403 if (!vb.buffer.resource) { 404 return false; 405 } 406 407 /* lower-left */ 408 verts[0].x = x0; 409 verts[0].y = y1; 410 verts[0].z = z; 411 verts[0].r = color[0]; 412 verts[0].g = color[1]; 413 verts[0].b = color[2]; 414 verts[0].a = color[3]; 415 verts[0].s = s0; 416 verts[0].t = t0; 417 418 /* lower-right */ 419 verts[1].x = x1; 420 verts[1].y = y1; 421 verts[1].z = z; 422 verts[1].r = color[0]; 423 verts[1].g = color[1]; 424 verts[1].b = color[2]; 425 verts[1].a = color[3]; 426 verts[1].s = s1; 427 verts[1].t = t0; 428 429 /* upper-right */ 430 verts[2].x = x1; 431 verts[2].y = y0; 432 verts[2].z = z; 433 verts[2].r = color[0]; 434 verts[2].g = color[1]; 435 verts[2].b = color[2]; 436 verts[2].a = color[3]; 437 verts[2].s = s1; 438 verts[2].t = t1; 439 440 /* upper-left */ 441 verts[3].x = x0; 442 verts[3].y = y0; 443 verts[3].z = z; 444 verts[3].r = color[0]; 445 verts[3].g = color[1]; 446 verts[3].b = color[2]; 447 verts[3].a = color[3]; 448 verts[3].s = s0; 449 verts[3].t = t1; 450 451 u_upload_unmap(st->pipe->stream_uploader); 452 453 cso_set_vertex_buffers(st->cso_context, 0, 1, &vb); 454 455 if (num_instances > 1) { 456 cso_draw_arrays_instanced(st->cso_context, PIPE_PRIM_TRIANGLE_FAN, 0, 4, 457 0, num_instances); 458 } else { 459 cso_draw_arrays(st->cso_context, PIPE_PRIM_TRIANGLE_FAN, 0, 4); 460 } 461 462 pipe_resource_reference(&vb.buffer.resource, NULL); 463 464 return true; 465} 466