From 3f7956f4e93a3fa8476961969f07e7a6c01807b7 Mon Sep 17 00:00:00 2001 From: David Rose Date: Sat, 19 Mar 2005 01:34:05 +0000 Subject: [PATCH] gl display lists with new geom --- panda/src/display/graphicsStateGuardian.cxx | 3 +- panda/src/display/graphicsStateGuardian.h | 2 +- panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx | 5 +- panda/src/dxgsg8/dxGraphicsStateGuardian8.h | 2 +- panda/src/glstuff/glGeomContext_src.h | 2 + .../glstuff/glGraphicsStateGuardian_src.cxx | 217 ++++++++++++------ .../src/glstuff/glGraphicsStateGuardian_src.h | 6 +- panda/src/gobj/config_gobj.cxx | 14 +- panda/src/gobj/config_gobj.h | 1 + panda/src/gobj/qpgeom.I | 40 +++- panda/src/gobj/qpgeom.cxx | 95 +++++++- panda/src/gobj/qpgeom.h | 13 ++ panda/src/gobj/qpgeomPrimitive.cxx | 3 +- panda/src/gobj/qpgeomUsageHint.h | 16 +- panda/src/gobj/qpgeomVertexArrayData.I | 37 --- panda/src/gobj/qpgeomVertexArrayData.cxx | 40 +++- panda/src/gobj/qpgeomVertexArrayData.h | 4 +- panda/src/gsgbase/graphicsStateGuardianBase.h | 3 +- 18 files changed, 370 insertions(+), 133 deletions(-) diff --git a/panda/src/display/graphicsStateGuardian.cxx b/panda/src/display/graphicsStateGuardian.cxx index 50c0349c39..3f06d8ec47 100644 --- a/panda/src/display/graphicsStateGuardian.cxx +++ b/panda/src/display/graphicsStateGuardian.cxx @@ -670,7 +670,7 @@ finish_decal() { // are ok, false to abort this group of primitives. //////////////////////////////////////////////////////////////////// bool GraphicsStateGuardian:: -begin_draw_primitives(const qpGeomVertexData *data) { +begin_draw_primitives(const qpGeom *, const qpGeomVertexData *data) { _vertex_data = data; return true; } @@ -719,6 +719,7 @@ draw_trifans(const qpGeomTrifans *primitive) { //////////////////////////////////////////////////////////////////// void GraphicsStateGuardian:: end_draw_primitives() { + _vertex_data = NULL; } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/display/graphicsStateGuardian.h b/panda/src/display/graphicsStateGuardian.h index 112dba745e..cbaafe1b6e 100644 --- a/panda/src/display/graphicsStateGuardian.h +++ b/panda/src/display/graphicsStateGuardian.h @@ -148,7 +148,7 @@ public: virtual CPT(RenderState) begin_decal_base_second(); virtual void finish_decal(); - virtual bool begin_draw_primitives(const qpGeomVertexData *vertex_data); + virtual bool begin_draw_primitives(const qpGeom *geom, const qpGeomVertexData *vertex_data); virtual void draw_triangles(const qpGeomTriangles *primitive); virtual void draw_tristrips(const qpGeomTristrips *primitive); virtual void draw_trifans(const qpGeomTrifans *primitive); diff --git a/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx b/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx index 6e55da86fe..53a26dec14 100644 --- a/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx +++ b/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx @@ -2606,10 +2606,10 @@ draw_sphere(GeomSphere *geom, GeomContext *gc) { // are ok, false to abort this group of primitives. //////////////////////////////////////////////////////////////////// bool DXGraphicsStateGuardian8:: -begin_draw_primitives(const qpGeomVertexData *vertex_data) { +begin_draw_primitives(const qpGeom *geom, const qpGeomVertexData *vertex_data) { DO_PSTATS_STUFF(_draw_primitive_pcollector.start()); - if (!GraphicsStateGuardian::begin_draw_primitives(vertex_data)) { + if (!GraphicsStateGuardian::begin_draw_primitives(geom, vertex_data)) { return false; } nassertr(_vertex_data != (qpGeomVertexData *)NULL, false); @@ -2694,6 +2694,7 @@ draw_tristrips(const qpGeomTristrips *primitive) { //////////////////////////////////////////////////////////////////// void DXGraphicsStateGuardian8:: end_draw_primitives() { + GraphicsStateGuardian::end_draw_primitives(); DO_PSTATS_STUFF(_draw_primitive_pcollector.stop()); } diff --git a/panda/src/dxgsg8/dxGraphicsStateGuardian8.h b/panda/src/dxgsg8/dxGraphicsStateGuardian8.h index af0266db54..4bd1c815e7 100644 --- a/panda/src/dxgsg8/dxGraphicsStateGuardian8.h +++ b/panda/src/dxgsg8/dxGraphicsStateGuardian8.h @@ -90,7 +90,7 @@ public: virtual void draw_trifan(GeomTrifan *geom, GeomContext *gc); virtual void draw_sphere(GeomSphere *geom, GeomContext *gc); - virtual bool begin_draw_primitives(const qpGeomVertexData *vertex_data); + virtual bool begin_draw_primitives(const qpGeom *geom, const qpGeomVertexData *vertex_data); virtual void draw_triangles(const qpGeomTriangles *primitive); virtual void draw_tristrips(const qpGeomTristrips *primitive); virtual void end_draw_primitives(); diff --git a/panda/src/glstuff/glGeomContext_src.h b/panda/src/glstuff/glGeomContext_src.h index 53eebfb474..267e7fe0b8 100644 --- a/panda/src/glstuff/glGeomContext_src.h +++ b/panda/src/glstuff/glGeomContext_src.h @@ -30,6 +30,8 @@ public: // This is the GL display list index. GLuint _index; + UpdateSeq _modified; + // The number of vertices encoded in the display list, for stats // reporting. #ifdef DO_PSTATS diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index a0c6801e04..36d06c5282 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -2030,14 +2030,53 @@ draw_sphere(GeomSphere *geom, GeomContext *gc) { // are ok, false to abort this group of primitives. //////////////////////////////////////////////////////////////////// bool CLP(GraphicsStateGuardian):: -begin_draw_primitives(const qpGeomVertexData *vertex_data) { +begin_draw_primitives(const qpGeom *geom, const qpGeomVertexData *vertex_data) { DO_PSTATS_STUFF(_draw_primitive_pcollector.start()); - if (!GraphicsStateGuardian::begin_draw_primitives(vertex_data)) { + if (!GraphicsStateGuardian::begin_draw_primitives(geom, vertex_data)) { return false; } nassertr(_vertex_data != (qpGeomVertexData *)NULL, false); + _geom_display_list = NULL; + + if (geom->get_usage_hint() == qpGeomUsageHint::UH_static && + _vertex_data->get_usage_hint() == qpGeomUsageHint::UH_static && + display_lists) { + // If the geom appears to be totally static, try to build it into + // a display list. + GeomContext *gc = ((qpGeom *)geom)->prepare_now(get_prepared_objects(), this); + nassertr(gc != (GeomContext *)NULL, false); + CLP(GeomContext) *ggc = DCAST(CLP(GeomContext), gc); + if (ggc->_modified == geom->get_modified()) { + // If it hasn't been modified, just play the display list again. + GLP(CallList)(ggc->_index); +#ifdef DO_PSTATS + _vertices_display_list_pcollector.add_level(ggc->_num_verts); +#endif + + // And now we don't need to do anything else for this geom. + return false; + } + + // If it has been modified, or this is the first time, then we + // need to build the display list up. + GLP(NewList)(ggc->_index, GL_COMPILE_AND_EXECUTE); + ggc->_modified = geom->get_modified(); + _geom_display_list = ggc; + +#ifdef DO_PSTATS + // Count up the number of vertices we're about to render, by + // checking the PStats vertex counters now, and at the end. This is + // kind of hacky, but this is debug code. + _num_display_list_verts_before = + _vertices_tristrip_pcollector.get_level() + + _vertices_trifan_pcollector.get_level() + + _vertices_tri_pcollector.get_level() + + _vertices_other_pcollector.get_level(); +#endif + } + const qpGeomVertexArrayData *array_data; int num_components; qpGeomVertexDataType::NumericType numeric_type; @@ -2051,9 +2090,6 @@ begin_draw_primitives(const qpGeomVertexData *vertex_data) { GLP(VertexPointer)(num_components, get_numeric_type(numeric_type), stride, client_pointer + start); GLP(EnableClientState)(GL_VERTEX_ARRAY); - } else { - // No vertex data? No primitives! - return false; } if (wants_normals() && @@ -2073,14 +2109,8 @@ begin_draw_primitives(const qpGeomVertexData *vertex_data) { 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, client_pointer + start); - - } else { - GLP(ColorPointer)(num_components, get_numeric_type(numeric_type), - stride, client_pointer + start); - } + GLP(ColorPointer)(num_components, get_numeric_type(numeric_type), + stride, client_pointer + start); GLP(EnableClientState)(GL_COLOR_ARRAY); } else { @@ -2105,8 +2135,6 @@ begin_draw_primitives(const qpGeomVertexData *vertex_data) { GLP(DisableClientState)(GL_TEXTURE_COORD_ARRAY); } - issue_scene_graph_color(); - return true; } @@ -2168,7 +2196,23 @@ draw_tristrips(const qpGeomTristrips *primitive) { //////////////////////////////////////////////////////////////////// void CLP(GraphicsStateGuardian):: end_draw_primitives() { - GLP(DisableClientState)(GL_VERTEX_ARRAY); + if (_geom_display_list != NULL) { + // If we were building a display list, close it now. + GLP(EndList)(); + +#ifdef DO_PSTATS + float num_verts_after = + _vertices_tristrip_pcollector.get_level() + + _vertices_trifan_pcollector.get_level() + + _vertices_tri_pcollector.get_level() + + _vertices_other_pcollector.get_level(); + float num_verts = num_verts_after - _num_display_list_verts_before; + _geom_display_list->_num_verts = (int)(num_verts + 0.5); +#endif + } + _geom_display_list = NULL; + + GraphicsStateGuardian::end_draw_primitives(); DO_PSTATS_STUFF(_draw_primitive_pcollector.stop()); } @@ -2262,69 +2306,94 @@ release_texture(TextureContext *tc) { //////////////////////////////////////////////////////////////////// GeomContext *CLP(GraphicsStateGuardian):: prepare_geom(Geom *geom) { - if (!_vertex_colors_enabled) { - // We can't build a display list (or play back a display list) if - // its color is overridden with a scene graph color. Maybe if we - // take advantage of the OpenGL color matrix we can do this, but - // for now we'll just ignore it. - return NULL; - } + // Temporary test until the experimental Geom rewrite becomes the + // actual Geom implementation. + if (geom->is_exact_type(qpGeom::get_class_type())) { + CLP(GeomContext) *ggc = new CLP(GeomContext)(geom); + ggc->_index = GLP(GenLists)(1); + if (GLCAT.is_debug()) { + GLCAT.debug() + << "preparing " << *geom << ", index " << ggc->_index << "\n"; + } + if (ggc->_index == 0) { + GLCAT.error() + << "Ran out of display list indices.\n"; + delete ggc; + return NULL; + } - if (geom->is_dynamic()) { - // If the Geom is dynamic in some way, we shouldn't try to - // display-list it. - return NULL; - } + report_my_gl_errors(); + return ggc; - CLP(GeomContext) *ggc = new CLP(GeomContext)(geom); - ggc->_index = GLP(GenLists)(1); - if (GLCAT.is_debug()) { - GLCAT.debug() - << "preparing " << *geom << ", index " << ggc->_index << "\n"; - } - if (ggc->_index == 0) { - GLCAT.error() - << "Ran out of display list indices.\n"; - delete ggc; - return NULL; - } + } else { + // Original Geom display list implementation. Slightly broken, + // since it doesn't work well with scene graph color + // manipulations. - // We need to temporarily force normals and UV's on, so the display - // list will have them built in. - //force_texcoords(); - force_normals(); + if (!_vertex_colors_enabled) { + // We can't build a display list (or play back a display list) if + // its color is overridden with a scene graph color. Maybe if we + // take advantage of the OpenGL color matrix we can do this, but + // for now we'll just ignore it. + return NULL; + } + + if (geom->is_dynamic()) { + // If the Geom is dynamic in some way, we shouldn't try to + // display-list it. + return NULL; + } + + CLP(GeomContext) *ggc = new CLP(GeomContext)(geom); + ggc->_index = GLP(GenLists)(1); + if (GLCAT.is_debug()) { + GLCAT.debug() + << "preparing " << *geom << ", index " << ggc->_index << "\n"; + } + if (ggc->_index == 0) { + GLCAT.error() + << "Ran out of display list indices.\n"; + delete ggc; + return NULL; + } + + // We need to temporarily force normals and UV's on, so the display + // list will have them built in. + //force_texcoords(); + force_normals(); #ifdef DO_PSTATS - // Count up the number of vertices we're about to render, by - // checking the PStats vertex counters now, and at the end. This is - // kind of hacky, but this is debug code. - float num_verts_before = - _vertices_tristrip_pcollector.get_level() + - _vertices_trifan_pcollector.get_level() + - _vertices_tri_pcollector.get_level() + - _vertices_other_pcollector.get_level(); + // Count up the number of vertices we're about to render, by + // checking the PStats vertex counters now, and at the end. This is + // kind of hacky, but this is debug code. + float num_verts_before = + _vertices_tristrip_pcollector.get_level() + + _vertices_trifan_pcollector.get_level() + + _vertices_tri_pcollector.get_level() + + _vertices_other_pcollector.get_level(); #endif - // Now define the display list. - GLP(NewList)(ggc->_index, GL_COMPILE); - geom->draw_immediate(this, NULL); - GLP(EndList)(); + // Now define the display list. + GLP(NewList)(ggc->_index, GL_COMPILE); + geom->draw_immediate(this, NULL); + GLP(EndList)(); #ifdef DO_PSTATS - float num_verts_after = - _vertices_tristrip_pcollector.get_level() + - _vertices_trifan_pcollector.get_level() + - _vertices_tri_pcollector.get_level() + - _vertices_other_pcollector.get_level(); - float num_verts = num_verts_after - num_verts_before; - ggc->_num_verts = (int)(num_verts + 0.5); + float num_verts_after = + _vertices_tristrip_pcollector.get_level() + + _vertices_trifan_pcollector.get_level() + + _vertices_tri_pcollector.get_level() + + _vertices_other_pcollector.get_level(); + float num_verts = num_verts_after - num_verts_before; + ggc->_num_verts = (int)(num_verts + 0.5); #endif - undo_force_normals(); - //undo_force_texcoords(); + undo_force_normals(); + //undo_force_texcoords(); - report_my_gl_errors(); - return ggc; + report_my_gl_errors(); + return ggc; + } } //////////////////////////////////////////////////////////////////// @@ -2464,7 +2533,7 @@ setup_array_data(const qpGeomVertexArrayData *data) { // No support for buffer objects; always render from client. return data->get_data(); } - if (!vertex_buffers || + if (!vertex_buffers || _geom_display_list != NULL || data->get_usage_hint() == qpGeomUsageHint::UH_client) { // The array specifies client rendering only, or buffer objects // are configured off. @@ -2534,12 +2603,12 @@ apply_index_buffer(IndexBufferContext *ibc) { } if (gibc->changed_size()) { _glBufferData(GL_ELEMENT_ARRAY_BUFFER, gibc->get_data()->get_data_size_bytes(), - gibc->get_data()->get_vertices(), + gibc->get_data()->get_flat_last_vertices(), get_usage(gibc->get_data()->get_usage_hint())); } else { _glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, gibc->get_data_size_bytes(), - gibc->get_data()->get_vertices()); + gibc->get_data()->get_flat_last_vertices()); } gibc->mark_loaded(); @@ -2593,19 +2662,19 @@ const unsigned short *CLP(GraphicsStateGuardian):: setup_primitive(const qpGeomPrimitive *data) { if (!_supports_buffers) { // No support for buffer objects; always render from client. - return data->get_vertices(); + return data->get_flat_last_vertices(); } - if (!vertex_buffers || + if (!vertex_buffers || _geom_display_list != NULL || data->get_usage_hint() == qpGeomUsageHint::UH_client) { // The array specifies client rendering only, or buffer objects // are configured off. _glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - return data->get_vertices(); + return data->get_flat_last_vertices(); } // Prepare the buffer object and bind it. IndexBufferContext *ibc = ((qpGeomPrimitive *)data)->prepare_now(get_prepared_objects(), this); - nassertr(ibc != (IndexBufferContext *)NULL, data->get_vertices()); + nassertr(ibc != (IndexBufferContext *)NULL, data->get_flat_last_vertices()); apply_index_buffer(ibc); // NULL is the OpenGL convention for the first byte of the buffer. diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.h b/panda/src/glstuff/glGraphicsStateGuardian_src.h index fcaba3e851..2a243e05ab 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.h +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.h @@ -58,6 +58,8 @@ typedef void (APIENTRYP PFNGLMULTITEXCOORD2FVPROC) (GLenum target, const GLfloat typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC) (GLenum mode); typedef void (APIENTRYP PFNGLBLENDCOLORPROC) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); +class CLP(GeomContext); + //////////////////////////////////////////////////////////////////// // Class : GLGraphicsStateGuardian // Description : A GraphicsStateGuardian specialized for rendering @@ -90,7 +92,7 @@ public: virtual void draw_trifan(GeomTrifan *geom, GeomContext *gc); virtual void draw_sphere(GeomSphere *geom, GeomContext *gc); - virtual bool begin_draw_primitives(const qpGeomVertexData *vertex_data); + virtual bool begin_draw_primitives(const qpGeom *geom, const qpGeomVertexData *vertex_data); virtual void draw_triangles(const qpGeomTriangles *primitive); virtual void draw_tristrips(const qpGeomTristrips *primitive); virtual void end_draw_primitives(); @@ -315,6 +317,8 @@ protected: int _pass_number; bool _auto_rescale_normal; + CLP(GeomContext) *_geom_display_list; + float _num_display_list_verts_before; int _error_count; diff --git a/panda/src/gobj/config_gobj.cxx b/panda/src/gobj/config_gobj.cxx index 6783266d9f..0f041caf3a 100644 --- a/panda/src/gobj/config_gobj.cxx +++ b/panda/src/gobj/config_gobj.cxx @@ -84,7 +84,9 @@ ConfigVariableBool retained_mode "creates specific cache information (like display lists or vertex " "buffers) with the GSG for static geometry, when supported by the " "GSG. Set it false to use only immediate mode, which sends the " - "vertices to the GSG every frame.")); + "vertices to the GSG every frame. This is used only in the " + "original Geom implementation; it is replaced by display-lists " + "in the experimental Geom rewrite.")); ConfigVariableBool vertex_buffers ("vertex-buffers", false, @@ -95,6 +97,16 @@ ConfigVariableBool vertex_buffers "graphics memory (which might otherwise be used for textures " "or offscreen buffers).")); +ConfigVariableBool display_lists +("display-lists", false, + PRC_DESC("Set this true to allow the use of OpenGL display lists for " + "rendering static geometry. On some systems, this can result " + "in a performance improvement over vertex buffers alone; on " + "other systems (particularly low-end systems) it makes little to " + "no difference. This has no effect on DirectX rendering. If " + "vertex-buffers is also enabled, then OpenGL buffer objects " + "will also be created for dynamic geometry.")); + ConfigVariableBool use_qpgeom ("use-qpgeom", false, PRC_DESC("A temporary variable while the experimental Geom rewrite is " diff --git a/panda/src/gobj/config_gobj.h b/panda/src/gobj/config_gobj.h index fdb94ba3b9..8c3b1edc63 100644 --- a/panda/src/gobj/config_gobj.h +++ b/panda/src/gobj/config_gobj.h @@ -52,6 +52,7 @@ 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 display_lists; extern EXPCL_PANDA ConfigVariableBool use_qpgeom; diff --git a/panda/src/gobj/qpgeom.I b/panda/src/gobj/qpgeom.I index ed716ddc24..1cd32c0a25 100644 --- a/panda/src/gobj/qpgeom.I +++ b/panda/src/gobj/qpgeom.I @@ -17,6 +17,23 @@ //////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////// +// Function: qpGeom::get_usage_hint +// Access: Published +// Description: Returns the minimum (i.e. most dynamic) usage_hint +// among all of the individual GeomPrimitives that have +// been added to the geom. +//////////////////////////////////////////////////////////////////// +INLINE qpGeomUsageHint::UsageHint qpGeom:: +get_usage_hint() const { + CDReader cdata(_cycler); + if (!cdata->_got_usage_hint) { + CDWriter cdataw(((qpGeom *)this)->_cycler, cdata); + ((qpGeom *)this)->reset_usage_hint(cdataw); + } + return cdata->_usage_hint; +} + //////////////////////////////////////////////////////////////////// // Function: qpGeom::get_vertex_data // Access: Published @@ -71,6 +88,7 @@ modify_primitive(int i) { clear_cache(); CDWriter cdata(_cycler); nassertr(i >= 0 && i < (int)cdata->_primitives.size(), NULL); + cdata->_got_usage_hint = false; return cdata->_primitives[i]; } @@ -85,6 +103,19 @@ set_primitive(int i, const qpGeomPrimitive *primitive) { clear_cache(); CDWriter cdata(_cycler); nassertv(i >= 0 && i < (int)cdata->_primitives.size()); + if (cdata->_got_usage_hint && + cdata->_primitives[i]->get_usage_hint() != primitive->get_usage_hint()) { + if (cdata->_primitives[i]->get_usage_hint() < primitive->get_usage_hint()) { + // If we're reducing the usage hint, we might also be reducing + // the minimum usage hit. + cdata->_usage_hint = min(cdata->_usage_hint, primitive->get_usage_hint()); + } else { // (cdata->_primitives[i]->get_usage_hint() > primitive->get_usage_hint()) + // If we're increasing it, we might have to rederive the minimum. + if (cdata->_usage_hint == cdata->_primitives[i]->get_usage_hint()) { + cdata->_got_usage_hint = false; + } + } + } cdata->_primitives[i] = (qpGeomPrimitive *)primitive; } @@ -94,7 +125,10 @@ set_primitive(int i, const qpGeomPrimitive *primitive) { // Description: //////////////////////////////////////////////////////////////////// INLINE qpGeom::CData:: -CData() { +CData() : + _usage_hint(qpGeomUsageHint::UH_static), + _got_usage_hint(false) +{ } //////////////////////////////////////////////////////////////////// @@ -105,7 +139,9 @@ CData() { INLINE qpGeom::CData:: CData(const qpGeom::CData ©) : _data(copy._data), - _primitives(copy._primitives) + _primitives(copy._primitives), + _usage_hint(copy._usage_hint), + _got_usage_hint(copy._got_usage_hint) { } diff --git a/panda/src/gobj/qpgeom.cxx b/panda/src/gobj/qpgeom.cxx index 923e9a948d..f140717f5a 100644 --- a/panda/src/gobj/qpgeom.cxx +++ b/panda/src/gobj/qpgeom.cxx @@ -22,6 +22,7 @@ #include "bamReader.h" #include "bamWriter.h" +UpdateSeq qpGeom::_next_modified; TypeHandle qpGeom::_type_handle; //////////////////////////////////////////////////////////////////// @@ -152,6 +153,10 @@ add_primitive(const qpGeomPrimitive *primitive) { clear_cache(); CDWriter cdata(_cycler); cdata->_primitives.push_back((qpGeomPrimitive *)primitive); + + if (cdata->_got_usage_hint) { + cdata->_usage_hint = min(cdata->_usage_hint, primitive->get_usage_hint()); + } } //////////////////////////////////////////////////////////////////// @@ -164,6 +169,12 @@ remove_primitive(int i) { clear_cache(); CDWriter cdata(_cycler); nassertv(i >= 0 && i < (int)cdata->_primitives.size()); + if (cdata->_got_usage_hint && + cdata->_usage_hint == cdata->_primitives[i]->get_usage_hint()) { + // Maybe we're raising the minimum usage_hint; we have to rederive + // the usage_hint later. + cdata->_got_usage_hint = false; + } cdata->_primitives.erase(cdata->_primitives.begin() + i); } @@ -203,6 +214,34 @@ get_num_bytes() const { return num_bytes; } +//////////////////////////////////////////////////////////////////// +// Function: qpGeom::get_modified +// Access: Published +// Description: Returns the maximum UpdateSeq of all the Geom's +// individual primitives and vertex arrays. This, +// therefore, will change only when any part of the Geom +// changes. +//////////////////////////////////////////////////////////////////// +UpdateSeq qpGeom:: +get_modified() const { + CDReader cdata(_cycler); + UpdateSeq seq; + + Primitives::const_iterator pi; + for (pi = cdata->_primitives.begin(); + pi != cdata->_primitives.end(); + ++pi) { + seq = max(seq, (*pi)->get_modified()); + } + + int num_arrays = cdata->_data->get_num_arrays(); + for (int i = 0; i < num_arrays; ++i) { + seq = max(seq, cdata->_data->get_array(i)->get_modified()); + } + + return seq; +} + //////////////////////////////////////////////////////////////////// // Function: qpGeom::munge_geom // Access: Published @@ -342,9 +381,25 @@ clear_cache() { //////////////////////////////////////////////////////////////////// void qpGeom:: draw(GraphicsStateGuardianBase *gsg, const qpGeomVertexData *vertex_data) const { - CDReader cdata(_cycler); +#ifdef DO_PIPELINING + // Make sure the usage_hint is already updated before we start to + // draw, so we don't end up with a circular lock if the GSG asks us + // to update this while we're holding the read lock. + { + CDReader cdata(_cycler); + if (!cdata->_got_usage_hint) { + CDWriter cdataw(((qpGeom *)this)->_cycler, cdata); + ((qpGeom *)this)->reset_usage_hint(cdataw); + } + } + // TODO: fix up the race condition between this line and the next. + // Maybe CDWriter's elevate-to-write should return the read lock to + // its original locked state when it's done. +#endif // DO_PIPELINING - if (gsg->begin_draw_primitives(vertex_data)) { + CDReader cdata(_cycler); + + if (gsg->begin_draw_primitives(this, vertex_data)) { Primitives::const_iterator pi; for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); @@ -355,6 +410,25 @@ draw(GraphicsStateGuardianBase *gsg, const qpGeomVertexData *vertex_data) const } } +//////////////////////////////////////////////////////////////////// +// Function: qpGeom::get_next_modified +// Access: Public +// Description: Returns a monotonically increasing sequence. Each +// time this is called, a new sequence number is +// returned, higher than the previous value. +// +// This is used to ensure that +// GeomVertexArrayData::get_modified() and +// GeomPrimitive::get_modified() update from the same +// space, so that Geom::get_modified() returns a +// meaningful value. +//////////////////////////////////////////////////////////////////// +UpdateSeq qpGeom:: +get_next_modified() { + ++_next_modified; + return _next_modified; +} + //////////////////////////////////////////////////////////////////// // Function: qpGeom::recompute_bound // Access: Protected, Virtual @@ -445,6 +519,23 @@ remove_cache_entry(const qpGeomMunger *modifier) const { ((qpGeom *)this)->_cycler.release_write_stage(0, cdata); } +//////////////////////////////////////////////////////////////////// +// Function: qpGeom::reset_usage_hint +// Access: Private +// Description: Recomputes the minimum usage_hint. +//////////////////////////////////////////////////////////////////// +void qpGeom:: +reset_usage_hint(qpGeom::CDWriter &cdata) { + cdata->_usage_hint = qpGeomUsageHint::UH_static; + Primitives::const_iterator pi; + for (pi = cdata->_primitives.begin(); + pi != cdata->_primitives.end(); + ++pi) { + cdata->_usage_hint = min(cdata->_usage_hint, (*pi)->get_usage_hint()); + } + cdata->_got_usage_hint = true; +} + //////////////////////////////////////////////////////////////////// // Function: qpGeom::register_with_read_factory // Access: Public, Static diff --git a/panda/src/gobj/qpgeom.h b/panda/src/gobj/qpgeom.h index f2baeff15d..9120d16b3f 100644 --- a/panda/src/gobj/qpgeom.h +++ b/panda/src/gobj/qpgeom.h @@ -29,6 +29,8 @@ #include "qpgeomVertexData.h" #include "qpgeomPrimitive.h" #include "qpgeomMunger.h" +#include "qpgeomUsageHint.h" +#include "updateSeq.h" #include "pointerTo.h" #include "geom.h" @@ -61,6 +63,8 @@ PUBLISHED: // Temporary. virtual Geom *make_copy() const; + INLINE qpGeomUsageHint::UsageHint get_usage_hint() const; + INLINE CPT(qpGeomVertexData) get_vertex_data() const; PT(qpGeomVertexData) modify_vertex_data(); void set_vertex_data(const qpGeomVertexData *data); @@ -74,6 +78,7 @@ PUBLISHED: void clear_primitives(); int get_num_bytes() const; + UpdateSeq get_modified() const; void munge_geom(const qpGeomMunger *munger, CPT(qpGeom) &result, CPT(qpGeomVertexData) &data) const; @@ -87,6 +92,8 @@ public: void draw(GraphicsStateGuardianBase *gsg, const qpGeomVertexData *vertex_data) const; + static UpdateSeq get_next_modified(); + protected: virtual BoundingVolume *recompute_bound(); @@ -120,6 +127,8 @@ private: PT(qpGeomVertexData) _data; Primitives _primitives; + qpGeomUsageHint::UsageHint _usage_hint; + bool _got_usage_hint; MungedCache _munged_cache; }; @@ -127,6 +136,10 @@ private: typedef CycleDataReader CDReader; typedef CycleDataWriter CDWriter; + void reset_usage_hint(CDWriter &cdata); + + static UpdateSeq _next_modified; + public: static void register_with_read_factory(); virtual void write_datagram(BamWriter *manager, Datagram &dg); diff --git a/panda/src/gobj/qpgeomPrimitive.cxx b/panda/src/gobj/qpgeomPrimitive.cxx index 68ba6845ee..3dd19b48af 100644 --- a/panda/src/gobj/qpgeomPrimitive.cxx +++ b/panda/src/gobj/qpgeomPrimitive.cxx @@ -17,6 +17,7 @@ //////////////////////////////////////////////////////////////////// #include "qpgeomPrimitive.h" +#include "qpgeom.h" #include "qpgeomVertexData.h" #include "qpgeomVertexArrayFormat.h" #include "qpgeomVertexDataType.h" @@ -536,7 +537,7 @@ clear_cache() { // This, on the other hand, should be applied to the current // pipeline stage. - ++(cdata->_modified); + cdata->_modified = qpGeom::get_next_modified(); } diff --git a/panda/src/gobj/qpgeomUsageHint.h b/panda/src/gobj/qpgeomUsageHint.h index 24a470f110..ff64cf0a1e 100644 --- a/panda/src/gobj/qpgeomUsageHint.h +++ b/panda/src/gobj/qpgeomUsageHint.h @@ -50,26 +50,30 @@ class EXPCL_PANDA qpGeomUsageHint { PUBLISHED: enum UsageHint { + // The following are intentionally ordered from most dynamic to + // most static. In general, if usage_a < usage_b, then usage_a is + // more dynamic than usage_b. + // UH_client: don't attempt to upload the data; 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. This should be used for short-lived - // temporary arrays. + // temporary objects. UH_stream, + // UH_dynamic: the data will be repeatedly modified and + // re-rendered. This is for data that will be modified at + // runtime, such as animated or soft-skinned vertices. + UH_dynamic, + // UH_static: the data will be created once, and used to render // many times, without modification. This is the most common // case, since typically vertex data is not directly animated // (this is not related to scene graph animation, e.g. from // adjusting transforms on a node). UH_static, - - // UH_dynamic: the data will be repeatedly modified and - // re-rendered. This is for data that will be modified at - // runtime, such as animated or soft-skinned vertices. - UH_dynamic, }; }; diff --git a/panda/src/gobj/qpgeomVertexArrayData.I b/panda/src/gobj/qpgeomVertexArrayData.I index d7d60c05c6..b73db4db84 100644 --- a/panda/src/gobj/qpgeomVertexArrayData.I +++ b/panda/src/gobj/qpgeomVertexArrayData.I @@ -52,43 +52,6 @@ get_data() const { 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 diff --git a/panda/src/gobj/qpgeomVertexArrayData.cxx b/panda/src/gobj/qpgeomVertexArrayData.cxx index 09639e338a..aa7262bb18 100644 --- a/panda/src/gobj/qpgeomVertexArrayData.cxx +++ b/panda/src/gobj/qpgeomVertexArrayData.cxx @@ -17,6 +17,7 @@ //////////////////////////////////////////////////////////////////// #include "qpgeomVertexArrayData.h" +#include "qpgeom.h" #include "preparedGraphicsObjects.h" #include "bamReader.h" #include "bamWriter.h" @@ -82,6 +83,43 @@ qpGeomVertexArrayData:: } +//////////////////////////////////////////////////////////////////// +// 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. +//////////////////////////////////////////////////////////////////// +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 = qpGeom::get_next_modified(); + + return cdata->_data; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomVertexArrayData::set_data +// Access: Published +// Description: Replaces the vertex data array with a completely new +// array. +//////////////////////////////////////////////////////////////////// +void qpGeomVertexArrayData:: +set_data(CPTA_uchar array) { + CDWriter cdata(_cycler); + cdata->_data = (PTA_uchar &)array; + cdata->_modified = qpGeom::get_next_modified(); +} + //////////////////////////////////////////////////////////////////// // Function: qpGeomVertexArrayData::set_num_vertices // Access: Published @@ -125,7 +163,7 @@ set_num_vertices(int n) { } } - ++(cdata->_modified); + cdata->_modified = qpGeom::get_next_modified(); return true; } diff --git a/panda/src/gobj/qpgeomVertexArrayData.h b/panda/src/gobj/qpgeomVertexArrayData.h index 11ef7d2c11..779ec7851e 100644 --- a/panda/src/gobj/qpgeomVertexArrayData.h +++ b/panda/src/gobj/qpgeomVertexArrayData.h @@ -66,8 +66,8 @@ PUBLISHED: INLINE qpGeomUsageHint::UsageHint get_usage_hint() const; INLINE CPTA_uchar get_data() const; - INLINE PTA_uchar modify_data(); - INLINE void set_data(CPTA_uchar data); + PTA_uchar modify_data(); + void set_data(CPTA_uchar data); INLINE int get_num_vertices() const; bool set_num_vertices(int n); diff --git a/panda/src/gsgbase/graphicsStateGuardianBase.h b/panda/src/gsgbase/graphicsStateGuardianBase.h index 729f532f40..d3219c2730 100644 --- a/panda/src/gsgbase/graphicsStateGuardianBase.h +++ b/panda/src/gsgbase/graphicsStateGuardianBase.h @@ -45,6 +45,7 @@ class GeomTri; class GeomTristrip; class GeomTrifan; class GeomSphere; +class qpGeom; class qpGeomVertexData; class qpGeomVertexArrayData; class qpGeomPrimitive; @@ -183,7 +184,7 @@ public: virtual void draw_trifan(GeomTrifan *geom, GeomContext *gc)=0; virtual void draw_sphere(GeomSphere *geom, GeomContext *gc)=0; - virtual bool begin_draw_primitives(const qpGeomVertexData *vertex_data)=0; + virtual bool begin_draw_primitives(const qpGeom *geom, const qpGeomVertexData *vertex_data)=0; virtual void draw_triangles(const qpGeomTriangles *primitive)=0; virtual void draw_tristrips(const qpGeomTristrips *primitive)=0; virtual void draw_trifans(const qpGeomTrifans *primitive)=0;