diff --git a/panda/src/display/displayRegion.cxx b/panda/src/display/displayRegion.cxx index 24fb4aed2c..d3e53a8d39 100644 --- a/panda/src/display/displayRegion.cxx +++ b/panda/src/display/displayRegion.cxx @@ -551,7 +551,7 @@ get_screenshot(PNMImage &image) { PixelBuffer::F_rgb); RenderBuffer buffer = gsg->get_render_buffer(get_screenshot_buffer_type()); - if (!p.copy(gsg, this, buffer)) { + if (!gsg->copy_pixel_buffer(&p, this, buffer)) { return false; } diff --git a/panda/src/display/graphicsBuffer.h b/panda/src/display/graphicsBuffer.h index cf84232ae6..d876873dbf 100644 --- a/panda/src/display/graphicsBuffer.h +++ b/panda/src/display/graphicsBuffer.h @@ -1,5 +1,5 @@ // Filename: graphicsBuffer.h -// Created by: mike (09Jan97) +// Created by: drose (06Feb04) // //////////////////////////////////////////////////////////////////// // diff --git a/panda/src/display/graphicsOutput.cxx b/panda/src/display/graphicsOutput.cxx index 7342b1c1d7..5d95c216ee 100644 --- a/panda/src/display/graphicsOutput.cxx +++ b/panda/src/display/graphicsOutput.cxx @@ -437,7 +437,8 @@ end_frame() { nassertv(has_texture()); DisplayRegion dr(this, _x_size, _y_size); RenderBuffer buffer = _gsg->get_render_buffer(get_draw_buffer_type()); - get_texture()->copy(_gsg, &dr, buffer); + TextureContext *tc = get_texture()->prepare_now(_gsg->get_prepared_objects(), _gsg); + _gsg->copy_texture(tc, &dr, buffer); } } diff --git a/panda/src/display/graphicsStateGuardian.I b/panda/src/display/graphicsStateGuardian.I index 7814d86710..542bae0428 100644 --- a/panda/src/display/graphicsStateGuardian.I +++ b/panda/src/display/graphicsStateGuardian.I @@ -40,6 +40,17 @@ ClipPlaneInfo() { } +//////////////////////////////////////////////////////////////////// +// Function: GraphicsStateGuardian::release_all_textures +// Access: Public +// Description: Frees the resources for all textures associated with +// this GSG. +//////////////////////////////////////////////////////////////////// +INLINE int GraphicsStateGuardian:: +release_all_textures() { + return _prepared_objects->release_all_textures(); +} + //////////////////////////////////////////////////////////////////// // Function: GraphicsStateGuardian::set_active // Access: Published diff --git a/panda/src/display/graphicsStateGuardian.cxx b/panda/src/display/graphicsStateGuardian.cxx index 0641b874cc..5d90f3f079 100644 --- a/panda/src/display/graphicsStateGuardian.cxx +++ b/panda/src/display/graphicsStateGuardian.cxx @@ -79,6 +79,7 @@ GraphicsStateGuardian(const FrameBufferProperties &properties) { _needs_reset = true; _closing_gsg = false; _active = true; + _prepared_objects = new PreparedGraphicsObjects; } //////////////////////////////////////////////////////////////////// @@ -146,58 +147,15 @@ get_render_buffer(int buffer_type) { } //////////////////////////////////////////////////////////////////// -// Function: GraphicsStateGuardian::release_all_textures -// Access: Public -// Description: Frees the resources for all textures associated with -// this GSG. +// Function: GraphicsStateGuardian::get_prepared_objects +// Access: Public, Virtual +// Description: Returns the set of texture and geom objects that have +// been prepared with this GSG (and possibly other GSG's +// that share objects). //////////////////////////////////////////////////////////////////// -void GraphicsStateGuardian:: -release_all_textures() { - // We must get a copy of the _prepared_textures list first, because - // each call to release_texture() will remove that texture from the - // list, and we don't want to traverse a list while we're modifying - // it! - - Textures temp = _prepared_textures; - for (Textures::const_iterator ti = temp.begin(); - ti != temp.end(); - ++ti) { - release_texture(*ti); - } - - // Now that we've released all of the textures, the - // _prepared_textures list should have completely emptied itself. - nassertv(_prepared_textures.empty()); -} - -//////////////////////////////////////////////////////////////////// -// Function: GraphicsStateGuardian::release_all_geoms -// Access: Public -// Description: Frees the resources for all Geoms and GeomNodes -// associated with this GSG. Warning! This may make -// the Geoms unrenderable, if the Panda-level -// information has been deleted. -//////////////////////////////////////////////////////////////////// -void GraphicsStateGuardian:: -release_all_geoms() { - // As above, for both Geoms and GeomNodes. - - Geoms temp_geoms = _prepared_geoms; - for (Geoms::const_iterator gi = temp_geoms.begin(); - gi != temp_geoms.end(); - ++gi) { - release_geom(*gi); - } - - GeomNodes temp_geom_nodes = _prepared_geom_nodes; - for (GeomNodes::const_iterator gni = temp_geom_nodes.begin(); - gni != temp_geom_nodes.end(); - ++gni) { - release_geom_node(*gni); - } - - nassertv(_prepared_geoms.empty()); - nassertv(_prepared_geom_nodes.empty()); +PreparedGraphicsObjects *GraphicsStateGuardian:: +get_prepared_objects() { + return _prepared_objects; } //////////////////////////////////////////////////////////////////// @@ -397,6 +355,12 @@ prepare_lens() { //////////////////////////////////////////////////////////////////// bool GraphicsStateGuardian:: begin_frame() { + // Now we know the GSG is the currently active context, so this is a + // good time to release any textures or geoms that had been queued + // up to release in the past frame, and load up any newly requested + // textures. + _prepared_objects->update(this); + // Undo any lighting we had enabled last frame, to force the lights // to be reissued, in case their parameters or positions have // changed between frames. @@ -1229,126 +1193,6 @@ set_blend_mode(ColorWriteAttrib::Mode, ColorBlendAttrib::Mode, TransparencyAttrib::Mode) { } -//////////////////////////////////////////////////////////////////// -// Function: GraphicsStateGuardian::mark_prepared_texture -// Access: Protected -// Description: This is intended to be called from within -// prepare_texture(). It adds the indicated -// TextureContext pointer to the _prepared_textures set, -// and returns true if it was successfully added -// (i.e. it was not already in the set). -//////////////////////////////////////////////////////////////////// -bool GraphicsStateGuardian:: -mark_prepared_texture(TextureContext *tc) { - bool prepared = _prepared_textures.insert(tc).second; -#ifdef DO_PSTATS - if (prepared) { - _total_texusage_pcollector.add_level(tc->estimate_texture_memory()); - } -#endif - return prepared; -} - -//////////////////////////////////////////////////////////////////// -// Function: GraphicsStateGuardian::unmark_prepared_texture -// Access: Protected -// Description: This is intended to be called from within -// release_texture(). It removes the indicated -// TextureContext pointer from the _prepared_textures -// set, and returns true if it was successfully removed -// (i.e. it had been in the set). -//////////////////////////////////////////////////////////////////// -bool GraphicsStateGuardian:: -unmark_prepared_texture(TextureContext *tc) { - bool removed = (_prepared_textures.erase(tc) != 0); -#ifdef DO_PSTATS - if (removed) { - _total_texusage_pcollector.sub_level(tc->estimate_texture_memory()); - } -#endif - return removed; -} - -//////////////////////////////////////////////////////////////////// -// Function: GraphicsStateGuardian::mark_prepared_geom -// Access: Protected -// Description: This is intended to be called from within -// prepare_geom(). It adds the indicated GeomContext -// pointer to the _prepared_geoms set, and returns true -// if it was successfully added (i.e. it was not already -// in the set). -//////////////////////////////////////////////////////////////////// -bool GraphicsStateGuardian:: -mark_prepared_geom(GeomContext *gc) { - bool prepared = _prepared_geoms.insert(gc).second; -#ifdef DO_PSTATS - if (prepared) { - _total_geom_pcollector.add_level(1); - } -#endif - return prepared; -} - -//////////////////////////////////////////////////////////////////// -// Function: GraphicsStateGuardian::unmark_prepared_geom -// Access: Protected -// Description: This is intended to be called from within -// release_geom(). It removes the indicated GeomContext -// pointer from the _prepared_geoms set, and returns -// true if it was successfully removed (i.e. it had been -// in the set). -//////////////////////////////////////////////////////////////////// -bool GraphicsStateGuardian:: -unmark_prepared_geom(GeomContext *gc) { - bool removed = (_prepared_geoms.erase(gc) != 0); -#ifdef DO_PSTATS - if (removed) { - _total_geom_pcollector.sub_level(1); - } -#endif - return removed; -} - -//////////////////////////////////////////////////////////////////// -// Function: GraphicsStateGuardian::mark_prepared_geom_node -// Access: Protected -// Description: This is intended to be called from within -// prepare_geom_node(). It adds the indicated -// GeomNodeContext pointer to the _prepared_geom_nodes -// set, and returns true if it was successfully added -// (i.e. it was not already in the set). -//////////////////////////////////////////////////////////////////// -bool GraphicsStateGuardian:: -mark_prepared_geom_node(GeomNodeContext *gnc) { - bool prepared = _prepared_geom_nodes.insert(gnc).second; -#ifdef DO_PSTATS - if (prepared) { - _total_geom_node_pcollector.add_level(1); - } -#endif - return prepared; -} - -//////////////////////////////////////////////////////////////////// -// Function: GraphicsStateGuardian::unmark_prepared_geom_node -// Access: Protected -// Description: This is intended to be called from within -// release_geom_node(). It removes the indicated -// GeomNodeContext pointer from the _prepared_geom_nodes -// set, and returns true if it was successfully removed -// (i.e. it had been in the set). -//////////////////////////////////////////////////////////////////// -bool GraphicsStateGuardian:: -unmark_prepared_geom_node(GeomNodeContext *gnc) { - bool removed = (_prepared_geom_nodes.erase(gnc) != 0); -#ifdef DO_PSTATS - if (removed) { - _total_geom_node_pcollector.sub_level(1); - } -#endif - return removed; -} - //////////////////////////////////////////////////////////////////// // Function: GraphicsStateGuardian::free_pointers // Access: Protected, Virtual @@ -1371,8 +1215,18 @@ void GraphicsStateGuardian:: close_gsg() { _closing_gsg = true; free_pointers(); - release_all_textures(); - release_all_geoms(); + + // If we're not sharing the prepared objects list with any other + // GSG, go ahread and release all the textures and geoms now. This + // isn't really a reliable test of whether we are sharing this list, + // but it's not too important if we get this wrong since this ought + // to be an optional cleanup anyway. (Presumably, the underlying + // graphics API will properly clean up outstanding textures and + // geoms when the last context using them is released.) + if (_prepared_objects->get_ref_count() == 1) { + release_all_textures(); + //release_all_geoms(); + } } //////////////////////////////////////////////////////////////////// @@ -1522,7 +1376,9 @@ get_untextured_state() { void GraphicsStateGuardian:: traverse_prepared_textures(bool (*pertex_callbackfn)(TextureContext *,void *),void *callback_arg) { - for (Textures::const_iterator ti = _prepared_textures.begin(); ti != _prepared_textures.end(); + PreparedGraphicsObjects::Textures::const_iterator ti; + for (ti = _prepared_objects->_prepared_textures.begin(); + ti != _prepared_objects->_prepared_textures.end(); ++ti) { bool bResult=(*pertex_callbackfn)(*ti,callback_arg); if(!bResult) diff --git a/panda/src/display/graphicsStateGuardian.h b/panda/src/display/graphicsStateGuardian.h index 873ca2eb76..99a3e2e8b1 100644 --- a/panda/src/display/graphicsStateGuardian.h +++ b/panda/src/display/graphicsStateGuardian.h @@ -26,6 +26,7 @@ #include "frameBufferProperties.h" #include "displayRegionStack.h" #include "lensStack.h" +#include "preparedGraphicsObjects.h" #include "graphicsStateGuardianBase.h" #include "graphicsThreadingModel.h" @@ -69,8 +70,8 @@ public: virtual ~GraphicsStateGuardian(); PUBLISHED: - void release_all_textures(); - void release_all_geoms(); + INLINE int release_all_textures(); + // int release_all_geoms(); INLINE void set_active(bool active); INLINE bool is_active() const; @@ -84,6 +85,8 @@ public: INLINE void set_scene(SceneSetup *scene_setup); INLINE SceneSetup *get_scene() const; + virtual PreparedGraphicsObjects *get_prepared_objects(); + virtual TextureContext *prepare_texture(Texture *tex); virtual void apply_texture(TextureContext *tc); virtual void release_texture(TextureContext *tc); @@ -193,13 +196,6 @@ protected: CPT(DisplayRegion) dr)=0; virtual void restore_frame_buffer(SavedFrameBuffer *frame_buffer)=0; - bool mark_prepared_texture(TextureContext *tc); - bool unmark_prepared_texture(TextureContext *tc); - bool mark_prepared_geom(GeomContext *gc); - bool unmark_prepared_geom(GeomContext *gc); - bool mark_prepared_geom_node(GeomNodeContext *gnc); - bool unmark_prepared_geom_node(GeomNodeContext *gnc); - virtual void free_pointers(); virtual void close_gsg(); void panic_deactivate(); @@ -276,6 +272,8 @@ protected: bool _closing_gsg; bool _active; + PT(PreparedGraphicsObjects) _prepared_objects; + public: // Statistics static PStatCollector _total_texusage_pcollector; @@ -321,15 +319,6 @@ private: pvector _clip_plane_info; bool _clip_planes_enabled_this_frame; - // NOTE: on win32 another DLL (e.g. libpandadx.dll) cannot access - // these sets directly due to exported template issue - typedef pset Textures; - Textures _prepared_textures; - typedef pset Geoms; - Geoms _prepared_geoms; - typedef pset GeomNodes; - GeomNodes _prepared_geom_nodes; - FrameBufferProperties _properties; PT(GraphicsPipe) _pipe; GraphicsEngine *_engine; diff --git a/panda/src/distort/nonlinearImager.cxx b/panda/src/distort/nonlinearImager.cxx index c29f34e1ab..1b0af4c59e 100644 --- a/panda/src/distort/nonlinearImager.cxx +++ b/panda/src/distort/nonlinearImager.cxx @@ -608,8 +608,9 @@ render_screen(GraphicsEngine *engine, NonlinearImager::Screen &screen) { // Copy the results of the render from the frame buffer into the // screen's texture. - screen._texture->copy(_gsg, scratch_region, - _gsg->get_render_buffer(RenderBuffer::T_back)); + TextureContext *tc = screen._texture->prepare_now(_gsg->get_prepared_objects(), _gsg); + _gsg->copy_texture(tc, scratch_region, + _gsg->get_render_buffer(RenderBuffer::T_back)); // It might be nice if we didn't throw away the scratch region every // time, which prevents us from preserving cull state from one frame diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index 923cf04beb..f8892198aa 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -1643,6 +1643,9 @@ draw_sphere(GeomSphere *geom, GeomContext *) { // responsibility of the calling function to later // call release_texture() with this same pointer (which // will also delete the pointer). +// +// This function should not be called directly to +// prepare a texture. Instead, call Texture::prepare(). //////////////////////////////////////////////////////////////////// TextureContext *CLP(GraphicsStateGuardian):: prepare_texture(Texture *tex) { @@ -1654,13 +1657,6 @@ prepare_texture(Texture *tex) { specify_texture(tex); apply_texture_immediate(tex); - bool inserted = mark_prepared_texture(gtc); - - // If this assertion fails, the same texture was prepared twice, - // which shouldn't be possible, since the texture itself should - // detect this. - nassertr(inserted, gtc); - report_my_gl_errors(); return gtc; } @@ -1695,32 +1691,19 @@ apply_texture(TextureContext *tc) { // Function: CLP(GraphicsStateGuardian)::release_texture // Access: Public, Virtual // Description: Frees the GL resources previously allocated for the -// texture. +// texture. This function should never be called +// directly; instead, call Texture::release() (or simply +// let the Texture destruct). //////////////////////////////////////////////////////////////////// void CLP(GraphicsStateGuardian):: release_texture(TextureContext *tc) { CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc); - Texture *tex = tc->_texture; - if (!_closing_gsg) { - // Don't bother to delete the GL texture if we're about to destroy - // the context anyway. - GLP(DeleteTextures)(1, >c->_index); - } + GLP(DeleteTextures)(1, >c->_index); + report_my_gl_errors(); + gtc->_index = 0; - - bool erased = unmark_prepared_texture(gtc); - - // If this assertion fails, a texture was released that hadn't been - // prepared (or a texture was released twice). - nassertv(erased); - - tex->clear_gsg(this); - delete gtc; - if (!_closing_gsg) { - report_my_gl_errors(); - } } //////////////////////////////////////////////////////////////////// @@ -1811,7 +1794,7 @@ prepare_geom_node(GeomNode *node) { _texturing_enabled = old_texturing_enabled; _vertex_colors_enabled = old_vertex_colors_enabled; - bool inserted = mark_prepared_geom_node(ggnc); + bool inserted = _prepared_objects->mark_prepared_geom_node(ggnc); // If this assertion fails, the same GeomNode was prepared twice, // which shouldn't be possible, since the GeomNode itself should @@ -1875,7 +1858,7 @@ release_geom_node(GeomNodeContext *gnc) { CLP(GeomNodeContext) *ggnc = DCAST(CLP(GeomNodeContext), gnc); GLP(DeleteLists)(ggnc->_index, 1); - bool erased = unmark_prepared_geom_node(ggnc); + bool erased = _prepared_objects->unmark_prepared_geom_node(ggnc); // If this assertion fails, a GeomNode was released that hadn't // been prepared (or a GeomNode was released twice). @@ -2220,7 +2203,9 @@ issue_texture(const TextureAttrib *attrib) { enable_texturing(true); Texture *tex = attrib->get_texture(); nassertv(tex != (Texture *)NULL); - tex->apply(this); + + TextureContext *tc = tex->prepare_now(_prepared_objects, this); + apply_texture(tc); } report_my_gl_errors(); } @@ -3916,7 +3901,8 @@ save_frame_buffer(const RenderBuffer &buffer, if (buffer._buffer_type & RenderBuffer::T_back) { // Save the color buffer. sfb->_back_rgba = new Texture; - copy_texture(sfb->_back_rgba->prepare(this), dr, buffer); + TextureContext *tc = sfb->_back_rgba->prepare_now(_prepared_objects, this); + copy_texture(tc, dr, buffer); } return sfb; @@ -3934,8 +3920,8 @@ restore_frame_buffer(SavedFrameBuffer *frame_buffer) { if (sfb->_back_rgba != (Texture *)NULL && (sfb->_buffer._buffer_type & RenderBuffer::T_back) != 0) { // Restore the color buffer. - draw_texture(sfb->_back_rgba->prepare(this), - sfb->_display_region, sfb->_buffer); + TextureContext *tc = sfb->_back_rgba->prepare_now(_prepared_objects, this); + draw_texture(tc, sfb->_display_region, sfb->_buffer); } if (sfb->_depth != (PixelBuffer *)NULL && diff --git a/panda/src/glxdisplay/glxGraphicsPipe.cxx b/panda/src/glxdisplay/glxGraphicsPipe.cxx index f7d09e4b0f..b644dd473d 100644 --- a/panda/src/glxdisplay/glxGraphicsPipe.cxx +++ b/panda/src/glxdisplay/glxGraphicsPipe.cxx @@ -183,7 +183,7 @@ make_gsg(const FrameBufferProperties &properties) { // Now we can make a GSG. PT(glxGraphicsStateGuardian) gsg = - new glxGraphicsStateGuardian(new_properties, context, fbconfig, + new glxGraphicsStateGuardian(new_properties, NULL, context, fbconfig, _display, _screen); return gsg.p(); } diff --git a/panda/src/glxdisplay/glxGraphicsStateGuardian.cxx b/panda/src/glxdisplay/glxGraphicsStateGuardian.cxx index 7c6a8e92f8..d9b8910acb 100644 --- a/panda/src/glxdisplay/glxGraphicsStateGuardian.cxx +++ b/panda/src/glxdisplay/glxGraphicsStateGuardian.cxx @@ -28,6 +28,7 @@ TypeHandle glxGraphicsStateGuardian::_type_handle; //////////////////////////////////////////////////////////////////// glxGraphicsStateGuardian:: glxGraphicsStateGuardian(const FrameBufferProperties &properties, + glxGraphicsStateGuardian *share_with, GLXContext context, GLXFBConfig fbconfig, Display *display, int screen) : GLGraphicsStateGuardian(properties), @@ -36,6 +37,9 @@ glxGraphicsStateGuardian(const FrameBufferProperties &properties, _display(display), _screen(screen) { + if (share_with != (glxGraphicsStateGuardian *)NULL) { + _prepared_objects = share_with->get_prepared_objects(); + } } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/glxdisplay/glxGraphicsStateGuardian.h b/panda/src/glxdisplay/glxGraphicsStateGuardian.h index 4733c4b416..40b4581337 100644 --- a/panda/src/glxdisplay/glxGraphicsStateGuardian.h +++ b/panda/src/glxdisplay/glxGraphicsStateGuardian.h @@ -32,6 +32,7 @@ class glxGraphicsStateGuardian : public GLGraphicsStateGuardian { public: glxGraphicsStateGuardian(const FrameBufferProperties &properties, + glxGraphicsStateGuardian *share_with, GLXContext context, GLXFBConfig fbconfig, Display *display, int screen); virtual ~glxGraphicsStateGuardian(); diff --git a/panda/src/gobj/Sources.pp b/panda/src/gobj/Sources.pp index 241323aece..4269c3564f 100644 --- a/panda/src/gobj/Sources.pp +++ b/panda/src/gobj/Sources.pp @@ -4,7 +4,7 @@ #begin lib_target #define TARGET gobj #define LOCAL_LIBS \ - event linmath mathutil pnmimage gsgbase putil + pstatclient event linmath mathutil pnmimage gsgbase putil #define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx @@ -19,7 +19,9 @@ matrixLens.I matrixLens.h \ orthographicLens.I orthographicLens.h perspectiveLens.I \ perspectiveLens.h pixelBuffer.I pixelBuffer.N \ - pixelBuffer.h lens.h lens.I \ + pixelBuffer.h \ + preparedGraphicsObjects.I preparedGraphicsObjects.h \ + lens.h lens.I \ savedContext.I savedContext.h \ texture.I texture.N texture.h \ textureContext.I textureContext.h \ @@ -33,7 +35,9 @@ geomQuad.cxx geomSphere.cxx geomSprite.cxx geomTri.cxx \ geomTrifan.cxx geomTristrip.cxx imageBuffer.cxx material.cxx \ materialPool.cxx matrixLens.cxx orthographicLens.cxx \ - perspectiveLens.cxx pixelBuffer.cxx lens.cxx \ + perspectiveLens.cxx pixelBuffer.cxx \ + preparedGraphicsObjects.cxx \ + lens.cxx \ savedContext.cxx texture.cxx textureContext.cxx texturePool.cxx #define INSTALL_HEADERS \ @@ -47,6 +51,7 @@ materialPool.I materialPool.h matrixLens.I matrixLens.h \ orthographicLens.I orthographicLens.h perspectiveLens.I \ perspectiveLens.h pixelBuffer.I pixelBuffer.h \ + preparedGraphicsObjects.I preparedGraphicsObjects.h \ lens.h lens.I \ savedContext.I savedContext.h \ texture.I texture.h \ diff --git a/panda/src/gobj/geom.cxx b/panda/src/gobj/geom.cxx index 58da88a50b..edb86a8396 100644 --- a/panda/src/gobj/geom.cxx +++ b/panda/src/gobj/geom.cxx @@ -138,8 +138,10 @@ ostream &operator << (ostream &out, GeomAttrType t) { //////////////////////////////////////////////////////////////////// Geom:: Geom(void) : dDrawable() { + /* _prepared_gsg = (GraphicsStateGuardianBase *)NULL; _prepared_context = (GeomContext *)NULL; + */ init(); } @@ -150,8 +152,10 @@ Geom(void) : dDrawable() { //////////////////////////////////////////////////////////////////// Geom:: Geom(const Geom& copy) : dDrawable() { + /* _prepared_gsg = (GraphicsStateGuardianBase *)NULL; _prepared_context = (GeomContext *)NULL; + */ *this = copy; } @@ -162,7 +166,7 @@ Geom(const Geom& copy) : dDrawable() { //////////////////////////////////////////////////////////////////// Geom:: ~Geom() { - unprepare(); + // unprepare(); } //////////////////////////////////////////////////////////////////// @@ -463,9 +467,10 @@ draw(GraphicsStateGuardianBase *gsg) { if (is_dirty()) { config(); } + /* if (_prepared_gsg == gsg) { draw_immediate(gsg, _prepared_context); - } else { + } else */ { draw_immediate(gsg, (GeomContext *)NULL); } } @@ -513,7 +518,7 @@ config() { } // Mark the Geom as needing to be prepared again. - unprepare(); + // unprepare(); } //////////////////////////////////////////////////////////////////// @@ -547,6 +552,7 @@ output(ostream &out) const { */ } +/* //////////////////////////////////////////////////////////////////// // Function: Geom::prepare // Access: Public @@ -620,6 +626,7 @@ clear_gsg(GraphicsStateGuardianBase *gsg) { _prepared_context = (GeomContext *)NULL; } } +*/ //////////////////////////////////////////////////////////////////// // Function: Geom::init diff --git a/panda/src/gobj/geom.h b/panda/src/gobj/geom.h index 013621cb03..2392e4ea3e 100644 --- a/panda/src/gobj/geom.h +++ b/panda/src/gobj/geom.h @@ -224,10 +224,12 @@ public: INLINE ColorIterator make_color_iterator() const; INLINE const Colorf &get_next_color(ColorIterator &citerator) const; + /* GeomContext *prepare(GraphicsStateGuardianBase *gsg); void unprepare(); void unprepare(GraphicsStateGuardianBase *gsg); void clear_gsg(GraphicsStateGuardianBase *gsg); + */ protected: void init(); @@ -261,8 +263,10 @@ protected: // intended to reduce memory overhead that would otherwise be // required to support a little-used feature (having two // simultaneous GSG's). + /* GraphicsStateGuardianBase *_prepared_gsg; GeomContext *_prepared_context; + */ public: //static void register_with_read_factory(void); diff --git a/panda/src/gobj/gobj_composite2.cxx b/panda/src/gobj/gobj_composite2.cxx index 87f5bba44d..c95f84a7a5 100644 --- a/panda/src/gobj/gobj_composite2.cxx +++ b/panda/src/gobj/gobj_composite2.cxx @@ -9,6 +9,7 @@ #include "matrixLens.cxx" #include "perspectiveLens.cxx" #include "pixelBuffer.cxx" +#include "preparedGraphicsObjects.cxx" #include "lens.cxx" #include "savedContext.cxx" #include "texture.cxx" diff --git a/panda/src/gobj/imageBuffer.h b/panda/src/gobj/imageBuffer.h index 15f147a92f..c36d467fb5 100644 --- a/panda/src/gobj/imageBuffer.h +++ b/panda/src/gobj/imageBuffer.h @@ -43,10 +43,6 @@ PUBLISHED: public: virtual void config( void ) { WritableConfigurable::config(); } - virtual bool copy(GraphicsStateGuardianBase *, const DisplayRegion *)=0; - virtual bool copy(GraphicsStateGuardianBase *, const DisplayRegion *, - const RenderBuffer &rb)=0; - PUBLISHED: INLINE bool has_filename() const; INLINE const Filename &get_filename() const; diff --git a/panda/src/gobj/pixelBuffer.cxx b/panda/src/gobj/pixelBuffer.cxx index e0d68bb8d4..857c7f5bdd 100644 --- a/panda/src/gobj/pixelBuffer.cxx +++ b/panda/src/gobj/pixelBuffer.cxx @@ -421,13 +421,3 @@ copy(const PixelBuffer *pb) { if (!pb->_image.empty()) _image.v() = pb->_image.v(); } - -bool PixelBuffer::copy(GraphicsStateGuardianBase *gsg, const DisplayRegion *dr) { - return gsg->copy_pixel_buffer(this, dr); -} - -bool PixelBuffer::copy(GraphicsStateGuardianBase *gsg, const DisplayRegion *dr, - const RenderBuffer &rb) { - return gsg->copy_pixel_buffer(this, dr, rb); -} - diff --git a/panda/src/gobj/pixelBuffer.h b/panda/src/gobj/pixelBuffer.h index 05e51b717c..1078fdffce 100644 --- a/panda/src/gobj/pixelBuffer.h +++ b/panda/src/gobj/pixelBuffer.h @@ -105,10 +105,6 @@ public: bool store( PNMImage& pnmimage ) const; void copy(const PixelBuffer *pb); - - virtual bool copy(GraphicsStateGuardianBase *gsg, const DisplayRegion *dr); - virtual bool copy(GraphicsStateGuardianBase *gsg, const DisplayRegion *dr, - const RenderBuffer &rb); INLINE void set_xsize(int size); INLINE void set_ysize(int size); diff --git a/panda/src/gobj/preparedGraphicsObjects.I b/panda/src/gobj/preparedGraphicsObjects.I new file mode 100644 index 0000000000..46dff6a32f --- /dev/null +++ b/panda/src/gobj/preparedGraphicsObjects.I @@ -0,0 +1,18 @@ +// Filename: preparedGraphicsObjects.I +// Created by: drose (23Feb04) +// +//////////////////////////////////////////////////////////////////// +// +// 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 . +// +//////////////////////////////////////////////////////////////////// + diff --git a/panda/src/gobj/preparedGraphicsObjects.cxx b/panda/src/gobj/preparedGraphicsObjects.cxx new file mode 100644 index 0000000000..8756bbf7e2 --- /dev/null +++ b/panda/src/gobj/preparedGraphicsObjects.cxx @@ -0,0 +1,243 @@ +// Filename: preparedGraphicsObjects.cxx +// Created by: drose (19Feb04) +// +//////////////////////////////////////////////////////////////////// +// +// 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 "preparedGraphicsObjects.h" +#include "textureContext.h" +#include "mutexHolder.h" + +#ifndef CPPPARSER +PStatCollector PreparedGraphicsObjects::_total_texusage_pcollector("Texture usage"); +#endif // CPPPARSER + +//////////////////////////////////////////////////////////////////// +// Function: PreparedGraphicsObjects::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +PreparedGraphicsObjects:: +PreparedGraphicsObjects() { +} + +//////////////////////////////////////////////////////////////////// +// Function: PreparedGraphicsObjects::Destructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +PreparedGraphicsObjects:: +~PreparedGraphicsObjects() { + // There may be texture objects that are still prepared when we + // destruct. If this is so, then all of the GSG's that own them + // have already destructed, so we can assume their resources were + // internally cleaned up. Quietly erase these remaining textures. + + MutexHolder holder(_lock); + + Textures::iterator tci; + for (tci = _prepared_textures.begin(); + tci != _prepared_textures.end(); + ++tci) { + TextureContext *tc = (*tci); + _total_texusage_pcollector.sub_level(tc->estimate_texture_memory()); + tc->_texture->clear_prepared(this); + } + + _prepared_textures.clear(); + _released_textures.clear(); + _enqueued_textures.clear(); +} + + +//////////////////////////////////////////////////////////////////// +// Function: PreparedGraphicsObjects::enqueue_texture +// Access: Public +// Description: Indicates that a texture 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_texture(Texture *tex) { + MutexHolder holder(_lock); + + _enqueued_textures.insert(tex); +} + +//////////////////////////////////////////////////////////////////// +// Function: PreparedGraphicsObjects::dequeue_texture +// Access: Public +// Description: Removes a texture from the queued list of textures 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 texture will +// automatically be dequeued and prepared at the next +// frame. +// +// The return value is true if the texture is +// successfully dequeued, false if it had not been +// queued. +//////////////////////////////////////////////////////////////////// +bool PreparedGraphicsObjects:: +dequeue_texture(Texture *tex) { + MutexHolder holder(_lock); + + EnqueuedTextures::iterator qi = _enqueued_textures.find(tex); + if (qi != _enqueued_textures.end()) { + _enqueued_textures.erase(qi); + return true; + } + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: PreparedGraphicsObjects::release_texture +// Access: Public +// Description: Indicates that a texture context, created by a +// previous call to prepare_texture(), 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 textures--this +// prevents conflicts from threading or multiple GSG's +// sharing textures (we have no way of knowing which +// graphics context is currently active, or what state +// it's in, at the time release_texture is called). +//////////////////////////////////////////////////////////////////// +void PreparedGraphicsObjects:: +release_texture(TextureContext *tc) { + MutexHolder holder(_lock); + + tc->_texture->clear_prepared(this); + _total_texusage_pcollector.sub_level(tc->estimate_texture_memory()); + + // We have to set the Texture pointer to NULL at this point, since + // the Texture itself might destruct at any time after it has been + // released. + tc->_texture = (Texture *)NULL; + + bool removed = (_prepared_textures.erase(tc) != 0); + nassertv(removed); + + _released_textures.insert(tc); +} + +//////////////////////////////////////////////////////////////////// +// Function: PreparedGraphicsObjects::release_all_textures +// Access: Public +// Description: Releases all textures at once. This will force them +// to be reloaded into texture memory for all GSG's that +// share this object. Returns the number of textures +// released. +//////////////////////////////////////////////////////////////////// +int PreparedGraphicsObjects:: +release_all_textures() { + MutexHolder holder(_lock); + + int num_textures = (int)_prepared_textures.size(); + + Textures::iterator tci; + for (tci = _prepared_textures.begin(); + tci != _prepared_textures.end(); + ++tci) { + TextureContext *tc = (*tci); + tc->_texture->clear_prepared(this); + _total_texusage_pcollector.sub_level(tc->estimate_texture_memory()); + tc->_texture = (Texture *)NULL; + + _released_textures.insert(tc); + } + + _prepared_textures.clear(); + + return num_textures; +} + +//////////////////////////////////////////////////////////////////// +// Function: PreparedGraphicsObjects::prepare_texture_now +// Access: Public +// Description: Immediately creates a new TextureContext for the +// indicated texture and returns it. This assumes that +// the GraphicsStateGuardian is the currently active +// rendering context and that it is ready to accept new +// textures. If this is not necessarily the case, you +// should use enqueue_texture() instead. +// +// Normally, this function is not called directly. Call +// Texture::prepare_now() instead. +// +// The TextureContext contains all of the pertinent +// information needed by the GSG to keep track of this +// one particular texture, and will exist as long as the +// texture is ready to be rendered. +// +// When either the Texture or the +// PreparedGraphicsObjects object destructs, the +// TextureContext will be deleted. +//////////////////////////////////////////////////////////////////// +TextureContext *PreparedGraphicsObjects:: +prepare_texture_now(Texture *tex, GraphicsStateGuardianBase *gsg) { + MutexHolder holder(_lock); + + // Ask the GSG to create a brand new TextureContext. There might + // be several GSG's sharing the same set of textures; if so, it + // doesn't matter which of them creates the context (since they're + // all shared anyway). + TextureContext *tc = gsg->prepare_texture(tex); + + bool prepared = _prepared_textures.insert(tc).second; + nassertr(prepared, tc); + + _total_texusage_pcollector.add_level(tc->estimate_texture_memory()); + return tc; +} + +//////////////////////////////////////////////////////////////////// +// Function: PreparedGraphicsObjects::update +// Access: Public +// Description: This is called by the GraphicsStateGuardian to +// indicate that it is in a state to load or release +// textures. +// +// Any texture contexts that were previously passed to +// release_texture() are actually passed to the GSG to +// be freed at this point; textures that were previously +// passed to prepare_texture are actually loaded. +//////////////////////////////////////////////////////////////////// +void PreparedGraphicsObjects:: +update(GraphicsStateGuardianBase *gsg) { + MutexHolder holder(_lock); + + // First, release all the textures awaiting release. + Textures::iterator tci; + for (tci = _released_textures.begin(); + tci != _released_textures.end(); + ++tci) { + TextureContext *tc = (*tci); + gsg->release_texture(tc); + } + + _released_textures.clear(); + + // Now prepare all the textures awaiting preparation. + EnqueuedTextures::iterator qi; + for (qi = _enqueued_textures.begin(); + qi != _enqueued_textures.end(); + ++qi) { + Texture *tex = (*qi); + tex->prepare_now(this, gsg); + } + + _enqueued_textures.clear(); +} diff --git a/panda/src/gobj/preparedGraphicsObjects.h b/panda/src/gobj/preparedGraphicsObjects.h new file mode 100644 index 0000000000..61ea7acb0d --- /dev/null +++ b/panda/src/gobj/preparedGraphicsObjects.h @@ -0,0 +1,80 @@ +// Filename: preparedGraphicsObjects.h +// Created by: drose (19Feb04) +// +//////////////////////////////////////////////////////////////////// +// +// 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 PREPAREDGRAPHICSOBJECTS_H +#define PREPAREDGRAPHICSOBJECTS_H + +#include "pandabase.h" +#include "referenceCount.h" +#include "texture.h" +#include "pStatCollector.h" +#include "pset.h" +#include "pmutex.h" + +class TextureContext; +class GeomContext; +class GeomNodeContext; +class GraphicsStateGuardianBase; + +//////////////////////////////////////////////////////////////////// +// Class : PreparedGraphicsObjects +// Description : A table of objects that are saved within the graphics +// context for reference by handle later. Generally, +// this represents things like OpenGL texture objects or +// display lists. +// +// This object simply records the pointers to the +// context objects created by the individual GSG's; +// these context objects will contain enough information +// to reference or release the actual object stored +// within the graphics context. +// +// These tables may potentially be shared between +// related graphics contexts, hence their storage here +// in a separate object rather than as a part of the +// GraphicsStateGuardian. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA PreparedGraphicsObjects : public ReferenceCount { +public: + PreparedGraphicsObjects(); + ~PreparedGraphicsObjects(); + + void enqueue_texture(Texture *tex); + bool dequeue_texture(Texture *tex); + void release_texture(TextureContext *tc); + int release_all_textures(); + + TextureContext *prepare_texture_now(Texture *tex, GraphicsStateGuardianBase *gsg); + void update(GraphicsStateGuardianBase *gsg); + +private: + typedef pset Textures; + typedef pset< PT(Texture) > EnqueuedTextures; + + Mutex _lock; + Textures _prepared_textures, _released_textures; + EnqueuedTextures _enqueued_textures; + + static PStatCollector _total_texusage_pcollector; + + friend class GraphicsStateGuardian; +}; + +#include "preparedGraphicsObjects.I" + +#endif diff --git a/panda/src/gobj/texture.I b/panda/src/gobj/texture.I index d70cd93c07..3a346faa77 100644 --- a/panda/src/gobj/texture.I +++ b/panda/src/gobj/texture.I @@ -150,14 +150,4 @@ get_keep_ram_image() const { return _keep_ram_image; } -//////////////////////////////////////////////////////////////////// -// Function: Texture::apply -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE void Texture:: -apply(GraphicsStateGuardianBase *gsg) { - gsg->apply_texture(prepare(gsg)); -} - diff --git a/panda/src/gobj/texture.cxx b/panda/src/gobj/texture.cxx index 9978b4f0bb..ea0bdb2cd8 100644 --- a/panda/src/gobj/texture.cxx +++ b/panda/src/gobj/texture.cxx @@ -26,6 +26,7 @@ #include "bamReader.h" #include "bamWriter.h" #include "string_utils.h" +#include "preparedGraphicsObjects.h" #include @@ -126,7 +127,7 @@ consider_downgrade(PNMImage &pnmimage, int num_channels, } //////////////////////////////////////////////////////////////////// -// Function: Constructor +// Function: Texture::Constructor // Access: Published // Description: //////////////////////////////////////////////////////////////////// @@ -146,7 +147,7 @@ Texture() : ImageBuffer() { //////////////////////////////////////////////////////////////////// -// Function: Constructor +// Function: Texture::Constructor // Access: Published // Description: //////////////////////////////////////////////////////////////////// @@ -166,17 +167,17 @@ Texture(int xsize, int ysize, int components, int component_width, PixelBuffer:: } //////////////////////////////////////////////////////////////////// -// Function: Destructor +// Function: Texture::Destructor // Access: Published // Description: //////////////////////////////////////////////////////////////////// Texture:: ~Texture() { - unprepare(); + release_all(); } //////////////////////////////////////////////////////////////////// -// Function: read +// Function: Texture::read // Access: Published // Description: Reads the texture from the indicated filename. If // num_channels is not 0, it specifies the number of @@ -215,7 +216,7 @@ read(const Filename &fullpath, int primary_file_num_channels) { } //////////////////////////////////////////////////////////////////// -// Function: read +// Function: Texture::read // Access: Published // Description: Combine a 3-component image with a grayscale image // to get a 4-component image @@ -309,7 +310,7 @@ read(const Filename &fullpath, const Filename &alpha_fullpath, } //////////////////////////////////////////////////////////////////// -// Function: write +// Function: Texture::write // Access: Published // Description: Writes the texture to the indicated filename. //////////////////////////////////////////////////////////////////// @@ -330,7 +331,7 @@ write(const Filename &name) const { } //////////////////////////////////////////////////////////////////// -// Function: set_wrapu +// Function: Texture::set_wrapu // Access: Published // Description: //////////////////////////////////////////////////////////////////// @@ -343,7 +344,7 @@ set_wrapu(Texture::WrapMode wrap) { } //////////////////////////////////////////////////////////////////// -// Function: set_wrapv +// Function: Texture::set_wrapv // Access: Published // Description: //////////////////////////////////////////////////////////////////// @@ -356,7 +357,7 @@ set_wrapv(Texture::WrapMode wrap) { } //////////////////////////////////////////////////////////////////// -// Function: set_minfilter +// Function: Texture::set_minfilter // Access: Published // Description: //////////////////////////////////////////////////////////////////// @@ -373,7 +374,7 @@ set_minfilter(Texture::FilterType filter) { } //////////////////////////////////////////////////////////////////// -// Function: set_magfilter +// Function: Texture::set_magfilter // Access: Published // Description: //////////////////////////////////////////////////////////////////// @@ -386,7 +387,7 @@ set_magfilter(Texture::FilterType filter) { } //////////////////////////////////////////////////////////////////// -// Function: set_anisotropic_degree +// Function: Texture::set_anisotropic_degree // Access: Published // Description: Specifies the level of anisotropic filtering to apply // to the texture. Normally, this is 1, to indicate @@ -403,7 +404,7 @@ set_anisotropic_degree(int anisotropic_degree) { } //////////////////////////////////////////////////////////////////// -// Function: set_border_color +// Function: Texture::set_border_color // Access: Published // Description: //////////////////////////////////////////////////////////////////// @@ -413,7 +414,24 @@ set_border_color(const Colorf &color) { } //////////////////////////////////////////////////////////////////// -// Function: load +// Function: Texture::prepare +// Access: Published +// Description: Indicates that the texture should be enqueued to be +// prepared in the indicated prepared_objects at the +// beginning of the next frame. This will ensure the +// texture is already loaded into texture memory if it +// is expected to be rendered soon. +// +// Use this function instead of prepare_now() to preload +// textures from a user interface standpoint. +//////////////////////////////////////////////////////////////////// +void Texture:: +prepare(PreparedGraphicsObjects *prepared_objects) { + prepared_objects->enqueue_texture(this); +} + +//////////////////////////////////////////////////////////////////// +// Function: Texture::load // Access: Public // Description: Creates the texture from the already-read PNMImage. //////////////////////////////////////////////////////////////////// @@ -428,7 +446,7 @@ load(const PNMImage &pnmimage) { } //////////////////////////////////////////////////////////////////// -// Function: store +// Function: Texture::store // Access: Public // Description: Saves the texture to the indicated PNMImage, but does // not write it to disk. @@ -459,22 +477,32 @@ is_mipmap(FilterType type) { } //////////////////////////////////////////////////////////////////// -// Function: prepare +// Function: Texture::prepare_now // Access: Public // Description: Creates a context for the texture on the particular // GSG, if it does not already exist. Returns the new -// (or old) TextureContext. +// (or old) TextureContext. This assumes that the +// GraphicsStateGuardian is the currently active +// rendering context and that it is ready to accept new +// textures. If this is not necessarily the case, you +// should use prepare_later() instead. +// +// Normally, this is not called directly except by the +// GraphicsStateGuardian; a texture does not need to be +// explicitly prepared by the user before it may be +// rendered. //////////////////////////////////////////////////////////////////// TextureContext *Texture:: -prepare(GraphicsStateGuardianBase *gsg) { +prepare_now(PreparedGraphicsObjects *prepared_objects, + GraphicsStateGuardianBase *gsg) { Contexts::const_iterator ci; - ci = _contexts.find(gsg); + ci = _contexts.find(prepared_objects); if (ci != _contexts.end()) { return (*ci).second; } - TextureContext *tc = gsg->prepare_texture(this); - _contexts[gsg] = tc; + TextureContext *tc = prepared_objects->prepare_texture_now(this, gsg); + _contexts[prepared_objects] = tc; // Now that we have a new TextureContext with zero dirty flags, our // intersection of all dirty flags must be zero. This doesn't mean @@ -498,67 +526,54 @@ prepare(GraphicsStateGuardianBase *gsg) { } //////////////////////////////////////////////////////////////////// -// Function: Texture::unprepare +// Function: Texture::release // Access: Public -// Description: Frees the context allocated on all GSG's for which -// the texture has been declared. +// Description: Frees the texture context only on the indicated object, +// if it exists there. Returns true if it was released, +// false if it had not been prepared. //////////////////////////////////////////////////////////////////// -void Texture:: -unprepare() { - // We have to traverse a copy of the _contexts list, because the GSG - // will call clear_gsg() in response to each release_texture(), and - // we don't want to be modifying the _contexts list while we're - // traversing it. +bool Texture:: +release(PreparedGraphicsObjects *prepared_objects) { + Contexts::iterator ci; + ci = _contexts.find(prepared_objects); + if (ci != _contexts.end()) { + TextureContext *tc = (*ci).second; + prepared_objects->release_texture(tc); + return true; + } + + // Maybe it wasn't prepared yet, but it's about to be. + return prepared_objects->dequeue_texture(this); +} + +//////////////////////////////////////////////////////////////////// +// Function: Texture::release_all +// Access: Public +// Description: Frees the context allocated on all objects for which +// the texture has been declared. Returns the number of +// contexts which have been freed. +//////////////////////////////////////////////////////////////////// +int Texture:: +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_texture(), 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) { - GraphicsStateGuardianBase *gsg = (*ci).first; + PreparedGraphicsObjects *prepared_objects = (*ci).first; TextureContext *tc = (*ci).second; - gsg->release_texture(tc); + prepared_objects->release_texture(tc); } - // Now that we've called release_texture() on every known GSG, the - // _contexts list should have completely emptied itself. - nassertv(_contexts.empty()); -} + // Now that we've called release_texture() on every known context, + // the _contexts list should have completely emptied itself. + nassertr(_contexts.empty(), num_freed); -//////////////////////////////////////////////////////////////////// -// Function: Texture::unprepare -// Access: Public -// Description: Frees the texture context only on the indicated GSG, -// if it exists there. -//////////////////////////////////////////////////////////////////// -void Texture:: -unprepare(GraphicsStateGuardianBase *gsg) { - Contexts::iterator ci; - ci = _contexts.find(gsg); - if (ci != _contexts.end()) { - TextureContext *tc = (*ci).second; - gsg->release_texture(tc); - } -} - -//////////////////////////////////////////////////////////////////// -// Function: Texture::clear_gsg -// Access: Public -// Description: Removes the indicated GSG from the Texture's known -// GSG's, without actually releasing the texture on that -// GSG. This is intended to be called only from -// GSG::release_texture(); it should never be called by -// user code. -//////////////////////////////////////////////////////////////////// -void Texture:: -clear_gsg(GraphicsStateGuardianBase *gsg) { - Contexts::iterator ci; - ci = _contexts.find(gsg); - if (ci != _contexts.end()) { - _contexts.erase(ci); - } else { - // If this assertion fails, clear_gsg() was called on a GSG which - // the texture didn't know about. - nassertv(false); - } + return num_freed; } //////////////////////////////////////////////////////////////////// @@ -606,17 +621,6 @@ get_ram_image() { } } -bool Texture::copy(GraphicsStateGuardianBase *gsg, const DisplayRegion *dr) { - gsg->copy_texture(prepare(gsg), dr); - return true; -} - -bool Texture::copy(GraphicsStateGuardianBase *gsg, const DisplayRegion *dr, - const RenderBuffer &rb) { - gsg->copy_texture(prepare(gsg), dr, rb); - return true; -} - //////////////////////////////////////////////////////////////////// // Function: Texture::mark_dirty // Access: Public @@ -650,6 +654,28 @@ mark_dirty(int flags_to_set) { _all_dirty_flags |= flags_to_set; } +//////////////////////////////////////////////////////////////////// +// Function: Texture::clear_prepared +// Access: Private +// Description: Removes the indicated PreparedGraphicsObjects table +// from the Texture's table, without actually releasing +// the texture. This is intended to be called only from +// PreparedGraphicsObjects::release_texture(); it should +// never be called by user code. +//////////////////////////////////////////////////////////////////// +void Texture:: +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 texture didn't know about. + nassertv(false); + } +} + //////////////////////////////////////////////////////////////////// // Function: Texture::string_wrap_mode // Access: Public diff --git a/panda/src/gobj/texture.h b/panda/src/gobj/texture.h index a2853ff1fc..53ca2bd3cd 100644 --- a/panda/src/gobj/texture.h +++ b/panda/src/gobj/texture.h @@ -28,6 +28,7 @@ class PNMImage; class TextureContext; class FactoryParams; +class PreparedGraphicsObjects; //////////////////////////////////////////////////////////////////// // Class : Texture @@ -98,28 +99,24 @@ PUBLISHED: INLINE int get_anisotropic_degree() const; INLINE bool uses_mipmaps() const; + void prepare(PreparedGraphicsObjects *prepared_objects); + public: bool load(const PNMImage &pnmimage); bool store(PNMImage &pnmimage) const; static bool is_mipmap(FilterType type); - TextureContext *prepare(GraphicsStateGuardianBase *gsg); - void unprepare(); - void unprepare(GraphicsStateGuardianBase *gsg); - void clear_gsg(GraphicsStateGuardianBase *gsg); + TextureContext *prepare_now(PreparedGraphicsObjects *prepared_objects, + GraphicsStateGuardianBase *gsg); + bool release(PreparedGraphicsObjects *prepared_objects); + int release_all(); INLINE bool has_ram_image() const; PixelBuffer *get_ram_image(); INLINE void set_keep_ram_image(bool keep_ram_image); INLINE bool get_keep_ram_image() const; - INLINE void apply(GraphicsStateGuardianBase *gsg); - - virtual bool copy(GraphicsStateGuardianBase *gsg, const DisplayRegion *dr); - virtual bool copy(GraphicsStateGuardianBase *gsg, const DisplayRegion *dr, - const RenderBuffer &rb); - // These bits are used as parameters to Texture::mark_dirty() and // also TextureContext::mark_dirty() (and related functions in // TextureContext). @@ -136,6 +133,8 @@ public: static FilterType string_filter_type(const string &string); private: + void clear_prepared(PreparedGraphicsObjects *prepared_objects); + WrapMode _wrapu; WrapMode _wrapv; FilterType _minfilter; @@ -144,11 +143,12 @@ private: bool _keep_ram_image; Colorf _border_color; - // A Texture keeps a list (actually, a map) of all the GSG's that it - // has been prepared into. Each GSG conversely keeps a list (a set) - // of all the Textures that have been prepared there. When either - // destructs, it removes itself from the other's list. - typedef pmap Contexts; + // A Texture 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 Textures that + // have been prepared there. When either destructs, it removes + // itself from the other's list. + typedef pmap Contexts; Contexts _contexts; // This value represents the intersection of all the dirty flags of @@ -201,6 +201,7 @@ private: static TypeHandle _type_handle; friend class TextureContext; + friend class PreparedGraphicsObjects; }; #include "texture.I" diff --git a/panda/src/gsgbase/graphicsStateGuardianBase.h b/panda/src/gsgbase/graphicsStateGuardianBase.h index ff7a73df93..8fe18d8101 100644 --- a/panda/src/gsgbase/graphicsStateGuardianBase.h +++ b/panda/src/gsgbase/graphicsStateGuardianBase.h @@ -44,6 +44,7 @@ class GeomTristrip; class GeomTrifan; class GeomSphere; +class PreparedGraphicsObjects; class TextureContext; class Texture; class PixelBuffer; @@ -111,6 +112,8 @@ public: // These are some general interface functions; they're defined here // mainly to make it easy to call these from code in some directory // that display depends on. + virtual PreparedGraphicsObjects *get_prepared_objects()=0; + virtual TextureContext *prepare_texture(Texture *tex)=0; virtual void apply_texture(TextureContext *tc)=0; virtual void release_texture(TextureContext *tc)=0; diff --git a/panda/src/pgraph/nodePath.cxx b/panda/src/pgraph/nodePath.cxx index 8a2b5cc959..b7550dad41 100644 --- a/panda/src/pgraph/nodePath.cxx +++ b/panda/src/pgraph/nodePath.cxx @@ -47,6 +47,7 @@ #include "globPattern.h" #include "config_gobj.h" #include "bamFile.h" +#include "preparedGraphicsObjects.h" #include "dcast.h" // stack seems to overflow on Intel C++ at 7000. If we need more than @@ -3246,19 +3247,18 @@ verify_complete() const { // but this may take some of the overhead away from that // process. // -// If force_retained_mode is true, retained mode is set -// on the geometry encountered, regardless of the -// setting of the retained-mode Config variable. -// Otherwise, retained mode is set only if the -// retained-mode Config variable is true. +// In particular, this will ensure that textures within +// the scene are loaded in texture memory, and display +// lists are built up from static geometry. //////////////////////////////////////////////////////////////////// void NodePath:: -prepare_scene(GraphicsStateGuardianBase *gsg, bool force_retained_mode) { +prepare_scene(GraphicsStateGuardianBase *gsg) { nassertv_always(!is_empty()); + PreparedGraphicsObjects *prepared_objects = gsg->get_prepared_objects(); + CPT(RenderState) net_state = get_net_state(); - r_prepare_scene(node(), net_state, gsg, - retained_mode || force_retained_mode); + r_prepare_scene(node(), net_state, prepared_objects); } //////////////////////////////////////////////////////////////////// @@ -3895,14 +3895,14 @@ r_find_all_textures(PandaNode *node, const RenderState *state, //////////////////////////////////////////////////////////////////// void NodePath:: r_prepare_scene(PandaNode *node, const RenderState *state, - GraphicsStateGuardianBase *gsg, bool do_retained_mode) { + PreparedGraphicsObjects *prepared_objects) { if (node->is_geom_node()) { GeomNode *gnode; DCAST_INTO_V(gnode, node); /* Not implemented yet in pgraph. Maybe we don't need this anyway. - if (do_retained_mode) { + if (retained_mode) { gnode->prepare(gsg); } */ @@ -3917,7 +3917,7 @@ r_prepare_scene(PandaNode *node, const RenderState *state, DCAST_INTO_V(ta, attrib); Texture *texture = ta->get_texture(); if (texture != (Texture *)NULL) { - texture->prepare(gsg); + texture->prepare(prepared_objects); } } } @@ -3927,6 +3927,6 @@ r_prepare_scene(PandaNode *node, const RenderState *state, for (int i = 0; i < num_children; i++) { PandaNode *child = node->get_child(i); CPT(RenderState) child_state = state->compose(child->get_state()); - r_prepare_scene(child, child_state, gsg, do_retained_mode); + r_prepare_scene(child, child_state, prepared_objects); } } diff --git a/panda/src/pgraph/nodePath.h b/panda/src/pgraph/nodePath.h index 25362dc4ca..c33112e37d 100644 --- a/panda/src/pgraph/nodePath.h +++ b/panda/src/pgraph/nodePath.h @@ -39,6 +39,7 @@ class Texture; class Material; class Fog; class GlobPattern; +class PreparedGraphicsObjects; // // A NodePath is the fundamental unit of high-level interaction with @@ -577,7 +578,7 @@ PUBLISHED: // Miscellaneous bool verify_complete() const; - void prepare_scene(GraphicsStateGuardianBase *gsg, bool force_retained_mode = false); + void prepare_scene(GraphicsStateGuardianBase *gsg); void show_bounds(); void hide_bounds(); @@ -635,7 +636,7 @@ private: void r_find_all_textures(PandaNode *node, const RenderState *state, Textures &textures) const; void r_prepare_scene(PandaNode *node, const RenderState *state, - GraphicsStateGuardianBase *gsg, bool do_retained_mode); + PreparedGraphicsObjects *prepared_objects); PT(NodePathComponent) _head; int _backup_key; diff --git a/panda/src/pgraph/spotlight.cxx b/panda/src/pgraph/spotlight.cxx index 4066bc3baa..293f15c46b 100644 --- a/panda/src/pgraph/spotlight.cxx +++ b/panda/src/pgraph/spotlight.cxx @@ -227,7 +227,9 @@ make_image(Texture *texture, float radius) { pb->set_uchar_rgb_texel(C, size - tx2 - 1, size - ty2 - 1, size); } } - texture->unprepare(); + + // Force the texture to be reloaded into texture memory. + texture->mark_dirty(Texture::DF_image); return true; }