generalize render-to-texture operations

This commit is contained in:
David Rose 2005-03-01 20:37:42 +00:00
parent 60053c0e17
commit b82f3bac1e
25 changed files with 205 additions and 142 deletions

View File

@ -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

View File

@ -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);
}
}
////////////////////////////////////////////////////////////////////

View File

@ -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();

View File

@ -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;

View File

@ -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,21 +635,37 @@ 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) {
PStatTimer timer(_copy_texture_pcollector);
nassertv(has_texture());
// 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";
}
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 we're not single-buffered, we're now ready to flip.
if (!_gsg->get_properties().is_single_buffered()) {

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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());
}

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -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();

View File

@ -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);
}

View File

@ -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:

View File

@ -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

View File

@ -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"

View File

@ -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);
}
////////////////////////////////////////////////////////////////////

View File

@ -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,

View File

@ -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

View File

@ -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;