mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 18:31:55 -04:00
generalize render-to-texture operations
This commit is contained in:
parent
60053c0e17
commit
b82f3bac1e
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user