1 2/* 3 * Mesa 3-D graphics library 4 * 5 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the "Software"), 9 * to deal in the Software without restriction, including without limitation 10 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 * and/or sell copies of the Software, and to permit persons to whom the 12 * Software is furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included 15 * in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 * OTHER DEALINGS IN THE SOFTWARE. 24 * 25 * Authors: 26 * Keith Whitwell <keithw@vmware.com> 27 */ 28 29/* Helper for drivers which find themselves rendering a range of 30 * indices starting somewhere above zero. Typically the application 31 * is issuing multiple DrawArrays() or DrawElements() to draw 32 * successive primitives layed out linearly in the vertex arrays. 33 * Unless the vertex arrays are all in a VBO, the OpenGL semantics 34 * imply that we need to re-upload the vertex data on each draw call. 35 * In that case, we want to avoid starting the upload at zero, as it 36 * will mean every draw call uploads an increasing amount of not-used 37 * vertex data. Worse - in the software tnl module, all those 38 * vertices will be transformed and lit. 39 * 40 * If we just upload the new data, however, the indices will be 41 * incorrect as we tend to upload each set of vertex data to a new 42 * region. 43 * 44 * This file provides a helper to adjust the arrays, primitives and 45 * indices of a draw call so that it can be re-issued with a min_index 46 * of zero. 47 */ 48 49#include <stdio.h> 50#include "main/bufferobj.h" 51#include "main/errors.h" 52#include "main/glheader.h" 53#include "main/macros.h" 54#include "main/mtypes.h" 55#include "vbo/vbo.h" 56 57#include "t_rebase.h" 58 59 60#define REBASE(TYPE) \ 61static void *rebase_##TYPE(const void *ptr, \ 62 unsigned start, \ 63 unsigned count, \ 64 TYPE min_index) \ 65{ \ 66 const TYPE *in = (TYPE *)ptr; \ 67 TYPE *tmp_indices = malloc((start + count) * sizeof(TYPE)); \ 68 \ 69 if (tmp_indices == NULL) { \ 70 _mesa_error_no_memory(__func__); \ 71 return NULL; \ 72 } \ 73 \ 74 for (unsigned i = 0; i < count; i++) \ 75 tmp_indices[start + i] = in[start + i] - min_index; \ 76 \ 77 return (void *)tmp_indices; \ 78} 79 80REBASE(GLuint) 81REBASE(GLushort) 82REBASE(GLubyte) 83 84 85/* Adjust primitives, indices and vertex definitions so that min_index 86 * becomes zero. There are lots of reasons for wanting to do this, eg: 87 * 88 * Software tnl: 89 * - any time min_index != 0, otherwise unused vertices lower than 90 * min_index will be transformed. 91 * 92 * Hardware tnl: 93 * - if ib != NULL and min_index != 0, otherwise vertices lower than 94 * min_index will be uploaded. Requires adjusting index values. 95 * 96 * - if ib == NULL and min_index != 0, just for convenience so this doesn't 97 * have to be handled within the driver. 98 * 99 * Hardware tnl with VBO support: 100 * - as above, but only when vertices are not (all?) in VBO's. 101 * - can't save time by trying to upload half a vbo - typically it is 102 * all or nothing. 103 */ 104void t_rebase_prims(struct gl_context *ctx, 105 const struct tnl_vertex_array *arrays, 106 const struct _mesa_prim *prim, 107 GLuint nr_prims, 108 const struct _mesa_index_buffer *ib, 109 GLuint min_index, 110 GLuint max_index, 111 GLuint num_instances, 112 GLuint base_instance, 113 tnl_draw_func draw) 114{ 115 struct gl_array_attributes tmp_attribs[VERT_ATTRIB_MAX]; 116 struct tnl_vertex_array tmp_arrays[VERT_ATTRIB_MAX]; 117 118 struct _mesa_index_buffer tmp_ib; 119 struct _mesa_prim *tmp_prims = NULL; 120 void *tmp_indices = NULL; 121 GLuint i; 122 123 assert(min_index != 0); 124 125 if (0) 126 printf("%s %d..%d\n", __func__, min_index, max_index); 127 128 /* XXX this path is disabled for now. 129 * There's rendering corruption in some apps when it's enabled. 130 */ 131 if (0 && ib && ctx->Extensions.ARB_draw_elements_base_vertex) { 132 /* If we can just tell the hardware or the TNL to interpret our indices 133 * with a different base, do so. 134 */ 135 tmp_prims = malloc(sizeof(*prim) * nr_prims); 136 137 if (tmp_prims == NULL) { 138 _mesa_error_no_memory(__func__); 139 return; 140 } 141 142 for (i = 0; i < nr_prims; i++) { 143 tmp_prims[i] = prim[i]; 144 tmp_prims[i].basevertex -= min_index; 145 } 146 147 prim = tmp_prims; 148 } else if (ib) { 149 unsigned start = prim[0].start; 150 for (i = 1; i < nr_prims; i++) { 151 if (prim[i].start != start) { 152 if (0) { 153 printf("%s recursing due to mismatched start " 154 "(prim[0].start = %u vs. prim[%u].start = %u)\n", 155 __func__, start, i, prim[i].start); 156 } 157 158 t_rebase_prims(ctx, arrays, &prim[0], i, ib, min_index, 159 max_index, num_instances, base_instance, draw); 160 t_rebase_prims(ctx, arrays, &prim[i], nr_prims - i, ib, min_index, 161 max_index, num_instances, base_instance, draw); 162 return; 163 } 164 } 165 166 /* Unfortunately need to adjust each index individually. 167 */ 168 bool map_ib = false; 169 const void *ptr; 170 171 if (ib->obj) { 172 if (!ib->obj->Mappings[MAP_INTERNAL].Pointer) { 173 ctx->Driver.MapBufferRange(ctx, 0, ib->obj->Size, GL_MAP_READ_BIT, 174 ib->obj, MAP_INTERNAL); 175 map_ib = true; 176 } 177 178 ptr = ADD_POINTERS(ib->obj->Mappings[MAP_INTERNAL].Pointer, ib->ptr); 179 } else 180 ptr = ib->ptr; 181 182 /* Some users might prefer it if we translated elements to GLuints here. 183 * Others wouldn't... 184 */ 185 switch (ib->index_size_shift) { 186 case 2: 187 tmp_indices = rebase_GLuint(ptr, start, ib->count, min_index); 188 break; 189 case 1: 190 tmp_indices = rebase_GLushort(ptr, start, ib->count, min_index); 191 break; 192 case 0: 193 tmp_indices = rebase_GLubyte(ptr, start, ib->count, min_index); 194 break; 195 } 196 197 if (map_ib) 198 ctx->Driver.UnmapBuffer(ctx, ib->obj, MAP_INTERNAL); 199 200 if (tmp_indices == NULL) 201 return; 202 203 tmp_ib.obj = NULL; 204 tmp_ib.ptr = tmp_indices; 205 tmp_ib.count = ib->count; 206 tmp_ib.index_size_shift = ib->index_size_shift; 207 208 ib = &tmp_ib; 209 } 210 else { 211 /* Otherwise the primitives need adjustment. */ 212 tmp_prims = malloc(sizeof(*prim) * nr_prims); 213 214 if (tmp_prims == NULL) { 215 _mesa_error_no_memory(__func__); 216 return; 217 } 218 219 for (i = 0; i < nr_prims; i++) { 220 /* If this fails, it could indicate an application error: */ 221 assert(prim[i].start >= min_index); 222 223 tmp_prims[i] = prim[i]; 224 tmp_prims[i].start -= min_index; 225 } 226 227 prim = tmp_prims; 228 } 229 230 /* Just need to adjust the pointer values on each incoming array. 231 * This works for VBO and non-vbo rendering and shouldn't pesimize 232 * VBO-based upload schemes. However this may still not be a fast 233 * path for hardware tnl for VBO based rendering as most machines 234 * will be happier if you just specify a starting vertex value in 235 * each primitive. 236 * 237 * For drivers with hardware tnl, you only want to do this if you 238 * are forced to, eg non-VBO indexed rendering with start != 0. 239 */ 240 for (i = 0; i < VERT_ATTRIB_MAX; i++) { 241 tmp_attribs[i] = *(arrays[i].VertexAttrib); 242 tmp_arrays[i].BufferBinding = arrays[i].BufferBinding; 243 tmp_arrays[i].VertexAttrib = &tmp_attribs[i]; 244 if (arrays[i].BufferBinding->BufferObj) 245 tmp_attribs[i].RelativeOffset += 246 min_index * arrays[i].BufferBinding->Stride; 247 else 248 tmp_attribs[i].Ptr += min_index * arrays[i].BufferBinding->Stride; 249 } 250 251 /* Re-issue the draw call. */ 252 draw(ctx, 253 tmp_arrays, 254 prim, 255 nr_prims, 256 ib, 257 GL_TRUE, 258 0, 259 max_index - min_index, 260 num_instances, base_instance); 261 262 free(tmp_indices); 263 free(tmp_prims); 264} 265 266 267 268