diff --git a/panda/src/display/graphicsStateGuardian.cxx b/panda/src/display/graphicsStateGuardian.cxx index 68c88d12b7..eb3b06e6c5 100644 --- a/panda/src/display/graphicsStateGuardian.cxx +++ b/panda/src/display/graphicsStateGuardian.cxx @@ -20,6 +20,7 @@ #include "graphicsStateGuardian.h" #include "config_display.h" #include "textureContext.h" +#include "dataContext.h" #include "renderBuffer.h" #include "colorAttrib.h" #include "colorScaleAttrib.h" @@ -46,6 +47,8 @@ PStatCollector GraphicsStateGuardian::_total_texusage_pcollector("Texture usage" PStatCollector GraphicsStateGuardian::_active_texusage_pcollector("Texture usage:Active"); PStatCollector GraphicsStateGuardian::_total_geom_pcollector("Prepared Geoms"); PStatCollector GraphicsStateGuardian::_active_geom_pcollector("Prepared Geoms:Active"); +PStatCollector GraphicsStateGuardian::_total_buffers_pcollector("Prepared Bufferss"); +PStatCollector GraphicsStateGuardian::_active_buffers_pcollector("Prepared Bufferss:Active"); PStatCollector GraphicsStateGuardian::_total_geom_node_pcollector("Prepared GeomNodes"); PStatCollector GraphicsStateGuardian::_active_geom_node_pcollector("Prepared GeomNodes:Active"); PStatCollector GraphicsStateGuardian::_total_texmem_pcollector("Texture memory"); @@ -267,6 +270,28 @@ void GraphicsStateGuardian:: release_geom(GeomContext *) { } +//////////////////////////////////////////////////////////////////// +// Function: GraphicsStateGuardian::prepare_data +// Access: Public, Virtual +// Description: Prepares the indicated data array for retained-mode +// rendering. +//////////////////////////////////////////////////////////////////// +DataContext *GraphicsStateGuardian:: +prepare_data(qpGeomVertexArrayData *) { + return (DataContext *)NULL; +} + +//////////////////////////////////////////////////////////////////// +// Function: GraphicsStateGuardian::release_data +// Access: Public, Virtual +// Description: Frees the resources previously allocated via a call +// to prepare_data(), including deleting the DataContext +// itself, if necessary. +//////////////////////////////////////////////////////////////////// +void GraphicsStateGuardian:: +release_data(DataContext *) { +} + //////////////////////////////////////////////////////////////////// // Function: GraphicsStateGuardian::get_geom_munger // Access: Public, Virtual @@ -1458,7 +1483,7 @@ add_to_texture_record(TextureContext *tc) { // Access: Protected // Description: Records that the indicated Geom has been drawn this // frame. This function is only used to update the -// PStats current_texmem collector; it gets compiled out +// PStats active_geom collector; it gets compiled out // if we aren't using PStats. //////////////////////////////////////////////////////////////////// void GraphicsStateGuardian:: @@ -1469,6 +1494,23 @@ add_to_geom_record(GeomContext *gc) { } } } + +//////////////////////////////////////////////////////////////////// +// Function: GraphicsStateGuardian::add_to_data_record +// Access: Protected +// Description: Records that the indicated data array has been drawn +// this frame. This function is only used to update the +// PStats active_buffers collector; it gets compiled out +// if we aren't using PStats. +//////////////////////////////////////////////////////////////////// +void GraphicsStateGuardian:: +add_to_data_record(DataContext *dc) { + if (PStatClient::is_connected()) { + if (dc != (DataContext *)NULL && _current_datas.insert(dc).second) { + _active_buffers_pcollector.add_level(dc->_data->get_num_bytes()); + } + } +} #endif // DO_PSTATS //////////////////////////////////////////////////////////////////// diff --git a/panda/src/display/graphicsStateGuardian.h b/panda/src/display/graphicsStateGuardian.h index 9355d061bc..f4747ee671 100644 --- a/panda/src/display/graphicsStateGuardian.h +++ b/panda/src/display/graphicsStateGuardian.h @@ -107,6 +107,9 @@ public: virtual GeomContext *prepare_geom(Geom *geom); virtual void release_geom(GeomContext *gc); + virtual DataContext *prepare_data(qpGeomVertexArrayData *data); + virtual void release_data(DataContext *gc); + virtual CPT(qpGeomMunger) get_geom_munger(const RenderState *state); virtual void set_state_and_transform(const RenderState *state, @@ -223,9 +226,11 @@ protected: void init_frame_pstats(); void add_to_texture_record(TextureContext *tc); void add_to_geom_record(GeomContext *gc); + void add_to_data_record(DataContext *dc); pset _current_textures; pset _current_geoms; + pset _current_datas; #else INLINE void init_frame_pstats() { } INLINE void add_to_texture_record(TextureContext *) { } @@ -308,6 +313,8 @@ public: static PStatCollector _active_texusage_pcollector; static PStatCollector _total_geom_pcollector; static PStatCollector _active_geom_pcollector; + static PStatCollector _total_buffers_pcollector; + static PStatCollector _active_buffers_pcollector; static PStatCollector _total_geom_node_pcollector; static PStatCollector _active_geom_node_pcollector; static PStatCollector _total_texmem_pcollector; diff --git a/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx b/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx index 39a3b9f2e3..669bd500c1 100644 --- a/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx +++ b/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx @@ -2684,7 +2684,7 @@ draw_triangles(const qpGeomTriangles *primitive) { primitive->get_num_primitives(), primitive->get_flat_first_vertices(), D3DFMT_INDEX16, - _vertex_data->get_array_data(0), + _vertex_data->get_array(0)->get_data(), _vertex_data->get_format()->get_array(0)->get_stride()); } @@ -2703,7 +2703,7 @@ draw_tristrips(const qpGeomTristrips *primitive) { CPTA_ushort maxs = primitive->get_maxs(); nassertv(mins.size() == ends.size() && maxs.size() == ends.size()); - CPTA_uchar array_data = _vertex_data->get_array_data(0); + CPTA_uchar array_data = _vertex_data->get_array(0)->get_data(); int stride = _vertex_data->get_format()->get_array(0)->get_stride(); unsigned int start = 0; diff --git a/panda/src/egg2pg/eggLoader.cxx b/panda/src/egg2pg/eggLoader.cxx index 8f5f5a3aab..ba048d6b96 100644 --- a/panda/src/egg2pg/eggLoader.cxx +++ b/panda/src/egg2pg/eggLoader.cxx @@ -1925,7 +1925,8 @@ make_vertex_data(EggVertexPool *vertex_pool, const LMatrix4d &transform) { qpGeomVertexFormat::register_format(new qpGeomVertexFormat(array_format)); // Now create a new GeomVertexData using the indicated format. - PT(qpGeomVertexData) vertex_data = new qpGeomVertexData(format); + PT(qpGeomVertexData) vertex_data = + new qpGeomVertexData(format, qpGeomVertexArrayData::UH_static); // And fill the data from the vertex pool. EggVertexPool::const_iterator vi; diff --git a/panda/src/framework/windowFramework.cxx b/panda/src/framework/windowFramework.cxx index fa26861e8d..cba12c1e90 100644 --- a/panda/src/framework/windowFramework.cxx +++ b/panda/src/framework/windowFramework.cxx @@ -632,7 +632,9 @@ load_default_model(const NodePath &parent) { if (use_qpgeom) { // New, experimental Geom code. - PT(qpGeomVertexData) vdata = new qpGeomVertexData(qpGeomVertexFormat::get_v3n3cpt2()); + PT(qpGeomVertexData) vdata = new qpGeomVertexData + (qpGeomVertexFormat::get_v3n3cpt2(), + qpGeomVertexArrayData::UH_static); qpGeomVertexIterator vertex(vdata, InternalName::get_vertex()); qpGeomVertexIterator normal(vdata, InternalName::get_normal()); qpGeomVertexIterator color(vdata, InternalName::get_color()); @@ -1057,7 +1059,9 @@ load_image_as_model(const Filename &filename) { } if (use_qpgeom) { - PT(qpGeomVertexData) vdata = new qpGeomVertexData(qpGeomVertexFormat::get_v3t2()); + PT(qpGeomVertexData) vdata = new qpGeomVertexData + (qpGeomVertexFormat::get_v3t2(), + qpGeomVertexArrayData::UH_static); qpGeomVertexIterator vertex(vdata, InternalName::get_vertex()); qpGeomVertexIterator texcoord(vdata, InternalName::get_texcoord()); diff --git a/panda/src/glstuff/Sources.pp b/panda/src/glstuff/Sources.pp index 6de45c86cb..65b4360a81 100644 --- a/panda/src/glstuff/Sources.pp +++ b/panda/src/glstuff/Sources.pp @@ -19,6 +19,9 @@ glstuff_src.cxx \ glstuff_src.h \ glstuff_undef_src.h \ + glDataContext_src.cxx \ + glDataContext_src.I \ + glDataContext_src.h \ glGeomContext_src.cxx \ glGeomContext_src.I \ glGeomContext_src.h \ diff --git a/panda/src/glstuff/glDataContext_src.I b/panda/src/glstuff/glDataContext_src.I new file mode 100644 index 0000000000..ea3f8b5077 --- /dev/null +++ b/panda/src/glstuff/glDataContext_src.I @@ -0,0 +1,30 @@ +// Filename: glDataContext_src.I +// Created by: drose (17Mar05) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: CLP(DataContext)::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE CLP(DataContext):: +CLP(DataContext)(qpGeomVertexArrayData *data) : + DataContext(data) +{ + _index = 0; +} diff --git a/panda/src/glstuff/glDataContext_src.cxx b/panda/src/glstuff/glDataContext_src.cxx new file mode 100644 index 0000000000..605db7e623 --- /dev/null +++ b/panda/src/glstuff/glDataContext_src.cxx @@ -0,0 +1,19 @@ +// Filename: glDataContext_src.cxx +// Created by: drose (17Mar05) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +TypeHandle CLP(DataContext)::_type_handle; diff --git a/panda/src/glstuff/glDataContext_src.h b/panda/src/glstuff/glDataContext_src.h new file mode 100644 index 0000000000..f35705d6bf --- /dev/null +++ b/panda/src/glstuff/glDataContext_src.h @@ -0,0 +1,52 @@ +// Filename: glDataContext_src.h +// Created by: drose (17Mar05) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#include "pandabase.h" +#include "dataContext.h" + +//////////////////////////////////////////////////////////////////// +// Class : GLDataContext +// Description : +//////////////////////////////////////////////////////////////////// +class EXPCL_GL CLP(DataContext) : public DataContext { +public: + INLINE CLP(DataContext)(qpGeomVertexArrayData *data); + + // This is the GL "name" of the data object. + GLuint _index; + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + DataContext::init_type(); + register_type(_type_handle, CLASSPREFIX_QUOTED "DataContext", + DataContext::get_class_type()); + } + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + +private: + static TypeHandle _type_handle; +}; + +#include "glDataContext_src.I" + diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index cfcb0e9a8e..da61634c6d 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -57,6 +57,7 @@ #include "vector_string.h" #include "string_utils.h" #include "pnmImage.h" +#include "config_gobj.h" #ifdef DO_PSTATS #include "pStatTimer.h" #endif @@ -455,6 +456,47 @@ reset() { _glActiveTexture = null_glActiveTexture; } + _supports_buffers = false; + + if (is_at_least_version(1, 5)) { + _supports_buffers = true; + + _glGenBuffers = (PFNGLGENBUFFERSPROC) + get_extension_func(GLPREFIX_QUOTED, "GenBuffers"); + _glBindBuffer = (PFNGLBINDBUFFERPROC) + get_extension_func(GLPREFIX_QUOTED, "BindBuffer"); + _glBufferData = (PFNGLBUFFERDATAPROC) + get_extension_func(GLPREFIX_QUOTED, "BufferData"); + _glBufferSubData = (PFNGLBUFFERSUBDATAPROC) + get_extension_func(GLPREFIX_QUOTED, "BufferSubData"); + _glDeleteBuffers = (PFNGLDELETEBUFFERSPROC) + get_extension_func(GLPREFIX_QUOTED, "DeleteBuffers"); + + } else if (has_extension("GL_ARB_vertex_buffer_object")) { + _supports_buffers = true; + + _glGenBuffers = (PFNGLGENBUFFERSPROC) + get_extension_func(GLPREFIX_QUOTED, "GenBuffersARB"); + _glBindBuffer = (PFNGLBINDBUFFERPROC) + get_extension_func(GLPREFIX_QUOTED, "BindBufferARB"); + _glBufferData = (PFNGLBUFFERDATAPROC) + get_extension_func(GLPREFIX_QUOTED, "BufferDataARB"); + _glBufferSubData = (PFNGLBUFFERSUBDATAPROC) + get_extension_func(GLPREFIX_QUOTED, "BufferSubDataARB"); + _glDeleteBuffers = (PFNGLDELETEBUFFERSPROC) + get_extension_func(GLPREFIX_QUOTED, "DeleteBuffersARB"); + } + + if (_supports_buffers) { + if (_glGenBuffers == NULL || _glBindBuffer == NULL || + _glBufferData == NULL || _glBufferSubData == NULL || + _glDeleteBuffers == NULL) { + GLCAT.warning() + << "Buffers advertised as supported by OpenGL runtime, but could not get pointers to extension functions.\n"; + _supports_buffers = false; + } + } + _glBlendEquation = NULL; if (has_extension("GL_EXT_blend_minmax") || is_at_least_version(1, 2)) { _glBlendEquation = (PFNGLBLENDEQUATIONPROC) @@ -1984,7 +2026,7 @@ begin_draw_primitives(const qpGeomVertexData *vertex_data) { } nassertr(_vertex_data != (qpGeomVertexData *)NULL, false); - CPTA_uchar array_data; + const qpGeomVertexArrayData *array_data; int num_components; qpGeomVertexDataType::NumericType numeric_type; int start; @@ -1993,8 +2035,9 @@ begin_draw_primitives(const qpGeomVertexData *vertex_data) { if (_vertex_data->get_array_info(InternalName::get_vertex(), array_data, num_components, numeric_type, start, stride)) { + const unsigned char *client_pointer = setup_array_data(array_data); GLP(VertexPointer)(num_components, get_numeric_type(numeric_type), - stride, array_data + start); + stride, client_pointer + start); GLP(EnableClientState)(GL_VERTEX_ARRAY); } else { // No vertex data? No primitives! @@ -2005,8 +2048,9 @@ begin_draw_primitives(const qpGeomVertexData *vertex_data) { _vertex_data->get_array_info(InternalName::get_normal(), array_data, num_components, numeric_type, start, stride)) { + const unsigned char *client_pointer = setup_array_data(array_data); GLP(NormalPointer)(get_numeric_type(numeric_type), stride, - array_data + start); + client_pointer + start); GLP(EnableClientState)(GL_NORMAL_ARRAY); } else { GLP(DisableClientState)(GL_NORMAL_ARRAY); @@ -2016,13 +2060,14 @@ begin_draw_primitives(const qpGeomVertexData *vertex_data) { if (_vertex_data->get_array_info(InternalName::get_color(), array_data, num_components, numeric_type, start, stride)) { + const unsigned char *client_pointer = setup_array_data(array_data); if (numeric_type == qpGeomVertexDataType::NT_packed_argb) { // Temporary hack--this will probably reverse r and b. - GLP(ColorPointer)(4, GL_UNSIGNED_BYTE, stride, array_data + start); + GLP(ColorPointer)(4, GL_UNSIGNED_BYTE, stride, client_pointer + start); } else { GLP(ColorPointer)(num_components, get_numeric_type(numeric_type), - stride, array_data + start); + stride, client_pointer + start); } GLP(EnableClientState)(GL_COLOR_ARRAY); @@ -2040,8 +2085,9 @@ begin_draw_primitives(const qpGeomVertexData *vertex_data) { _vertex_data->get_array_info(InternalName::get_texcoord(), array_data, num_components, numeric_type, start, stride)) { + const unsigned char *client_pointer = setup_array_data(array_data); GLP(TexCoordPointer)(num_components, get_numeric_type(numeric_type), - stride, array_data + start); + stride, client_pointer + start); GLP(EnableClientState)(GL_TEXTURE_COORD_ARRAY); } else { GLP(DisableClientState)(GL_TEXTURE_COORD_ARRAY); @@ -2287,6 +2333,130 @@ release_geom(GeomContext *gc) { delete ggc; } +//////////////////////////////////////////////////////////////////// +// Function: CLP(GraphicsStateGuardian)::prepare_data +// Access: Public, Virtual +// Description: Creates a new retained-mode representation of the +// given data, and returns a newly-allocated +// DataContext pointer to reference it. It is the +// responsibility of the calling function to later +// call release_data() with this same pointer (which +// will also delete the pointer). +// +// This function should not be called directly to +// prepare a data. Instead, call Data::prepare(). +//////////////////////////////////////////////////////////////////// +DataContext *CLP(GraphicsStateGuardian):: +prepare_data(qpGeomVertexArrayData *data) { + cerr << "prepare_data\n"; + + if (_supports_buffers) { + CLP(DataContext) *gdc = new CLP(DataContext)(data); + _glGenBuffers(1, &gdc->_index); + + _glBindBuffer(GL_ARRAY_BUFFER, gdc->_index); + _glBufferData(GL_ARRAY_BUFFER, gdc->_data->get_num_bytes(), + gdc->_data->get_data(), + get_usage(gdc->_data->get_usage_hint())); + gdc->_modified = gdc->_data->get_modified(); + + report_my_gl_errors(); + return gdc; + } + + return NULL; +} + +//////////////////////////////////////////////////////////////////// +// Function: CLP(GraphicsStateGuardian)::apply_data +// Access: Public, Virtual +// Description: Makes the data the currently available data for +// rendering. +//////////////////////////////////////////////////////////////////// +void CLP(GraphicsStateGuardian):: +apply_data(DataContext *dc) { + cerr << "apply_data\n"; + + nassertv(_supports_buffers); + + CLP(DataContext) *gdc = DCAST(CLP(DataContext), dc); + + add_to_data_record(gdc); + _glBindBuffer(GL_ARRAY_BUFFER, gdc->_index); + + if (gdc->_modified != gdc->_data->get_modified()) { + _glBufferSubData(GL_ARRAY_BUFFER, 0, gdc->_data->get_num_bytes(), + gdc->_data->get_data()); + + gdc->_modified = gdc->_data->get_modified(); + } + + report_my_gl_errors(); +} + +//////////////////////////////////////////////////////////////////// +// Function: CLP(GraphicsStateGuardian)::release_data +// Access: Public, Virtual +// Description: Frees the GL resources previously allocated for the +// data. This function should never be called +// directly; instead, call Data::release() (or simply +// let the Data destruct). +//////////////////////////////////////////////////////////////////// +void CLP(GraphicsStateGuardian):: +release_data(DataContext *dc) { + cerr << "release_data\n"; + + nassertv(_supports_buffers); + + CLP(DataContext) *gdc = DCAST(CLP(DataContext), dc); + + _glDeleteBuffers(1, &gdc->_index); + report_my_gl_errors(); + + gdc->_index = 0; + + delete gdc; +} + +//////////////////////////////////////////////////////////////////// +// Function: CLP(GraphicsStateGuardian)::setup_array_data +// Access: Public +// Description: Internal function to bind a buffer object for the +// indicated data array, if appropriate, or to unbind a +// buffer object if it should be rendered from client +// memory. +// +// If the buffer object is bound, this function returns +// NULL (reprsenting the start of the buffer object in +// server memory); if the buffer object is not bound, +// this function returns the pointer to the data array +// in client memory, that is, the data array passed in. +//////////////////////////////////////////////////////////////////// +const unsigned char *CLP(GraphicsStateGuardian):: +setup_array_data(const qpGeomVertexArrayData *data) { + if (!_supports_buffers) { + // No support for buffer objects; always render from client. + return data->get_data(); + } + if (!vertex_buffers || + data->get_usage_hint() == qpGeomVertexArrayData::UH_client) { + // The array specifies client rendering only, or buffer objects + // are configured off. + _glBindBuffer(GL_ARRAY_BUFFER, 0); + return data->get_data(); + } + + // Prepare the buffer object and bind it. + DataContext *dc = ((qpGeomVertexArrayData *)data)->prepare_now(get_prepared_objects(), this); + nassertr(dc != (DataContext *)NULL, data->get_data()); + + CLP(DataContext) *gdc = DCAST(CLP(DataContext), dc); + _glBindBuffer(GL_ARRAY_BUFFER, gdc->_index); + + // NULL is the OpenGL convention for the first byte of the buffer. + return NULL; +} + #if 0 static int logs[] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 0 }; @@ -4406,6 +4576,32 @@ get_blend_func(ColorBlendAttrib::Operand operand) { return GL_ZERO; } +//////////////////////////////////////////////////////////////////// +// Function: CLP(GraphicsStateGuardian)::get_usage +// Access: Public, Static +// Description: Maps from UsageHint to the GL symbol. +//////////////////////////////////////////////////////////////////// +GLenum CLP(GraphicsStateGuardian):: +get_usage(qpGeomVertexArrayData::UsageHint usage_hint) { + switch (usage_hint) { + case qpGeomVertexArrayData::UH_stream: + return GL_STREAM_DRAW; + + case qpGeomVertexArrayData::UH_static: + return GL_STATIC_DRAW; + + case qpGeomVertexArrayData::UH_dynamic: + return GL_DYNAMIC_DRAW; + + case qpGeomVertexArrayData::UH_client: + break; + } + + GLCAT.error() + << "Unexpected usage_hint " << (int)usage_hint << endl; + return GL_STATIC_DRAW; +} + //////////////////////////////////////////////////////////////////// // Function: CLP(GraphicsStateGuardian)::print_gfx_visual diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.h b/panda/src/glstuff/glGraphicsStateGuardian_src.h index 62b81fcf7b..600b9641be 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.h +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.h @@ -37,6 +37,7 @@ #include "graphicsWindow.h" #include "pset.h" #include "pmap.h" +#include "qpgeomVertexArrayData.h" #ifdef HAVE_CGGL #include "cgShader.h" #endif @@ -103,6 +104,11 @@ public: virtual GeomContext *prepare_geom(Geom *geom); virtual void release_geom(GeomContext *gc); + virtual DataContext *prepare_data(qpGeomVertexArrayData *data); + virtual void apply_data(DataContext *dc); + virtual void release_data(DataContext *dc); + const unsigned char *setup_array_data(const qpGeomVertexArrayData *data); + virtual CPT(qpGeomMunger) get_geom_munger(const RenderState *state); virtual void framebuffer_copy_to_texture @@ -236,6 +242,7 @@ protected: static GLenum get_fog_mode_type(Fog::Mode m); static GLenum get_blend_equation_type(ColorBlendAttrib::Mode mode); static GLenum get_blend_func(ColorBlendAttrib::Operand operand); + static GLenum get_usage(qpGeomVertexArrayData::UsageHint usage_hint); static CPT(RenderState) get_untextured_state(); static CPT(RenderState) get_smooth_state(); @@ -326,6 +333,13 @@ public: PFNGLACTIVETEXTUREPROC _glActiveTexture; PFNGLMULTITEXCOORD2FVPROC _glMultiTexCoord2fv; + bool _supports_buffers; + PFNGLGENBUFFERSPROC _glGenBuffers; + PFNGLBINDBUFFERPROC _glBindBuffer; + PFNGLBUFFERDATAPROC _glBufferData; + PFNGLBUFFERSUBDATAPROC _glBufferSubData; + PFNGLDELETEBUFFERSPROC _glDeleteBuffers; + PFNGLBLENDEQUATIONPROC _glBlendEquation; PFNGLBLENDCOLORPROC _glBlendColor; diff --git a/panda/src/glstuff/glmisc_src.cxx b/panda/src/glstuff/glmisc_src.cxx index 2e1fc4af92..4747d53e2c 100644 --- a/panda/src/glstuff/glmisc_src.cxx +++ b/panda/src/glstuff/glmisc_src.cxx @@ -63,6 +63,7 @@ void CLP(init_classes)() { CLP(GraphicsStateGuardian)::init_type(); CLP(TextureContext)::init_type(); CLP(GeomContext)::init_type(); + CLP(DataContext)::init_type(); PandaSystem *ps = PandaSystem::get_global_ptr(); ps->add_system(GLSYSTEM_NAME); diff --git a/panda/src/glstuff/glstuff_src.cxx b/panda/src/glstuff/glstuff_src.cxx index 1ab571e7e9..cb420cf01c 100644 --- a/panda/src/glstuff/glstuff_src.cxx +++ b/panda/src/glstuff/glstuff_src.cxx @@ -23,6 +23,7 @@ #include "glmisc_src.cxx" #include "glTextureContext_src.cxx" +#include "glDataContext_src.cxx" #include "glGeomContext_src.cxx" #include "glGeomMunger_src.cxx" #include "glCgShaderContext_src.cxx" diff --git a/panda/src/glstuff/glstuff_src.h b/panda/src/glstuff/glstuff_src.h index b15c7c9f34..998ba44c24 100644 --- a/panda/src/glstuff/glstuff_src.h +++ b/panda/src/glstuff/glstuff_src.h @@ -41,6 +41,7 @@ #include "glmisc_src.h" #include "glTextureContext_src.h" +#include "glDataContext_src.h" #include "glGeomContext_src.h" #include "glGeomMunger_src.h" #include "glCgShaderContext_src.h" diff --git a/panda/src/gobj/Sources.pp b/panda/src/gobj/Sources.pp index 4cbdd624fa..845f422377 100644 --- a/panda/src/gobj/Sources.pp +++ b/panda/src/gobj/Sources.pp @@ -11,7 +11,9 @@ #define SOURCES \ boundedObject.I boundedObject.h \ - config_gobj.h drawable.h \ + config_gobj.h \ + dataContext.I dataContext.h \ + drawable.h \ geom.I geom.h \ geomContext.I geomContext.h \ geomLine.h geomLinestrip.h geomPoint.h geomPolygon.h \ @@ -23,6 +25,7 @@ qpgeomTriangles.h \ qpgeomTristrips.h \ qpgeomTrifans.h \ + qpgeomVertexArrayData.h qpgeomVertexArrayData.I \ qpgeomVertexArrayFormat.h qpgeomVertexArrayFormat.I \ qpgeomVertexCacheManager.h qpgeomVertexCacheManager.I \ qpgeomVertexData.h qpgeomVertexData.I \ @@ -44,7 +47,9 @@ #define INCLUDED_SOURCES \ boundedObject.cxx \ - config_gobj.cxx drawable.cxx geom.cxx \ + config_gobj.cxx \ + dataContext.cxx \ + drawable.cxx geom.cxx \ geomContext.cxx \ geomLine.cxx geomLinestrip.cxx geomPoint.cxx geomPolygon.cxx \ geomQuad.cxx geomSphere.cxx geomSprite.cxx geomTri.cxx \ @@ -55,6 +60,7 @@ qpgeomTriangles.cxx \ qpgeomTristrips.cxx \ qpgeomTrifans.cxx \ + qpgeomVertexArrayData.cxx \ qpgeomVertexArrayFormat.cxx \ qpgeomVertexCacheManager.cxx \ qpgeomVertexData.cxx \ @@ -73,6 +79,7 @@ #define INSTALL_HEADERS \ boundedObject.I boundedObject.h \ config_gobj.h \ + dataContext.I dataContext.h \ drawable.h geom.I geom.h \ textureContext.I textureContext.h \ geomLine.h \ @@ -85,6 +92,7 @@ qpgeomTriangles.h \ qpgeomTristrips.h \ qpgeomTrifans.h \ + qpgeomVertexArrayData.h qpgeomVertexArrayData.I \ qpgeomVertexArrayFormat.h qpgeomVertexArrayFormat.I \ qpgeomVertexCacheManager.h qpgeomVertexCacheManager.I \ qpgeomVertexData.h qpgeomVertexData.I \ diff --git a/panda/src/gobj/config_gobj.cxx b/panda/src/gobj/config_gobj.cxx index 32c49c0e00..49d98a2fcc 100644 --- a/panda/src/gobj/config_gobj.cxx +++ b/panda/src/gobj/config_gobj.cxx @@ -28,6 +28,7 @@ #include "qpgeomTriangles.h" #include "qpgeomTristrips.h" #include "qpgeomTrifans.h" +#include "qpgeomVertexArrayData.h" #include "qpgeomVertexArrayFormat.h" #include "qpgeomVertexData.h" #include "qpgeomVertexFormat.h" @@ -38,6 +39,9 @@ #include "lens.h" #include "texture.h" #include "textureStage.h" +#include "textureContext.h" +#include "geomContext.h" +#include "dataContext.h" #include "internalName.h" #include "dconfig.h" @@ -81,6 +85,15 @@ ConfigVariableBool retained_mode "GSG. Set it false to use only immediate mode, which sends the " "vertices to the GSG every frame.")); +ConfigVariableBool vertex_buffers +("vertex-buffers", false, + PRC_DESC("Set this true to allow the use of vertex buffers (or buffer " + "objects, as OpenGL dubs them) for rendering vertex data. This " + "can greatly improve rendering performance, especially on " + "higher-end graphics cards, at the cost of some additional " + "graphics memory (which might otherwise be used for textures " + "or offscreen buffers).")); + ConfigVariableBool use_qpgeom ("use-qpgeom", false, PRC_DESC("A temporary variable while the experimental Geom rewrite is " @@ -163,9 +176,13 @@ ConfigureFn(config_gobj) { qpGeomTriangles::init_type(); qpGeomTristrips::init_type(); qpGeomTrifans::init_type(); + qpGeomVertexArrayData::init_type(); qpGeomVertexArrayFormat::init_type(); qpGeomVertexData::init_type(); qpGeomVertexFormat::init_type(); + TextureContext::init_type(); + GeomContext::init_type(); + DataContext::init_type(); Material::init_type(); OrthographicLens::init_type(); MatrixLens::init_type(); @@ -192,6 +209,7 @@ ConfigureFn(config_gobj) { qpGeomTriangles::register_with_read_factory(); qpGeomTristrips::register_with_read_factory(); qpGeomTrifans::register_with_read_factory(); + qpGeomVertexArrayData::register_with_read_factory(); qpGeomVertexArrayFormat::register_with_read_factory(); qpGeomVertexData::register_with_read_factory(); qpGeomVertexFormat::register_with_read_factory(); diff --git a/panda/src/gobj/config_gobj.h b/panda/src/gobj/config_gobj.h index 4a6146b2d7..fdb94ba3b9 100644 --- a/panda/src/gobj/config_gobj.h +++ b/panda/src/gobj/config_gobj.h @@ -51,6 +51,7 @@ extern EXPCL_PANDA ConfigVariableInt max_texture_dimension; extern EXPCL_PANDA ConfigVariableBool keep_texture_ram; extern EXPCL_PANDA ConfigVariableBool keep_geom_ram; extern EXPCL_PANDA ConfigVariableBool retained_mode; +extern EXPCL_PANDA ConfigVariableBool vertex_buffers; extern EXPCL_PANDA ConfigVariableBool use_qpgeom; diff --git a/panda/src/gobj/dataContext.I b/panda/src/gobj/dataContext.I new file mode 100644 index 0000000000..ef7ffea77b --- /dev/null +++ b/panda/src/gobj/dataContext.I @@ -0,0 +1,29 @@ +// Filename: dataContext.I +// Created by: drose (17Mar05) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: DataContext::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE DataContext:: +DataContext(qpGeomVertexArrayData *data) : + _data(data) +{ +} diff --git a/panda/src/gobj/dataContext.cxx b/panda/src/gobj/dataContext.cxx new file mode 100644 index 0000000000..2844754deb --- /dev/null +++ b/panda/src/gobj/dataContext.cxx @@ -0,0 +1,21 @@ +// Filename: dataContext.cxx +// Created by: drose (17Mar05) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#include "dataContext.h" + +TypeHandle DataContext::_type_handle; diff --git a/panda/src/gobj/dataContext.h b/panda/src/gobj/dataContext.h new file mode 100644 index 0000000000..02abd9a11f --- /dev/null +++ b/panda/src/gobj/dataContext.h @@ -0,0 +1,71 @@ +// Filename: dataContext.h +// Created by: drose (17Mar05) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#ifndef DATACONTEXT_H +#define DATACONTEXT_H + +#include "pandabase.h" + +#include "savedContext.h" +#include "updateSeq.h" + +class qpGeomVertexArrayData; + +//////////////////////////////////////////////////////////////////// +// Class : DataContext +// Description : This is a special class object that holds all the +// information returned by a particular GSG to indicate +// the vertex data array's internal context identifier. +// +// This allows the GSG to cache the vertex data array in +// whatever way makes sense. For instance, DirectX can +// allocate a vertex buffer for the array. OpenGL can +// create a buffer object. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA DataContext : public SavedContext { +public: + INLINE DataContext(qpGeomVertexArrayData *data); + + // This cannot be a PT(qpGeomVertexArrayData), because the data and + // the GSG both own their DataContexts! That would create a + // circular reference count. + qpGeomVertexArrayData *_data; + UpdateSeq _modified; + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + SavedContext::init_type(); + register_type(_type_handle, "DataContext", + SavedContext::get_class_type()); + } + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + +private: + static TypeHandle _type_handle; +}; + +#include "dataContext.I" + +#endif + diff --git a/panda/src/gobj/gobj_composite1.cxx b/panda/src/gobj/gobj_composite1.cxx index c087c14987..a41098d5e1 100644 --- a/panda/src/gobj/gobj_composite1.cxx +++ b/panda/src/gobj/gobj_composite1.cxx @@ -1,5 +1,6 @@ #include "boundedObject.cxx" +#include "dataContext.cxx" #include "geom.cxx" #include "geomLine.cxx" #include "geomLinestrip.cxx" @@ -17,6 +18,7 @@ #include "qpgeomTriangles.cxx" #include "qpgeomTristrips.cxx" #include "qpgeomTrifans.cxx" +#include "qpgeomVertexArrayData.cxx" #include "qpgeomVertexArrayFormat.cxx" #include "qpgeomVertexCacheManager.cxx" #include "qpgeomVertexData.cxx" diff --git a/panda/src/gobj/preparedGraphicsObjects.cxx b/panda/src/gobj/preparedGraphicsObjects.cxx index e31737bca2..0d4f1c6707 100644 --- a/panda/src/gobj/preparedGraphicsObjects.cxx +++ b/panda/src/gobj/preparedGraphicsObjects.cxx @@ -357,6 +357,146 @@ prepare_geom_now(Geom *geom, GraphicsStateGuardianBase *gsg) { return gc; } +//////////////////////////////////////////////////////////////////// +// Function: PreparedGraphicsObjects::enqueue_data +// Access: Public +// Description: Indicates that a data array would like to be put on the +// list to be prepared when the GSG is next ready to +// do this (presumably at the next frame). +//////////////////////////////////////////////////////////////////// +void PreparedGraphicsObjects:: +enqueue_data(qpGeomVertexArrayData *data) { + MutexHolder holder(_lock); + + _enqueued_datas.insert(data); +} + +//////////////////////////////////////////////////////////////////// +// Function: PreparedGraphicsObjects::dequeue_data +// Access: Public +// Description: Removes a data array from the queued list of data +// arrays to be prepared. Normally it is not necessary +// to call this, unless you change your mind about +// preparing it at the last minute, since the data will +// automatically be dequeued and prepared at the next +// frame. +// +// The return value is true if the data array is +// successfully dequeued, false if it had not been +// queued. +//////////////////////////////////////////////////////////////////// +bool PreparedGraphicsObjects:: +dequeue_data(qpGeomVertexArrayData *data) { + MutexHolder holder(_lock); + + EnqueuedDatas::iterator qi = _enqueued_datas.find(data); + if (qi != _enqueued_datas.end()) { + _enqueued_datas.erase(qi); + return true; + } + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: PreparedGraphicsObjects::release_data +// Access: Public +// Description: Indicates that a data context, created by a +// previous call to prepare_data(), is no longer +// needed. The driver resources will not be freed until +// some GSG calls update(), indicating it is at a +// stage where it is ready to release datas--this +// prevents conflicts from threading or multiple GSG's +// sharing datas (we have no way of knowing which +// graphics context is currently active, or what state +// it's in, at the time release_data is called). +//////////////////////////////////////////////////////////////////// +void PreparedGraphicsObjects:: +release_data(DataContext *gc) { + MutexHolder holder(_lock); + + gc->_data->clear_prepared(this); + + // We have to set the Data pointer to NULL at this point, since + // the Data itself might destruct at any time after it has been + // released. + gc->_data = (qpGeomVertexArrayData *)NULL; + + bool removed = (_prepared_datas.erase(gc) != 0); + nassertv(removed); + + _released_datas.insert(gc); +} + +//////////////////////////////////////////////////////////////////// +// Function: PreparedGraphicsObjects::release_all_datas +// Access: Public +// Description: Releases all datas at once. This will force them +// to be reloaded into data memory for all GSG's that +// share this object. Returns the number of datas +// released. +//////////////////////////////////////////////////////////////////// +int PreparedGraphicsObjects:: +release_all_datas() { + MutexHolder holder(_lock); + + int num_datas = (int)_prepared_datas.size(); + + Datas::iterator gci; + for (gci = _prepared_datas.begin(); + gci != _prepared_datas.end(); + ++gci) { + DataContext *gc = (*gci); + gc->_data->clear_prepared(this); + gc->_data = (qpGeomVertexArrayData *)NULL; + + _released_datas.insert(gc); + } + + _prepared_datas.clear(); + + return num_datas; +} + +//////////////////////////////////////////////////////////////////// +// Function: PreparedGraphicsObjects::prepare_data_now +// Access: Public +// Description: Immediately creates a new DataContext for the +// indicated data and returns it. This assumes that +// the GraphicsStateGuardian is the currently active +// rendering context and that it is ready to accept new +// datas. If this is not necessarily the case, you +// should use enqueue_data() instead. +// +// Normally, this function is not called directly. Call +// Data::prepare_now() instead. +// +// The DataContext contains all of the pertinent +// information needed by the GSG to keep track of this +// one particular data, and will exist as long as the +// data is ready to be rendered. +// +// When either the Data or the +// PreparedGraphicsObjects object destructs, the +// DataContext will be deleted. +//////////////////////////////////////////////////////////////////// +DataContext *PreparedGraphicsObjects:: +prepare_data_now(qpGeomVertexArrayData *data, GraphicsStateGuardianBase *gsg) { + MutexHolder holder(_lock); + + // Ask the GSG to create a brand new DataContext. There might + // be several GSG's sharing the same set of datas; if so, it + // doesn't matter which of them creates the context (since they're + // all shared anyway). + DataContext *gc = gsg->prepare_data(data); + + if (gc != (DataContext *)NULL) { + bool prepared = _prepared_datas.insert(gc).second; + nassertr(prepared, gc); + } + + return gc; +} + //////////////////////////////////////////////////////////////////// // Function: PreparedGraphicsObjects::update // Access: Public diff --git a/panda/src/gobj/preparedGraphicsObjects.h b/panda/src/gobj/preparedGraphicsObjects.h index e964371528..b84b16bbf4 100644 --- a/panda/src/gobj/preparedGraphicsObjects.h +++ b/panda/src/gobj/preparedGraphicsObjects.h @@ -22,12 +22,16 @@ #include "pandabase.h" #include "referenceCount.h" #include "texture.h" +#include "geom.h" +#include "qpgeomVertexArrayData.h" +#include "pointerTo.h" #include "pStatCollector.h" #include "pset.h" #include "pmutex.h" class TextureContext; class GeomContext; +class DataContext; class GraphicsStateGuardianBase; //////////////////////////////////////////////////////////////////// @@ -68,6 +72,14 @@ public: GeomContext *prepare_geom_now(Geom *geom, GraphicsStateGuardianBase *gsg); + void enqueue_data(qpGeomVertexArrayData *data); + bool dequeue_data(qpGeomVertexArrayData *data); + void release_data(DataContext *gc); + int release_all_datas(); + + DataContext *prepare_data_now(qpGeomVertexArrayData *data, + GraphicsStateGuardianBase *gsg); + void update(GraphicsStateGuardianBase *gsg); private: @@ -75,12 +87,16 @@ private: typedef phash_set< PT(Texture) > EnqueuedTextures; typedef phash_set Geoms; typedef phash_set< PT(Geom) > EnqueuedGeoms; + typedef phash_set Datas; + typedef phash_set< PT(qpGeomVertexArrayData) > EnqueuedDatas; Mutex _lock; Textures _prepared_textures, _released_textures; EnqueuedTextures _enqueued_textures; Geoms _prepared_geoms, _released_geoms; EnqueuedGeoms _enqueued_geoms; + Datas _prepared_datas, _released_datas; + EnqueuedDatas _enqueued_datas; static PStatCollector _total_texusage_pcollector; diff --git a/panda/src/gobj/qpgeom.cxx b/panda/src/gobj/qpgeom.cxx index 93a6322a60..923e9a948d 100644 --- a/panda/src/gobj/qpgeom.cxx +++ b/panda/src/gobj/qpgeom.cxx @@ -389,7 +389,7 @@ recompute_bound() { int start = data_type->get_start(); int num_components = data_type->get_num_components(); - CPTA_uchar array_data = cdata->_data->get_array_data(array_index); + CPTA_uchar array_data = cdata->_data->get_array(array_index)->get_data(); if (stride == 3 * sizeof(PN_float32) && start == 0 && num_components == 3 && (array_data.size() % stride) == 0) { diff --git a/panda/src/gobj/qpgeomPrimitive.cxx b/panda/src/gobj/qpgeomPrimitive.cxx index c3c6fa04e9..f918173698 100644 --- a/panda/src/gobj/qpgeomPrimitive.cxx +++ b/panda/src/gobj/qpgeomPrimitive.cxx @@ -560,7 +560,7 @@ calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point, int start = data_type->get_start(); int num_components = data_type->get_num_components(); - CPTA_uchar array_data = vertex_data->get_array_data(array_index); + CPTA_uchar array_data = vertex_data->get_array(array_index)->get_data(); PTA_ushort::const_iterator ii; for (ii = cdata->_vertices.begin(); ii != cdata->_vertices.end(); ++ii) { diff --git a/panda/src/gobj/qpgeomVertexArrayData.I b/panda/src/gobj/qpgeomVertexArrayData.I new file mode 100644 index 0000000000..578fdc01dc --- /dev/null +++ b/panda/src/gobj/qpgeomVertexArrayData.I @@ -0,0 +1,167 @@ +// Filename: qpgeomVertexArrayData.I +// Created by: drose (17Mar05) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomVertexArrayData::get_array_format +// Access: Published +// Description: Returns the format object that describes this array. +//////////////////////////////////////////////////////////////////// +INLINE const qpGeomVertexArrayFormat *qpGeomVertexArrayData:: +get_array_format() const { + return _array_format; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomVertexArrayData::get_usage_hint +// Access: Published +// Description: Returns the usage hint that describes to the +// rendering backend how often the vertex data will be +// modified and/or rendered. This is provided as a +// performance optimization only, and does not +// constraing actual usage; although it may be an +// important optimization. +// +// This may only be specified to the GeomVertexArrayData +// constructor. If you need to change it, you must +// create a new GeomVertexArrayData object (but you can +// just assign the same data pointer to the new object). +//////////////////////////////////////////////////////////////////// +INLINE qpGeomVertexArrayData::UsageHint qpGeomVertexArrayData:: +get_usage_hint() const { + return _usage_hint; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomVertexArrayData::get_data +// Access: Published +// Description: Returns a const pointer to the actual vertex data, +// for application code to directly examine (but not +// modify). +//////////////////////////////////////////////////////////////////// +INLINE CPTA_uchar qpGeomVertexArrayData:: +get_data() const { + CDReader cdata(_cycler); + return cdata->_data; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomVertexArrayData::modify_data +// Access: Published +// Description: Returns a modifiable pointer to the actual vertex +// array, so that application code may directly +// manipulate the vertices. +//////////////////////////////////////////////////////////////////// +INLINE PTA_uchar qpGeomVertexArrayData:: +modify_data() { + // Perform copy-on-write: if the reference count on the vertex data + // is greater than 1, assume some other GeomVertexData has the same + // pointer, so make a copy of it first. + CDWriter cdata(_cycler); + + if (cdata->_data.get_ref_count() > 1) { + PTA_uchar orig_data = cdata->_data; + cdata->_data = PTA_uchar(); + cdata->_data.v() = orig_data.v(); + } + ++(cdata->_modified); + + return cdata->_data; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomVertexArrayData::set_data +// Access: Published +// Description: Replaces the vertex data array with a completely new +// array. +//////////////////////////////////////////////////////////////////// +INLINE void qpGeomVertexArrayData:: +set_data(CPTA_uchar array) { + CDWriter cdata(_cycler); + cdata->_data = (PTA_uchar &)array; + ++(cdata->_modified); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomVertexArrayData::get_num_vertices +// Access: Published +// Description: Returns the number of vertices stored in the array, +// based on the number of bytes and the stride. This +// should be the same for all arrays within a given +// GeomVertexData object. +//////////////////////////////////////////////////////////////////// +INLINE int qpGeomVertexArrayData:: +get_num_vertices() const { + return get_num_bytes() / _array_format->get_stride(); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomVertexArrayData::clear_vertices +// Access: Published +// Description: Removes all of the vertices in the array. +// Functionally equivalent to set_num_vertices(0). +//////////////////////////////////////////////////////////////////// +INLINE void qpGeomVertexArrayData:: +clear_vertices() { + set_data(PTA_uchar()); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomVertexArrayData::get_num_bytes +// Access: Published +// Description: Returns the number of bytes stored in the array. +//////////////////////////////////////////////////////////////////// +INLINE int qpGeomVertexArrayData:: +get_num_bytes() const { + CDReader cdata(_cycler); + return cdata->_data.size(); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomVertexArrayData::get_modified +// Access: Published +// Description: Returns a sequence number which is guaranteed to +// change at least every time the array vertex data is +// modified. +//////////////////////////////////////////////////////////////////// +INLINE UpdateSeq qpGeomVertexArrayData:: +get_modified() const { + CDReader cdata(_cycler); + return cdata->_modified; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomVertexArrayData::CData::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE qpGeomVertexArrayData::CData:: +CData() { +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomVertexArrayData::CData::Copy Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE qpGeomVertexArrayData::CData:: +CData(const qpGeomVertexArrayData::CData ©) : + _data(copy._data), + _modified(copy._modified) +{ +} diff --git a/panda/src/gobj/qpgeomVertexArrayData.cxx b/panda/src/gobj/qpgeomVertexArrayData.cxx new file mode 100644 index 0000000000..0344f897cc --- /dev/null +++ b/panda/src/gobj/qpgeomVertexArrayData.cxx @@ -0,0 +1,360 @@ +// Filename: qpgeomVertexArrayData.cxx +// Created by: drose (17Mar05) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#include "qpgeomVertexArrayData.h" +#include "preparedGraphicsObjects.h" +#include "bamReader.h" +#include "bamWriter.h" +#include "pset.h" + +TypeHandle qpGeomVertexArrayData::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomVertexArrayData::Default Constructor +// Access: Private +// Description: Constructs an invalid object. This is only used when +// reading from the bam file. +//////////////////////////////////////////////////////////////////// +qpGeomVertexArrayData:: +qpGeomVertexArrayData() { +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomVertexArrayData::Constructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +qpGeomVertexArrayData:: +qpGeomVertexArrayData(const qpGeomVertexArrayFormat *array_format, + qpGeomVertexArrayData::UsageHint usage_hint) : + _array_format(array_format), + _usage_hint(usage_hint) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomVertexArrayData::Copy Constructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +qpGeomVertexArrayData:: +qpGeomVertexArrayData(const qpGeomVertexArrayData ©) : + _array_format(copy._array_format), + _usage_hint(copy._usage_hint), + _cycler(copy._cycler) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomVertexArrayData::Copy Assignment Operator +// Access: Private +// Description: Directly copying ArrayData objects by assignment is +// disallowed. +//////////////////////////////////////////////////////////////////// +void qpGeomVertexArrayData:: +operator = (const qpGeomVertexArrayData &) { + nassertv(false); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomVertexArrayData::Destructor +// Access: Published, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +qpGeomVertexArrayData:: +~qpGeomVertexArrayData() { + release_all(); +} + + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomVertexArrayData::set_num_vertices +// Access: Published +// Description: Sets the length of the array to n vertices. +// Normally, you would not call this directly, since all +// of the arrays in a particular GeomVertexData must +// have the same number of vertices; instead, call +// GeomVertexData::set_num_vertices(). +// +// The return value is true if the number of vertices +// was changed, false if the object already contained n +// vertices (or if there was some error). +//////////////////////////////////////////////////////////////////// +bool qpGeomVertexArrayData:: +set_num_vertices(int n) { + CDWriter cdata(_cycler); + + int stride = _array_format->get_stride(); + int delta = n - (cdata->_data.size() / stride); + + if (delta != 0) { + if (cdata->_data.get_ref_count() > 1) { + // Copy-on-write: the data is already reffed somewhere else, + // so we're just going to make a copy. + PTA_uchar new_data; + new_data.reserve(n * stride); + new_data.insert(new_data.end(), n * stride, uchar()); + memcpy(new_data, cdata->_data, + min((size_t)(n * stride), cdata->_data.size())); + cdata->_data = new_data; + + } else { + // We've got the only reference to the data, so we can change + // it directly. + if (delta > 0) { + cdata->_data.insert(cdata->_data.end(), delta * stride, uchar()); + + } else { + cdata->_data.erase(cdata->_data.begin() + n * stride, + cdata->_data.end()); + } + } + + ++(cdata->_modified); + + return true; + } + + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomVertexArrayData::prepare +// Access: Published +// Description: Indicates that the data should be enqueued to be +// prepared in the indicated prepared_objects at the +// beginning of the next frame. This will ensure the +// data is already loaded into the GSG if it is expected +// to be rendered soon. +// +// Use this function instead of prepare_now() to preload +// datas from a user interface standpoint. +//////////////////////////////////////////////////////////////////// +void qpGeomVertexArrayData:: +prepare(PreparedGraphicsObjects *prepared_objects) { + prepared_objects->enqueue_data(this); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomVertexArrayData::prepare_now +// Access: Public +// Description: Creates a context for the data on the particular +// GSG, if it does not already exist. Returns the new +// (or old) DataContext. This assumes that the +// GraphicsStateGuardian is the currently active +// rendering context and that it is ready to accept new +// datas. If this is not necessarily the case, you +// should use prepare() instead. +// +// Normally, this is not called directly except by the +// GraphicsStateGuardian; a data does not need to be +// explicitly prepared by the user before it may be +// rendered. +//////////////////////////////////////////////////////////////////// +DataContext *qpGeomVertexArrayData:: +prepare_now(PreparedGraphicsObjects *prepared_objects, + GraphicsStateGuardianBase *gsg) { + Contexts::const_iterator ci; + ci = _contexts.find(prepared_objects); + if (ci != _contexts.end()) { + return (*ci).second; + } + + DataContext *dc = prepared_objects->prepare_data_now(this, gsg); + if (dc != (DataContext *)NULL) { + _contexts[prepared_objects] = dc; + } + return dc; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomVertexArrayData::release +// Access: Public +// Description: Frees the data context only on the indicated object, +// if it exists there. Returns true if it was released, +// false if it had not been prepared. +//////////////////////////////////////////////////////////////////// +bool qpGeomVertexArrayData:: +release(PreparedGraphicsObjects *prepared_objects) { + Contexts::iterator ci; + ci = _contexts.find(prepared_objects); + if (ci != _contexts.end()) { + DataContext *dc = (*ci).second; + prepared_objects->release_data(dc); + return true; + } + + // Maybe it wasn't prepared yet, but it's about to be. + return prepared_objects->dequeue_data(this); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomVertexArrayData::release_all +// Access: Public +// Description: Frees the context allocated on all objects for which +// the data has been declared. Returns the number of +// contexts which have been freed. +//////////////////////////////////////////////////////////////////// +int qpGeomVertexArrayData:: +release_all() { + // We have to traverse a copy of the _contexts list, because the + // PreparedGraphicsObjects object will call clear_prepared() in response + // to each release_data(), and we don't want to be modifying the + // _contexts list while we're traversing it. + Contexts temp = _contexts; + int num_freed = (int)_contexts.size(); + + Contexts::const_iterator ci; + for (ci = temp.begin(); ci != temp.end(); ++ci) { + PreparedGraphicsObjects *prepared_objects = (*ci).first; + DataContext *dc = (*ci).second; + prepared_objects->release_data(dc); + } + + // Now that we've called release_data() on every known context, + // the _contexts list should have completely emptied itself. + nassertr(_contexts.empty(), num_freed); + + return num_freed; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomVertexArrayData::clear_prepared +// Access: Private +// Description: Removes the indicated PreparedGraphicsObjects table +// from the data array's table, without actually +// releasing the data array. This is intended to be +// called only from +// PreparedGraphicsObjects::release_data(); it should +// never be called by user code. +//////////////////////////////////////////////////////////////////// +void qpGeomVertexArrayData:: +clear_prepared(PreparedGraphicsObjects *prepared_objects) { + Contexts::iterator ci; + ci = _contexts.find(prepared_objects); + if (ci != _contexts.end()) { + _contexts.erase(ci); + } else { + // If this assertion fails, clear_prepared() was given a + // prepared_objects which the data array didn't know about. + nassertv(false); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomVertexArrayData::register_with_read_factory +// Access: Public, Static +// Description: Tells the BamReader how to create objects of type +// qpGeomVertexArrayData. +//////////////////////////////////////////////////////////////////// +void qpGeomVertexArrayData:: +register_with_read_factory() { + BamReader::get_factory()->register_factory(get_class_type(), make_from_bam); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomVertexArrayData::write_datagram +// Access: Public, Virtual +// Description: Writes the contents of this object to the datagram +// for shipping out to a Bam file. +//////////////////////////////////////////////////////////////////// +void qpGeomVertexArrayData:: +write_datagram(BamWriter *manager, Datagram &dg) { + TypedWritable::write_datagram(manager, dg); + + manager->write_cdata(dg, _cycler); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomVertexArrayData::make_from_bam +// Access: Protected, Static +// Description: This function is called by the BamReader's factory +// when a new object of type qpGeomVertexArrayData is encountered +// in the Bam file. It should create the qpGeomVertexArrayData +// and extract its information from the file. +//////////////////////////////////////////////////////////////////// +TypedWritable *qpGeomVertexArrayData:: +make_from_bam(const FactoryParams ¶ms) { + qpGeomVertexArrayData *object = new qpGeomVertexArrayData; + DatagramIterator scan; + BamReader *manager; + + parse_params(params, scan, manager); + object->fillin(scan, manager); + + return object; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomVertexArrayData::fillin +// Access: Protected +// Description: This internal function is called by make_from_bam to +// read in all of the relevant data from the BamFile for +// the new qpGeomVertexArrayData. +//////////////////////////////////////////////////////////////////// +void qpGeomVertexArrayData:: +fillin(DatagramIterator &scan, BamReader *manager) { + TypedWritable::fillin(scan, manager); + + manager->read_cdata(scan, _cycler); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomVertexArrayData::CData::make_copy +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +CycleData *qpGeomVertexArrayData::CData:: +make_copy() const { + return new CData(*this); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomVertexArrayData::CData::write_datagram +// Access: Public, Virtual +// Description: Writes the contents of this object to the datagram +// for shipping out to a Bam file. +//////////////////////////////////////////////////////////////////// +void qpGeomVertexArrayData::CData:: +write_datagram(BamWriter *manager, Datagram &dg) const { +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomVertexArrayData::CData::complete_pointers +// Access: Public, Virtual +// Description: Receives an array of pointers, one for each time +// manager->read_pointer() was called in fillin(). +// Returns the number of pointers processed. +//////////////////////////////////////////////////////////////////// +int qpGeomVertexArrayData::CData:: +complete_pointers(TypedWritable **p_list, BamReader *manager) { + int pi = CycleData::complete_pointers(p_list, manager); + + return pi; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomVertexArrayData::CData::fillin +// Access: Public, Virtual +// Description: This internal function is called by make_from_bam to +// read in all of the relevant data from the BamFile for +// the new qpGeomVertexArrayData. +//////////////////////////////////////////////////////////////////// +void qpGeomVertexArrayData::CData:: +fillin(DatagramIterator &scan, BamReader *manager) { +} diff --git a/panda/src/gobj/qpgeomVertexArrayData.h b/panda/src/gobj/qpgeomVertexArrayData.h new file mode 100644 index 0000000000..385520c33c --- /dev/null +++ b/panda/src/gobj/qpgeomVertexArrayData.h @@ -0,0 +1,164 @@ +// Filename: qpgeomVertexArrayData.h +// Created by: drose (17Mar05) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#ifndef qpGEOMVERTEXARRAYDATA_H +#define qpGEOMVERTEXARRAYDATA_H + +#include "pandabase.h" +#include "typedWritableReferenceCount.h" +#include "qpgeomVertexArrayFormat.h" +#include "pta_uchar.h" +#include "updateSeq.h" +#include "cycleData.h" +#include "cycleDataReader.h" +#include "cycleDataWriter.h" +#include "pipelineCycler.h" +#include "pmap.h" + +class PreparedGraphicsObjects; +class DataContext; + +//////////////////////////////////////////////////////////////////// +// Class : qpGeomVertexArrayData +// Description : This is the data for one array of a GeomVertexData +// structure. Many GeomVertexData structures will only +// define one array; some will define multiple arrays. +// DirectX calls this concept a "stream". +// +// This object is just a block of data. See +// GeomVertexData for the organizing structure. +// +// This is part of the experimental Geom rewrite. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA qpGeomVertexArrayData : public TypedWritableReferenceCount { +private: + qpGeomVertexArrayData(); + +PUBLISHED: + enum UsageHint { + // UH_client: don't attempt to upload the data as a "vertex + // buffer"; always keep it on the client. + UH_client, + + // UH_stream: the data will be created once, used to render a few + // times, and then discarded. + UH_stream, + + // UH_static: the data will be created once, and used to render + // many times, without modification. + UH_static, + + // UH_dynamic: the data will be repeatedly modified and + // re-rendered. + UH_dynamic, + }; + + qpGeomVertexArrayData(const qpGeomVertexArrayFormat *array_format, + UsageHint usage_hint); + qpGeomVertexArrayData(const qpGeomVertexArrayData ©); +private: + void operator = (const qpGeomVertexArrayData ©); +PUBLISHED: + virtual ~qpGeomVertexArrayData(); + + INLINE const qpGeomVertexArrayFormat *get_array_format() const; + INLINE UsageHint get_usage_hint() const; + + INLINE CPTA_uchar get_data() const; + INLINE PTA_uchar modify_data(); + INLINE void set_data(CPTA_uchar data); + + INLINE int get_num_vertices() const; + bool set_num_vertices(int n); + INLINE void clear_vertices(); + + INLINE int get_num_bytes() const; + INLINE UpdateSeq get_modified() const; + + void prepare(PreparedGraphicsObjects *prepared_objects); + +public: + DataContext *prepare_now(PreparedGraphicsObjects *prepared_objects, + GraphicsStateGuardianBase *gsg); + bool release(PreparedGraphicsObjects *prepared_objects); + int release_all(); + +private: + void clear_prepared(PreparedGraphicsObjects *prepared_objects); + + CPT(qpGeomVertexArrayFormat) _array_format; + UsageHint _usage_hint; + + // A GeomVertexArrayData keeps a list (actually, a map) of all the + // PreparedGraphicsObjects tables that it has been prepared into. + // Each PGO conversely keeps a list (a set) of all the Geoms that + // have been prepared there. When either destructs, it removes + // itself from the other's list. + typedef pmap Contexts; + Contexts _contexts; + + // This is the data that must be cycled between pipeline stages. + class EXPCL_PANDA CData : public CycleData { + public: + INLINE CData(); + INLINE CData(const CData ©); + virtual CycleData *make_copy() const; + virtual void write_datagram(BamWriter *manager, Datagram &dg) const; + virtual int complete_pointers(TypedWritable **plist, BamReader *manager); + virtual void fillin(DatagramIterator &scan, BamReader *manager); + + PTA_uchar _data; + UpdateSeq _modified; + }; + + PipelineCycler _cycler; + typedef CycleDataReader CDReader; + typedef CycleDataWriter CDWriter; + +public: + static void register_with_read_factory(); + virtual void write_datagram(BamWriter *manager, Datagram &dg); + +protected: + static TypedWritable *make_from_bam(const FactoryParams ¶ms); + void fillin(DatagramIterator &scan, BamReader *manager); + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + TypedWritableReferenceCount::init_type(); + register_type(_type_handle, "qpGeomVertexArrayData", + TypedWritableReferenceCount::get_class_type()); + } + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + +private: + static TypeHandle _type_handle; + + friend class qpGeomVertexCacheManager; + friend class PreparedGraphicsObjects; +}; + +#include "qpgeomVertexArrayData.I" + +#endif diff --git a/panda/src/gobj/qpgeomVertexData.I b/panda/src/gobj/qpgeomVertexData.I index 742cc647fc..8ebc1f3c78 100644 --- a/panda/src/gobj/qpgeomVertexData.I +++ b/panda/src/gobj/qpgeomVertexData.I @@ -34,11 +34,15 @@ get_format() const { // Description: Sets the length of the array to n vertices in all of // the various arrays (presumably by adding vertices). // The new vertex data is uninitialized. +// +// The return value is true if the number of vertices +// was changed, false if the object already contained n +// vertices (or if there was some error). //////////////////////////////////////////////////////////////////// -INLINE void qpGeomVertexData:: +INLINE bool qpGeomVertexData:: set_num_vertices(int n) { CDWriter cdata(_cycler); - do_set_num_vertices(n, cdata); + return do_set_num_vertices(n, cdata); } //////////////////////////////////////////////////////////////////// @@ -55,17 +59,17 @@ get_num_arrays() const { } //////////////////////////////////////////////////////////////////// -// Function: qpGeomVertexData::get_array_data +// Function: qpGeomVertexData::get_array // Access: Published // Description: Returns a const pointer to the vertex data for the // indicated array, for application code to directly // examine (but not modify) the underlying vertex data. //////////////////////////////////////////////////////////////////// -INLINE CPTA_uchar qpGeomVertexData:: -get_array_data(int array) const { +INLINE const qpGeomVertexArrayData *qpGeomVertexData:: +get_array(int i) const { CDReader cdata(_cycler); - nassertr(array >= 0 && array < (int)cdata->_arrays.size(), CPTA_uchar()); - return cdata->_arrays[array]; + nassertr(i >= 0 && i < (int)cdata->_arrays.size(), NULL); + return cdata->_arrays[i]; } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/gobj/qpgeomVertexData.cxx b/panda/src/gobj/qpgeomVertexData.cxx index a2f42cee69..184b9cf4bf 100644 --- a/panda/src/gobj/qpgeomVertexData.cxx +++ b/panda/src/gobj/qpgeomVertexData.cxx @@ -43,15 +43,21 @@ qpGeomVertexData() { // Description: //////////////////////////////////////////////////////////////////// qpGeomVertexData:: -qpGeomVertexData(const qpGeomVertexFormat *format) : +qpGeomVertexData(const qpGeomVertexFormat *format, + qpGeomVertexArrayData::UsageHint usage_hint) : _format(format) { nassertv(_format->is_registered()); // Create some empty arrays as required by the format. CDWriter cdata(_cycler); - cdata->_arrays.insert(cdata->_arrays.end(), _format->get_num_arrays(), - PTA_uchar()); + + int num_arrays = _format->get_num_arrays(); + for (int i = 0; i < num_arrays; i++) { + PT(qpGeomVertexArrayData) array = new qpGeomVertexArrayData + (_format->get_array(i), usage_hint); + cdata->_arrays.push_back(array); + } } //////////////////////////////////////////////////////////////////// @@ -125,7 +131,7 @@ get_num_vertices() const { // Look up the answer on the first array (since any array will do). int stride = _format->get_array(0)->get_stride(); - return cdata->_arrays[0].size() / stride; + return cdata->_arrays[0]->get_num_bytes() / stride; } //////////////////////////////////////////////////////////////////// @@ -137,6 +143,7 @@ get_num_vertices() const { //////////////////////////////////////////////////////////////////// void qpGeomVertexData:: clear_vertices() { + clear_cache(); CDWriter cdata(_cycler); nassertv(_format->get_num_arrays() == (int)cdata->_arrays.size()); @@ -144,12 +151,12 @@ clear_vertices() { for (ai = cdata->_arrays.begin(); ai != cdata->_arrays.end(); ++ai) { - (*ai).clear(); + (*ai)->clear_vertices(); } } //////////////////////////////////////////////////////////////////// -// Function: qpGeomVertexData::modify_array_data +// Function: qpGeomVertexData::modify_array // Access: Published // Description: Returns a modifiable pointer to the indicated vertex // array, so that application code may directly @@ -157,27 +164,24 @@ clear_vertices() { // the length of this array, since all of the arrays // should be kept in sync--use add_vertices() instead. //////////////////////////////////////////////////////////////////// -PTA_uchar qpGeomVertexData:: -modify_array_data(int array) { +qpGeomVertexArrayData *qpGeomVertexData:: +modify_array(int i) { // Perform copy-on-write: if the reference count on the vertex data // is greater than 1, assume some other GeomVertexData has the same // pointer, so make a copy of it first. - + clear_cache(); CDWriter cdata(_cycler); - nassertr(array >= 0 && array < (int)cdata->_arrays.size(), PTA_uchar()); + nassertr(i >= 0 && i < (int)cdata->_arrays.size(), NULL); - if (cdata->_arrays[array].get_ref_count() > 1) { - PTA_uchar orig_data = cdata->_arrays[array]; - cdata->_arrays[array] = PTA_uchar(); - cdata->_arrays[array].v() = orig_data.v(); + if (cdata->_arrays[i]->get_ref_count() > 1) { + cdata->_arrays[i] = new qpGeomVertexArrayData(*cdata->_arrays[i]); } - clear_cache(); - return cdata->_arrays[array]; + return cdata->_arrays[i]; } //////////////////////////////////////////////////////////////////// -// Function: qpGeomVertexData::set_array_data +// Function: qpGeomVertexData::set_array // Access: Published // Description: Replaces the indicated vertex data array with // a completely new array. You should be careful that @@ -185,10 +189,11 @@ modify_array_data(int array) { // unless you know what you are doing. //////////////////////////////////////////////////////////////////// void qpGeomVertexData:: -set_array_data(int array, PTA_uchar array_data) { +set_array(int i, const qpGeomVertexArrayData *array) { + clear_cache(); CDWriter cdata(_cycler); - nassertv(array >= 0 && array < (int)cdata->_arrays.size()); - cdata->_arrays[array] = array_data; + nassertv(i >= 0 && i < (int)cdata->_arrays.size()); + cdata->_arrays[i] = (qpGeomVertexArrayData *)array; } //////////////////////////////////////////////////////////////////// @@ -205,7 +210,7 @@ get_num_bytes() const { Arrays::const_iterator ai; for (ai = cdata->_arrays.begin(); ai != cdata->_arrays.end(); ++ai) { - num_bytes += (*ai).size(); + num_bytes += (*ai)->get_num_bytes(); } return num_bytes; @@ -257,33 +262,34 @@ convert_to(const qpGeomVertexFormat *new_format) const { } PStatTimer timer(_munge_data_pcollector); - PT(qpGeomVertexData) new_data = new qpGeomVertexData(new_format); + PT(qpGeomVertexData) new_data = + new qpGeomVertexData(new_format, qpGeomVertexArrayData::UH_client); pset done_arrays; int num_arrays = _format->get_num_arrays(); - int array; + int i; // First, check to see if any arrays can be simply appropriated for // the new format, without changing the data. - for (array = 0; array < num_arrays; ++array) { + for (i = 0; i < num_arrays; ++i) { const qpGeomVertexArrayFormat *array_format = - _format->get_array(array); + _format->get_array(i); bool array_done = false; int new_num_arrays = new_format->get_num_arrays(); - for (int new_array = 0; - new_array < new_num_arrays && !array_done; - ++new_array) { + for (int new_i = 0; + new_i < new_num_arrays && !array_done; + ++new_i) { const qpGeomVertexArrayFormat *new_array_format = - new_format->get_array(new_array); + new_format->get_array(new_i); if (new_array_format->is_data_subset_of(*array_format)) { // Great! Just use the same data for this one. - new_data->set_array_data(new_array, (PTA_uchar &)get_array_data(array)); + new_data->set_array(new_i, get_array(i)); array_done = true; - done_arrays.insert(new_array); + done_arrays.insert(new_i); } } } @@ -292,27 +298,30 @@ convert_to(const qpGeomVertexFormat *new_format) const { new_data->set_num_vertices(num_vertices); // Now go back through and copy any data that's left over. - for (array = 0; array < num_arrays; ++array) { - CPTA_uchar array_data = get_array_data(array); - const qpGeomVertexArrayFormat *array_format = - _format->get_array(array); + for (i = 0; i < num_arrays; ++i) { + CPTA_uchar data = get_array(i)->get_data(); + const qpGeomVertexArrayFormat *array_format = _format->get_array(i); int num_data_types = array_format->get_num_data_types(); for (int di = 0; di < num_data_types; ++di) { const qpGeomVertexDataType *data_type = array_format->get_data_type(di); - int new_array = new_format->get_array_with(data_type->get_name()); - if (new_array >= 0 && done_arrays.count(new_array) == 0) { + int new_i = new_format->get_array_with(data_type->get_name()); + if (new_i >= 0 && done_arrays.count(new_i) == 0) { // The data type exists in the new format; we have to copy it. - PTA_uchar new_array_data = new_data->modify_array_data(new_array); + PT(qpGeomVertexArrayData) new_array_data = new + qpGeomVertexArrayData(*get_array(i)); + new_data->set_array(new_i, new_array_data); + PTA_uchar new_data = new_array_data->modify_data(); + const qpGeomVertexArrayFormat *new_array_format = - new_format->get_array(new_array); + new_format->get_array(new_i); const qpGeomVertexDataType *new_data_type = new_array_format->get_data_type(data_type->get_name()); new_data_type->copy_records - (new_array_data + new_data_type->get_start(), + (new_data + new_data_type->get_start(), new_array_format->get_stride(), - array_data + data_type->get_start(), array_format->get_stride(), + data + data_type->get_start(), array_format->get_stride(), data_type, num_vertices); } } @@ -397,7 +406,7 @@ set_data(int array, const qpGeomVertexDataType *data_type, { CDReader cdata(_cycler); - int array_size = (int)cdata->_arrays[array].size(); + int array_size = (int)cdata->_arrays[array]->get_num_bytes(); if (element + data_type->get_total_bytes() > array_size) { // Whoops, we need more vertices! CDWriter cdataw(_cycler, cdata); @@ -405,7 +414,7 @@ set_data(int array, const qpGeomVertexDataType *data_type, } } - PTA_uchar array_data = modify_array_data(array); + PTA_uchar array_data = modify_array(array)->modify_data(); nassertv(element >= 0 && element + data_type->get_total_bytes() <= (int)array_data.size()); switch (data_type->get_numeric_type()) { @@ -484,7 +493,7 @@ set_data(int array, const qpGeomVertexDataType *data_type, void qpGeomVertexData:: get_data(int array, const qpGeomVertexDataType *data_type, int vertex, float *data, int num_values) const { - CPTA_uchar array_data = get_array_data(array); + CPTA_uchar array_data = get_array(array)->get_data(); int stride = _format->get_array(array)->get_stride(); int element = vertex * stride + data_type->get_start(); nassertv(element >= 0 && element + data_type->get_total_bytes() <= (int)array_data.size()); @@ -561,7 +570,8 @@ get_data(int array, const qpGeomVertexDataType *data_type, // which case none of the output parameters are valid). //////////////////////////////////////////////////////////////////// bool qpGeomVertexData:: -get_array_info(const InternalName *name, CPTA_uchar &array_data, +get_array_info(const InternalName *name, + const qpGeomVertexArrayData *&array_data, int &num_components, qpGeomVertexDataType::NumericType &numeric_type, int &start, int &stride) const { @@ -712,45 +722,23 @@ remove_cache_entry(const qpGeomVertexFormat *modifier) const { // Access: Private // Description: The private implementation of set_num_vertices(). //////////////////////////////////////////////////////////////////// -void qpGeomVertexData:: -do_set_num_vertices(int n, CDWriter &cdata) { - nassertv(_format->get_num_arrays() == (int)cdata->_arrays.size()); +bool qpGeomVertexData:: +do_set_num_vertices(int n, qpGeomVertexData::CDWriter &cdata) { + nassertr(_format->get_num_arrays() == (int)cdata->_arrays.size(), false); bool any_changed = false; for (size_t i = 0; i < cdata->_arrays.size(); i++) { - int stride = _format->get_array(i)->get_stride(); - int delta = n - (cdata->_arrays[i].size() / stride); - - if (delta != 0) { + if (cdata->_arrays[i]->set_num_vertices(n)) { any_changed = true; - if (cdata->_arrays[i].get_ref_count() > 1) { - // Copy-on-write: the array is already reffed somewhere else, - // so we're just going to make a copy. - PTA_uchar new_array; - new_array.reserve(n * stride); - new_array.insert(new_array.end(), n * stride, uchar()); - memcpy(new_array, cdata->_arrays[i], - min((size_t)(n * stride), cdata->_arrays[i].size())); - cdata->_arrays[i] = new_array; - - } else { - // We've got the only reference to the array, so we can change - // it directly. - if (delta > 0) { - cdata->_arrays[i].insert(cdata->_arrays[i].end(), delta * stride, uchar()); - - } else { - cdata->_arrays[i].erase(cdata->_arrays[i].begin() + n * stride, - cdata->_arrays[i].end()); - } - } } } if (any_changed) { clear_cache(); } + + return any_changed; } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/gobj/qpgeomVertexData.h b/panda/src/gobj/qpgeomVertexData.h index afcf6c3b3d..f1a568ce2c 100644 --- a/panda/src/gobj/qpgeomVertexData.h +++ b/panda/src/gobj/qpgeomVertexData.h @@ -23,6 +23,7 @@ #include "typedWritableReferenceCount.h" #include "qpgeomVertexFormat.h" #include "qpgeomVertexDataType.h" +#include "qpgeomVertexArrayData.h" #include "internalName.h" #include "cycleData.h" #include "cycleDataReader.h" @@ -32,7 +33,6 @@ #include "pointerTo.h" #include "pmap.h" #include "pvector.h" -#include "pta_uchar.h" class FactoryParams; class qpGeomVertexDataType; @@ -62,7 +62,8 @@ class EXPCL_PANDA qpGeomVertexData : public TypedWritableReferenceCount { private: qpGeomVertexData(); PUBLISHED: - qpGeomVertexData(const qpGeomVertexFormat *format); + qpGeomVertexData(const qpGeomVertexFormat *format, + qpGeomVertexArrayData::UsageHint usage_hint); qpGeomVertexData(const qpGeomVertexData ©); void operator = (const qpGeomVertexData ©); virtual ~qpGeomVertexData(); @@ -70,13 +71,13 @@ PUBLISHED: INLINE const qpGeomVertexFormat *get_format() const; int get_num_vertices() const; - INLINE void set_num_vertices(int n); + INLINE bool set_num_vertices(int n); void clear_vertices(); INLINE int get_num_arrays() const; - INLINE CPTA_uchar get_array_data(int array) const; - PTA_uchar modify_array_data(int array); - void set_array_data(int array, PTA_uchar array_data); + INLINE const qpGeomVertexArrayData *get_array(int i) const; + qpGeomVertexArrayData *modify_array(int i); + void set_array(int i, const qpGeomVertexArrayData *array); int get_num_bytes() const; @@ -93,7 +94,8 @@ public: void get_data(int array, const qpGeomVertexDataType *data_type, int vertex, float *data, int num_values) const; - bool get_array_info(const InternalName *name, CPTA_uchar &array_data, + bool get_array_info(const InternalName *name, + const qpGeomVertexArrayData *&array_data, int &num_components, qpGeomVertexDataType::NumericType &numeric_type, int &start, int &stride) const; @@ -111,7 +113,7 @@ private: private: CPT(qpGeomVertexFormat) _format; - typedef pvector Arrays; + typedef pvector< PT(qpGeomVertexArrayData) > Arrays; // We have to use reference-counting pointers here instead of having // explicit cleanup in the GeomVertexFormat destructor, because the @@ -139,7 +141,7 @@ private: typedef CycleDataWriter CDWriter; private: - void do_set_num_vertices(int n, CDWriter &cdata); + bool do_set_num_vertices(int n, CDWriter &cdata); static PStatCollector _munge_data_pcollector; diff --git a/panda/src/gobj/qpgeomVertexFormat.cxx b/panda/src/gobj/qpgeomVertexFormat.cxx index 5935829acf..b933d27478 100644 --- a/panda/src/gobj/qpgeomVertexFormat.cxx +++ b/panda/src/gobj/qpgeomVertexFormat.cxx @@ -321,7 +321,7 @@ write_with_data(ostream &out, int indent_level, indent(out, indent_level) << data->get_num_vertices() << " vertices.\n"; for (size_t i = 0; i < _arrays.size(); i++) { - CPTA_uchar array_data = data->get_array_data(i); + CPTA_uchar array_data = data->get_array(i)->get_data(); indent(out, indent_level) << "Array " << i << " (" << (void *)array_data.p() << "):\n"; _arrays[i]->write_with_data(out, indent_level + 2, data, i); diff --git a/panda/src/gsgbase/graphicsStateGuardianBase.h b/panda/src/gsgbase/graphicsStateGuardianBase.h index 35dc30f72a..b58f91a714 100644 --- a/panda/src/gsgbase/graphicsStateGuardianBase.h +++ b/panda/src/gsgbase/graphicsStateGuardianBase.h @@ -30,6 +30,7 @@ class RenderBuffer; class GraphicsWindow; class NodePath; +class DataContext; class GeomContext; class GeomNode; class Geom; @@ -44,6 +45,7 @@ class GeomTristrip; class GeomTrifan; class GeomSphere; class qpGeomVertexData; +class qpGeomVertexArrayData; class qpGeomTriangles; class qpGeomTristrips; class qpGeomTrifans; @@ -132,6 +134,9 @@ public: virtual GeomContext *prepare_geom(Geom *geom)=0; virtual void release_geom(GeomContext *gc)=0; + virtual DataContext *prepare_data(qpGeomVertexArrayData *data)=0; + virtual void release_data(DataContext *gc)=0; + virtual CPT(qpGeomMunger) get_geom_munger(const RenderState *state)=0; virtual void set_state_and_transform(const RenderState *state,