diff --git a/panda/src/display/config_display.cxx b/panda/src/display/config_display.cxx index c15e438626..704c997b8a 100644 --- a/panda/src/display/config_display.cxx +++ b/panda/src/display/config_display.cxx @@ -89,10 +89,10 @@ ConfigVariableBool show_buffers ConfigVariableBool prefer_parasite_buffer ("prefer-parasite-buffer", true, - PRC_DESC("Set this true to make GraphicsOutput::make_render_texture() try to " + PRC_DESC("Set this true to make GraphicsOutput::make_texture_buffer() try to " "create a parasite buffer before it tries to create an offscreen " "buffer. This may be desired if you know your graphics API does not " - "support render-directly-to-texture and you want to minimize " + "support render-to-texture and you want to minimize " "framebuffer memory.")); ConfigVariableBool prefer_single_buffer diff --git a/panda/src/display/graphicsBuffer.cxx b/panda/src/display/graphicsBuffer.cxx index 7ab4fa61e7..8f7aff6019 100644 --- a/panda/src/display/graphicsBuffer.cxx +++ b/panda/src/display/graphicsBuffer.cxx @@ -29,7 +29,7 @@ TypeHandle GraphicsBuffer::_type_handle; //////////////////////////////////////////////////////////////////// GraphicsBuffer:: GraphicsBuffer(GraphicsPipe *pipe, GraphicsStateGuardian *gsg, - const string &name, int x_size, int y_size, bool want_texture) : + const string &name, int x_size, int y_size) : GraphicsOutput(pipe, gsg, name) { #ifdef DO_MEMORY_USAGE @@ -47,10 +47,6 @@ GraphicsBuffer(GraphicsPipe *pipe, GraphicsStateGuardian *gsg, _has_size = true; _default_display_region->compute_pixels(_x_size, _y_size); _open_request = OR_none; - - if (want_texture) { - setup_copy_texture(_name); - } } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/display/graphicsBuffer.h b/panda/src/display/graphicsBuffer.h index d876873dbf..49ca35327d 100644 --- a/panda/src/display/graphicsBuffer.h +++ b/panda/src/display/graphicsBuffer.h @@ -30,19 +30,11 @@ // Description : An offscreen buffer for rendering into. This is // similar in function to a GraphicsWindow, except that // the output is not visible to the user. -// -// If want_texture is passed true into the constructor, -// the GraphicsBuffer will render directly into a -// texture which can be retrieved via get_texture(). -// This may then be applied to geometry for rendering in -// other windows or buffers using the same -// GraphicsStateGuardian. //////////////////////////////////////////////////////////////////// class EXPCL_PANDA GraphicsBuffer : public GraphicsOutput { protected: GraphicsBuffer(GraphicsPipe *pipe, GraphicsStateGuardian *gsg, - const string &name, - int x_size, int y_size, bool want_texture); + const string &name, int x_size, int y_size); PUBLISHED: virtual ~GraphicsBuffer(); diff --git a/panda/src/display/graphicsEngine.cxx b/panda/src/display/graphicsEngine.cxx index 0f089c9071..a272ae44ba 100644 --- a/panda/src/display/graphicsEngine.cxx +++ b/panda/src/display/graphicsEngine.cxx @@ -250,7 +250,7 @@ make_buffer(GraphicsStateGuardian *gsg, const string &name, window->request_properties(props); if (want_texture) { - window->setup_copy_texture(name); + window->setup_render_texture(); } return window; @@ -265,9 +265,12 @@ make_buffer(GraphicsStateGuardian *gsg, const string &name, // TODO: ask the window thread to make the buffer. PT(GraphicsBuffer) buffer = - gsg->get_pipe()->make_buffer(gsg, name, x_size, y_size, want_texture); + gsg->get_pipe()->make_buffer(gsg, name, x_size, y_size); if (buffer != (GraphicsBuffer *)NULL) { buffer->_sort = sort; + if (want_texture) { + buffer->setup_render_texture(); + } do_add_window(buffer, gsg, threading_model); } return buffer; @@ -299,7 +302,7 @@ make_parasite(GraphicsOutput *host, const string &name, props.set_fixed_size(true); props.set_title(name); window->request_properties(props); - window->setup_copy_texture(name); + window->setup_render_texture(); return window; } @@ -313,6 +316,7 @@ make_parasite(GraphicsOutput *host, const string &name, ParasiteBuffer *buffer = new ParasiteBuffer(host, name, x_size, y_size); buffer->_sort = sort; + buffer->setup_render_texture(); do_add_window(buffer, gsg, threading_model); return buffer; diff --git a/panda/src/display/graphicsOutput.cxx b/panda/src/display/graphicsOutput.cxx index f8b815c04b..60378600d4 100644 --- a/panda/src/display/graphicsOutput.cxx +++ b/panda/src/display/graphicsOutput.cxx @@ -53,6 +53,7 @@ GraphicsOutput(GraphicsPipe *pipe, GraphicsStateGuardian *gsg, _has_size = false; _is_valid = false; _copy_texture = false; + _render_texture = false; _flip_ready = false; _needs_context = true; _sort = 0; @@ -158,32 +159,48 @@ GraphicsOutput:: // Access: Published // Description: Disassociates the texture from the GraphicsOutput. // The texture will no longer be filled as the frame -// renders, and it may be used (with its current -// contents) as an ordinary texture in its own right. +// renders, and it may be used as an ordinary texture in +// its own right. However, its contents may be +// undefined. //////////////////////////////////////////////////////////////////// void GraphicsOutput:: detach_texture() { MutexHolder holder(_lock); + + if (_render_texture && _gsg != (GraphicsStateGuardian *)NULL) { + _gsg->framebuffer_release_texture(this, get_texture()); + } + _texture = NULL; _copy_texture = false; + _render_texture = false; set_inverted(window_inverted); } //////////////////////////////////////////////////////////////////// -// Function: GraphicsOutput::setup_copy_texture -// Access: Published -// Description: Creates a new Texture object, suitable for copying +// Function: GraphicsOutput::setup_render_texture +// Access: Published, Virtual +// Description: Creates a new Texture object, suitable for rendering // the contents of this buffer into, and stores it in // _texture. This also disassociates the previous // texture (if any). +// +// If the backend supports it, this will actually set up +// the framebuffer to render directly into texture +// memory; otherwise, the framebuffer will be copied +// into the texture after each frame. //////////////////////////////////////////////////////////////////// void GraphicsOutput:: -setup_copy_texture(const string &name) { +setup_render_texture() { MutexHolder holder(_lock); + if (_render_texture && _gsg != (GraphicsStateGuardian *)NULL) { + _gsg->framebuffer_release_texture(this, get_texture()); + } + _texture = new Texture(true); - _texture->set_name(name); + _texture->set_name(get_name()); _texture->set_wrapu(Texture::WM_clamp); _texture->set_wrapv(Texture::WM_clamp); @@ -195,6 +212,7 @@ setup_copy_texture(const string &name) { } _copy_texture = true; + _render_texture = false; nassertv(_gsg != (GraphicsStateGuardian *)NULL); set_inverted(_gsg->get_copy_texture_inverted()); @@ -428,7 +446,7 @@ make_texture_buffer(const string &name, int x_size, int y_size) { GraphicsOutput *buffer = NULL; - // If the user so indicated in the Configrc file, try to create a + // If the user so indicated in the Config.prc file, try to create a // parasite buffer first. We can only do this if the requested size // fits within the available framebuffer size. if (prefer_parasite_buffer && @@ -575,6 +593,12 @@ begin_frame() { // Okay, we already have a GSG, so activate it. make_current(); + + if (_render_texture) { + // Release the texture so we can render into the pbuffer. + _gsg->framebuffer_release_texture(this, get_texture()); + } + return _gsg->begin_frame(); } @@ -611,20 +635,36 @@ end_frame() { nassertv(_gsg != (GraphicsStateGuardian *)NULL); _gsg->end_frame(); - // If _copy_texture is true, it means we should copy the framebuffer - // to the GraphicsOutput's associated texture after the frame has - // rendered. GraphicsBuffer objects that are set up to render - // directly into texture memory don't need to do this; they will set - // _copy_texture to false. + // If _copy_texture is true, it means we should copy or lock the + // framebuffer to the GraphicsOutput's associated texture after the + // frame has rendered. if (_copy_texture) { - if (display_cat.is_debug()) { - display_cat.debug() - << "Copying texture for " << (void *)this << " at frame end.\n"; - } PStatTimer timer(_copy_texture_pcollector); nassertv(has_texture()); - RenderBuffer buffer = _gsg->get_render_buffer(get_draw_buffer_type()); - _gsg->copy_texture(get_texture(), _default_display_region, buffer); + + // If _render_texture is true, it means we should attempt to lock + // the framebuffer directly to the texture memory, avoiding the + // copy. + if (_render_texture) { + if (display_cat.is_debug()) { + display_cat.debug() + << "Locking texture for " << (void *)this << " at frame end.\n"; + } + if (!_gsg->framebuffer_bind_to_texture(this, get_texture())) { + display_cat.warning() + << "Lock-to-texture failed, resorting to copy.\n"; + _render_texture = false; + } + } + + if (!_render_texture) { + if (display_cat.is_debug()) { + display_cat.debug() + << "Copying texture for " << (void *)this << " at frame end.\n"; + } + RenderBuffer buffer = _gsg->get_render_buffer(get_draw_buffer_type()); + _gsg->copy_texture(get_texture(), _default_display_region, buffer); + } } // If we're not single-buffered, we're now ready to flip. diff --git a/panda/src/display/graphicsOutput.h b/panda/src/display/graphicsOutput.h index 1798391663..4b68d67327 100644 --- a/panda/src/display/graphicsOutput.h +++ b/panda/src/display/graphicsOutput.h @@ -75,7 +75,7 @@ PUBLISHED: INLINE bool has_texture() const; INLINE Texture *get_texture() const; void detach_texture(); - void setup_copy_texture(const string &name); + virtual void setup_render_texture(); INLINE int get_x_size() const; INLINE int get_y_size() const; @@ -157,6 +157,7 @@ protected: string _name; PT(Texture) _texture; bool _copy_texture; + bool _render_texture; bool _flip_ready; bool _needs_context; diff --git a/panda/src/display/graphicsPipe.cxx b/panda/src/display/graphicsPipe.cxx index f46c41b2a9..1eddb5b1ee 100644 --- a/panda/src/display/graphicsPipe.cxx +++ b/panda/src/display/graphicsPipe.cxx @@ -203,7 +203,7 @@ make_window(GraphicsStateGuardian *, const string &) { // Description: Creates a new offscreen buffer on the pipe, if possible. //////////////////////////////////////////////////////////////////// PT(GraphicsBuffer) GraphicsPipe:: -make_buffer(GraphicsStateGuardian *, const string &, int, int, bool) { +make_buffer(GraphicsStateGuardian *, const string &, int, int) { display_cat.error() << get_type() << " cannot create offscreen buffers.\n"; return NULL; diff --git a/panda/src/display/graphicsPipe.h b/panda/src/display/graphicsPipe.h index eb862739a0..b26c8af73a 100644 --- a/panda/src/display/graphicsPipe.h +++ b/panda/src/display/graphicsPipe.h @@ -100,7 +100,7 @@ protected: const string &name); virtual PT(GraphicsBuffer) make_buffer(GraphicsStateGuardian *gsg, const string &name, - int x_size, int y_size, bool want_texture); + int x_size, int y_size); Mutex _lock; diff --git a/panda/src/display/graphicsStateGuardian.I b/panda/src/display/graphicsStateGuardian.I index c2714e634c..7a5b9fcf24 100644 --- a/panda/src/display/graphicsStateGuardian.I +++ b/panda/src/display/graphicsStateGuardian.I @@ -193,6 +193,19 @@ get_supports_generate_mipmap() const { return _supports_generate_mipmap; } +//////////////////////////////////////////////////////////////////// +// Function: GraphicsStateGuardian::get_supports_render_texture +// Access: Published +// Description: Returns true if this particular GSG can render +// directly into a texture, or false if it must always +// copy-to-texture at the end of each frame to achieve +// this effect. +//////////////////////////////////////////////////////////////////// +INLINE bool GraphicsStateGuardian:: +get_supports_render_texture() const { + return _supports_render_texture; +} + //////////////////////////////////////////////////////////////////// // Function: GraphicsStateGuardian::set_scene diff --git a/panda/src/display/graphicsStateGuardian.cxx b/panda/src/display/graphicsStateGuardian.cxx index c9b6d6d0cd..8b821907af 100644 --- a/panda/src/display/graphicsStateGuardian.cxx +++ b/panda/src/display/graphicsStateGuardian.cxx @@ -97,6 +97,7 @@ GraphicsStateGuardian(const FrameBufferProperties &properties, // Similarly with these capabilities flags. _supports_multisample = false; _supports_generate_mipmap = false; + _supports_render_texture = false; } //////////////////////////////////////////////////////////////////// @@ -585,6 +586,39 @@ finish_decal() { // No need to do anything special here. } +//////////////////////////////////////////////////////////////////// +// Function: GraphicsStateGuardian::framebuffer_bind_to_texture +// Access: Public, Virtual +// Description: Works in lieu of copy_texture() to bind the primary +// render buffer of the framebuffer to the indicated +// texture (which must have been created via +// GraphicsOutput::setup_render_texture()). +// +// If supported by the graphics backend, this will make +// the framebuffer memory directly accessible within the +// texture, but the frame cannot be rendered again until +// framebuffer_release_texture() is called. +// +// The return value is true if successful, false on +// failure. +//////////////////////////////////////////////////////////////////// +bool GraphicsStateGuardian:: +framebuffer_bind_to_texture(GraphicsOutput *, Texture *) { + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: GraphicsStateGuardian::framebuffer_release_texture +// Access: Public, Virtual +// Description: Undoes a previous call to +// framebuffer_bind_to_texture(). The framebuffer may +// again be rendered into, and the contents of the +// texture is undefined. +//////////////////////////////////////////////////////////////////// +void GraphicsStateGuardian:: +framebuffer_release_texture(GraphicsOutput *, Texture *) { +} + //////////////////////////////////////////////////////////////////// // Function: GraphicsStateGuardian::set_coordinate_system // Access: Public diff --git a/panda/src/display/graphicsStateGuardian.h b/panda/src/display/graphicsStateGuardian.h index dcb93fc690..8bb41e6a6b 100644 --- a/panda/src/display/graphicsStateGuardian.h +++ b/panda/src/display/graphicsStateGuardian.h @@ -87,6 +87,7 @@ PUBLISHED: INLINE bool get_copy_texture_inverted() const; virtual bool get_supports_multisample() const; INLINE bool get_supports_generate_mipmap() const; + INLINE bool get_supports_render_texture() const; public: INLINE bool set_scene(SceneSetup *scene_setup); @@ -135,6 +136,9 @@ public: virtual CPT(RenderState) begin_decal_base_second(); virtual void finish_decal(); + virtual bool framebuffer_bind_to_texture(GraphicsOutput *win, Texture *tex); + virtual void framebuffer_release_texture(GraphicsOutput *win, Texture *tex); + INLINE bool reset_if_new(); virtual void reset(); @@ -285,6 +289,7 @@ protected: bool _copy_texture_inverted; bool _supports_multisample; bool _supports_generate_mipmap; + bool _supports_render_texture; public: // Statistics diff --git a/panda/src/display/parasiteBuffer.cxx b/panda/src/display/parasiteBuffer.cxx index 0a017aefac..987e769523 100644 --- a/panda/src/display/parasiteBuffer.cxx +++ b/panda/src/display/parasiteBuffer.cxx @@ -51,8 +51,6 @@ ParasiteBuffer(GraphicsOutput *host, const string &name, _is_valid = true; - setup_copy_texture(_name); - nassertv(_x_size <= host->get_x_size() && _y_size <= host->get_y_size()); } diff --git a/panda/src/glxdisplay/glxGraphicsPipe.cxx b/panda/src/glxdisplay/glxGraphicsPipe.cxx index 0abd9fd864..d67d809699 100644 --- a/panda/src/glxdisplay/glxGraphicsPipe.cxx +++ b/panda/src/glxdisplay/glxGraphicsPipe.cxx @@ -304,13 +304,13 @@ make_window(GraphicsStateGuardian *gsg, const string &name) { //////////////////////////////////////////////////////////////////// PT(GraphicsBuffer) glxGraphicsPipe:: make_buffer(GraphicsStateGuardian *gsg, const string &name, - int x_size, int y_size, bool want_texture) { + int x_size, int y_size) { if (!_is_valid) { return NULL; } #ifdef HAVE_GLXFBCONFIG - return new glxGraphicsBuffer(this, gsg, name, x_size, y_size, want_texture); + return new glxGraphicsBuffer(this, gsg, name, x_size, y_size); #else return NULL; #endif // HAVE_GLXFBCONFIG diff --git a/panda/src/glxdisplay/glxGraphicsPipe.h b/panda/src/glxdisplay/glxGraphicsPipe.h index c49111f831..26ab831e75 100644 --- a/panda/src/glxdisplay/glxGraphicsPipe.h +++ b/panda/src/glxdisplay/glxGraphicsPipe.h @@ -112,7 +112,7 @@ protected: const string &name); virtual PT(GraphicsBuffer) make_buffer(GraphicsStateGuardian *gsg, const string &name, - int x_size, int y_size, bool want_texture); + int x_size, int y_size); private: #ifdef HAVE_GLXFBCONFIG diff --git a/panda/src/gsgbase/graphicsStateGuardianBase.h b/panda/src/gsgbase/graphicsStateGuardianBase.h index c05e7ea74a..6f0f242c01 100644 --- a/panda/src/gsgbase/graphicsStateGuardianBase.h +++ b/panda/src/gsgbase/graphicsStateGuardianBase.h @@ -45,6 +45,7 @@ class GeomTrifan; class GeomSphere; class PreparedGraphicsObjects; +class GraphicsOutput; class TextureContext; class Texture; class PixelBuffer; @@ -169,6 +170,9 @@ public: virtual void copy_texture(Texture *tex, const DisplayRegion *dr, const RenderBuffer &rb)=0; + virtual bool framebuffer_bind_to_texture(GraphicsOutput *win, Texture *tex)=0; + virtual void framebuffer_release_texture(GraphicsOutput *win, Texture *tex)=0; + virtual void texture_to_pixel_buffer(TextureContext *tc, PixelBuffer *pb)=0; virtual void texture_to_pixel_buffer(TextureContext *tc, PixelBuffer *pb, const DisplayRegion *dr)=0; diff --git a/panda/src/mesadisplay/osMesaGraphicsBuffer.cxx b/panda/src/mesadisplay/osMesaGraphicsBuffer.cxx index 6f162b8043..e308085f29 100644 --- a/panda/src/mesadisplay/osMesaGraphicsBuffer.cxx +++ b/panda/src/mesadisplay/osMesaGraphicsBuffer.cxx @@ -31,8 +31,8 @@ TypeHandle OsMesaGraphicsBuffer::_type_handle; OsMesaGraphicsBuffer:: OsMesaGraphicsBuffer(GraphicsPipe *pipe, GraphicsStateGuardian *gsg, const string &name, - int x_size, int y_size, bool want_texture) : - GraphicsBuffer(pipe, gsg, name, x_size, y_size, want_texture) + int x_size, int y_size) : + GraphicsBuffer(pipe, gsg, name, x_size, y_size) { _type = GL_UNSIGNED_BYTE; } diff --git a/panda/src/mesadisplay/osMesaGraphicsBuffer.h b/panda/src/mesadisplay/osMesaGraphicsBuffer.h index b350da51df..da7d48cf0f 100644 --- a/panda/src/mesadisplay/osMesaGraphicsBuffer.h +++ b/panda/src/mesadisplay/osMesaGraphicsBuffer.h @@ -34,7 +34,7 @@ class EXPCL_PANDAMESA OsMesaGraphicsBuffer : public GraphicsBuffer { public: OsMesaGraphicsBuffer(GraphicsPipe *pipe, GraphicsStateGuardian *gsg, const string &name, - int x_size, int y_size, bool want_texture); + int x_size, int y_size); virtual ~OsMesaGraphicsBuffer(); diff --git a/panda/src/mesadisplay/osMesaGraphicsPipe.cxx b/panda/src/mesadisplay/osMesaGraphicsPipe.cxx index 93c8157ed6..fa27b42db9 100644 --- a/panda/src/mesadisplay/osMesaGraphicsPipe.cxx +++ b/panda/src/mesadisplay/osMesaGraphicsPipe.cxx @@ -125,6 +125,6 @@ make_gsg(const FrameBufferProperties &properties, //////////////////////////////////////////////////////////////////// PT(GraphicsBuffer) OsMesaGraphicsPipe:: make_buffer(GraphicsStateGuardian *gsg, const string &name, - int x_size, int y_size, bool want_texture) { - return new OsMesaGraphicsBuffer(this, gsg, name, x_size, y_size, want_texture); + int x_size, int y_size) { + return new OsMesaGraphicsBuffer(this, gsg, name, x_size, y_size); } diff --git a/panda/src/mesadisplay/osMesaGraphicsPipe.h b/panda/src/mesadisplay/osMesaGraphicsPipe.h index d55de0ed6c..fb2123a526 100644 --- a/panda/src/mesadisplay/osMesaGraphicsPipe.h +++ b/panda/src/mesadisplay/osMesaGraphicsPipe.h @@ -50,7 +50,7 @@ protected: GraphicsStateGuardian *share_with); virtual PT(GraphicsBuffer) make_buffer(GraphicsStateGuardian *gsg, const string &name, - int x_size, int y_size, bool want_texture); + int x_size, int y_size); private: diff --git a/panda/src/wgldisplay/wglGraphicsBuffer.cxx b/panda/src/wgldisplay/wglGraphicsBuffer.cxx index 0e8526557b..d6f800f8af 100644 --- a/panda/src/wgldisplay/wglGraphicsBuffer.cxx +++ b/panda/src/wgldisplay/wglGraphicsBuffer.cxx @@ -34,8 +34,8 @@ TypeHandle wglGraphicsBuffer::_type_handle; wglGraphicsBuffer:: wglGraphicsBuffer(GraphicsPipe *pipe, GraphicsStateGuardian *gsg, const string &name, - int x_size, int y_size, bool want_texture) : - GraphicsBuffer(pipe, gsg, name, x_size, y_size, want_texture) + int x_size, int y_size) : + GraphicsBuffer(pipe, gsg, name, x_size, y_size) { _pbuffer = (HPBUFFERARB)0; _pbuffer_dc = (HDC)0; @@ -73,12 +73,6 @@ begin_frame() { wglGraphicsStateGuardian *wglgsg; DCAST_INTO_R(wglgsg, _gsg, false); - if (_render_texture) { - // Release the texture so we can render into the pbuffer. - // wglgsg->_wglReleaseTexImageARB(_pbuffer, get_draw_buffer_type() == RenderBuffer::T_back ? WGL_BACK_LEFT_ARB : WGL_FRONT_LEFT_ARB); - wglgsg->_wglReleaseTexImageARB(_pbuffer, WGL_FRONT_LEFT_ARB); - } - if (_pbuffer_dc) { int flag = 0; wglgsg->_wglQueryPbufferARB(_pbuffer, WGL_PBUFFER_LOST_ARB, &flag); @@ -95,81 +89,6 @@ begin_frame() { return GraphicsBuffer::begin_frame(); } -//////////////////////////////////////////////////////////////////// -// Function: wglGraphicsBuffer::end_frame -// Access: Public, Virtual -// Description: This function will be called within the draw thread -// after rendering is completed for a given frame. It -// should do whatever finalization is required. -//////////////////////////////////////////////////////////////////// -void wglGraphicsBuffer:: -end_frame() { - nassertv(_gsg != (GraphicsStateGuardian *)NULL); - _gsg->end_frame(); - - wglGraphicsStateGuardian *wglgsg; - DCAST_INTO_V(wglgsg, _gsg); - - // If we've lost the pbuffer image (due to a mode-switch, for - // instance), don't attempt to copy it to the texture, since the - // frame is invalid. In fact, now we need to recreate the - // pbuffer. - if (_pbuffer_dc) { - int flag = 0; - wglgsg->_wglQueryPbufferARB(_pbuffer, WGL_PBUFFER_LOST_ARB, &flag); - if (flag != 0) { - wgldisplay_cat.info() - << "Pbuffer contents lost.\n"; - return; - } - } - - if (_copy_texture) { - nassertv(has_texture()); - Texture *tex = get_texture(); - - if (_render_texture) { - // Bind the pbuffer to our associated texture. This is a newer - // extension that might allow us to use the same memory directly - // without having to pay for a copy operation. But we can't - // render again to the pbuffer while the texture is valid. - TextureContext *tc = tex->prepare_now(wglgsg->get_prepared_objects(), wglgsg); - nassertv(tc != (TextureContext *)NULL); - wglgsg->bind_texture(tc); - - // wglgsg->_wglBindTexImageARB(_pbuffer, get_draw_buffer_type() == RenderBuffer::T_back ? WGL_BACK_LEFT_ARB : WGL_FRONT_LEFT_ARB); - wglgsg->_wglBindTexImageARB(_pbuffer, WGL_FRONT_LEFT_ARB); - - } else { - // Copy the contents of the frame buffer to our associated - // texture. This is an older interface that guarantees a copy - // operation will take place, and it might even require - // reformatting pixels on the way, so it may be slower. - if (display_cat.is_debug()) { - display_cat.debug() - << "Copying texture for " << (void *)this << " at frame end.\n"; - } - PStatTimer timer(_copy_texture_pcollector); - RenderBuffer buffer = wglgsg->get_render_buffer(get_draw_buffer_type()); - wglgsg->copy_texture(tex, _default_display_region, buffer); - } - } - - // If we're not single-buffered, we're now ready to flip. - if (!_gsg->get_properties().is_single_buffered()) { - _flip_ready = true; - } - - if (_one_shot && !show_buffers) { - // In one-shot mode, we request the GraphicsEngine to delete the - // window after we have rendered a frame. But when show-buffers - // mode is enabled, we don't do this, to give the user a chance to - // see the output. - _active = false; - _delete_flag = true; - } -} - //////////////////////////////////////////////////////////////////// // Function: wglGraphicsBuffer::make_current // Access: Public, Virtual diff --git a/panda/src/wgldisplay/wglGraphicsBuffer.h b/panda/src/wgldisplay/wglGraphicsBuffer.h index d5b0beed45..1a0d742599 100644 --- a/panda/src/wgldisplay/wglGraphicsBuffer.h +++ b/panda/src/wgldisplay/wglGraphicsBuffer.h @@ -43,11 +43,10 @@ class EXPCL_PANDAGL wglGraphicsBuffer : public GraphicsBuffer { public: wglGraphicsBuffer(GraphicsPipe *pipe, GraphicsStateGuardian *gsg, const string &name, - int x_size, int y_size, bool want_texture); + int x_size, int y_size); virtual ~wglGraphicsBuffer(); virtual bool begin_frame(); - virtual void end_frame(); virtual void make_current(); virtual void release_gsg(); @@ -84,6 +83,8 @@ public: private: static TypeHandle _type_handle; + + friend class wglGraphicsStateGuardian; }; #include "wglGraphicsBuffer.I" diff --git a/panda/src/wgldisplay/wglGraphicsPipe.cxx b/panda/src/wgldisplay/wglGraphicsPipe.cxx index 9021e23a18..5c4b710b5d 100644 --- a/panda/src/wgldisplay/wglGraphicsPipe.cxx +++ b/panda/src/wgldisplay/wglGraphicsPipe.cxx @@ -206,8 +206,8 @@ make_window(GraphicsStateGuardian *gsg, const string &name) { //////////////////////////////////////////////////////////////////// PT(GraphicsBuffer) wglGraphicsPipe:: make_buffer(GraphicsStateGuardian *gsg, const string &name, - int x_size, int y_size, bool want_texture) { - return new wglGraphicsBuffer(this, gsg, name, x_size, y_size, want_texture); + int x_size, int y_size) { + return new wglGraphicsBuffer(this, gsg, name, x_size, y_size); } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/wgldisplay/wglGraphicsPipe.h b/panda/src/wgldisplay/wglGraphicsPipe.h index 07816a2d4c..f04971cfe1 100644 --- a/panda/src/wgldisplay/wglGraphicsPipe.h +++ b/panda/src/wgldisplay/wglGraphicsPipe.h @@ -45,7 +45,7 @@ protected: const string &name); virtual PT(GraphicsBuffer) make_buffer(GraphicsStateGuardian *gsg, const string &name, - int x_size, int y_size, bool want_texture); + int x_size, int y_size); private: static int choose_pfnum(const FrameBufferProperties &properties, HDC hdc); static int try_for_pfnum(HDC hdc, bool hardware, bool software, diff --git a/panda/src/wgldisplay/wglGraphicsStateGuardian.cxx b/panda/src/wgldisplay/wglGraphicsStateGuardian.cxx index 1859897e0e..35b476e178 100755 --- a/panda/src/wgldisplay/wglGraphicsStateGuardian.cxx +++ b/panda/src/wgldisplay/wglGraphicsStateGuardian.cxx @@ -17,6 +17,7 @@ //////////////////////////////////////////////////////////////////// #include "wglGraphicsStateGuardian.h" +#include "wglGraphicsBuffer.h" #include "string_utils.h" TypeHandle wglGraphicsStateGuardian::_type_handle; @@ -46,7 +47,6 @@ wglGraphicsStateGuardian(const FrameBufferProperties &properties, _supports_pbuffer = false; _supports_pixel_format = false; _supports_wgl_multisample = false; - _supports_render_texture = false; } //////////////////////////////////////////////////////////////////// @@ -63,6 +63,60 @@ wglGraphicsStateGuardian:: } } +//////////////////////////////////////////////////////////////////// +// Function: wglGraphicsStateGuardian::framebuffer_bind_to_texture +// Access: Public, Virtual +// Description: Works in lieu of copy_texture() to bind the primary +// render buffer of the framebuffer to the indicated +// texture (which must have been created via +// GraphicsOutput::setup_render_texture()). +// +// If supported by the graphics backend, this will make +// the framebuffer memory directly accessible within the +// texture, but the frame cannot be rendered again until +// framebuffer_release_texture() is called. +// +// The return value is true if successful, false on +// failure. +//////////////////////////////////////////////////////////////////// +bool wglGraphicsStateGuardian:: +framebuffer_bind_to_texture(GraphicsOutput *win, Texture *tex) { + wglGraphicsBuffer *buffer; + DCAST_INTO_R(buffer, win, false); + + TextureContext *tc = tex->prepare_now(get_prepared_objects(), this); + nassertr(tc != (TextureContext *)NULL, false); + bind_texture(tc); + + if (get_properties().is_single_buffered()) { + _wglBindTexImageARB(buffer->_pbuffer, WGL_FRONT_LEFT_ARB); + } else { + _wglBindTexImageARB(buffer->_pbuffer, WGL_BACK_LEFT_ARB); + } + + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: wglGraphicsStateGuardian::framebuffer_release_texture +// Access: Public, Virtual +// Description: Undoes a previous call to +// framebuffer_bind_to_texture(). The framebuffer may +// again be rendered into, and the contents of the +// texture is undefined. +//////////////////////////////////////////////////////////////////// +void wglGraphicsStateGuardian:: +framebuffer_release_texture(GraphicsOutput *win, Texture *) { + wglGraphicsBuffer *buffer; + DCAST_INTO_V(buffer, win); + + if (get_properties().is_single_buffered()) { + _wglReleaseTexImageARB(buffer->_pbuffer, WGL_FRONT_LEFT_ARB); + } else { + _wglReleaseTexImageARB(buffer->_pbuffer, WGL_BACK_LEFT_ARB); + } +} + //////////////////////////////////////////////////////////////////// // Function: wglGraphicsStateGuardian::reset // Access: Public, Virtual diff --git a/panda/src/wgldisplay/wglGraphicsStateGuardian.h b/panda/src/wgldisplay/wglGraphicsStateGuardian.h index a96cd24d80..5f6d29b863 100755 --- a/panda/src/wgldisplay/wglGraphicsStateGuardian.h +++ b/panda/src/wgldisplay/wglGraphicsStateGuardian.h @@ -43,6 +43,9 @@ public: INLINE bool made_context() const; INLINE HGLRC get_context(HDC hdc); + virtual bool framebuffer_bind_to_texture(GraphicsOutput *win, Texture *tex); + virtual void framebuffer_release_texture(GraphicsOutput *win, Texture *tex); + virtual void reset(); INLINE HDC get_twindow_dc(); @@ -95,7 +98,6 @@ public: bool _supports_wgl_multisample; - bool _supports_render_texture; PFNWGLBINDTEXIMAGEARBPROC _wglBindTexImageARB; PFNWGLRELEASETEXIMAGEARBPROC _wglReleaseTexImageARB; PFNWGLSETPBUFFERATTRIBARBPROC _wglSetPbufferAttribARB;