vbo_save_loopback.c revision 8a1362ad
1/************************************************************************** 2 * 3 * Copyright 2005 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#include <stdio.h> 29#include "main/context.h" 30#include "main/glheader.h" 31#include "main/enums.h" 32#include "main/imports.h" 33#include "main/dispatch.h" 34#include "glapi/glapi.h" 35 36#include "vbo_private.h" 37 38 39typedef void (*attr_func)(struct gl_context *ctx, GLint index, const GLfloat *); 40 41 42/* This file makes heavy use of the aliasing of NV vertex attributes 43 * with the legacy attributes, and also with ARB and Material 44 * attributes as currently implemented. 45 */ 46static void 47VertexAttrib1fvNV(struct gl_context *ctx, GLint index, const GLfloat *v) 48{ 49 CALL_VertexAttrib1fvNV(ctx->Exec, (index, v)); 50} 51 52 53static void 54VertexAttrib2fvNV(struct gl_context *ctx, GLint index, const GLfloat *v) 55{ 56 CALL_VertexAttrib2fvNV(ctx->Exec, (index, v)); 57} 58 59 60static void 61VertexAttrib3fvNV(struct gl_context *ctx, GLint index, const GLfloat *v) 62{ 63 CALL_VertexAttrib3fvNV(ctx->Exec, (index, v)); 64} 65 66 67static void 68VertexAttrib4fvNV(struct gl_context *ctx, GLint index, const GLfloat *v) 69{ 70 CALL_VertexAttrib4fvNV(ctx->Exec, (index, v)); 71} 72 73 74static attr_func vert_attrfunc[4] = { 75 VertexAttrib1fvNV, 76 VertexAttrib2fvNV, 77 VertexAttrib3fvNV, 78 VertexAttrib4fvNV 79}; 80 81 82struct loopback_attr { 83 enum vbo_attrib index; 84 GLuint offset; 85 attr_func func; 86}; 87 88 89/** 90 * Don't emit ends and begins on wrapped primitives. Don't replay 91 * wrapped vertices. If we get here, it's probably because the 92 * precalculated wrapping is wrong. 93 */ 94static void 95loopback_prim(struct gl_context *ctx, 96 const GLubyte *buffer, 97 const struct _mesa_prim *prim, 98 GLuint wrap_count, 99 GLuint stride, 100 const struct loopback_attr *la, GLuint nr) 101{ 102 GLuint start = prim->start; 103 const GLuint end = start + prim->count; 104 const GLubyte *data; 105 106 if (0) 107 printf("loopback prim %s(%s,%s) verts %d..%d vsize %d\n", 108 _mesa_lookup_prim_by_nr(prim->mode), 109 prim->begin ? "begin" : "..", 110 prim->end ? "end" : "..", 111 start, end, 112 stride); 113 114 if (prim->begin) { 115 CALL_Begin(GET_DISPATCH(), (prim->mode)); 116 } 117 else { 118 start += wrap_count; 119 } 120 121 data = buffer + start * stride; 122 123 for (GLuint j = start; j < end; j++) { 124 for (GLuint k = 0; k < nr; k++) 125 la[k].func(ctx, la[k].index, (const GLfloat *)(data + la[k].offset)); 126 127 data += stride; 128 } 129 130 if (prim->end) { 131 CALL_End(GET_DISPATCH(), ()); 132 } 133} 134 135 136static inline void 137append_attr(GLuint *nr, struct loopback_attr la[], int i, int shift, 138 const struct gl_vertex_array_object *vao) 139{ 140 la[*nr].index = shift + i; 141 la[*nr].offset = vao->VertexAttrib[i].RelativeOffset; 142 la[*nr].func = vert_attrfunc[vao->VertexAttrib[i].Format.Size - 1]; 143 (*nr)++; 144} 145 146 147void 148_vbo_loopback_vertex_list(struct gl_context *ctx, 149 const struct vbo_save_vertex_list* node) 150{ 151 struct loopback_attr la[VBO_ATTRIB_MAX]; 152 GLuint nr = 0; 153 154 /* All Legacy, NV, ARB and Material attributes are routed through 155 * the NV attributes entrypoints: 156 */ 157 const struct gl_vertex_array_object *vao = node->VAO[VP_MODE_FF]; 158 GLbitfield mask = vao->Enabled & VERT_BIT_MAT_ALL; 159 while (mask) { 160 const int i = u_bit_scan(&mask); 161 append_attr(&nr, la, i, VBO_MATERIAL_SHIFT, vao); 162 } 163 164 vao = node->VAO[VP_MODE_SHADER]; 165 mask = vao->Enabled & ~(VERT_BIT_POS | VERT_BIT_GENERIC0); 166 while (mask) { 167 const int i = u_bit_scan(&mask); 168 append_attr(&nr, la, i, 0, vao); 169 } 170 171 /* The last in the list should be the vertex provoking attribute */ 172 if (vao->Enabled & VERT_BIT_GENERIC0) { 173 append_attr(&nr, la, VERT_ATTRIB_GENERIC0, 0, vao); 174 } else if (vao->Enabled & VERT_BIT_POS) { 175 append_attr(&nr, la, VERT_ATTRIB_POS, 0, vao); 176 } 177 178 const GLuint wrap_count = node->wrap_count; 179 const GLuint stride = _vbo_save_get_stride(node); 180 const GLubyte *buffer = NULL; 181 if (0 < nr) { 182 /* Compute the minimal offset into the vertex buffer object */ 183 GLuint offset = ~0u; 184 for (GLuint i = 0; i < nr; ++i) 185 offset = MIN2(offset, la[i].offset); 186 for (GLuint i = 0; i < nr; ++i) 187 la[i].offset -= offset; 188 189 /* Get the mapped base pointer, assert sufficient mapping */ 190 struct gl_buffer_object *bufferobj = vao->BufferBinding[0].BufferObj; 191 assert(bufferobj && bufferobj->Mappings[MAP_INTERNAL].Pointer); 192 buffer = bufferobj->Mappings[MAP_INTERNAL].Pointer; 193 assert(bufferobj->Mappings[MAP_INTERNAL].Offset 194 <= vao->BufferBinding[0].Offset + offset 195 + stride*(_vbo_save_get_min_index(node) + wrap_count)); 196 buffer += vao->BufferBinding[0].Offset + offset 197 - bufferobj->Mappings[MAP_INTERNAL].Offset; 198 assert(stride*(_vbo_save_get_vertex_count(node) - wrap_count) 199 <= bufferobj->Mappings[MAP_INTERNAL].Length); 200 } 201 202 /* Replay the primitives */ 203 const struct _mesa_prim *prims = node->prims; 204 const GLuint prim_count = node->prim_count; 205 for (GLuint i = 0; i < prim_count; i++) { 206 loopback_prim(ctx, buffer, &prims[i], wrap_count, stride, la, nr); 207 } 208} 209