mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 10:22:45 -04:00
More work on glGraphicsBuffers (will compile soon)
This commit is contained in:
parent
67f79bc9c4
commit
f35a7469d0
@ -24,14 +24,32 @@ TypeHandle CLP(GraphicsBuffer)::_type_handle;
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CLP(GraphicsBuffer)::
|
||||
CLP(GraphicsBuffer)(GraphicsPipe *pipe, GraphicsStateGuardian *gsg,
|
||||
CLP(GraphicsBuffer)(GraphicsPipe *pipe,
|
||||
const string &name,
|
||||
int x_size, int y_size) :
|
||||
GraphicsBuffer(pipe, gsg, name, x_size, y_size)
|
||||
int x_size, int y_size, int flags,
|
||||
GraphicsStateGuardian *gsg,
|
||||
GraphicsOutput *host) :
|
||||
GraphicsBuffer(pipe, name, x_size, y_size, flags, gsg, host)
|
||||
{
|
||||
// Since the FBO never gets flipped, we get screenshots from the
|
||||
// same buffer we draw into.
|
||||
_screenshot_buffer_type = _draw_buffer_type;
|
||||
|
||||
// Initialize these.
|
||||
_fbo = 0;
|
||||
_rb_size_x = 0;
|
||||
_rb_size_y = 0;
|
||||
for (int i=0; i<SLOT_COUNT; i++) {
|
||||
_rb[i] = 0;
|
||||
_attached[i] = 0;
|
||||
}
|
||||
_attach_point[SLOT_depth] = GL_DEPTH_ATTACHMENT_EXT;
|
||||
_attach_point[SLOT_stencil] = GL_STENCIL_ATTACHMENT_EXT;
|
||||
_attach_point[SLOT_color] = GL_COLOR_ATTACHMENT0_EXT;
|
||||
|
||||
_slot_format[SLOT_depth] = GL_DEPTH_COMPONENT;
|
||||
_slot_format[SLOT_stencil] = GL_STENCIL_INDEX;
|
||||
_slot_format[SLOT_color] = GL_RGBA;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -44,7 +62,7 @@ CLP(GraphicsBuffer)::
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: wglGraphicsBuffer::begin_frame
|
||||
// Function: glGraphicsBuffer::begin_frame
|
||||
// Access: Public, Virtual
|
||||
// Description: This function will be called within the draw thread
|
||||
// before beginning rendering for a given frame. It
|
||||
@ -52,12 +70,10 @@ CLP(GraphicsBuffer)::
|
||||
// if the frame should be rendered, or false if it
|
||||
// should be skipped.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool wglGraphicsBuffer::
|
||||
bool glGraphicsBuffer::
|
||||
begin_frame(FrameMode mode) {
|
||||
PStatTimer timer(_make_current_pcollector);
|
||||
|
||||
begin_frame_spam();
|
||||
if (_gsg == (GraphicsStateGuardian *)NULL) {
|
||||
if (!_is_valid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -65,45 +81,220 @@ begin_frame(FrameMode mode) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_track_host_size) {
|
||||
// Figure out the desired size of the buffer.
|
||||
if (mode == FM_render) {
|
||||
rebuild_bitplanes();
|
||||
clear_cube_map_selection();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: glGraphicsBuffer::rebuild_bitplanes
|
||||
// Access: Public, Virtual
|
||||
// Description: This function will be called within the draw thread
|
||||
// to allocate/reallocate the fbo and all the associated
|
||||
// renderbuffers, just before rendering a frame.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void glGraphicsBuffer::
|
||||
rebuild_bitplanes() {
|
||||
|
||||
glGraphicsStateGuardian *glgsg;
|
||||
DCAST_INTO_R(glgsg, _gsg, false);
|
||||
|
||||
// Bind the FBO
|
||||
|
||||
if (_fbo == 0) {
|
||||
glgsg->_glGenFramebuffersEXT(1, &_fbo);
|
||||
if (_fbo == 0) {
|
||||
glgsg->report_my_gl_errors();
|
||||
return;
|
||||
}
|
||||
}
|
||||
glgsg->_glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _fbo);
|
||||
|
||||
// Calculate bitplane size. This can be larger than the buffer.
|
||||
|
||||
if (_creation_flags & GraphicsPipe::BF_track_host_size) {
|
||||
if ((_host->get_x_size() != _x_size)||
|
||||
(_host->get_y_size() != _y_size)) {
|
||||
set_size_and_recalc(_host->get_x_size(),
|
||||
_host->get_y_size());
|
||||
}
|
||||
}
|
||||
int desired_x = _x_size;
|
||||
int desired_y = _y_size;
|
||||
if (!glgsg->get_supports_tex_non_pow2()) {
|
||||
desired_x = Texture::up_to_power_2(desired_x);
|
||||
desired_y = Texture::up_to_power_2(desired_y);
|
||||
}
|
||||
|
||||
// This function also contains the code to *reopen* the window
|
||||
// in the event that configuration parameters (ie, size, texture
|
||||
// bindings) have changed.
|
||||
open_window();
|
||||
// Scan the textures list and determine what should be attached.
|
||||
|
||||
// bind the FBO
|
||||
Texture *attach[SLOT_COUNT];
|
||||
for (int i=0; i<SLOT_COUNT; i++) {
|
||||
attach[i] = 0;
|
||||
}
|
||||
for (int i=0; i<count_textures(); i++) {
|
||||
if (get_rtm_mode(i) != RTM_bind_or_copy) {
|
||||
continue;
|
||||
}
|
||||
Texture *tex = get_texture(i);
|
||||
Texture::Format fmt = tex->get_format();
|
||||
|
||||
if (mode == FM_render) {
|
||||
begin_render_texture();
|
||||
clear_cube_map_selection();
|
||||
// If it's a not a 2D texture or a cube map, punt it.
|
||||
if ((tex->get_texture_type() != Texture::TT_2d_texture)&&
|
||||
(tex->get_texture_type() != Texture::TT_cube_map)) {
|
||||
_rtm_mode[i] = RTM_copy_texture;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Identify right attachment point.
|
||||
|
||||
int slot = SLOT_COUNT;
|
||||
if (fmt == Texture::F_depth_component) {
|
||||
slot = SLOT_depth;
|
||||
} else if (fmt == Texture::F_stencil_index) {
|
||||
slot = SLOT_stencil;
|
||||
} else if (fmt == Texture::F_rgba) {
|
||||
slot = SLOT_color;
|
||||
} else {
|
||||
_rtm_mode[i] = RTM_copy_texture;
|
||||
continue;
|
||||
}
|
||||
|
||||
// If there's already a texture bound to this slot,
|
||||
// then punt this texture.
|
||||
if (attach[slot]) {
|
||||
_rtm_mode[i] = RTM_copy_texture;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Assign the texture to this slot.
|
||||
attach[slot] = tex;
|
||||
}
|
||||
|
||||
|
||||
// For all slots, update the slot.
|
||||
|
||||
for (int slot=0; slot<SLOT_COUNT; slot++) {
|
||||
Texture *tex = attach[slot];
|
||||
if (tex) {
|
||||
// If the texture is already bound to the slot, and it's
|
||||
// the right size, then no update of this slot is needed.
|
||||
if ((_tex[slot] == tex)&&
|
||||
(tex->get_x_size() == desired_x)&&
|
||||
(tex->get_y_size() == desired_y)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Bind the texture to the slot.
|
||||
tex->set_x_size(desired_x);
|
||||
tex->set_y_size(desired_y);
|
||||
TextureContext *tc = tex->prepare_now(get_prepared_objects(), this);
|
||||
nassertv(tc != (TextureContext *)NULL);
|
||||
CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
|
||||
|
||||
if (tex->get_texture_type() == Texture::TT_2d_texture) {
|
||||
glgsg->_glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, _attach_point[slot],
|
||||
GL_TEXTURE_2D, gtc->_index, 0);
|
||||
} else {
|
||||
glgsg->_glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, _attach_point[slot],
|
||||
GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, gtc->_index, 0);
|
||||
}
|
||||
_tex[slot] = tex;
|
||||
|
||||
// If there was a renderbuffer bound to this slot, delete it.
|
||||
if (_rb[slot] != 0) {
|
||||
glgsg->_glDeleteRenderbuffers(1, &(_rb[slot]));
|
||||
_rb[slot] = 0;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// If a renderbuffer is already attached to the slot, and it's
|
||||
// the right size, then no update of this slot is needed.
|
||||
if ((_rb[slot] != 0)&&
|
||||
(_rb_size_x == desired_x)&&
|
||||
(_rb_size_y == desired_y)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If there's no renderbuffer for this slot, create one.
|
||||
if (_rb[slot] == 0) {
|
||||
glgsg->_glGenRenderbuffers(1, &(_rb[slot]));
|
||||
}
|
||||
|
||||
// Resize the renderbuffer appropriately.
|
||||
glgsg->_glBindRenderbuffer(GL_RENDERBUFFER_EXT, _rb[slot]);
|
||||
glgsg->_glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, _slot_format[slot],
|
||||
desired_x, desired_y);
|
||||
glgsg->_glBindRenderbuffer(GL_RENDERBUFFER_EXT, 0);
|
||||
|
||||
// Bind the renderbuffer to the slot.
|
||||
glgsg->_glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, _attach_point[slot],
|
||||
GL_RENDERBUFFER_EXT, _rb[slot]);
|
||||
|
||||
// Toss any texture that was connected to the slot.
|
||||
_tex[slot] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// These record the size of all nonzero renderbuffers.
|
||||
_rb_size_x = desired_x;
|
||||
_rb_size_y = desired_y;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: glGraphicsBuffer::generate_mipmaps
|
||||
// Access: Private
|
||||
// Description: This function will be called within the draw thread
|
||||
// after rendering is completed for a given frame.
|
||||
// If we've just rendered into level zero of a mipmapped
|
||||
// texture, then all subsequent mipmap levels will now
|
||||
// be calculated.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void glGraphicsBuffer::
|
||||
generate_mipmaps() {
|
||||
glGraphicsStateGuardian *glgsg;
|
||||
DCAST_INTO_R(glgsg, _gsg, false);
|
||||
|
||||
for (int slot=0; slot<SLOT_COUNT; slot++) {
|
||||
Texture *tex = _tex[slot];
|
||||
if ((tex != 0) && (tex->uses_mipmaps())) {
|
||||
glgsg->_state._texture = 0;
|
||||
TextureContext *tc = tex->prepare_now(get_prepared_objects(), this);
|
||||
nassert(tc != (TextureContext *)NULL);
|
||||
CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
|
||||
GLenum target = get_texture_target(tex->get_texture_type());
|
||||
GLP(BindTexture)(target, gtc->_index);
|
||||
glgsg->_glGenerateMipmap(target);
|
||||
GLP(BindTexture)(target, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: wglGraphicsBuffer::end_frame
|
||||
// Function: glGraphicsBuffer::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::
|
||||
void glGraphicsBuffer::
|
||||
end_frame(FrameMode mode) {
|
||||
end_frame_spam();
|
||||
nassertv(_gsg != (GraphicsStateGuardian *)NULL);
|
||||
|
||||
if (mode == FM_render) {
|
||||
end_render_texture();
|
||||
copy_to_textures();
|
||||
}
|
||||
|
||||
// Unbind the FBO
|
||||
glgsg->_glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
|
||||
|
||||
if (mode == FM_render) {
|
||||
generate_mipmaps();
|
||||
}
|
||||
|
||||
_host->end_frame(FM_parasite);
|
||||
|
||||
@ -127,68 +318,58 @@ end_frame(FrameMode mode) {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CLP(GraphicsBuffer)::
|
||||
select_cube_map(int cube_map_index) {
|
||||
open_buffer();
|
||||
GLCAT.error() << "select_cube_map not implemented yet.\n";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: wglGraphicsBuffer::open_buffer
|
||||
// Function: glGraphicsBuffer::open_buffer
|
||||
// Access: Protected, Virtual
|
||||
// Description: Opens the window right now. Called from the window
|
||||
// thread. Returns true if the window is successfully
|
||||
// opened, or false if there was a problem.
|
||||
//
|
||||
// This particular version of open_buffer is also
|
||||
// capable of reopening the buffer, which is necessary
|
||||
// if the texture bindings, size, or cube face has
|
||||
// changed. Caution: since this function is called
|
||||
// at every cube-map switch, it needs to be reasonably
|
||||
// fast in the case that little is changing.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool wglGraphicsBuffer::
|
||||
bool glGraphicsBuffer::
|
||||
open_buffer() {
|
||||
// Make sure the FBO is allocated.
|
||||
|
||||
// Figure out the desired size of the FBO
|
||||
int desired_x = _x_size;
|
||||
int desired_y = _y_size;
|
||||
if (!_gsg->get_supports_tex_non_pow2()) {
|
||||
desired_x = Texture::up_to_power_2(desired_x);
|
||||
desired_y = Texture::up_to_power_2(desired_y);
|
||||
// Check for support of relevant extensions.
|
||||
glGraphicsStateGuardian *glgsg;
|
||||
DCAST_INTO_R(glgsg, _gsg, false);
|
||||
if ((!glgsg->_supports_framebuffer_object)||
|
||||
(glgsg->_glDrawBuffers == 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Scan the textures list to see which textures should be attached.
|
||||
Texture *attach_color = 0;
|
||||
Texture *attach_depth = 0;
|
||||
Texture *attach_stencil = 0;
|
||||
|
||||
|
||||
// For all slots containing textures, detach if:
|
||||
// - they aren't supposed to be attached any more, or
|
||||
// - there is a size mismatch, or
|
||||
// - there is a cube-face mismatch
|
||||
|
||||
// For all renderbuffers, detach and deallocate if:
|
||||
// - there is a size mismatch, or,
|
||||
// - there is a texture to be attached at that point
|
||||
|
||||
// For all to-be-attached textures, attach if not already
|
||||
// attached. During attachment process, resize and reformat
|
||||
// if needed.
|
||||
|
||||
// For all unfilled slots, allocate and attach render buffers.
|
||||
_is_valid = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: wglGraphicsBuffer::close_buffer
|
||||
// Function: glGraphicsBuffer::close_buffer
|
||||
// Access: Protected, Virtual
|
||||
// Description: Closes the buffer right now. Called from the window
|
||||
// thread.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void wglGraphicsBuffer::
|
||||
void glGraphicsBuffer::
|
||||
close_buffer() {
|
||||
// Detach all renderbuffers
|
||||
// Detach all textures
|
||||
// Deallocate the FBO itself.
|
||||
|
||||
// Get the glgsg.
|
||||
glGraphicsStateGuardian *glgsg;
|
||||
DCAST_INTO_R(glgsg, _gsg, false);
|
||||
|
||||
// Delete the renderbuffers.
|
||||
for (int i=0; i<SLOT_COUNT; i++) {
|
||||
if (_rb[i] != 0) {
|
||||
glgsg->_glDeleteRenderbuffersEXT(1, &(_rb[i]));
|
||||
_rb[i] = 0;
|
||||
}
|
||||
_tex[i] = 0;
|
||||
}
|
||||
_rb_size_x = 0;
|
||||
_rb_size_y = 0;
|
||||
|
||||
// Delete the FBO itself.
|
||||
nassertv(_fbo != 0, false);
|
||||
glgsg->_glDeleteFramebuffersEXT(1, &_fbo);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
@ -24,38 +24,38 @@
|
||||
// Class : glGraphicsBuffer
|
||||
// Description : An offscreen render buffer.
|
||||
//
|
||||
// The glGraphicsBuffer can export its color buffer as a
|
||||
// texture. It can also export its depth buffer as a depth
|
||||
// texture and its stencil buffer as a stencil texture.
|
||||
// Finally, it can have auxiliary buffers (additional
|
||||
// bitplanes above and beyond the usual set), which can
|
||||
// also be exported as textures. This is the key advantage
|
||||
// of the glGraphicsBuffer: it can render to many textures
|
||||
// at the same time.
|
||||
// The glGraphicsBuffer is based on the OpenGL
|
||||
// EXT_framebuffer_object and ARB_draw_buffers extensions.
|
||||
// This design has three significant advantages over the
|
||||
// wglGraphicsBuffer and glxGraphicsBuffer.
|
||||
//
|
||||
// The glGraphicsBuffer shares a gsg with a host window.
|
||||
// If the host window is destroyed, the glGraphicsBuffer is
|
||||
// lost as well. If desired, the glGraphicsBuffer can
|
||||
// track the size of the host window.
|
||||
// As you might expect, this type of buffer can export
|
||||
// its color buffer as a texture. But it can also export
|
||||
// its depth buffer, its stencil buffer, and any number
|
||||
// of auxiliary buffers. This is the biggest advantage:
|
||||
// it can render to many textures at the same time.
|
||||
//
|
||||
// The glGraphicsBuffer is implemented using the following
|
||||
// OpenGL extensions:
|
||||
// There is also a speed advantage. When using a
|
||||
// glGraphicsBuffer, it is not necessary to call the
|
||||
// extremely expensive wglMakeCurrent on buffer switches.
|
||||
//
|
||||
// EXT_framebuffer_object
|
||||
// ARB_draw_buffers
|
||||
// The glGraphicsBuffer can also track the size of a host
|
||||
// window, and automatically resize itself to match.
|
||||
//
|
||||
// If any of these extensions is missing, then
|
||||
// glGraphicsBuffer is not available (although it may
|
||||
// still be possible to create a wglGraphicsBuffer or
|
||||
// glxGraphicsBuffer).
|
||||
// If either of the necessary OpenGL extensions is not
|
||||
// available, then the glGraphicsBuffer will not be
|
||||
// available (although it may still be possible to
|
||||
// create a wglGraphicsBuffer or glxGraphicsBuffer).
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
class EXPCL_GL CLP(GraphicsBuffer) : public GraphicsBuffer {
|
||||
public:
|
||||
CLP(GraphicsBuffer)(GraphicsPipe *pipe, GraphicsStateGuardian *gsg,
|
||||
CLP(GraphicsBuffer)(GraphicsPipe *pipe,
|
||||
const string &name,
|
||||
int x_size, int y_size);
|
||||
int x_size, int y_size, int flags,
|
||||
GraphicsStateGuardian *gsg,
|
||||
GraphicsOutput *host);
|
||||
virtual ~CLP(GraphicsBuffer)();
|
||||
|
||||
virtual bool begin_frame(FrameMode mode);
|
||||
@ -68,19 +68,24 @@ protected:
|
||||
virtual bool open_buffer();
|
||||
|
||||
private:
|
||||
PT(GraphicsOutput) _host;
|
||||
bool _track_host_size;
|
||||
|
||||
int _fbo;
|
||||
int _fbo_size_x;
|
||||
int _fbo_size_y;
|
||||
int _attached_cube_face;
|
||||
Texture *_attached_color;
|
||||
Texture *_attached_depth;
|
||||
Texture *_attached_stencil;
|
||||
int _attached_color_rb;
|
||||
int _attached_depth_rb;
|
||||
int _attached_stencil_rb;
|
||||
void generate_mipmaps();
|
||||
void rebuild_bitplanes();
|
||||
|
||||
enum {
|
||||
SLOT_color,
|
||||
SLOT_depth,
|
||||
SLOT_stencil,
|
||||
SLOT_COUNT
|
||||
};
|
||||
|
||||
GLuint _fbo;
|
||||
int _rb_size_x;
|
||||
int _rb_size_y;
|
||||
GLuint _rb[SLOT_COUNT];
|
||||
PT(Texture) _tex[SLOT_COUNT];
|
||||
GLenum _attach_point[SLOT_COUNT];
|
||||
GLenum _slot_format[SLOT_COUNT];
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user