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