Support for stereo FBOs

This commit is contained in:
rdb 2013-08-25 19:52:31 +00:00
parent fd3fb16ec1
commit eaab45dc9a
6 changed files with 161 additions and 38 deletions

View File

@ -108,6 +108,7 @@ GraphicsOutput(GraphicsEngine *engine, GraphicsPipe *pipe,
_flip_ready = false;
_cube_map_index = -1;
_cube_map_dr = NULL;
_tex_view_offset = -1;
_sort = 0;
_child_sort = 0;
_got_child_sort = false;
@ -1384,6 +1385,29 @@ change_scenes(DisplayRegionPipelineReader *new_dr) {
}
}
}
int new_tex_view_offset = new_dr->get_tex_view_offset();
if (new_tex_view_offset != _tex_view_offset) {
int old_tex_view_offset = _tex_view_offset;
//DisplayRegion *old_cube_map_dr = _cube_map_dr;
_tex_view_offset = new_tex_view_offset;
//_cube_map_dr = new_dr->get_object();
CDReader cdata(_cycler);
RenderTextures::const_iterator ri;
for (ri = cdata->_textures.begin(); ri != cdata->_textures.end(); ++ri) {
RenderTextureMode rtm_mode = (*ri)._rtm_mode;
Texture *texture = (*ri)._texture;
if (rtm_mode == RTM_bind_or_copy || rtm_mode == RTM_bind_layered) {
// In render-to-texture mode, switch the rendering backend to
// the new view, so that the subsequent frame will be
// rendered to the new view.
select_tex_view(new_tex_view_offset);
break;
}
}
}
}
////////////////////////////////////////////////////////////////////
@ -1399,6 +1423,18 @@ void GraphicsOutput::
select_cube_map(int) {
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsOutput::select_tex_view
// Access: Public, Virtual
// Description: Called internally when the window is in
// render-to-a-texture mode and the DisplayRegion
// requests that we switch rendering to a different
// texture view.
////////////////////////////////////////////////////////////////////
void GraphicsOutput::
select_tex_view(int) {
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsOutput::begin_flip
// Access: Public, Virtual

View File

@ -261,6 +261,7 @@ public:
void change_scenes(DisplayRegionPipelineReader *new_dr);
virtual void select_cube_map(int cube_map_index);
virtual void select_tex_view(int tex_view_offset);
// These methods will be called within the app (main) thread.
virtual void begin_flip();
@ -312,6 +313,7 @@ protected:
bool _flip_ready;
int _cube_map_index;
DisplayRegion *_cube_map_dr;
int _tex_view_offset;
PT(Geom) _texture_card;
bool _trigger_copy;

View File

@ -52,24 +52,9 @@ StereoDisplayRegion::
////////////////////////////////////////////////////////////////////
void StereoDisplayRegion::
set_clear_active(int n, bool clear_active) {
// The clear_active flag gets set only on the parent, stereo display
// region.
DisplayRegion::set_clear_active(n, clear_active);
// Except for depth and stencil buffers. These also get set on the
// right display region by default, on the assumption that we want
// to clear these buffers between drawing the eyes, and that the
// right eye is the second of the pair.
switch (n) {
case RTP_stencil:
case RTP_depth_stencil:
case RTP_depth:
_right_eye->set_clear_active(n, clear_active);
break;
default:
break;
}
//DisplayRegion::set_clear_active(n, clear_active);
_left_eye->set_clear_active(n, clear_active);
_right_eye->set_clear_active(n, clear_active);
}
////////////////////////////////////////////////////////////////////
@ -79,7 +64,7 @@ set_clear_active(int n, bool clear_active) {
////////////////////////////////////////////////////////////////////
void StereoDisplayRegion::
set_clear_value(int n, const LColor &clear_value) {
DisplayRegion::set_clear_value(n, clear_value);
//DisplayRegion::set_clear_value(n, clear_value);
_left_eye->set_clear_value(n, clear_value);
_right_eye->set_clear_value(n, clear_value);
}

View File

@ -81,6 +81,7 @@ CLP(GraphicsBuffer)(GraphicsEngine *engine, GraphicsPipe *pipe,
_shared_depth_buffer = 0;
_active_cube_map_index = -1;
_bound_tex_view = 0;
}
////////////////////////////////////////////////////////////////////
@ -304,6 +305,7 @@ rebuild_bitplanes() {
for (size_t i = 0; i != cdata->_textures.size(); ++i) {
const RenderTexture &rt = cdata->_textures[i];
RenderTextureMode rtm_mode = rt._rtm_mode;
RenderTexturePlane plane = rt._plane;
Texture *tex = rt._texture;
if (rtm_mode == RTM_bind_layered) {
@ -311,11 +313,13 @@ rebuild_bitplanes() {
GLCAT.warning()
<< "All textures attached to layered FBO should have the same layer count!\n";
}
} else if (tex->get_z_size() > 1) {
num_fbos = max(num_fbos, tex->get_z_size());
// Assign the texture to this slot.
attach[plane] = tex;
continue;
}
if (rtm_mode != RTM_bind_or_copy && rtm_mode != RTM_bind_layered) {
if (rtm_mode != RTM_bind_or_copy) {
continue;
}
@ -339,12 +343,15 @@ rebuild_bitplanes() {
// If I can't find an appropriate slot, or if there's
// already a texture bound to this slot, then punt
// this texture.
RenderTexturePlane plane = rt._plane;
if (attach[plane]) {
((CData *)cdata.p())->_textures[i]._rtm_mode = RTM_copy_texture;
continue;
}
if (tex->get_z_size() > 1) {
num_fbos = max(num_fbos, tex->get_z_size());
}
// Assign the texture to this slot.
attach[plane] = tex;
}
@ -491,6 +498,7 @@ rebuild_bitplanes() {
_fb_properties.set_alpha_bits(0);
}
_bound_tex_view = 0;
_initial_clear = false;
report_my_gl_errors();
@ -1030,6 +1038,20 @@ end_frame(FrameMode mode, Thread *current_thread) {
report_my_gl_errors();
}
////////////////////////////////////////////////////////////////////
// Function: glGraphicsBuffer::set_size
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
void CLP(GraphicsBuffer)::
set_size(int x, int y) {
if (_x_size != x || _y_size != y) {
_needs_rebuild = true;
}
set_size_and_recalc(x, y);
}
////////////////////////////////////////////////////////////////////
// Function: glGraphicsBuffer::select_cube_map
// Access: Public, Virtual
@ -1059,6 +1081,79 @@ select_cube_map(int cube_map_index) {
report_my_gl_errors();
}
////////////////////////////////////////////////////////////////////
// Function: glGraphicsBuffer::select_tex_view
// Access: Public, Virtual
// Description: Called internally when the window is in
// render-to-a-texture mode and the DisplayRegion
// requests that we switch rendering to a different
// texture view.
//
// In the FBO case, we do this by re-binding the
// texture that is attached to the color plane.
////////////////////////////////////////////////////////////////////
void CLP(GraphicsBuffer)::
select_tex_view(int view) {
CLP(GraphicsStateGuardian) *glgsg;
DCAST_INTO_V(glgsg, _gsg);
if (view == _bound_tex_view) {
return;
}
// We assume that we've already configured the texture earlier
// in bind_bitplanes. Therefore, since we can safely assume that
// all texture views have the same format, we can just bind the
// new view here.
Texture *tex = _tex[RTP_color];
if (tex != NULL) {
if (view >= tex->get_num_views()) {
tex->set_num_views(view + 1);
}
GLenum target = glgsg->get_texture_target(tex->get_texture_type());
if (target == GL_TEXTURE_CUBE_MAP) {
target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + _active_cube_map_index;
}
// Create the OpenGL texture object.
TextureContext *tc = tex->prepare_now(view, glgsg->get_prepared_objects(), glgsg);
nassertv(tc != (TextureContext *)NULL);
CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
glgsg->update_texture(tc, true);
GLCAT.spam() << "Binding texture " << *tex
<< " view " << view << " to color attachment.\n";
#ifndef OPENGLES
GLclampf priority = 1.0f;
glPrioritizeTextures(1, &gtc->_index, &priority);
#endif
glgsg->update_texture(tc, true);
if (_rb_size_z == 1) {
if (target == GL_TEXTURE_3D) {
glgsg->_glFramebufferTexture3D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
target, gtc->_index, 0, _active_cube_map_index);
} else if (target == GL_TEXTURE_2D_ARRAY_EXT) {
glgsg->_glFramebufferTextureLayer(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
gtc->_index, 0, _active_cube_map_index);
} else {
glgsg->_glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
target, gtc->_index, 0);
}
} else {
glgsg->_glFramebufferTexture(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
gtc->_index, 0);
}
report_my_gl_errors();
}
_bound_tex_view = view;
}
////////////////////////////////////////////////////////////////////
// Function: glGraphicsBuffer::open_buffer
// Access: Protected, Virtual
@ -1139,7 +1234,7 @@ open_buffer() {
_fb_properties.set_back_buffers(0);
_fb_properties.set_indexed_color(0);
_fb_properties.set_rgb_color(1);
_fb_properties.set_stereo(0);
//_fb_properties.set_stereo(0);
_fb_properties.set_force_hardware(_host->get_fb_properties().get_force_hardware());
_fb_properties.set_force_software(_host->get_fb_properties().get_force_software());

View File

@ -72,7 +72,10 @@ public:
virtual bool begin_frame(FrameMode mode, Thread *current_thread);
virtual void end_frame(FrameMode mode, Thread *current_thread);
virtual void set_size(int x, int y);
virtual void select_cube_map(int cube_map_index);
virtual void select_tex_view(int tex_view_offset);
virtual bool share_depth_buffer(GraphicsOutput *graphics_output);
virtual void unshare_depth_buffer();
@ -127,6 +130,7 @@ private:
// The cube map face we are currently drawing to or have just
// finished drawing to, or -1 if we are not drawing to a cube map.
int _active_cube_map_index;
int _bound_tex_view;
bool _initial_clear;
bool _needs_rebuild;

View File

@ -1939,6 +1939,16 @@ clear(DrawableRegion *clearable) {
}
}
// In the past, it was possible to set the draw buffer
// once in prepare_display_region and then forget about it.
// Now, with aux layers, it is necessary to occasionally
// change the draw buffer. In time, I think there will need
// to be a draw buffer attrib. Until then, this little hack
// to put things back the way they were after
// prepare_display_region will do.
set_draw_buffer(_draw_buffer_type);
if (_current_properties->get_color_bits() > 0) {
if (clearable->get_clear_color_active()) {
LColor v = clearable->get_clear_color();
@ -1948,7 +1958,6 @@ clear(DrawableRegion *clearable) {
}
_state_mask.clear_bit(ColorWriteAttrib::get_class_slot());
mask |= GL_COLOR_BUFFER_BIT;
set_draw_buffer(clearable->get_draw_buffer_type());
}
}
@ -1971,18 +1980,8 @@ clear(DrawableRegion *clearable) {
GLP(ClearStencil)(clearable->get_clear_stencil());
mask |= GL_STENCIL_BUFFER_BIT;
}
GLP(Clear)(mask);
// In the past, it was possible to set the draw buffer
// once in prepare_display_region and then forget about it.
// Now, with aux layers, it is necessary to occasionally
// change the draw buffer. In time, I think there will need
// to be a draw buffer attrib. Until then, this little hack
// to put things back the way they were after
// prepare_display_region will do.
set_draw_buffer(_draw_buffer_type);
if (GLCAT.is_spam()) {
GLCAT.spam() << "glClear(";
@ -2225,7 +2224,8 @@ end_scene() {
GraphicsStateGuardian::end_scene();
#ifndef OPENGLES_1
if (_vertex_array_shader_context != 0) {
// This breaks shaders across multiple regions.
/*if (_vertex_array_shader_context != 0) {
_vertex_array_shader_context->disable_shader_vertex_arrays(this);
_vertex_array_shader = (Shader *)NULL;
_vertex_array_shader_context = (CLP(ShaderContext) *)NULL;
@ -2239,7 +2239,7 @@ end_scene() {
_current_shader_context->unbind(this);
_current_shader = (Shader *)NULL;
_current_shader_context = (CLP(ShaderContext) *)NULL;
}
}*/
#endif
_dlights.clear();
@ -4648,6 +4648,7 @@ do_issue_shader(bool state_has_changed) {
if (!shader) {
shader = _default_shader;
}
#endif
if (shader) {
context = (CLP(ShaderContext) *)(shader->prepare_now(get_prepared_objects(), this));