*** empty log message ***

This commit is contained in:
Josh Yelon 2005-10-27 21:11:26 +00:00
parent 5c29aace8d
commit efc2a9ce26
10 changed files with 356 additions and 276 deletions

View File

@ -60,30 +60,36 @@ get_name() const {
return _name; return _name;
} }
////////////////////////////////////////////////////////////////////
// Function: GraphicsOutput::count_textures
// Access: Published
// Description: If the GraphicsOutput is set to render into a
// texture, returns the number of textures that are
// being rendered into. Normally, the textures would
// be associated with different buffers - a color
// texture, a depth texture, and a stencil texture.
////////////////////////////////////////////////////////////////////
INLINE int GraphicsOutput::
count_textures() const {
return _textures.size();
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: GraphicsOutput::has_texture // Function: GraphicsOutput::has_texture
// Access: Published // Access: Published
// Description: Returns true if the GraphicsOutput is set to render // Description: Returns true if the GraphicsOutput is rendering
// into a texture, or false otherwise. // into any textures at all.
//
// Normally, this will only be true for a GraphicsBuffer
// object, and only when want_texture is passed in as
// true to the GraphicsBuffer constructor. If
// show-buffers is true, this may also be set for a
// GraphicsWindow, which is in this case serving in the
// place of a GraphicsBuffer.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE bool GraphicsOutput:: INLINE bool GraphicsOutput::
has_texture() const { has_texture() const {
return !(_texture.is_null()); return (_textures.size() > 0);
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: GraphicsOutput::get_texture // Function: GraphicsOutput::get_texture
// Access: Published // Access: Published
// Description: Returns the texture into which the GraphicsOutput // Description: Returns the nth texture into which the GraphicsOutput
// renders, if has_texture() is true, or NULL if // renders. Returns NULL if there is no such texture.
// has_texture() is false.
// //
// If the texture is non-NULL, it may be applied to // If the texture is non-NULL, it may be applied to
// geometry to be rendered for any other windows or // geometry to be rendered for any other windows or
@ -93,8 +99,26 @@ has_texture() const {
// the texture will be invalid. // the texture will be invalid.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE Texture *GraphicsOutput:: INLINE Texture *GraphicsOutput::
get_texture() const { get_texture(int i) const {
return _texture; if ((i < 0) || (i >= ((int)_textures.size()))) {
return (Texture *)NULL;
}
return _textures[i]._texture;
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsOutput::get_rtm_mode
// Access: Published
// Description: Returns the RenderTextureMode associated with the
// nth texture. Returns RTM_none if there is no such
// texture.
////////////////////////////////////////////////////////////////////
INLINE GraphicsOutput::RenderTextureMode GraphicsOutput::
get_rtm_mode(int i) const {
if ((i < 0) || (i >= ((int)_textures.size()))) {
return RTM_none;
}
return _textures[i]._rtm_mode;
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -225,7 +249,12 @@ INLINE bool GraphicsOutput::
get_delete_flag() const { get_delete_flag() const {
// We only delete the window or buffer automatically when it is // We only delete the window or buffer automatically when it is
// no longer associated with a texture. // no longer associated with a texture.
return _delete_flag && !_hold_texture.is_valid_pointer(); for (int i=0; i<(int)_hold_textures.size(); i++) {
if (_hold_textures[i].is_valid_pointer()) {
return false;
}
}
return _delete_flag;
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////

View File

@ -80,7 +80,6 @@ GraphicsOutput(GraphicsPipe *pipe, GraphicsStateGuardian *gsg,
_y_size = 0; _y_size = 0;
_has_size = false; _has_size = false;
_is_valid = false; _is_valid = false;
_rtm_mode = RTM_none;
_flip_ready = false; _flip_ready = false;
_needs_context = true; _needs_context = true;
_cube_map_index = -1; _cube_map_index = -1;
@ -187,12 +186,24 @@ GraphicsOutput::
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: GraphicsOutput::setup_render_texture // Function: GraphicsOutput::clear_render_textures
// Access: Published
// Description: If the GraphicsOutput is currently rendering to
// a texture, then all textures are dissociated from
// the GraphicsOuput.
////////////////////////////////////////////////////////////////////
void GraphicsOutput::
clear_render_textures() {
MutexHolder holder(_lock);
_textures.clear();
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsOutput::add_render_texture
// Access: Published // Access: Published
// Description: Creates a new Texture object, suitable for rendering // Description: Creates a new Texture object, suitable for rendering
// the contents of this buffer into, and stores it in // the contents of this buffer into, and appends it to
// _texture. This also disassociates the previous // the list of render textures.
// texture (if any).
// //
// If tex is not NULL, it is the texture that will be // If tex is not NULL, it is the texture that will be
// set up for rendering into; otherwise, a new Texture // set up for rendering into; otherwise, a new Texture
@ -200,66 +211,84 @@ GraphicsOutput::
// get_texture() to retrieve the new texture pointer // get_texture() to retrieve the new texture pointer
// later). // later).
// //
// If allow_bind is true, and this GraphicsOutput is an
// offscreen graphics buffer that has not yet been
// rendered into, it will attempt to set up the buffer
// for rendering directly into the texture, avoiding the
// cost of the copy-to-texture-memory each frame. This
// is not supported by all graphics hardware, but if it
// is not supported, this option is quietly ignored.
//
// If to_ram is true, the texture image will be
// downloaded from the framebuffer memory into system
// RAM each frame, which is more expensive but allows
// the texture to subsequently be applied to any GSG.
// Otherwise, the texture image remains in texture
// memory only.
//
// Also see make_texture_buffer(), which is a // Also see make_texture_buffer(), which is a
// higher-level interface for preparing // higher-level interface for preparing
// render-to-a-texture mode. // render-to-a-texture mode.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
void GraphicsOutput:: void GraphicsOutput::
setup_render_texture(Texture *tex, RenderTextureMode mode) { add_render_texture(Texture *tex, RenderTextureMode mode) {
if (mode == RTM_none) { if (mode == RTM_none) {
return; return;
} }
MutexHolder holder(_lock); MutexHolder holder(_lock);
_rtm_mode = mode;
if (tex == (Texture *)NULL) { if (tex == (Texture *)NULL) {
_texture = new Texture(get_name()); tex = new Texture(get_name());
_texture->set_wrap_u(Texture::WM_clamp); tex->set_wrap_u(Texture::WM_clamp);
_texture->set_wrap_v(Texture::WM_clamp); tex->set_wrap_v(Texture::WM_clamp);
} else { } else {
_texture = tex; tex->clear_ram_image();
_texture->clear_ram_image();
} }
_texture->set_match_framebuffer_format(true); tex->set_match_framebuffer_format(true);
// Go ahead and tell the texture our anticipated size, even if it // Go ahead and tell the texture our anticipated size, even if it
// might be inaccurate (particularly if this is a GraphicsWindow, // might be inaccurate (particularly if this is a GraphicsWindow,
// which has system-imposed restrictions on size). // which has system-imposed restrictions on size).
_texture->set_x_size(get_x_size()); tex->set_x_size(get_x_size());
_texture->set_y_size(get_y_size()); tex->set_y_size(get_y_size());
RenderTexture result;
result._texture = tex;
result._rtm_mode = mode;
_textures.push_back(result);
nassertv(_gsg != (GraphicsStateGuardian *)NULL); nassertv(_gsg != (GraphicsStateGuardian *)NULL);
set_inverted(_gsg->get_copy_texture_inverted()); set_inverted(_gsg->get_copy_texture_inverted());
// Sanity check that we don't have two textures of the same type.
int count_stencil_textures = 0;
int count_depth_textures = 0;
int count_color_textures = 0;
for (int i=0; i<count_textures(); i++) {
Texture::Format fmt = get_texture(i)->get_format();
if (fmt == Texture::F_depth_component) {
count_depth_textures += 1;
} else if (fmt == Texture::F_stencil_index) {
count_stencil_textures += 1;
} else {
count_color_textures += 1;
}
}
if ((count_color_textures > 1)||
(count_depth_textures > 1)||
(count_stencil_textures > 1)) {
display_cat.error() <<
"Currently, each GraphicsOutput can only render to one color texture, "
"one depth texture, and one stencil texture at a time. RTM aborted.\n";
clear_render_textures();
}
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: GraphicsOutput::setup_render_texture // Function: GraphicsOutput::setup_render_texture
// Access: Published // Access: Published
// Description: // Description: This is a deprecated interface that made sense back
// when GraphicsOutputs could only render into one
// texture at a time. From now on, use
// clear_render_textures and add_render_texture
// instead.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
void GraphicsOutput:: void GraphicsOutput::
setup_render_texture(Texture *tex, bool allow_bind, bool to_ram) { setup_render_texture(Texture *tex, bool allow_bind, bool to_ram) {
display_cat.warning() <<
"Using deprecated setup_render_texture interface.\n";
clear_render_textures();
if (to_ram) { if (to_ram) {
setup_render_texture(tex, RTM_copy_ram); add_render_texture(tex, RTM_copy_ram);
} else if (allow_bind) { } else if (allow_bind) {
setup_render_texture(tex, RTM_bind_or_copy); add_render_texture(tex, RTM_bind_or_copy);
} else { } else {
setup_render_texture(tex, RTM_copy_texture); add_render_texture(tex, RTM_copy_texture);
} }
} }
@ -577,7 +606,20 @@ get_texture_card() {
PT(GeomNode) gnode = new GeomNode("texture card"); PT(GeomNode) gnode = new GeomNode("texture card");
gnode->add_geom(_texture_card); gnode->add_geom(_texture_card);
NodePath path(gnode); NodePath path(gnode);
path.set_texture(get_texture(), 0);
// The texture card, by default, is textured with the first
// render-to-texture output texture. Depth and stencil
// textures are ignored. The user can freely alter the
// card's texture attrib.
for (int i=0; i<count_textures(); i++) {
Texture *texture = get_texture(i);
if ((texture->get_format() != Texture::F_depth_component) &&
(texture->get_format() != Texture::F_stencil_index)) {
path.set_texture(texture, 0);
break;
}
}
return path; return path;
} }
@ -635,7 +677,7 @@ make_texture_buffer(const string &name, int x_size, int y_size,
// host window size. If the user requests this, we have to use a // host window size. If the user requests this, we have to use a
// parasite buffer. // parasite buffer.
buffer = engine->make_parasite(host, name, sort, x_size, y_size); buffer = engine->make_parasite(host, name, sort, x_size, y_size);
buffer->setup_render_texture(tex, false, to_ram); buffer->add_render_texture(tex, to_ram ? RTM_copy_ram : RTM_copy_texture);
return buffer; return buffer;
} }
@ -644,7 +686,7 @@ make_texture_buffer(const string &name, int x_size, int y_size,
// since it all amounts to the same thing anyway--this will // since it all amounts to the same thing anyway--this will
// actually create a new GraphicsWindow. // actually create a new GraphicsWindow.
buffer = engine->make_buffer(gsg, name, sort, x_size, y_size); buffer = engine->make_buffer(gsg, name, sort, x_size, y_size);
buffer->setup_render_texture(tex, false, to_ram); buffer->add_render_texture(tex, to_ram ? RTM_copy_ram : RTM_copy_texture);
return buffer; return buffer;
} }
@ -661,7 +703,7 @@ make_texture_buffer(const string &name, int x_size, int y_size,
(x_size <= host->get_x_size() && y_size <= host->get_y_size())) { (x_size <= host->get_x_size() && y_size <= host->get_y_size())) {
buffer = engine->make_parasite(host, name, sort, x_size, y_size); buffer = engine->make_parasite(host, name, sort, x_size, y_size);
if (buffer != (GraphicsOutput *)NULL) { if (buffer != (GraphicsOutput *)NULL) {
buffer->setup_render_texture(tex, false, to_ram); buffer->add_render_texture(tex, to_ram ? RTM_copy_ram : RTM_copy_texture);
return buffer; return buffer;
} }
} }
@ -680,7 +722,11 @@ make_texture_buffer(const string &name, int x_size, int y_size,
buffer = engine->make_buffer(sb_gsg, name, sort, x_size, y_size); buffer = engine->make_buffer(sb_gsg, name, sort, x_size, y_size);
if (buffer != (GraphicsOutput *)NULL) { if (buffer != (GraphicsOutput *)NULL) {
// Check the buffer for goodness. // Check the buffer for goodness.
buffer->setup_render_texture(tex, allow_bind, to_ram); if (allow_bind) {
buffer->add_render_texture(tex, RTM_bind_or_copy);
} else {
buffer->add_render_texture(tex, to_ram ? RTM_copy_ram : RTM_copy_texture);
}
engine->open_windows(); engine->open_windows();
if (buffer->is_valid()) { if (buffer->is_valid()) {
return buffer; return buffer;
@ -700,7 +746,11 @@ make_texture_buffer(const string &name, int x_size, int y_size,
// source window is double-buffered. // source window is double-buffered.
buffer = engine->make_buffer(gsg, name, sort, x_size, y_size); buffer = engine->make_buffer(gsg, name, sort, x_size, y_size);
if (buffer != (GraphicsOutput *)NULL) { if (buffer != (GraphicsOutput *)NULL) {
buffer->setup_render_texture(tex, allow_bind, to_ram); if (allow_bind) {
buffer->add_render_texture(tex, RTM_bind_or_copy);
} else {
buffer->add_render_texture(tex, to_ram ? RTM_copy_ram : RTM_copy_texture);
}
engine->open_windows(); engine->open_windows();
if (buffer->is_valid()) { if (buffer->is_valid()) {
return buffer; return buffer;
@ -714,7 +764,7 @@ make_texture_buffer(const string &name, int x_size, int y_size,
// Looks like we have to settle for a parasite buffer. // Looks like we have to settle for a parasite buffer.
if (x_size <= host->get_x_size() && y_size <= host->get_y_size()) { if (x_size <= host->get_x_size() && y_size <= host->get_y_size()) {
buffer = engine->make_parasite(host, name, sort, x_size, y_size); buffer = engine->make_parasite(host, name, sort, x_size, y_size);
buffer->setup_render_texture(tex, false, to_ram); buffer->add_render_texture(tex, to_ram ? RTM_copy_ram : RTM_copy_texture);
return buffer; return buffer;
} }
@ -926,10 +976,7 @@ begin_frame() {
// Okay, we already have a GSG, so activate it. // Okay, we already have a GSG, so activate it.
make_current(); make_current();
if (_rtm_mode == RTM_bind_or_copy) { begin_render_texture();
// Release the texture so we can render into the frame buffer.
_gsg->framebuffer_release_texture(this, get_texture());
}
_cube_map_index = -1; _cube_map_index = -1;
_cube_map_dr = NULL; _cube_map_dr = NULL;
@ -982,33 +1029,24 @@ end_frame() {
nassertv(_gsg != (GraphicsStateGuardian *)NULL); nassertv(_gsg != (GraphicsStateGuardian *)NULL);
_gsg->end_frame(); _gsg->end_frame();
// If _rtm_mode isn't RTM_none, it means we should copy or lock the // Handle all render-to-texture operations that use bind-to-texture
// framebuffer to the GraphicsOutput's associated texture after the end_render_texture();
// frame has rendered.
if (_rtm_mode != RTM_none) { // Handle all render-to-texture operations that use copy-to-texture
for (int i=0; i<count_textures(); i++) {
RenderTextureMode rtm_mode = get_rtm_mode(i);
if ((rtm_mode == RTM_none)||(rtm_mode == RTM_bind_or_copy)) {
continue;
}
Texture *texture = get_texture(i);
PStatTimer timer(_copy_texture_pcollector); PStatTimer timer(_copy_texture_pcollector);
nassertv(has_texture()); nassertv(has_texture());
// If _rtm_mode is one of the bind-modes, it means we should attempt if ((rtm_mode == RTM_copy_texture)||
// to lock the framebuffer directly to the texture memory, avoiding (rtm_mode == RTM_copy_ram)||
// the copy. ((rtm_mode == RTM_triggered_copy_texture)&&(_trigger_copy))||
if (_rtm_mode == RTM_bind_or_copy) { ((rtm_mode == RTM_triggered_copy_ram)&&(_trigger_copy))) {
if (display_cat.is_debug()) {
display_cat.debug()
<< "Locking texture for " << get_name() << " at frame end.\n";
}
if (!_gsg->framebuffer_bind_to_texture(this, get_texture())) {
display_cat.warning()
<< "Lock-to-texture failed, resorting to copy.\n";
_rtm_mode = RTM_copy_texture;
}
}
if ((_rtm_mode == RTM_copy_texture)||
(_rtm_mode == RTM_copy_ram)||
((_rtm_mode == RTM_triggered_copy_texture)&&(_trigger_copy))||
((_rtm_mode == RTM_triggered_copy_ram)&&(_trigger_copy))) {
_trigger_copy = false;
if (display_cat.is_debug()) { if (display_cat.is_debug()) {
display_cat.debug() display_cat.debug()
<< "Copying texture for " << get_name() << " at frame end.\n"; << "Copying texture for " << get_name() << " at frame end.\n";
@ -1017,24 +1055,25 @@ end_frame() {
} }
RenderBuffer buffer = _gsg->get_render_buffer(get_draw_buffer_type()); RenderBuffer buffer = _gsg->get_render_buffer(get_draw_buffer_type());
if (_cube_map_dr != (DisplayRegion *)NULL) { if (_cube_map_dr != (DisplayRegion *)NULL) {
if ((_rtm_mode == RTM_copy_ram)||(_rtm_mode == RTM_triggered_copy_ram)) { if ((rtm_mode == RTM_copy_ram)||(rtm_mode == RTM_triggered_copy_ram)) {
_gsg->framebuffer_copy_to_ram(get_texture(), _cube_map_index, _gsg->framebuffer_copy_to_ram(texture, _cube_map_index,
_cube_map_dr, buffer); _cube_map_dr, buffer);
} else { } else {
_gsg->framebuffer_copy_to_texture(get_texture(), _cube_map_index, _gsg->framebuffer_copy_to_texture(texture, _cube_map_index,
_cube_map_dr, buffer); _cube_map_dr, buffer);
} }
} else { } else {
if ((_rtm_mode == RTM_copy_ram)||(_rtm_mode == RTM_triggered_copy_ram)) { if ((rtm_mode == RTM_copy_ram)||(rtm_mode == RTM_triggered_copy_ram)) {
_gsg->framebuffer_copy_to_ram(get_texture(), _cube_map_index, _gsg->framebuffer_copy_to_ram(texture, _cube_map_index,
_default_display_region, buffer); _default_display_region, buffer);
} else { } else {
_gsg->framebuffer_copy_to_texture(get_texture(), _cube_map_index, _gsg->framebuffer_copy_to_texture(texture, _cube_map_index,
_default_display_region, buffer); _default_display_region, buffer);
} }
} }
} }
} }
_trigger_copy = false;
// If we're not single-buffered, we're now ready to flip. // If we're not single-buffered, we're now ready to flip.
if (!_gsg->get_properties().is_single_buffered()) { if (!_gsg->get_properties().is_single_buffered()) {
@ -1059,23 +1098,53 @@ end_frame() {
// If we were rendering directly to texture, we can't delete the // If we were rendering directly to texture, we can't delete the
// buffer until the texture is gone too. // buffer until the texture is gone too.
if (_rtm_mode == RTM_bind_or_copy) { for (int i=0; i<count_textures(); i++) {
_hold_texture = _texture; if (get_rtm_mode(i) == RTM_bind_or_copy) {
_hold_textures.push_back(get_texture(i));
}
} }
} }
// We have to be sure to clear the _texture pointer, though, or // We have to be sure to clear the _textures pointers, though, or
// we'll end up holding a reference to it forever. // we'll end up holding a reference to the textures forever.
_texture = NULL; clear_render_textures();
// And we need to stop trying to copy to the texture.
_rtm_mode = RTM_none;
} }
_cube_map_index = -1; _cube_map_index = -1;
_cube_map_dr = NULL; _cube_map_dr = NULL;
} }
////////////////////////////////////////////////////////////////////
// Function: GraphicsOutput::begin_render_texture
// Access: Public, Virtual
// Description: If the GraphicsOutput supports direct render-to-texture,
// and if any setup needs to be done during begin_frame,
// then the setup code should go here. Any textures that
// can not be rendered to directly should be reflagged
// as RTM_copy_texture.
////////////////////////////////////////////////////////////////////
void GraphicsOutput::
begin_render_texture() {
for (int i=0; i<count_textures(); i++) {
if (get_rtm_mode(i) == RTM_bind_or_copy) {
_textures[i]._rtm_mode = RTM_copy_texture;
}
}
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsOutput::end_render_texture
// Access: Public, Virtual
// Description: If the GraphicsOutput supports direct render-to-texture,
// and if any setup needs to be done during end_frame,
// then the setup code should go here. Any textures that
// could not be rendered to directly should be reflagged
// as RTM_copy_texture.
////////////////////////////////////////////////////////////////////
void GraphicsOutput::
end_render_texture() {
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: GraphicsOutput::change_scenes // Function: GraphicsOutput::change_scenes
// Access: Public // Access: Public
@ -1095,31 +1164,35 @@ change_scenes(DisplayRegion *new_dr) {
_cube_map_index = new_cube_map_index; _cube_map_index = new_cube_map_index;
_cube_map_dr = new_dr; _cube_map_dr = new_dr;
if (_rtm_mode != RTM_none) { for (int i=0; i<count_textures(); i++) {
if (_rtm_mode == RTM_bind_or_copy) { Texture *texture = get_texture(i);
// In render-to-texture mode, switch the rendering backend to RenderTextureMode rtm_mode = get_rtm_mode(i);
// the new cube map face, so that the subsequent frame will be if (rtm_mode != RTM_none) {
// rendered to the new face. if (rtm_mode == RTM_bind_or_copy) {
// In render-to-texture mode, switch the rendering backend to
// the new cube map face, so that the subsequent frame will be
// rendered to the new face.
select_cube_map(new_cube_map_index); select_cube_map(new_cube_map_index);
} else if (old_cube_map_index != -1) { } else if (old_cube_map_index != -1) {
// In copy-to-texture mode, copy the just-rendered framebuffer // In copy-to-texture mode, copy the just-rendered framebuffer
// to the old cube map face. // to the old cube map face.
nassertv(old_cube_map_dr != (DisplayRegion *)NULL); nassertv(old_cube_map_dr != (DisplayRegion *)NULL);
if (display_cat.is_debug()) { if (display_cat.is_debug()) {
display_cat.debug() display_cat.debug()
<< "Copying texture for " << get_name() << " at scene change.\n"; << "Copying texture for " << get_name() << " at scene change.\n";
display_cat.debug() display_cat.debug()
<< "cube_map_index = " << old_cube_map_index << "\n"; << "cube_map_index = " << old_cube_map_index << "\n";
} }
RenderBuffer buffer = _gsg->get_render_buffer(get_draw_buffer_type()); RenderBuffer buffer = _gsg->get_render_buffer(get_draw_buffer_type());
if (_rtm_mode == RTM_copy_ram) { if (rtm_mode == RTM_copy_ram) {
_gsg->framebuffer_copy_to_ram(get_texture(), old_cube_map_index, _gsg->framebuffer_copy_to_ram(texture, old_cube_map_index,
old_cube_map_dr, buffer); old_cube_map_dr, buffer);
} else { } else {
_gsg->framebuffer_copy_to_texture(get_texture(), old_cube_map_index, _gsg->framebuffer_copy_to_texture(texture, old_cube_map_index,
old_cube_map_dr, buffer); old_cube_map_dr, buffer);
}
} }
} }
} }

View File

@ -84,9 +84,12 @@ PUBLISHED:
INLINE GraphicsPipe *get_pipe() const; INLINE GraphicsPipe *get_pipe() const;
INLINE const string &get_name() const; INLINE const string &get_name() const;
INLINE int count_textures() const;
INLINE bool has_texture() const; INLINE bool has_texture() const;
INLINE Texture *get_texture() const; INLINE Texture *get_texture(int i=0) const;
void setup_render_texture(Texture *tex, RenderTextureMode mode); INLINE RenderTextureMode get_rtm_mode(int i=0) const;
void clear_render_textures();
void add_render_texture(Texture *tex, RenderTextureMode mode);
void setup_render_texture(Texture *tex, bool allow_bind, bool to_ram); void setup_render_texture(Texture *tex, bool allow_bind, bool to_ram);
INLINE int get_x_size() const; INLINE int get_x_size() const;
@ -157,10 +160,13 @@ public:
// It is an error to call any of the following methods from any // It is an error to call any of the following methods from any
// thread other than the draw thread. These methods are normally // thread other than the draw thread. These methods are normally
// called by the GraphicsEngine. // called by the GraphicsEngine.
virtual bool begin_frame();
void clear(); void clear();
virtual bool begin_frame();
virtual void end_frame(); virtual void end_frame();
virtual void begin_render_texture();
virtual void end_render_texture();
void change_scenes(DisplayRegion *new_dr); void change_scenes(DisplayRegion *new_dr);
virtual void select_cube_map(int cube_map_index); virtual void select_cube_map(int cube_map_index);
@ -182,11 +188,15 @@ public:
protected: protected:
class RenderTexture {
public:
PT(Texture) _texture;
RenderTextureMode _rtm_mode;
};
PT(GraphicsStateGuardian) _gsg; PT(GraphicsStateGuardian) _gsg;
PT(GraphicsPipe) _pipe; PT(GraphicsPipe) _pipe;
string _name; string _name;
PT(Texture) _texture; pvector<RenderTexture> _textures;
RenderTextureMode _rtm_mode;
bool _flip_ready; bool _flip_ready;
bool _needs_context; bool _needs_context;
int _cube_map_index; int _cube_map_index;
@ -211,11 +221,11 @@ protected:
bool _inverted; bool _inverted;
bool _delete_flag; bool _delete_flag;
// This weak pointer is used to keep track of whether the buffer's // These weak pointers are used to keep track of whether the
// bound Texture has been deleted or not. Until it has, we don't // buffer's bound Texture has been deleted or not. Until they have,
// auto-close the buffer (since that would deallocate the memory // we don't auto-close the buffer (since that would deallocate the
// associated with the texture). // memory associated with the texture).
WPT(Texture) _hold_texture; pvector<WPT(Texture)> _hold_textures;
protected: protected:
Mutex _lock; Mutex _lock;

View File

@ -971,39 +971,6 @@ end_draw_primitives() {
_vertex_data = NULL; _vertex_data = NULL;
} }
////////////////////////////////////////////////////////////////////
// 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::do_issue_color_scale // Function: GraphicsStateGuardian::do_issue_color_scale
// Access: Public, Virtual // Access: Public, Virtual

View File

@ -191,9 +191,6 @@ public:
virtual void draw_points(const GeomPoints *primitive); virtual void draw_points(const GeomPoints *primitive);
virtual void end_draw_primitives(); virtual void end_draw_primitives();
virtual bool framebuffer_bind_to_texture(GraphicsOutput *win, Texture *tex);
virtual void framebuffer_release_texture(GraphicsOutput *win, Texture *tex);
INLINE bool reset_if_new(); INLINE bool reset_if_new();
INLINE void mark_new(); INLINE void mark_new();
virtual void reset(); virtual void reset();

View File

@ -203,9 +203,6 @@ public:
virtual bool framebuffer_copy_to_ram virtual bool framebuffer_copy_to_ram
(Texture *tex, int z, const DisplayRegion *dr, const RenderBuffer &rb)=0; (Texture *tex, int z, 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 CoordinateSystem get_internal_coordinate_system() const=0; virtual CoordinateSystem get_internal_coordinate_system() const=0;
virtual void bind_light(PointLight *light_obj, const NodePath &light, virtual void bind_light(PointLight *light_obj, const NodePath &light,

View File

@ -89,6 +89,75 @@ begin_frame() {
return GraphicsBuffer::begin_frame(); return GraphicsBuffer::begin_frame();
} }
////////////////////////////////////////////////////////////////////
// Function: wglGraphicsStateGuardian::begin_render_texture
// Access: Public, Virtual
// Description: If the GraphicsOutput supports direct render-to-texture,
// and if any setup needs to be done during begin_frame,
// then the setup code should go here. Any textures that
// can not be rendered to directly should be reflagged
// as RTM_copy_texture.
////////////////////////////////////////////////////////////////////
void wglGraphicsBuffer::
begin_render_texture() {
wglGraphicsStateGuardian *wglgsg;
DCAST_INTO_V(wglgsg, _gsg);
if (_gsg->get_properties().is_single_buffered()) {
wglgsg->_wglReleaseTexImageARB(_pbuffer, WGL_FRONT_LEFT_ARB);
} else {
wglgsg->_wglReleaseTexImageARB(_pbuffer, WGL_BACK_LEFT_ARB);
}
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsOutput::end_render_texture
// Access: Public, Virtual
// Description: If the GraphicsOutput supports direct render-to-texture,
// and if any setup needs to be done during end_frame,
// then the setup code should go here. Any textures that
// could not be rendered to directly should be reflagged
// as RTM_copy_texture.
////////////////////////////////////////////////////////////////////
void wglGraphicsBuffer::
end_render_texture() {
wglGraphicsStateGuardian *wglgsg;
DCAST_INTO_V(wglgsg, _gsg);
// Find the color texture, if there is one. That one can be bound to
// the framebuffer. All others must be marked RTM_copy_to_texture.
int tex_index = -1;
for (int i=0; i<count_textures(); i++) {
if (get_rtm_mode(i) == RTM_bind_or_copy) {
if ((get_texture(i)->get_format() != Texture::F_depth_component)&&
(get_texture(i)->get_format() != Texture::F_stencil_index)&&
(tex_index < 0)) {
tex_index = i;
} else {
_textures[i]._rtm_mode = RTM_copy_texture;
}
}
}
if (tex_index >= 0) {
Texture *tex = get_texture(tex_index);
TextureContext *tc = tex->prepare_now(_gsg->get_prepared_objects(), _gsg);
nassertv(tc != (TextureContext *)NULL);
CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
GLenum target = wglgsg->get_texture_target(tex->get_texture_type());
if (target == GL_NONE) {
_textures[tex_index]._rtm_mode = RTM_copy_texture;
return;
}
GLP(BindTexture)(target, gtc->_index);
if (_gsg->get_properties().is_single_buffered()) {
wglgsg->_wglBindTexImageARB(_pbuffer, WGL_FRONT_LEFT_ARB);
} else {
wglgsg->_wglBindTexImageARB(_pbuffer, WGL_BACK_LEFT_ARB);
}
}
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: wglGraphicsBuffer::select_cube_map // Function: wglGraphicsBuffer::select_cube_map
// Access: Public, Virtual // Access: Public, Virtual
@ -231,29 +300,6 @@ open_buffer() {
} }
_pbuffer_dc = wglgsg->_wglGetPbufferDCARB(_pbuffer); _pbuffer_dc = wglgsg->_wglGetPbufferDCARB(_pbuffer);
if (wgldisplay_cat.is_debug()) {
wgldisplay_cat.debug()
<< "Created PBuffer " << _pbuffer << ", DC " << _pbuffer_dc << "\n";
switch (_rtm_mode) {
case RTM_bind_or_copy:
wgldisplay_cat.debug()
<< "pbuffer renders directly to texture.\n";
break;
case RTM_copy_texture:
wgldisplay_cat.debug()
<< "pbuffer copies indirectly into texture.\n";
break;
case RTM_copy_ram:
wgldisplay_cat.debug()
<< "pbuffer copies indirectly into system RAM.\n";
break;
default:
break;
}
}
wglMakeCurrent(_pbuffer_dc, wglgsg->get_context(_pbuffer_dc)); wglMakeCurrent(_pbuffer_dc, wglgsg->get_context(_pbuffer_dc));
wglgsg->report_my_gl_errors(); wglgsg->report_my_gl_errors();
@ -286,9 +332,15 @@ make_pbuffer(HDC twindow_dc) {
if (wglgsg->_supports_pixel_format) { if (wglgsg->_supports_pixel_format) {
bool got_pbuffer_format = false; bool got_pbuffer_format = false;
bool any_binds = false;
if ((_rtm_mode == RTM_bind_or_copy) && for (int i=0; i<count_textures(); i++) {
wglgsg->_supports_render_texture) { if (get_rtm_mode(i) == RTM_bind_or_copy) {
any_binds = true;
}
}
if (any_binds && wglgsg->_supports_render_texture) {
// First, try to get a pbuffer format that supports // First, try to get a pbuffer format that supports
// render-to-texture. // render-to-texture.
int new_pbformat = choose_pbuffer_format(twindow_dc, true); int new_pbformat = choose_pbuffer_format(twindow_dc, true);
@ -299,8 +351,13 @@ make_pbuffer(HDC twindow_dc) {
} }
if (!got_pbuffer_format) { if (!got_pbuffer_format) {
// Failing that, just get a matching pbuffer format. // Failing that, just get a matching pbuffer format,
_rtm_mode = RTM_copy_texture; // and disable RTM_bind_or_copy.
for (int i=0; i<count_textures(); i++) {
if (get_rtm_mode(i) == RTM_bind_or_copy) {
_textures[i]._rtm_mode = RTM_copy_texture;
}
}
int new_pbformat = choose_pbuffer_format(twindow_dc, false); int new_pbformat = choose_pbuffer_format(twindow_dc, false);
if (new_pbformat != 0) { if (new_pbformat != 0) {
pbformat = new_pbformat; pbformat = new_pbformat;
@ -322,8 +379,18 @@ make_pbuffer(HDC twindow_dc) {
int iattrib_list[max_attrib_list]; int iattrib_list[max_attrib_list];
int ni = 0; int ni = 0;
if (_rtm_mode == RTM_bind_or_copy) { // Find the texture to bind to the color buffer.
nassertr(_texture != (Texture *)NULL, false); Texture *bindtexture = NULL;
for (int i=0; i<count_textures(); i++) {
if ((get_rtm_mode(i) == RTM_bind_or_copy)&&
(get_texture(i)->get_format() != Texture::F_depth_component)&&
(get_texture(i)->get_format() != Texture::F_stencil_index)) {
bindtexture = get_texture(i);
break;
}
}
if (bindtexture != 0) {
if (_gsg->get_properties().get_frame_buffer_mode() & FrameBufferProperties::FM_alpha) { if (_gsg->get_properties().get_frame_buffer_mode() & FrameBufferProperties::FM_alpha) {
iattrib_list[ni++] = WGL_TEXTURE_FORMAT_ARB; iattrib_list[ni++] = WGL_TEXTURE_FORMAT_ARB;
@ -333,12 +400,12 @@ make_pbuffer(HDC twindow_dc) {
iattrib_list[ni++] = WGL_TEXTURE_RGB_ARB; iattrib_list[ni++] = WGL_TEXTURE_RGB_ARB;
} }
if (_texture->uses_mipmaps()) { if (bindtexture->uses_mipmaps()) {
iattrib_list[ni++] = WGL_MIPMAP_TEXTURE_ARB; iattrib_list[ni++] = WGL_MIPMAP_TEXTURE_ARB;
iattrib_list[ni++] = 1; iattrib_list[ni++] = 1;
} }
switch (_texture->get_texture_type()) { switch (bindtexture->get_texture_type()) {
case Texture::TT_cube_map: case Texture::TT_cube_map:
iattrib_list[ni++] = WGL_TEXTURE_TARGET_ARB; iattrib_list[ni++] = WGL_TEXTURE_TARGET_ARB;
iattrib_list[ni++] = WGL_TEXTURE_CUBE_MAP_ARB; iattrib_list[ni++] = WGL_TEXTURE_CUBE_MAP_ARB;

View File

@ -52,6 +52,9 @@ public:
virtual void make_current(); virtual void make_current();
virtual void release_gsg(); virtual void release_gsg();
virtual void begin_render_texture();
virtual void end_render_texture();
virtual void process_events(); virtual void process_events();
protected: protected:

View File

@ -63,66 +63,6 @@ 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);
CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
GLenum target = get_texture_target(tex->get_texture_type());
if (target == GL_NONE) {
// Invalid texture, can't bind it.
return false;
}
GLP(BindTexture)(target, gtc->_index);
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 // Function: wglGraphicsStateGuardian::reset
// Access: Public, Virtual // Access: Public, Virtual

View File

@ -43,9 +43,6 @@ public:
INLINE bool made_context() const; INLINE bool made_context() const;
INLINE HGLRC get_context(HDC hdc); 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(); virtual void reset();
INLINE HDC get_twindow_dc(); INLINE HDC get_twindow_dc();