diff --git a/panda/src/dxgsg8/dxIndexBufferContext8.cxx b/panda/src/dxgsg8/dxIndexBufferContext8.cxx index c10ca78579..288f6d312c 100644 --- a/panda/src/dxgsg8/dxIndexBufferContext8.cxx +++ b/panda/src/dxgsg8/dxIndexBufferContext8.cxx @@ -90,8 +90,8 @@ upload_data() { int data_size = get_data()->get_data_size_bytes(); - if (dxgsg8_cat.is_debug()) { - dxgsg8_cat.debug() + if (dxgsg8_cat.is_spam()) { + dxgsg8_cat.spam() << "copying " << data_size << " bytes into index buffer " << _ibuffer << "\n"; } diff --git a/panda/src/dxgsg8/dxVertexBufferContext8.cxx b/panda/src/dxgsg8/dxVertexBufferContext8.cxx index 3a95634439..bcef4b471d 100644 --- a/panda/src/dxgsg8/dxVertexBufferContext8.cxx +++ b/panda/src/dxgsg8/dxVertexBufferContext8.cxx @@ -185,8 +185,8 @@ upload_data() { int data_size = get_data()->get_data_size_bytes(); - if (dxgsg8_cat.is_debug()) { - dxgsg8_cat.debug() + if (dxgsg8_cat.is_spam()) { + dxgsg8_cat.spam() << "copying " << data_size << " bytes into vertex buffer " << _vbuffer << "\n"; } diff --git a/panda/src/glstuff/glGeomMunger_src.cxx b/panda/src/glstuff/glGeomMunger_src.cxx index f3c53582bb..f8292948ba 100644 --- a/panda/src/glstuff/glGeomMunger_src.cxx +++ b/panda/src/glstuff/glGeomMunger_src.cxx @@ -65,6 +65,39 @@ munge_format_impl(const qpGeomVertexFormat *orig, qpGeomVertexColumn::C_color, color_type->get_start()); } + if (animation.get_animation_type() == qpGeomVertexAnimationSpec::AT_hardware && + animation.get_num_transforms() > 0) { + // If we want hardware animation, we need to reserve space for the + // blend weights. + + PT(qpGeomVertexArrayFormat) new_array_format = new qpGeomVertexArrayFormat; + new_array_format->add_column + (InternalName::get_transform_weight(), animation.get_num_transforms() - 1, + qpGeomVertexColumn::NT_float32, qpGeomVertexColumn::C_other); + + if (animation.get_indexed_transforms()) { + // Also, if we'll be indexing into the transform palette, reserve + // space for the index. + + // TODO: We should examine the maximum palette index so we can + // decide whether we need 16-bit indices. That implies saving + // the maximum palette index, presumably in the AnimationSpec. + new_array_format->add_column + (InternalName::get_transform_index(), animation.get_num_transforms(), + qpGeomVertexColumn::NT_uint8, qpGeomVertexColumn::C_index); + } + + // Make sure the old weights and indices are removed, just in + // case. + new_format->remove_column(InternalName::get_transform_weight()); + new_format->remove_column(InternalName::get_transform_index()); + + // And we don't need the transform_blend table any more. + new_format->remove_column(InternalName::get_transform_blend()); + + new_format->add_array(new_array_format); + } + /* if (true) { // Split out the interleaved array into n parallel arrays. diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index 013b384778..f712f61caa 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -364,12 +364,78 @@ reset() { get_extra_extensions(); report_extensions(); + _supports_vertex_blend = has_extension("GL_ARB_vertex_blend"); + + if (_supports_vertex_blend) { + _glWeightPointerARB = (PFNGLWEIGHTPOINTERARBPROC) + get_extension_func(GLPREFIX_QUOTED, "WeightPointerARB"); + _glVertexBlendARB = (PFNGLVERTEXBLENDARBPROC) + get_extension_func(GLPREFIX_QUOTED, "VertexBlendARB"); + + if (_glWeightPointerARB == NULL || _glVertexBlendARB == NULL) { + GLCAT.warning() + << "Vertex blending advertised as supported by OpenGL runtime, but could not get pointers to extension functions.\n"; + _supports_vertex_blend = false; + } + } + + if (_supports_vertex_blend) { + GLP(Enable)(GL_WEIGHT_SUM_UNITY_ARB); + + GLint max_vertex_units; + GLP(GetIntegerv)(GL_MAX_VERTEX_UNITS_ARB, &max_vertex_units); + _max_vertex_transforms = max_vertex_units; + GLCAT.debug() + << "max vertex transforms = " << _max_vertex_transforms << "\n"; + } + + _supports_matrix_palette = has_extension("GL_ARB_matrix_palette"); + + if (_supports_matrix_palette) { + _glCurrentPaletteMatrixARB = (PFNGLCURRENTPALETTEMATRIXARBPROC) + get_extension_func(GLPREFIX_QUOTED, "CurrentPaletteMatrixARB"); + _glMatrixIndexPointerARB = (PFNGLMATRIXINDEXPOINTERARBPROC) + get_extension_func(GLPREFIX_QUOTED, "MatrixIndexPointerARB"); + + if (_glCurrentPaletteMatrixARB == NULL || _glMatrixIndexPointerARB == NULL) { + GLCAT.warning() + << "Matrix palette advertised as supported by OpenGL runtime, but could not get pointers to extension functions.\n"; + _supports_matrix_palette = false; + } + } + + /* + The matrix_palette support in this module is completely untested + (because I don't happen to have a card handy whose driver supports + this extension), so I have this ConfigVariable set to + unconditionally set this flag off for now, to protect the unwary. + When we have shown that the code works, we should remove this bit. + In the meantime, you must put both "matrix-palette 1" and + "gl-matrix-palette 1" in your Config.prc to exercise the new + code. */ + if (!ConfigVariableBool("gl-matrix-palette", false, PRC_DESC("Temporary hack variable protecting untested code. See glGraphicsStateGuardian_src.cxx."))) { + if (_supports_matrix_palette) { + GLCAT.debug() << "Forcing off matrix palette support.\n"; + } + _supports_matrix_palette = false; + } + + if (_supports_matrix_palette) { + GLint max_palette_matrices; + GLP(GetIntegerv)(GL_MAX_PALETTE_MATRICES_ARB, &max_palette_matrices); + _max_vertex_transform_indices = max_palette_matrices; + GLCAT.debug() + << "max vertex transform indices = " << _max_vertex_transform_indices << "\n"; + } + + _supports_draw_range_elements = false; + if (is_at_least_version(1, 2)) { _supports_draw_range_elements = true; _glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC) get_extension_func(GLPREFIX_QUOTED, "DrawRangeElements"); - } else if (has_extension("EXT_draw_range_elements")) { + } else if (has_extension("GL_EXT_draw_range_elements")) { _supports_draw_range_elements = true; _glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC) get_extension_func(GLPREFIX_QUOTED, "DrawRangeElementsEXT"); @@ -721,6 +787,9 @@ reset() { _auto_antialias_mode = false; _render_mode = RenderModeAttrib::M_filled; + _transform_stale = false; + _vertex_blending_enabled = false; + report_my_gl_errors(); // Make sure the GL state matches all of our initial attribute @@ -2084,9 +2153,93 @@ begin_draw_primitives(const qpGeom *geom, const qpGeomMunger *munger, } } + const qpGeomVertexAnimationSpec &animation = + vertex_data->get_format()->get_animation(); + bool hardware_animation = (animation.get_animation_type() == qpGeomVertexAnimationSpec::AT_hardware); + if (hardware_animation) { + // Set up the transform matrices for vertex blending. + GLP(Enable)(GL_VERTEX_BLEND_ARB); + _glVertexBlendARB(animation.get_num_transforms() - 1); + + const TransformPalette *palette = vertex_data->get_transform_palette(); + if (palette != (TransformPalette *)NULL) { + if (animation.get_indexed_transforms()) { + // We are loading the indexed matrix palette. The ARB decided + // to change this interface from that for the list of + // nonindexed matrices, to make it easier to load an arbitrary + // number of matrices. + GLP(Enable)(GL_MATRIX_PALETTE_ARB); + + GLP(MatrixMode)(GL_MATRIX_PALETTE_ARB); + + for (int i = 0; i < palette->get_num_transforms(); ++i) { + LMatrix4f mat; + palette->get_transform(i)->mult_matrix(mat, _transform->get_mat()); + _glCurrentPaletteMatrixARB(i); + GLP(LoadMatrixf)(mat.get_data()); + } + + // Presumably loading the matrix palette does not step on the + // GL_MODELVIEW matrix? + + } else { + // We are loading the list of nonindexed matrices. This is a + // little clumsier. + + if (_supports_matrix_palette) { + GLP(Disable)(GL_MATRIX_PALETTE_ARB); + } + + // GL_MODELVIEW0 and 1 are different than the rest. + int i = 0; + if (i < palette->get_num_transforms()) { + LMatrix4f mat; + palette->get_transform(i)->mult_matrix(mat, _transform->get_mat()); + GLP(MatrixMode)(GL_MODELVIEW0_ARB); + GLP(LoadMatrixf)(mat.get_data()); + ++i; + } + if (i < palette->get_num_transforms()) { + LMatrix4f mat; + palette->get_transform(i)->mult_matrix(mat, _transform->get_mat()); + GLP(MatrixMode)(GL_MODELVIEW1_ARB); + GLP(LoadMatrixf)(mat.get_data()); + ++i; + } + while (i < palette->get_num_transforms()) { + LMatrix4f mat; + palette->get_transform(i)->mult_matrix(mat, _transform->get_mat()); + GLP(MatrixMode)(GL_MODELVIEW2_ARB + i - 2); + GLP(LoadMatrixf)(mat.get_data()); + ++i; + } + + // Setting the GL_MODELVIEW0 matrix steps on the world matrix, + // so we have to set a flag to reload the world matrix later. + _transform_stale = true; + } + } + _vertex_blending_enabled = true; + + } else { + // We're not using vertex blending. + if (_vertex_blending_enabled) { + GLP(Disable)(GL_VERTEX_BLEND_ARB); + if (_supports_matrix_palette) { + GLP(Disable)(GL_MATRIX_PALETTE_ARB); + } + _vertex_blending_enabled = false; + } + + if (_transform_stale) { + GLP(MatrixMode)(GL_MODELVIEW); + GLP(LoadMatrixf)(_transform->get_mat().get_data()); + } + } + if (geom->get_usage_hint() == qpGeomUsageHint::UH_static && _vertex_data->get_usage_hint() == qpGeomUsageHint::UH_static && - display_lists) { + display_lists && (!hardware_animation || display_list_animation)) { // If the geom claims to be totally static, try to build it into // a display list. GeomContext *gc = ((qpGeom *)geom)->prepare_now(get_prepared_objects(), this); @@ -2105,8 +2258,10 @@ begin_draw_primitives(const qpGeom *geom, const qpGeomMunger *munger, #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. + _geom_display_list = 0; + end_draw_primitives(); return false; } @@ -2218,6 +2373,42 @@ begin_draw_primitives(const qpGeom *geom, const qpGeomMunger *munger, } _last_max_stage_index = max_stage_index; + if (_supports_vertex_blend) { + if (hardware_animation) { + // Issue the weights and/or transform indices for vertex blending. + if (_vertex_data->get_array_info(InternalName::get_transform_weight(), + array_data, num_values, numeric_type, + start, stride)) { + const unsigned char *client_pointer = setup_array_data(array_data); + _glWeightPointerARB(num_values, get_numeric_type(numeric_type), + stride, client_pointer + start); + GLP(EnableClientState)(GL_WEIGHT_ARRAY_ARB); + } else { + GLP(DisableClientState)(GL_WEIGHT_ARRAY_ARB); + } + + if (animation.get_indexed_transforms()) { + // Issue the matrix palette indices. + if (_vertex_data->get_array_info(InternalName::get_transform_index(), + array_data, num_values, numeric_type, + start, stride)) { + const unsigned char *client_pointer = setup_array_data(array_data); + _glMatrixIndexPointerARB(num_values, get_numeric_type(numeric_type), + stride, client_pointer + start); + GLP(EnableClientState)(GL_MATRIX_INDEX_ARRAY_ARB); + } else { + GLP(DisableClientState)(GL_MATRIX_INDEX_ARRAY_ARB); + } + } + + } else { + GLP(DisableClientState)(GL_WEIGHT_ARRAY_ARB); + if (_supports_matrix_palette) { + GLP(DisableClientState)(GL_MATRIX_INDEX_ARRAY_ARB); + } + } + } + return true; } @@ -2336,6 +2527,20 @@ end_draw_primitives() { } _geom_display_list = 0; + // Clean up the vertex blending state. + if (_vertex_blending_enabled) { + GLP(Disable)(GL_VERTEX_BLEND_ARB); + if (_supports_matrix_palette) { + GLP(Disable)(GL_MATRIX_PALETTE_ARB); + } + _vertex_blending_enabled = false; + } + + if (_transform_stale) { + GLP(MatrixMode)(GL_MODELVIEW); + GLP(LoadMatrixf)(_transform->get_mat().get_data()); + } + GraphicsStateGuardian::end_draw_primitives(); } @@ -2585,8 +2790,8 @@ apply_vertex_buffer(VertexBufferContext *vbc) { add_to_vertex_buffer_record(gvbc); if (gvbc->was_modified()) { - if (GLCAT.is_debug()) { - GLCAT.debug() + if (GLCAT.is_spam()) { + GLCAT.spam() << "copying " << gvbc->get_data()->get_data_size_bytes() << " bytes into vertex buffer " << gvbc->_index << "\n"; } @@ -2716,8 +2921,8 @@ apply_index_buffer(IndexBufferContext *ibc) { add_to_index_buffer_record(gibc); if (gibc->was_modified()) { - if (GLCAT.is_debug()) { - GLCAT.debug() + if (GLCAT.is_spam()) { + GLCAT.spam() << "copying " << gibc->get_data()->get_data_size_bytes() << " bytes into index buffer " << gibc->_index << "\n"; } @@ -3081,6 +3286,7 @@ issue_transform(const TransformState *transform) { DO_PSTATS_STUFF(_transform_state_pcollector.add_level(1)); GLP(MatrixMode)(GL_MODELVIEW); GLP(LoadMatrixf)(transform->get_mat().get_data()); + _transform_stale = false; _transform = transform; if (_auto_rescale_normal) { diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.h b/panda/src/glstuff/glGraphicsStateGuardian_src.h index b60275aedb..462db6859d 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.h +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.h @@ -314,6 +314,9 @@ protected: bool _auto_antialias_mode; RenderModeAttrib::Mode _render_mode; + bool _transform_stale; + bool _vertex_blending_enabled; + CPT(DisplayRegion) _actual_display_region; #ifdef HAVE_CGGL PT(CgShader) _cg_shader; // The current CgShader object @@ -332,6 +335,14 @@ protected: pset _extensions; public: + bool _supports_vertex_blend; + PFNGLWEIGHTPOINTERARBPROC _glWeightPointerARB; + PFNGLVERTEXBLENDARBPROC _glVertexBlendARB; + + bool _supports_matrix_palette; + PFNGLCURRENTPALETTEMATRIXARBPROC _glCurrentPaletteMatrixARB; + PFNGLMATRIXINDEXPOINTERARBPROC _glMatrixIndexPointerARB; + bool _supports_draw_range_elements; PFNGLDRAWRANGEELEMENTSPROC _glDrawRangeElements; diff --git a/panda/src/gobj/config_gobj.cxx b/panda/src/gobj/config_gobj.cxx index f0d3dd9b80..7a918189da 100644 --- a/panda/src/gobj/config_gobj.cxx +++ b/panda/src/gobj/config_gobj.cxx @@ -99,16 +99,17 @@ ConfigVariableBool retained_mode "in the experimental Geom rewrite.")); ConfigVariableBool vertex_buffers -("vertex-buffers", false, +("vertex-buffers", true, 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 " + "can greatly improve rendering performance on " "higher-end graphics cards, at the cost of some additional " "graphics memory (which might otherwise be used for textures " - "or offscreen buffers).")); + "or offscreen buffers). On lower-end graphics cards this will " + "make little or no difference.")); ConfigVariableBool display_lists -("display-lists", false, +("display-lists", true, 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 " @@ -118,7 +119,7 @@ ConfigVariableBool display_lists "on dynamic geometry (e.g. soft-skinned animation).")); ConfigVariableBool hardware_animated_vertices -("hardware-animated-vertices", false, +("hardware-animated-vertices", true, PRC_DESC("Set this true to allow the transforming of soft-skinned " "animated vertices via hardware, if supported, or false always " "to perform the vertex animation via software within Panda. " @@ -132,16 +133,25 @@ ConfigVariableBool hardware_animated_vertices ConfigVariableBool matrix_palette ("matrix-palette", false, PRC_DESC("Set this true to allow the use of the matrix palette when " - "animating vertices in hardware (if hardware-animated-vertices " - "is also true). The matrix palette is not supported by all " - "devices, but if it is, using it can allow animation of more " - "sophisticated meshes in hardware, and it can also improve the " + "animating vertices in hardware. The matrix palette is " + "not supported by all devices, but if it is, using " + "it can allow animation of more sophisticated meshes " + "in hardware, and it can also improve the " "performance of animating some simpler meshes. Without " "this option, certain meshes will have to be animated in " "software. However, this option is not enabled by default, " "because its support seems to be buggy in certain drivers " "(ATI FireGL T2 8.103 in particular.)")); +ConfigVariableBool display_list_animation +("display-list-animation", false, + PRC_DESC("Set this true to allow the use of OpenGL display lists for " + "rendering animated geometry (when the geometry is animated " + "by the hardware). This is not on by default because there " + "appear to be some driver issues with this on my FireGL T2, " + "but it should be perfectly doable in principle, and might get " + "you a small performance boost.")); + ConfigVariableBool connect_triangle_strips ("connect-triangle-strips", true, PRC_DESC("Set this true to set a batch of triangle strips to the graphics " diff --git a/panda/src/gobj/config_gobj.h b/panda/src/gobj/config_gobj.h index 5ac62631d2..cdaa68de13 100644 --- a/panda/src/gobj/config_gobj.h +++ b/panda/src/gobj/config_gobj.h @@ -55,6 +55,7 @@ extern EXPCL_PANDA ConfigVariableBool vertex_buffers; extern EXPCL_PANDA ConfigVariableBool display_lists; extern EXPCL_PANDA ConfigVariableBool hardware_animated_vertices; extern EXPCL_PANDA ConfigVariableBool matrix_palette; +extern EXPCL_PANDA ConfigVariableBool display_list_animation; extern EXPCL_PANDA ConfigVariableBool connect_triangle_strips; extern EXPCL_PANDA ConfigVariableBool use_qpgeom;