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