1848b8605Smrg/* 2848b8605Smrg * Mesa 3-D graphics library 3848b8605Smrg * 4848b8605Smrg * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. 5848b8605Smrg * 6848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a 7848b8605Smrg * copy of this software and associated documentation files (the "Software"), 8848b8605Smrg * to deal in the Software without restriction, including without limitation 9848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the 11848b8605Smrg * Software is furnished to do so, subject to the following conditions: 12848b8605Smrg * 13848b8605Smrg * The above copyright notice and this permission notice shall be included 14848b8605Smrg * in all copies or substantial portions of the Software. 15848b8605Smrg * 16848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE. 23848b8605Smrg */ 24848b8605Smrg 25848b8605Smrg/* Author: 26848b8605Smrg * Keith Whitwell <keithw@vmware.com> 27848b8605Smrg */ 28848b8605Smrg 29b8e80941Smrg#include <stdbool.h> 30b8e80941Smrg#include "main/arrayobj.h" 31848b8605Smrg#include "main/glheader.h" 32848b8605Smrg#include "main/bufferobj.h" 33848b8605Smrg#include "main/context.h" 34848b8605Smrg#include "main/imports.h" 35848b8605Smrg#include "main/macros.h" 36848b8605Smrg#include "main/light.h" 37848b8605Smrg#include "main/state.h" 38b8e80941Smrg#include "main/varray.h" 39b8e80941Smrg#include "util/bitscan.h" 40848b8605Smrg 41b8e80941Smrg#include "vbo_private.h" 42848b8605Smrg 43848b8605Smrg 44848b8605Smrgstatic void 45b8e80941Smrgcopy_vao(struct gl_context *ctx, const struct gl_vertex_array_object *vao, 46b8e80941Smrg GLbitfield mask, GLbitfield state, int shift, fi_type **data) 47848b8605Smrg{ 48848b8605Smrg struct vbo_context *vbo = vbo_context(ctx); 49848b8605Smrg 50b8e80941Smrg mask &= vao->Enabled; 51b8e80941Smrg while (mask) { 52b8e80941Smrg const int i = u_bit_scan(&mask); 53b8e80941Smrg const struct gl_array_attributes *attrib = &vao->VertexAttrib[i]; 54b8e80941Smrg struct gl_array_attributes *currval = &vbo->current[shift + i]; 55b8e80941Smrg const GLubyte size = attrib->Format.Size; 56b8e80941Smrg const GLenum16 type = attrib->Format.Type; 57b8e80941Smrg fi_type tmp[8]; 58b8e80941Smrg int dmul = 1; 59b8e80941Smrg 60b8e80941Smrg if (type == GL_DOUBLE || 61b8e80941Smrg type == GL_UNSIGNED_INT64_ARB) 62b8e80941Smrg dmul = 2; 63b8e80941Smrg 64b8e80941Smrg if (dmul == 2) 65b8e80941Smrg memcpy(tmp, *data, size * dmul * sizeof(GLfloat)); 66848b8605Smrg else 67b8e80941Smrg COPY_CLEAN_4V_TYPE_AS_UNION(tmp, size, *data, type); 68848b8605Smrg 69b8e80941Smrg if (type != currval->Format.Type || 70b8e80941Smrg memcmp(currval->Ptr, tmp, 4 * sizeof(GLfloat) * dmul) != 0) { 71b8e80941Smrg memcpy((fi_type*)currval->Ptr, tmp, 4 * sizeof(GLfloat) * dmul); 72848b8605Smrg 73b8e80941Smrg vbo_set_vertex_format(&currval->Format, size, type); 74848b8605Smrg 75b8e80941Smrg ctx->NewState |= state; 76848b8605Smrg } 77b8e80941Smrg 78b8e80941Smrg *data += size; 79848b8605Smrg } 80b8e80941Smrg} 81b8e80941Smrg 82b8e80941Smrg/** 83b8e80941Smrg * After playback, copy everything but the position from the 84b8e80941Smrg * last vertex to the saved state 85b8e80941Smrg */ 86b8e80941Smrgstatic void 87b8e80941Smrgplayback_copy_to_current(struct gl_context *ctx, 88b8e80941Smrg const struct vbo_save_vertex_list *node) 89b8e80941Smrg{ 90b8e80941Smrg if (!node->current_data) 91b8e80941Smrg return; 92b8e80941Smrg 93b8e80941Smrg fi_type *data = node->current_data; 94b8e80941Smrg /* Copy conventional attribs and generics except pos */ 95b8e80941Smrg copy_vao(ctx, node->VAO[VP_MODE_SHADER], ~VERT_BIT_POS & VERT_BIT_ALL, 96b8e80941Smrg _NEW_CURRENT_ATTRIB, 0, &data); 97b8e80941Smrg /* Copy materials */ 98b8e80941Smrg copy_vao(ctx, node->VAO[VP_MODE_FF], VERT_BIT_MAT_ALL, 99b8e80941Smrg _NEW_CURRENT_ATTRIB | _NEW_LIGHT, VBO_MATERIAL_SHIFT, &data); 100848b8605Smrg 101848b8605Smrg /* Colormaterial -- this kindof sucks. 102848b8605Smrg */ 103848b8605Smrg if (ctx->Light.ColorMaterialEnabled) { 104848b8605Smrg _mesa_update_color_material(ctx, ctx->Current.Attrib[VBO_ATTRIB_COLOR0]); 105848b8605Smrg } 106848b8605Smrg 107848b8605Smrg /* CurrentExecPrimitive 108848b8605Smrg */ 109848b8605Smrg if (node->prim_count) { 110b8e80941Smrg const struct _mesa_prim *prim = &node->prims[node->prim_count - 1]; 111848b8605Smrg if (prim->end) 112b8e80941Smrg ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END; 113848b8605Smrg else 114b8e80941Smrg ctx->Driver.CurrentExecPrimitive = prim->mode; 115848b8605Smrg } 116848b8605Smrg} 117848b8605Smrg 118848b8605Smrg 119848b8605Smrg 120848b8605Smrg/** 121b8e80941Smrg * Set the appropriate VAO to draw. 122848b8605Smrg */ 123b8e80941Smrgstatic void 124b8e80941Smrgbind_vertex_list(struct gl_context *ctx, 125b8e80941Smrg const struct vbo_save_vertex_list *node) 126848b8605Smrg{ 127b8e80941Smrg const gl_vertex_processing_mode mode = ctx->VertexProgram._VPMode; 128b8e80941Smrg _mesa_set_draw_vao(ctx, node->VAO[mode], _vbo_get_vao_filter(mode)); 129848b8605Smrg} 130848b8605Smrg 131848b8605Smrg 132848b8605Smrgstatic void 133b8e80941Smrgloopback_vertex_list(struct gl_context *ctx, 134b8e80941Smrg const struct vbo_save_vertex_list *list) 135848b8605Smrg{ 136b8e80941Smrg struct gl_buffer_object *bo = list->VAO[0]->BufferBinding[0].BufferObj; 137b8e80941Smrg ctx->Driver.MapBufferRange(ctx, 0, bo->Size, GL_MAP_READ_BIT, /* ? */ 138b8e80941Smrg bo, MAP_INTERNAL); 139b8e80941Smrg 140b8e80941Smrg /* Note that the range of referenced vertices must be mapped already */ 141b8e80941Smrg _vbo_loopback_vertex_list(ctx, list); 142b8e80941Smrg 143b8e80941Smrg ctx->Driver.UnmapBuffer(ctx, bo, MAP_INTERNAL); 144848b8605Smrg} 145848b8605Smrg 146848b8605Smrg 147848b8605Smrg/** 148848b8605Smrg * Execute the buffer and save copied verts. 149848b8605Smrg * This is called from the display list code when executing 150848b8605Smrg * a drawing command. 151848b8605Smrg */ 152848b8605Smrgvoid 153848b8605Smrgvbo_save_playback_vertex_list(struct gl_context *ctx, void *data) 154848b8605Smrg{ 155848b8605Smrg const struct vbo_save_vertex_list *node = 156848b8605Smrg (const struct vbo_save_vertex_list *) data; 157b8e80941Smrg struct vbo_context *vbo = vbo_context(ctx); 158b8e80941Smrg struct vbo_save_context *save = &vbo->save; 159848b8605Smrg GLboolean remap_vertex_store = GL_FALSE; 160848b8605Smrg 161b8e80941Smrg if (save->vertex_store && save->vertex_store->buffer_map) { 162848b8605Smrg /* The vertex store is currently mapped but we're about to replay 163848b8605Smrg * a display list. This can happen when a nested display list is 164848b8605Smrg * being build with GL_COMPILE_AND_EXECUTE. 165848b8605Smrg * We never want to have mapped vertex buffers when we're drawing. 166848b8605Smrg * Unmap the vertex store, execute the list, then remap the vertex 167848b8605Smrg * store. 168848b8605Smrg */ 169848b8605Smrg vbo_save_unmap_vertex_store(ctx, save->vertex_store); 170848b8605Smrg remap_vertex_store = GL_TRUE; 171848b8605Smrg } 172848b8605Smrg 173b8e80941Smrg FLUSH_FOR_DRAW(ctx); 174848b8605Smrg 175848b8605Smrg if (node->prim_count > 0) { 176848b8605Smrg 177b8e80941Smrg if (_mesa_inside_begin_end(ctx) && node->prims[0].begin) { 178848b8605Smrg /* Error: we're about to begin a new primitive but we're already 179848b8605Smrg * inside a glBegin/End pair. 180848b8605Smrg */ 181848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 182848b8605Smrg "draw operation inside glBegin/End"); 183848b8605Smrg goto end; 184848b8605Smrg } 185848b8605Smrg else if (save->replay_flags) { 186b8e80941Smrg /* Various degenerate cases: translate into immediate mode 187b8e80941Smrg * calls rather than trying to execute in place. 188b8e80941Smrg */ 189b8e80941Smrg loopback_vertex_list(ctx, node); 190848b8605Smrg 191848b8605Smrg goto end; 192848b8605Smrg } 193b8e80941Smrg 194b8e80941Smrg bind_vertex_list(ctx, node); 195b8e80941Smrg 196b8e80941Smrg /* Need that at least one time. */ 197848b8605Smrg if (ctx->NewState) 198b8e80941Smrg _mesa_update_state(ctx); 199848b8605Smrg 200848b8605Smrg /* XXX also need to check if shader enabled, but invalid */ 201b8e80941Smrg if ((ctx->VertexProgram.Enabled && 202b8e80941Smrg !_mesa_arb_vertex_program_enabled(ctx)) || 203b8e80941Smrg (ctx->FragmentProgram.Enabled && 204b8e80941Smrg !_mesa_arb_fragment_program_enabled(ctx))) { 205848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 206848b8605Smrg "glBegin (invalid vertex/fragment program)"); 207848b8605Smrg return; 208848b8605Smrg } 209848b8605Smrg 210b8e80941Smrg assert(ctx->NewState == 0); 211848b8605Smrg 212b8e80941Smrg if (node->vertex_count > 0) { 213b8e80941Smrg GLuint min_index = _vbo_save_get_min_index(node); 214b8e80941Smrg GLuint max_index = _vbo_save_get_max_index(node); 215b8e80941Smrg ctx->Driver.Draw(ctx, node->prims, node->prim_count, NULL, GL_TRUE, 216b8e80941Smrg min_index, max_index, NULL, 0, NULL); 217848b8605Smrg } 218848b8605Smrg } 219848b8605Smrg 220848b8605Smrg /* Copy to current? 221848b8605Smrg */ 222b8e80941Smrg playback_copy_to_current(ctx, node); 223848b8605Smrg 224848b8605Smrgend: 225848b8605Smrg if (remap_vertex_store) { 226848b8605Smrg save->buffer_ptr = vbo_save_map_vertex_store(ctx, save->vertex_store); 227848b8605Smrg } 228848b8605Smrg} 229