From 2274f2e651b8ac07b93d5069835eec229b06aa8b Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 13 Aug 2013 12:44:27 +0000 Subject: [PATCH] FBO overhaul: support layered framebuffers (RTM_bind_layered), support render-to-2d-array, better respect FrameBufferProperties, more simple handling of RTP_depth_stencil --- panda/src/cocoadisplay/cocoaGraphicsPipe.mm | 6 +- panda/src/display/graphicsEngine.cxx | 3 +- panda/src/display/graphicsOutput.cxx | 45 +- panda/src/display/graphicsOutput.h | 24 +- panda/src/display/graphicsPipe.h | 1 + panda/src/display/graphicsStateGuardian.cxx | 4 +- panda/src/glstuff/glGraphicsBuffer_src.cxx | 647 ++++++++++++------ panda/src/glstuff/glGraphicsBuffer_src.h | 5 +- .../glstuff/glGraphicsStateGuardian_src.cxx | 210 ++++-- .../src/glstuff/glGraphicsStateGuardian_src.h | 6 + panda/src/glxdisplay/glxGraphicsPipe.cxx | 17 +- panda/src/osxdisplay/osxGraphicsPipe.cxx | 8 +- panda/src/wgldisplay/wglGraphicsPipe.cxx | 6 +- 13 files changed, 656 insertions(+), 326 deletions(-) diff --git a/panda/src/cocoadisplay/cocoaGraphicsPipe.mm b/panda/src/cocoadisplay/cocoaGraphicsPipe.mm index d172a436b2..8a66bfd87a 100644 --- a/panda/src/cocoadisplay/cocoaGraphicsPipe.mm +++ b/panda/src/cocoadisplay/cocoaGraphicsPipe.mm @@ -314,7 +314,8 @@ make_output(const string &name, ((flags&BF_size_track_host)!=0)|| ((flags&BF_rtt_cumulative)!=0)|| ((flags&BF_can_bind_color)!=0)|| - ((flags&BF_can_bind_every)!=0)) { + ((flags&BF_can_bind_every)!=0)|| + ((flags&BF_can_bind_layered)!=0)) { return NULL; } return new CocoaGraphicsWindow(engine, this, name, fb_prop, win_prop, @@ -359,7 +360,8 @@ make_output(const string &name, if (((flags&BF_require_parasite)!=0)|| ((flags&BF_require_window)!=0)|| ((flags&BF_resizeable)!=0)|| - ((flags&BF_size_track_host)!=0)) { + ((flags&BF_size_track_host)!=0)|| + ((flags&BF_can_bind_layered)!=0)) { return NULL; } diff --git a/panda/src/display/graphicsEngine.cxx b/panda/src/display/graphicsEngine.cxx index 1a1ddc3eda..2b036f5beb 100644 --- a/panda/src/display/graphicsEngine.cxx +++ b/panda/src/display/graphicsEngine.cxx @@ -368,7 +368,8 @@ make_output(GraphicsPipe *pipe, ((flags&GraphicsPipe::BF_refuse_parasite)==0)&& ((flags&GraphicsPipe::BF_can_bind_color)==0)&& ((flags&GraphicsPipe::BF_can_bind_every)==0)&& - ((flags&GraphicsPipe::BF_rtt_cumulative)==0)) { + ((flags&GraphicsPipe::BF_rtt_cumulative)==0)&& + ((flags&GraphicsPipe::BF_can_bind_layered)==0)) { if ((flags&GraphicsPipe::BF_fb_props_optional) || (host->get_fb_properties().subsumes(fb_prop))) { can_use_parasite = true; diff --git a/panda/src/display/graphicsOutput.cxx b/panda/src/display/graphicsOutput.cxx index 870f17e06a..b060b587a5 100644 --- a/panda/src/display/graphicsOutput.cxx +++ b/panda/src/display/graphicsOutput.cxx @@ -322,9 +322,9 @@ add_render_texture(Texture *tex, RenderTextureMode mode, // Choose a default bitplane. if (plane == RTP_COUNT) { - if (tex->get_format()==Texture::F_depth_stencil) { + if (tex->get_format() == Texture::F_depth_stencil) { plane = RTP_depth_stencil; - } else if (tex->get_format()==Texture::F_depth_component) { + } else if (tex->get_format() == Texture::F_depth_component) { plane = RTP_depth; } else { plane = RTP_color; @@ -339,6 +339,7 @@ add_render_texture(Texture *tex, RenderTextureMode mode, tex->set_match_framebuffer_format(true); } else if (plane == RTP_depth_stencil) { tex->set_format(Texture::F_depth_stencil); + tex->set_component_type(Texture::T_unsigned_int_24_8); tex->set_match_framebuffer_format(true); } else if ((plane == RTP_color)|| (plane == RTP_aux_rgba_0)|| @@ -358,6 +359,7 @@ add_render_texture(Texture *tex, RenderTextureMode mode, (plane == RTP_aux_float_2)|| (plane == RTP_aux_float_3)) { tex->set_format(Texture::F_rgba32); + tex->set_component_type(Texture::T_float); tex->set_match_framebuffer_format(true); } else { display_cat.error() << @@ -368,17 +370,32 @@ add_render_texture(Texture *tex, RenderTextureMode mode, // Go ahead and tell the texture our anticipated size, even if it // might be inaccurate (particularly if this is a GraphicsWindow, // which has system-imposed restrictions on size). - tex->set_size_padded(get_x_size(), get_y_size()); + tex->set_size_padded(get_x_size(), get_y_size(), tex->get_z_size()); - if (mode == RTM_bind_or_copy) { - if (!support_render_texture || !get_supports_render_texture()) { - // Binding is not supported or it is disabled, so just fall back - // to copy instead. + if (!support_render_texture || !get_supports_render_texture()) { + // Binding is not supported or it is disabled, so just fall back + // to copy instead. + if (mode == RTM_bind_or_copy) { mode = RTM_copy_texture; + } else if (mode == RTM_bind_layered) { + // We can't fallback to copy, because that doesn't work + // for layered textures. The best thing we can do is raise + // an error message. + display_cat.error() << + "add_render_texture: RTM_bind_layered was requested but " + "render-to-texture is not supported or has been disabled!\n"; } } - if (mode == RTM_bind_or_copy) { + if (mode == RTM_bind_layered && _gsg != NULL && !_gsg->get_supports_geometry_shaders()) { + // Layered FBOs require a geometry shader to write to + // any but the first layer. + display_cat.warning() << + "add_render_texture: RTM_bind_layered was requested but " + "geometry shaders are not supported!\n"; + } + + if (mode == RTM_bind_or_copy || mode == RTM_bind_layered) { // If we're still planning on binding, indicate it in texture // properly. tex->set_render_to_texture(true); @@ -1037,8 +1054,7 @@ make_cube_map(const string &name, int size, NodePath &camera_rig, buffer->set_clear_depth_active(false); buffer->set_clear_stencil_active(false); - PT(Lens) lens = new PerspectiveLens; - lens->set_fov(90.0f); + PT(Lens) lens = new PerspectiveLens(90, 90); for (int i = 0; i < 6; i++) { PT(Camera) camera = new Camera(cube_faces[i]._name); @@ -1336,7 +1352,7 @@ change_scenes(DisplayRegionPipelineReader *new_dr) { RenderTextureMode rtm_mode = (*ri)._rtm_mode; Texture *texture = (*ri)._texture; if (rtm_mode != RTM_none) { - if (rtm_mode == RTM_bind_or_copy) { + if (rtm_mode == RTM_bind_or_copy || rtm_mode == RTM_bind_layered) { // 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. @@ -1469,7 +1485,7 @@ prepare_for_deletion() { // buffer until all the textures are gone too. RenderTextures::iterator ri; for (ri = cdata->_textures.begin(); ri != cdata->_textures.end(); ++ri) { - if ((*ri)._rtm_mode == RTM_bind_or_copy) { + if ((*ri)._rtm_mode == RTM_bind_or_copy || (*ri)._rtm_mode == RTM_bind_layered) { _hold_textures.push_back((*ri)._texture); } } @@ -1488,7 +1504,10 @@ prepare_for_deletion() { // Function: GraphicsOutput::promote_to_copy_texture // Access: Protected // Description: If any textures are marked RTM_bind_or_copy, change -// them to RTM_copy_texture. +// them to RTM_copy_texture. This does not change +// textures that are set to RTM_bind_layered, as +// layered framebuffers aren't supported with +// RTM_copy_texture. //////////////////////////////////////////////////////////////////// void GraphicsOutput:: promote_to_copy_texture() { diff --git a/panda/src/display/graphicsOutput.h b/panda/src/display/graphicsOutput.h index 28348ac536..1d58096195 100644 --- a/panda/src/display/graphicsOutput.h +++ b/panda/src/display/graphicsOutput.h @@ -83,11 +83,29 @@ private: PUBLISHED: enum RenderTextureMode { RTM_none, + + // Try to render to the texture directly, but if that is + // not possible, fall back to RTM_copy_texture. RTM_bind_or_copy, + + // Copy the image from the buffer to the texture every frame. RTM_copy_texture, + + // Copy the image from the buffer to system RAM every frame. RTM_copy_ram, + + // Copy the image from the buffer to the texture after a + // call to trigger_copy(). RTM_triggered_copy_texture, + + // Copy the image from the buffer to system RAM after a + // call to trigger_copy(). RTM_triggered_copy_ram, + + // Render directly to a layered texture, such as a cube map, + // 3D texture or 2D texture array. The layer that is being + // rendered to is selected by a geometry shader. + RTM_bind_layered, }; // There are many reasons to call begin_frame/end_frame. @@ -167,7 +185,7 @@ PUBLISHED: INLINE int get_child_sort() const; INLINE void trigger_copy(); - + INLINE DisplayRegion *make_display_region(); INLINE DisplayRegion *make_display_region(PN_stdfloat l, PN_stdfloat r, PN_stdfloat b, PN_stdfloat t); DisplayRegion *make_display_region(const LVecBase4 &dimensions); @@ -233,7 +251,7 @@ public: virtual void clear_pipe(); void set_size_and_recalc(int x, int y); - + // It is an error to call any of the following methods from any // thread other than the draw thread. These methods are normally // called by the GraphicsEngine. @@ -262,7 +280,7 @@ protected: void prepare_for_deletion(); void promote_to_copy_texture(); bool copy_to_textures(); - + INLINE void begin_frame_spam(FrameMode mode); INLINE void end_frame_spam(FrameMode mode); INLINE void clear_cube_map_selection(); diff --git a/panda/src/display/graphicsPipe.h b/panda/src/display/graphicsPipe.h index 5c771e0a3e..998a81ace1 100644 --- a/panda/src/display/graphicsPipe.h +++ b/panda/src/display/graphicsPipe.h @@ -89,6 +89,7 @@ PUBLISHED: BF_fb_props_optional = 0x0800, // FrameBufferProperties can be ignored. BF_size_square = 0x1000, // x_size must equal y_size (e.g. for cube maps) BF_size_power_2 = 0x2000, // x_size and y_size must each be a power of two + BF_can_bind_layered = 0x4000, // Need capability: support RTM_bind_layered. }; INLINE bool is_valid() const; diff --git a/panda/src/display/graphicsStateGuardian.cxx b/panda/src/display/graphicsStateGuardian.cxx index 6694dabf9c..bd6316fa84 100644 --- a/panda/src/display/graphicsStateGuardian.cxx +++ b/panda/src/display/graphicsStateGuardian.cxx @@ -2722,9 +2722,9 @@ make_shadow_buffer(const NodePath &light_np, GraphicsOutputBase *host) { display_cat.error() << "PointLight shadow buffers must have an equal width and height!\n"; } - tex->setup_cube_map(light->_sb_xsize, Texture::T_float, Texture::F_depth_component); + tex->setup_cube_map(light->_sb_xsize, Texture::T_unsigned_byte, Texture::F_depth_component); } else { - tex->setup_2d_texture(light->_sb_xsize, light->_sb_ysize, Texture::T_float, Texture::F_depth_component); + tex->setup_2d_texture(light->_sb_xsize, light->_sb_ysize, Texture::T_unsigned_byte, Texture::F_depth_component); } tex->make_ram_image(); sbuffer->add_render_texture(tex, GraphicsOutput::RTM_bind_or_copy, GraphicsOutput::RTP_depth); diff --git a/panda/src/glstuff/glGraphicsBuffer_src.cxx b/panda/src/glstuff/glGraphicsBuffer_src.cxx index 6f72e4ce83..7a05dae167 100644 --- a/panda/src/glstuff/glGraphicsBuffer_src.cxx +++ b/panda/src/glstuff/glGraphicsBuffer_src.cxx @@ -13,7 +13,6 @@ //////////////////////////////////////////////////////////////////// TypeHandle CLP(GraphicsBuffer)::_type_handle; - //////////////////////////////////////////////////////////////////// // Function: glGraphicsBuffer::Constructor @@ -37,8 +36,6 @@ CLP(GraphicsBuffer)(GraphicsEngine *engine, GraphicsPipe *pipe, _screenshot_buffer_type = RenderBuffer::T_front; // Initialize these. - _num_faces = 0; - memset(_fbo, 0, sizeof(_fbo)); _fbo_multisample = 0; _initial_clear = true; _needs_rebuild = true; @@ -75,6 +72,7 @@ CLP(GraphicsBuffer)(GraphicsEngine *engine, GraphicsPipe *pipe, _rb_size_x = 0; _rb_size_y = 0; + _rb_size_z = 0; for (int i=0; i::iterator graphics_buffer_iterator; - graphics_buffer_iterator = _shared_depth_buffer_list.begin( ); - while (graphics_buffer_iterator != _shared_depth_buffer_list.end( )) { + graphics_buffer_iterator = _shared_depth_buffer_list.begin(); + while (graphics_buffer_iterator != _shared_depth_buffer_list.end()) { graphics_buffer = (*graphics_buffer_iterator); if (graphics_buffer) { // this call removes the entry from the list - graphics_buffer -> unshare_depth_buffer(); + graphics_buffer->unshare_depth_buffer(); } - graphics_buffer_iterator = _shared_depth_buffer_list.begin( ); + graphics_buffer_iterator = _shared_depth_buffer_list.begin(); } } } @@ -164,9 +162,9 @@ begin_frame(FrameMode mode, Thread *current_thread) { _needs_rebuild = true; } } - + rebuild_bitplanes(); - + if (_needs_rebuild) { // If we still need rebuild, something went wrong with // rebuild_bitplanes(). @@ -196,24 +194,28 @@ check_fbo() { GLCAT.error() << "EXT_framebuffer_object reports non-framebuffer-completeness:\n"; switch(status) { case GL_FRAMEBUFFER_UNSUPPORTED_EXT: - GLCAT.error() << "FRAMEBUFFER_UNSUPPORTED_EXT"; break; + GLCAT.error() << "FRAMEBUFFER_UNSUPPORTED"; break; case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: - GLCAT.error() << "FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT"; break; + GLCAT.error() << "FRAMEBUFFER_INCOMPLETE_ATTACHMENT"; break; case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: - GLCAT.error() << "FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT"; break; + GLCAT.error() << "FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"; break; case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: - GLCAT.error() << "FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT"; break; + GLCAT.error() << "FRAMEBUFFER_INCOMPLETE_DIMENSIONS"; break; #ifndef OPENGLES_2 case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: - GLCAT.error() << "FRAMEBUFFER_INCOMPLETE_FORMATS_EXT"; break; + GLCAT.error() << "FRAMEBUFFER_INCOMPLETE_FORMATS"; break; #endif #ifndef OPENGLES case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: - GLCAT.error() << "FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT"; break; + GLCAT.error() << "FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER"; break; case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: - GLCAT.error() << "FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT"; break; + GLCAT.error() << "FRAMEBUFFER_INCOMPLETE_READ_BUFFER"; break; case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT: - GLCAT.error() << "FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT"; break; + GLCAT.error() << "FRAMEBUFFER_INCOMPLETE_MULTISAMPLE"; break; + case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_ARB: + GLCAT.error() << "FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS"; break; + case GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_ARB: + GLCAT.error() << "FRAMEBUFFER_INCOMPLETE_LAYER_COUNT"; break; #endif default: GLCAT.error() << "UNKNOWN PROBLEM " << (int)status; break; @@ -246,10 +248,14 @@ rebuild_bitplanes() { DCAST_INTO_V(glgsg, _gsg); if (!_needs_rebuild) { - glgsg->bind_fbo(_fbo[0]); + if (_fbo.size() > 0) { + glgsg->bind_fbo(_fbo[0]); + } else { + glgsg->bind_fbo(0); + } return; } - + // Calculate bitplane size. This can be larger than the buffer. if (_creation_flags & GraphicsPipe::BF_size_track_host) { if ((_host->get_x_size() != _x_size)|| @@ -271,34 +277,69 @@ rebuild_bitplanes() { _rb_size_y = bitplane_y; rb_resize = true; } - + _rb_size_z = 1; + + int num_fbos = 1; + // These variables indicate what should be bound to each bitplane. Texture *attach[RTP_COUNT]; memset(attach, 0, sizeof(Texture *) * RTP_COUNT); - + // Sort the textures list into appropriate slots. - bool any_cube_maps = false; { CDReader cdata(_cycler); + + // Determine whether this will be a layered or a regular FBO. + // If layered, the number of _rb_size_z will be higher than 1. for (size_t i = 0; i != cdata->_textures.size(); ++i) { const RenderTexture &rt = cdata->_textures[i]; RenderTextureMode rtm_mode = rt._rtm_mode; - if (rtm_mode != RTM_bind_or_copy) { + Texture *tex = rt._texture; + + if (rtm_mode == RTM_bind_layered) { + _rb_size_z = max(_rb_size_z, tex->get_z_size()); + } + } + + for (size_t i = 0; i != cdata->_textures.size(); ++i) { + const RenderTexture &rt = cdata->_textures[i]; + RenderTextureMode rtm_mode = rt._rtm_mode; + Texture *tex = rt._texture; + + if (rtm_mode == RTM_bind_layered) { + if (tex->get_z_size() != _rb_size_z) { + 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()); + } + + if (rtm_mode != RTM_bind_or_copy && rtm_mode != RTM_bind_layered) { continue; } - Texture *tex = rt._texture; - RenderTexturePlane plane = rt._plane; - - // If it's a not a 2D texture or a cube map, punt it. + + // If we can't bind this type of texture, punt it. if ((tex->get_texture_type() != Texture::TT_2d_texture) && + (tex->get_texture_type() != Texture::TT_3d_texture) && + (tex->get_texture_type() != Texture::TT_2d_texture_array) && (tex->get_texture_type() != Texture::TT_cube_map)) { ((CData *)cdata.p())->_textures[i]._rtm_mode = RTM_copy_texture; continue; } + if (_rb_size_z > 1 && tex->get_texture_type() == Texture::TT_2d_texture) { + // We can't bind a 2D texture to a layered FBO. If the user happened + // to request RTM_bind_layered for a 2D texture, that's just silly, + // and we can't render to anything but the first layer anyway. + ((CData *)cdata.p())->_textures[i]._rtm_mode = RTM_copy_texture; + continue; + } + // 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; @@ -306,55 +347,93 @@ rebuild_bitplanes() { // Assign the texture to this slot. attach[plane] = tex; - if (tex->get_texture_type() == Texture::TT_cube_map) { - any_cube_maps = true; - } } } - + + // Decide whether we should use a depth stencil or just a regular depth attachment. + // If nothing was attached to either RTP_depth_stencil or RTP_depth, we use a + // depth-stencil renderbuffer. + _use_depth_stencil = false; + if (_gsg->get_supports_depth_stencil()) { + if (attach[RTP_depth_stencil]) { + // This is the obvious case, of course. + _use_depth_stencil = true; + + } else if (attach[RTP_depth]) { + // We won't use a depth stencil texture as the user + // explicitly bound something to RTP_depth. + _use_depth_stencil = false; + + } else if (_fb_properties.get_depth_bits() > 24) { + // We can't give more than 24 depth bits with a depth-stencil buffer. + _use_depth_stencil = false; + + } else if (_fb_properties.get_stencil_bits() > 0) { + // The user requested stencil bits. Let's take the hint. + _use_depth_stencil = true; + + } else if (_fb_properties.get_depth_bits() > 0) { + // Let's use a depth stencil buffer by default, if a depth + // buffer was requested. + _use_depth_stencil = true; + } + } + + // Knowing this, we can already be a tiny bit + // more accurate about the framebuffer properties. + if (_use_depth_stencil) { + _fb_properties.set_depth_bits(24); + _fb_properties.set_stencil_bits(8); + } else { + _fb_properties.set_stencil_bits(0); + } + // Having both a depth texture and a depth_stencil texture is // invalid: depth_stencil implies depth, and we can't bind them // both. Detect that case, normalize it, and complain. - if (( attach[RTP_depth] != NULL ) && ( attach[RTP_depth_stencil] != NULL )) { + if (_use_depth_stencil && attach[RTP_depth] && attach[RTP_depth_stencil]) { attach[RTP_depth] = NULL; - GLCAT.warning() << "Attempt to bind both Depth and DepthStencil bitplanes.\n"; - } - - _num_faces = 1; - if (any_cube_maps) { - _num_faces = 6; + GLCAT.warning() << "Attempt to bind both RTP_depth and RTP_depth_stencil bitplanes.\n"; } // Now create the FBO's. - for (int face = 0; face < _num_faces; ++face) { + _fbo.reserve(num_fbos); + for (int layer = 0; layer < num_fbos; ++layer) { + if (layer >= _fbo.size()) { + _fbo.push_back(0); + } + // Bind the FBO - if (_fbo[face] == 0) { - glgsg->_glGenFramebuffers(1, &_fbo[face]); - if (_fbo[face] == 0) { + if (_fbo[layer] == 0) { + glgsg->_glGenFramebuffers(1, &_fbo[layer]); + if (_fbo[layer] == 0) { report_my_gl_errors(); return; } } - glgsg->bind_fbo(_fbo[face]); + glgsg->bind_fbo(_fbo[layer]); // For all slots, update the slot. - - bind_slot(face, rb_resize, attach, RTP_depth_stencil, GL_DEPTH_ATTACHMENT_EXT); - bind_slot(face, rb_resize, attach, RTP_depth, GL_DEPTH_ATTACHMENT_EXT); - bind_slot(face, rb_resize, attach, RTP_color, GL_COLOR_ATTACHMENT0_EXT); + if (_use_depth_stencil) { + bind_slot(layer, rb_resize, attach, RTP_depth_stencil, GL_DEPTH_ATTACHMENT_EXT); + } else if (attach[RTP_depth] || _fb_properties.get_depth_bits() > 0) { + bind_slot(layer, rb_resize, attach, RTP_depth, GL_DEPTH_ATTACHMENT_EXT); + } + + int next = GL_COLOR_ATTACHMENT0_EXT; + if (attach[RTP_color] || _fb_properties.get_color_bits() > 0) { + bind_slot(layer, rb_resize, attach, RTP_color, next++); + } + #ifndef OPENGLES - int next = GL_COLOR_ATTACHMENT1_EXT; for (int i=0; i<_fb_properties.get_aux_rgba(); i++) { - bind_slot(face, rb_resize, attach, (RenderTexturePlane)(RTP_aux_rgba_0+i), next); - next += 1; + bind_slot(layer, rb_resize, attach, (RenderTexturePlane)(RTP_aux_rgba_0+i), next++); } for (int i=0; i<_fb_properties.get_aux_hrgba(); i++) { - bind_slot(face, rb_resize, attach, (RenderTexturePlane)(RTP_aux_hrgba_0+i), next); - next += 1; + bind_slot(layer, rb_resize, attach, (RenderTexturePlane)(RTP_aux_hrgba_0+i), next++); } for (int i=0; i<_fb_properties.get_aux_float(); i++) { - bind_slot(face, rb_resize, attach, (RenderTexturePlane)(RTP_aux_float_0+i), next); - next += 1; + bind_slot(layer, rb_resize, attach, (RenderTexturePlane)(RTP_aux_float_0+i), next++); } #endif // OPENGLES @@ -366,26 +445,32 @@ rebuild_bitplanes() { } #ifndef OPENGLES - // Setup any required multisample buffers. - if (_requested_multisamples) { + // Setup any required multisample buffers. Does not work for layered buffers. + if (_requested_multisamples && _rb_size_z == 1) { if (_fbo_multisample == 0) { glgsg->_glGenFramebuffers(1, &_fbo_multisample); } glgsg->bind_fbo(_fbo_multisample); - bind_slot_multisample(rb_resize, attach, RTP_depth, GL_DEPTH_ATTACHMENT_EXT); - bind_slot_multisample(rb_resize, attach, RTP_color, GL_COLOR_ATTACHMENT0_EXT); - int next = GL_COLOR_ATTACHMENT1_EXT; + if (_use_depth_stencil || attach[RTP_depth] || _fb_properties.get_depth_bits() > 0) { + bind_slot_multisample(rb_resize, attach, RTP_depth, GL_DEPTH_ATTACHMENT_EXT); + } + + int next = GL_COLOR_ATTACHMENT0_EXT; + if (attach[RTP_color] || _fb_properties.get_color_bits() > 0) { + bind_slot_multisample(rb_resize, attach, RTP_color, next++); + } + for (int i=0; i<_fb_properties.get_aux_rgba(); i++) { - bind_slot_multisample(rb_resize, attach, (RenderTexturePlane)(RTP_aux_rgba_0+i), next); + bind_slot_multisample(rb_resize, attach, (RenderTexturePlane)(RTP_aux_rgba_0+i), next++); next += 1; } for (int i=0; i<_fb_properties.get_aux_hrgba(); i++) { - bind_slot_multisample(rb_resize, attach, (RenderTexturePlane)(RTP_aux_hrgba_0+i), next); + bind_slot_multisample(rb_resize, attach, (RenderTexturePlane)(RTP_aux_hrgba_0+i), next++); next += 1; } for (int i=0; i<_fb_properties.get_aux_float(); i++) { - bind_slot_multisample(rb_resize, attach, (RenderTexturePlane)(RTP_aux_float_0+i), next); + bind_slot_multisample(rb_resize, attach, (RenderTexturePlane)(RTP_aux_float_0+i), next++); next += 1; } glEnable(GL_MULTISAMPLE); @@ -432,96 +517,155 @@ rebuild_bitplanes() { // specified bitplane. //////////////////////////////////////////////////////////////////// void CLP(GraphicsBuffer):: -bind_slot(int face, bool rb_resize, Texture **attach, RenderTexturePlane slot, GLenum attachpoint) { +bind_slot(int layer, bool rb_resize, Texture **attach, RenderTexturePlane slot, GLenum attachpoint) { CLP(GraphicsStateGuardian) *glgsg; DCAST_INTO_V(glgsg, _gsg); -#ifdef OPENGLES - GLuint glFormat = GL_RGBA4; -#else - GLuint glFormat = GL_RGBA; - switch (slot) { - case RTP_aux_rgba_0: - case RTP_aux_rgba_1: - case RTP_aux_rgba_2: - case RTP_aux_rgba_3: - glFormat = GL_RGBA; - break; - case RTP_aux_hrgba_0: - case RTP_aux_hrgba_1: - case RTP_aux_hrgba_2: - case RTP_aux_hrgba_3: - glFormat = GL_RGBA16F_ARB; - break; - }; -#endif - Texture *tex = attach[slot]; - if (tex) { - bool is_cube_map = (tex->get_texture_type() == Texture::TT_cube_map); + _tex[slot] = tex; - GLenum target = GL_TEXTURE_2D; - if (is_cube_map) { - target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face; + if (tex && layer >= tex->get_z_size()) { + // If the requested layer index exceeds the number of layers + // in the texture, we will not bind this layer. + tex = NULL; + } + + if (!tex && _rb_size_z > 1) { + // Since there is no such thing as a layered renderbuffer (to my knowledge), + // we have to create a dummy texture to render to if no texture was provided. + tex = new Texture(); + + if (_rb_size_z > 1) { + // Apparently, it doesn't make a difference whether we use setup_cube_map + // or setup_2d_texture_array here, since it's the same internal storage. + tex->setup_2d_texture_array(_rb_size_z); + } else { + tex->setup_2d_texture(); + } + } + + if (tex) { + GLenum target = glgsg->get_texture_target(tex->get_texture_type()); + if (target == GL_TEXTURE_CUBE_MAP) { + target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer; } // Bind the texture to the slot. tex->set_x_size(_rb_size_x); tex->set_y_size(_rb_size_y); + if (target != GL_TEXTURE_CUBE_MAP && _rb_size_z > 1) { + tex->set_z_size(_rb_size_z); + } tex->set_pad_size(_rb_size_x - _x_size, _rb_size_y - _y_size); + // Adjust the texture format based on the requested framebuffer settings. + switch (slot) { + case RTP_depth: + if (_fb_properties.get_depth_bits() >= 32) { + tex->set_format(Texture::F_depth_component32); + } else if (_fb_properties.get_depth_bits() > 16) { + tex->set_format(Texture::F_depth_component24); + } else if (_fb_properties.get_depth_bits() > 8) { + tex->set_format(Texture::F_depth_component16); + } else { + tex->set_format(Texture::F_depth_component); + } + break; + case RTP_depth_stencil: + tex->set_format(Texture::F_depth_stencil); + tex->set_component_type(Texture::T_unsigned_int_24_8); + break; + case RTP_aux_hrgba_0: + case RTP_aux_hrgba_1: + case RTP_aux_hrgba_2: + case RTP_aux_hrgba_3: + tex->set_format(Texture::F_rgba16); + break; + case RTP_aux_float_0: + case RTP_aux_float_1: + case RTP_aux_float_2: + case RTP_aux_float_3: + tex->set_format(Texture::F_rgba32); + tex->set_component_type(Texture::T_float); + break; + default: + tex->set_format(Texture::F_rgba); + } + + // Create the OpenGL texture object. TextureContext *tc = tex->prepare_now(0, glgsg->get_prepared_objects(), glgsg); nassertv(tc != (TextureContext *)NULL); CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc); glgsg->update_texture(tc, true); - _use_depth_stencil = false; if (attachpoint == GL_DEPTH_ATTACHMENT_EXT) { - if ( _gsg->get_supports_depth_stencil() && tex->get_format() == Texture::F_depth_stencil ) { - tex->set_component_type(Texture::T_unsigned_int_24_8); - _use_depth_stencil = true; - } #ifndef OPENGLES GLclampf priority = 1.0f; glPrioritizeTextures(1, >c->_index, &priority); #endif - glgsg->_glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, - target, gtc->_index, 0); - if (_use_depth_stencil) { - glgsg->_glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, - target, gtc->_index, 0); + if (_rb_size_z == 1) { + if (target == GL_TEXTURE_3D) { + glgsg->_glFramebufferTexture3D(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, + target, gtc->_index, 0, layer); + } else if (target == GL_TEXTURE_2D_ARRAY_EXT) { + glgsg->_glFramebufferTextureLayer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, + gtc->_index, 0, layer); + } else { + glgsg->_glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, + target, gtc->_index, 0); + } + } else { + glgsg->_glFramebufferTexture(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, + gtc->_index, 0); } -#ifndef OPENGLES - GLint depth_size = 0, stencil_size = 0; + GLint depth_size = 0; GLP(GetTexLevelParameteriv)(target, 0, GL_TEXTURE_DEPTH_SIZE, &depth_size); - if (_use_depth_stencil) { - GLP(GetTexLevelParameteriv)(target, 0, GL_TEXTURE_STENCIL_SIZE, &stencil_size); - } _fb_properties.set_depth_bits(depth_size); - _fb_properties.set_stencil_bits(stencil_size); -#endif + + if (slot == RTP_depth_stencil) { + if (_rb_size_z == 1) { + if (target == GL_TEXTURE_3D) { + glgsg->_glFramebufferTexture3D(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, + target, gtc->_index, 0, layer); + } else if (target == GL_TEXTURE_2D_ARRAY_EXT) { + glgsg->_glFramebufferTextureLayer(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, + gtc->_index, 0, layer); + } else { + glgsg->_glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, + target, gtc->_index, 0); + } + } else { + glgsg->_glFramebufferTexture(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, + gtc->_index, 0); + } + + GLint stencil_size = 0; + GLP(GetTexLevelParameteriv)(target, 0, GL_TEXTURE_STENCIL_SIZE, &stencil_size); + _fb_properties.set_stencil_bits(stencil_size); + } } else { -#ifdef OPENGLES - tex->set_format(Texture::F_rgba4); -#else - if (glFormat == GL_RGBA16F_ARB) { - tex->set_format(Texture::F_rgba16); - } else if (glFormat == GL_RGBA32F_ARB) { - tex->set_format(Texture::F_rgba32); - } else { - tex->set_format(Texture::F_rgba); - } -#endif - #ifndef OPENGLES GLclampf priority = 1.0f; glPrioritizeTextures(1, >c->_index, &priority); #endif glgsg->update_texture(tc, true); - glgsg->_glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, attachpoint, - target, gtc->_index, 0); + if (_rb_size_z == 1) { + if (target == GL_TEXTURE_3D) { + glgsg->_glFramebufferTexture3D(GL_FRAMEBUFFER_EXT, attachpoint, + target, gtc->_index, 0, layer); + } else if (target == GL_TEXTURE_2D_ARRAY_EXT) { + glgsg->_glFramebufferTextureLayer(GL_FRAMEBUFFER_EXT, attachpoint, + gtc->_index, 0, layer); + } else { + glgsg->_glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, attachpoint, + target, gtc->_index, 0); + } + } else { + glgsg->_glFramebufferTexture(GL_FRAMEBUFFER_EXT, attachpoint, + gtc->_index, 0); + } #ifndef OPENGLES if (attachpoint == GL_COLOR_ATTACHMENT0_EXT) { GLint red_size = 0, green_size = 0, blue_size = 0, alpha_size = 0; @@ -536,28 +680,77 @@ bind_slot(int face, bool rb_resize, Texture **attach, RenderTexturePlane slot, G #endif } - _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; } + report_my_gl_errors(); + } else { - - // Disconnect from any texture that was previously bound to this slot. - _tex[slot] = 0; - -#ifndef OPENGLES_2 - // Check for the tricky case of a depth_stencil buffer: - // If we think we need one, but we have a texture bound in the depth slot, - // then we DON'T want to create a depth_stencil buffer here (because depth is - // a subset of depth_stencil). - if (( slot == RTP_depth_stencil ) && ( _gsg->get_supports_depth_stencil() != false ) && - ( attach[RTP_depth] != NULL )) { - return; + // No texture to bind. Instead, create a renderbuffer. + // Choose a suitable renderbuffer format based on the requirements. +#ifdef OPENGLES + GLuint gl_format = GL_RGBA4; + switch (slot) { + case RTP_depth_stencil: + gl_format = GL_DEPTH_STENCIL_OES; + break; + case RTP_depth: + gl_format = GL_DEPTH_COMPONENT16; + break; + //case RTP_stencil: + // gl_format = GL_STENCIL_INDEX8; + // break + default: + if (_fb_properties.get_alpha_bits() == 0) { + gl_format = GL_RGB565; + } else if (_fb_properties.get_color_bits() == 15 + && _fb_properties.get_alpha_bits() == 1) { + gl_format = GL_RGB5_A1; + } } +#else + GLuint gl_format = GL_RGBA; + switch (slot) { + case RTP_depth_stencil: + gl_format = GL_DEPTH_STENCIL_EXT; + break; + case RTP_depth: + if (_fb_properties.get_depth_bits() >= 32) { + gl_format = GL_DEPTH_COMPONENT32; + } else if (_fb_properties.get_depth_bits() > 16) { + gl_format = GL_DEPTH_COMPONENT24; + } else if (_fb_properties.get_depth_bits() > 8) { + gl_format = GL_DEPTH_COMPONENT16; + } else { + gl_format = GL_DEPTH_COMPONENT; + } + break; + case RTP_aux_rgba_0: + case RTP_aux_rgba_1: + case RTP_aux_rgba_2: + case RTP_aux_rgba_3: + gl_format = GL_RGBA; + break; + case RTP_aux_hrgba_0: + case RTP_aux_hrgba_1: + case RTP_aux_hrgba_2: + case RTP_aux_hrgba_3: + gl_format = GL_RGBA16F_ARB; + break; + case RTP_aux_float_0: + case RTP_aux_float_1: + case RTP_aux_float_2: + case RTP_aux_float_3: + gl_format = GL_RGBA32F_ARB; + break; + default: + if (_fb_properties.get_alpha_bits() == 0) { + gl_format = GL_RGB; + } + }; #endif // If there's no renderbuffer for this slot, create one. @@ -567,71 +760,51 @@ bind_slot(int face, bool rb_resize, Texture **attach, RenderTexturePlane slot, G // Allocate and bind the renderbuffer. glgsg->_glBindRenderbuffer(GL_RENDERBUFFER_EXT, _rb[slot]); - if (attachpoint == GL_DEPTH_ATTACHMENT_EXT) { -#ifndef OPENGLES_2 - if ( _gsg->get_supports_depth_stencil() != false ) { - if ( slot == RTP_depth_stencil ) { - glgsg->_glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_DEPTH_STENCIL_EXT, - _rb_size_x, _rb_size_y); - GLint depth_size = 0; - glgsg->_glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_DEPTH_SIZE_EXT, &depth_size); - _fb_properties.set_depth_bits(depth_size); - GLint stencil_size = 0; - glgsg->_glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_STENCIL_SIZE_EXT, &stencil_size); - _fb_properties.set_stencil_bits(stencil_size); + if (slot == RTP_depth_stencil) { + // Allocate renderbuffer storage for depth stencil. + GLint depth_size = 0, stencil_size = 0; + glgsg->_glRenderbufferStorage(GL_RENDERBUFFER_EXT, gl_format, _rb_size_x, _rb_size_y); + glgsg->_glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_DEPTH_SIZE_EXT, &depth_size); + glgsg->_glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_STENCIL_SIZE_EXT, &stencil_size); + _fb_properties.set_depth_bits(depth_size); + _fb_properties.set_stencil_bits(stencil_size); - glgsg->_glBindRenderbuffer(GL_RENDERBUFFER_EXT, 0); + glgsg->_glBindRenderbuffer(GL_RENDERBUFFER_EXT, 0); - GLuint rb; - - rb = _rb[slot]; - if (_shared_depth_buffer) { - rb = _shared_depth_buffer -> _rb[slot]; - } - - glgsg->_glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, - GL_RENDERBUFFER_EXT, rb); - - glgsg->_glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, - GL_RENDERBUFFER_EXT, rb); - return; - - } else if ( slot == RTP_depth ) { - // This is the uber-tricky case, where we DON'T want to bind a depth buffer - // if there's already any form of depth_stencil buffer bound (because depth_stencil - // is a superset that includes depth). - if (( _rb[RTP_depth_stencil] != 0 ) || ( attach[RTP_depth_stencil] != NULL )) { - return; - } - - } + GLuint rb = _rb[slot]; + if (_shared_depth_buffer) { + rb = _shared_depth_buffer->_rb[slot]; } - // We'll bail out before here if we set a depth_stencil buffer, - // or figure out that we're GOING to set a depth_stencil buffer. + glgsg->_glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, + GL_RENDERBUFFER_EXT, rb); - // If we get here, we're using the simple fallback case. -#endif - glgsg->_glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT16, - _rb_size_x, _rb_size_y); + glgsg->_glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, + GL_RENDERBUFFER_EXT, rb); + + report_my_gl_errors(); + + } else if (slot == RTP_depth) { + // Allocate renderbuffer storage for regular depth. GLint depth_size = 0; + glgsg->_glRenderbufferStorage(GL_RENDERBUFFER_EXT, gl_format, _rb_size_x, _rb_size_y); glgsg->_glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_DEPTH_SIZE_EXT, &depth_size); _fb_properties.set_depth_bits(depth_size); glgsg->_glBindRenderbuffer(GL_RENDERBUFFER_EXT, 0); - GLuint rb; - - rb = _rb[slot]; + GLuint rb = _rb[slot]; if (_shared_depth_buffer) { - rb = _shared_depth_buffer -> _rb[slot]; + rb = _shared_depth_buffer->_rb[slot]; } glgsg->_glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, rb); + + report_my_gl_errors(); + } else { - glgsg->_glRenderbufferStorage(GL_RENDERBUFFER_EXT, glFormat, - _rb_size_x, _rb_size_y); + glgsg->_glRenderbufferStorage(GL_RENDERBUFFER_EXT, gl_format, _rb_size_x, _rb_size_y); GLint red_size = 0, green_size = 0, blue_size = 0, alpha_size = 0; glgsg->_glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_RED_SIZE_EXT, &red_size); glgsg->_glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_GREEN_SIZE_EXT, &green_size); @@ -643,10 +816,9 @@ bind_slot(int face, bool rb_resize, Texture **attach, RenderTexturePlane slot, G glgsg->_glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, attachpoint, GL_RENDERBUFFER_EXT, _rb[slot]); + report_my_gl_errors(); } } - - report_my_gl_errors(); } //////////////////////////////////////////////////////////////////// @@ -675,7 +847,7 @@ bind_slot_multisample(bool rb_resize, Texture **attach, RenderTexturePlane slot, if (attachpoint == GL_DEPTH_ATTACHMENT_EXT) { #ifndef OPENGLES_2 - if (_gsg->get_supports_depth_stencil() && _use_depth_stencil) { + if (_use_depth_stencil) { glgsg->_glBindRenderbuffer(GL_RENDERBUFFER_EXT, _rbm[slot]); if (_requested_coverage_samples) { glgsg->_glRenderbufferStorageMultisampleCoverage(GL_RENDERBUFFER_EXT, _requested_coverage_samples, @@ -699,12 +871,17 @@ bind_slot_multisample(bool rb_resize, Texture **attach, RenderTexturePlane slot, glgsg->_glBindRenderbuffer(GL_RENDERBUFFER_EXT, _rbm[slot]); GLuint format = GL_DEPTH_COMPONENT; if (tex) { - if (tex->get_format() == Texture::F_depth_component16) + switch (tex->get_format()) { + case Texture::F_depth_component16: format = GL_DEPTH_COMPONENT16; - if (tex->get_format() == Texture::F_depth_component24) + break; + case Texture::F_depth_component24: format = GL_DEPTH_COMPONENT24; - if (tex->get_format() == Texture::F_depth_component32) + break; + case Texture::F_depth_component32: format = GL_DEPTH_COMPONENT32; + break; + } } if (_requested_coverage_samples) { glgsg->_glRenderbufferStorageMultisampleCoverage(GL_RENDERBUFFER_EXT, _requested_coverage_samples, @@ -726,29 +903,35 @@ bind_slot_multisample(bool rb_resize, Texture **attach, RenderTexturePlane slot, } } else { Texture *Tex = attach[slot]; - GLuint glFormat = GL_RGBA; + GLuint gl_format = GL_RGBA; #ifndef OPENGLES switch (slot) { case RTP_aux_rgba_0: case RTP_aux_rgba_1: case RTP_aux_rgba_2: case RTP_aux_rgba_3: - glFormat = GL_RGBA; + gl_format = GL_RGBA; break; case RTP_aux_hrgba_0: case RTP_aux_hrgba_1: case RTP_aux_hrgba_2: case RTP_aux_hrgba_3: - glFormat = GL_RGBA16F_ARB; + gl_format = GL_RGBA16F_ARB; + break; + case RTP_aux_float_0: + case RTP_aux_float_1: + case RTP_aux_float_2: + case RTP_aux_float_3: + gl_format = GL_RGBA32F_ARB; break; }; #endif glgsg->_glBindRenderbuffer(GL_RENDERBUFFER_EXT, _rbm[slot]); if (_requested_coverage_samples) { glgsg->_glRenderbufferStorageMultisampleCoverage(GL_RENDERBUFFER_EXT, _requested_coverage_samples, - _requested_multisamples, glFormat, _rb_size_x, _rb_size_y); + _requested_multisamples, gl_format, _rb_size_x, _rb_size_y); } else { - glgsg->_glRenderbufferStorageMultisample(GL_RENDERBUFFER_EXT, _requested_multisamples, glFormat, + glgsg->_glRenderbufferStorageMultisample(GL_RENDERBUFFER_EXT, _requested_multisamples, gl_format, _rb_size_x, _rb_size_y); } #ifndef OPENGLES @@ -838,13 +1021,13 @@ end_frame(FrameMode mode, Thread *current_thread) { // Access: Public, Virtual // Description: Called internally when the window is in // render-to-a-texture mode and we are in the process of -// rendering the six faces of a cube map. This should +// rendering the six layers of a cube map. This should // do whatever needs to be done to switch the buffer to // the indicated face. //////////////////////////////////////////////////////////////////// void CLP(GraphicsBuffer):: select_cube_map(int cube_map_index) { - nassertv(cube_map_index >=0 && cube_map_index < _num_faces); + nassertv(cube_map_index >= 0 && cube_map_index < _fbo.size()); if (_active_cube_map_index != -1) { // Resolve the multisample rendering for the previous face. @@ -891,23 +1074,40 @@ open_buffer() { // Describe the framebuffer properties of the FBO. // - // The rule is that the properties should be as close - // as possible to those requested, subject to the limits - // of the implementation. This particular implementation - // is fairly limited. But that's okay, we just have to - // tell the truth about what we actually provide by setting - // the _fb_properties accurately. + // Unfortunately, we can't possibly predict which formats + // the implementation will allow us to use at this point, so + // we'll just have to make some guesses and parrot the rest + // of the properties back to the user. + // When we actually attach the textures, we'll update the + // properties more appropriately. + // This is probably safe, as we can usually bind just about + // any supported texture format to the FBO. - _fb_properties.set_depth_bits(1); - _fb_properties.set_color_bits(1); - _fb_properties.set_alpha_bits(_host->get_fb_properties().get_alpha_bits()); - if (_gsg->get_supports_depth_stencil()) { - _fb_properties.set_stencil_bits(1); - } else { + // Rounding the depth bits is not spectacular, but at least we're + // telling the user *something* about what we're going to get. + if (_fb_properties.get_depth_bits() >= 32) { + _fb_properties.set_depth_bits(32); + } else if (_fb_properties.get_depth_bits() > 16) { + _fb_properties.set_depth_bits(24); + } else if (_fb_properties.get_depth_bits() > 8) { + _fb_properties.set_depth_bits(16); + } + + // We're not going to get more than this, ever. + if (_fb_properties.get_color_bits() > 96) { + _fb_properties.set_color_bits(96); + } + if (_fb_properties.get_alpha_bits() > 32) { + _fb_properties.set_alpha_bits(32); + } + + if (!_gsg->get_supports_depth_stencil()) { + // At least we know we won't be getting stencil bits. _fb_properties.set_stencil_bits(0); } _fb_properties.set_accum_bits(0); _fb_properties.set_multisamples(_host->get_fb_properties().get_multisamples()); + _fb_properties.set_back_buffers(0); _fb_properties.set_indexed_color(0); _fb_properties.set_rgb_color(1); @@ -918,6 +1118,7 @@ open_buffer() { _is_valid = true; _needs_rebuild = true; report_my_gl_errors(); + return true; } @@ -963,10 +1164,10 @@ close_buffer() { report_my_gl_errors(); // Delete the FBO itself. - for (int face = 0; face < _num_faces; ++face) { - glgsg->_glDeleteFramebuffers(1, &_fbo[face]); + for (int i = 0; i < _fbo.size(); ++i) { + glgsg->_glDeleteFramebuffers(1, &_fbo[i]); } - _num_faces = 0; + _fbo.clear(); report_my_gl_errors(); @@ -994,34 +1195,34 @@ share_depth_buffer(GraphicsOutput *graphics_output) { if (this != input_graphics_output && input_graphics_output) { state = true; - this -> unshare_depth_buffer(); + this->unshare_depth_buffer(); // check buffer sizes - if (this -> get_x_size() != input_graphics_output -> get_x_size()) { - GLCAT.error() << "share_depth_buffer: non matching width \n"; + if (this->get_x_size() != input_graphics_output->get_x_size()) { + GLCAT.error() << "share_depth_buffer: non-matching width\n"; state = false; } - if (this -> get_y_size() != input_graphics_output -> get_y_size()) { - GLCAT.error() << "share_depth_buffer: non matching height \n"; + if (this->get_y_size() != input_graphics_output->get_y_size()) { + GLCAT.error() << "share_depth_buffer: non-matching height\n"; state = false; } // Check multisample compatibility. - if ( this->get_multisample_count() != input_graphics_output->get_multisample_count() ) { - GLCAT.error() << "share_depth_buffer: non matching multisamples \n"; + if (this->get_multisample_count() != input_graphics_output->get_multisample_count()) { + GLCAT.error() << "share_depth_buffer: non-matching multisamples\n"; state = false; } - if ( this->get_coverage_sample_count() != input_graphics_output->get_coverage_sample_count() ) { - GLCAT.error() << "share_depth_buffer: non matching multisamples \n"; + if (this->get_coverage_sample_count() != input_graphics_output->get_coverage_sample_count()) { + GLCAT.error() << "share_depth_buffer: non-matching multisamples\n"; state = false; } if (state) { // let the input GraphicsOutput know that there is an object // sharing its depth buffer - input_graphics_output -> register_shared_depth_buffer(this); + input_graphics_output->register_shared_depth_buffer(this); _shared_depth_buffer = input_graphics_output; state = true; } @@ -1041,7 +1242,7 @@ unshare_depth_buffer() { if (_shared_depth_buffer) { // let the GraphicsOutput know that this object is no longer // sharing its depth buffer - _shared_depth_buffer -> unregister_shared_depth_buffer(this); + _shared_depth_buffer->unregister_shared_depth_buffer(this); _shared_depth_buffer = 0; _needs_rebuild = true; } @@ -1139,13 +1340,15 @@ resolve_multisamples() { CLP(GraphicsStateGuardian) *glgsg; DCAST_INTO_V(glgsg, _gsg); + nassertv(_fbo.size() > 0); + glgsg->report_my_gl_errors(); GLuint fbo = _fbo[0]; if (_active_cube_map_index != -1) { fbo = _fbo[_active_cube_map_index]; } - glgsg->_glBindFramebuffer( GL_DRAW_FRAMEBUFFER_EXT, fbo ); - glgsg->_glBindFramebuffer( GL_READ_FRAMEBUFFER_EXT, _fbo_multisample ); + glgsg->_glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, fbo); + glgsg->_glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, _fbo_multisample); // If the depth buffer is shared, resolve it only on the last to render FBO. int do_depth_blit = 0; diff --git a/panda/src/glstuff/glGraphicsBuffer_src.h b/panda/src/glstuff/glGraphicsBuffer_src.h index ffcf27f5c5..95fe110788 100644 --- a/panda/src/glstuff/glGraphicsBuffer_src.h +++ b/panda/src/glstuff/glGraphicsBuffer_src.h @@ -103,8 +103,7 @@ private: // We create one FBO for each cube map face we'll be rendering to. // If we aren't rendering to any cube maps, we use only _fbo[0]. - GLuint _fbo[6]; - int _num_faces; + pvector _fbo; // For multisample we render first to a multisample buffer, then // filter it to _fbo[face] at the end of the frame. @@ -115,6 +114,7 @@ private: int _rb_size_x; int _rb_size_y; + int _rb_size_z; // The texture or render buffer bound to each plane. PT(Texture) _tex[RTP_COUNT]; @@ -158,4 +158,3 @@ private: }; #include "glGraphicsBuffer_src.I" - diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index 8f7fde52ee..926d00bce8 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -581,6 +581,8 @@ reset() { get_extension_func(GLPREFIX_QUOTED, "TexImage3D"); _glTexSubImage3D = (PFNGLTEXSUBIMAGE3DPROC) get_extension_func(GLPREFIX_QUOTED, "TexSubImage3D"); + _glCopyTexSubImage3D = (PFNGLCOPYTEXSUBIMAGE3DPROC) + get_extension_func(GLPREFIX_QUOTED, "CopyTexSubImage3D"); } else if (has_extension("GL_EXT_texture3D")) { _supports_3d_texture = true; @@ -589,14 +591,23 @@ reset() { get_extension_func(GLPREFIX_QUOTED, "TexImage3DEXT"); _glTexSubImage3D = (PFNGLTEXSUBIMAGE3DPROC) get_extension_func(GLPREFIX_QUOTED, "TexSubImage3DEXT"); - } else if (has_extension("GL_OES_texture3D") || has_extension("GL_OES_texture_3D")) { + + _glCopyTexSubImage3D = NULL; + if (has_extension("GL_EXT_copy_texture")) { + _glCopyTexSubImage3D = (PFNGLCOPYTEXSUBIMAGE3DPROC) + get_extension_func(GLPREFIX_QUOTED, "CopyTexSubImage3DEXT"); + } + + } else if (has_extension("GL_OES_texture_3D")) { _supports_3d_texture = true; _glTexImage3D = (PFNGLTEXIMAGE3DPROC_P) get_extension_func(GLPREFIX_QUOTED, "TexImage3DOES"); _glTexSubImage3D = (PFNGLTEXSUBIMAGE3DPROC) get_extension_func(GLPREFIX_QUOTED, "TexSubImage3DOES"); - + _glCopyTexSubImage3D = (PFNGLCOPYTEXSUBIMAGE3DPROC) + get_extension_func(GLPREFIX_QUOTED, "CopyTexSubImage3DOES"); + #ifdef OPENGLES_2 _glFramebufferTexture3D = (PFNGLFRAMEBUFFERTEXTURE3DOES) get_extension_func(GLPREFIX_QUOTED, "FramebufferTexture3DOES"); @@ -611,9 +622,18 @@ reset() { } } + _supports_2d_texture_array = false; #ifndef OPENGLES _supports_2d_texture_array = has_extension("GL_EXT_texture_array"); + if (_supports_2d_texture_array) { + _glFramebufferTextureLayer = (PFNGLFRAMEBUFFERTEXTURELAYERPROC) + get_extension_func(GLPREFIX_QUOTED, "FramebufferTextureLayerEXT"); + } else { + // ARB_geometry_shader4 also provides a version. + _glFramebufferTextureLayer = NULL; + } #endif + #ifdef OPENGLES_2 _supports_cube_map = true; #else @@ -1048,6 +1068,13 @@ reset() { if (_supports_geometry_shaders) { _glProgramParameteri = (PFNGLPROGRAMPARAMETERIPROC) get_extension_func(GLPREFIX_QUOTED, "ProgramParameteri"); + _glFramebufferTexture = (PFNGLFRAMEBUFFERTEXTUREARBPROC) + get_extension_func(GLPREFIX_QUOTED, "FramebufferTextureARB"); + + if (_glFramebufferTextureLayer == NULL) { + _glFramebufferTextureLayer = (PFNGLFRAMEBUFFERTEXTURELAYERPROC) + get_extension_func(GLPREFIX_QUOTED, "FramebufferTextureLayerARB"); + } } if (_supports_tessellation_shaders) { _glPatchParameteri = (PFNGLPATCHPARAMETERIPROC) @@ -1113,12 +1140,6 @@ reset() { _glCheckFramebufferStatus = glCheckFramebufferStatus; _glFramebufferTexture1D = NULL; _glFramebufferTexture2D = glFramebufferTexture2D; - if (has_extension("GL_OES_texture3D")) { - _glFramebufferTexture3D = (PFNGLFRAMEBUFFERTEXTURE3DOES) - get_extension_func(GLPREFIX_QUOTED, "FramebufferTexture3DOES"); - } else { - _glFramebufferTexture3D = NULL; - } _glFramebufferRenderbuffer = glFramebufferRenderbuffer; _glGetFramebufferAttachmentParameteriv = glGetFramebufferAttachmentParameteriv; _glGenerateMipmap = glGenerateMipmap; @@ -1189,7 +1210,6 @@ reset() { _glFramebufferTexture1D = NULL; _glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DOESPROC) get_extension_func(GLPREFIX_QUOTED, "FramebufferTexture2DOES"); - _glFramebufferTexture3D = NULL; _glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFEROESPROC) get_extension_func(GLPREFIX_QUOTED, "FramebufferRenderbufferOES"); _glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVOESPROC) @@ -4170,8 +4190,8 @@ make_geom_munger(const RenderState *state, Thread *current_thread) { // Description: Copy the pixels within the indicated display // region from the framebuffer into texture memory. // -// If z > -1, it is the cube map index into which to -// copy. +// If z > -1, it is the cube map index or layer index +// into which to copy. //////////////////////////////////////////////////////////////////// bool CLP(GraphicsStateGuardian):: framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr, @@ -4184,7 +4204,7 @@ framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr, int xo, yo, w, h; dr->get_region_pixels(xo, yo, w, h); - tex->set_size_padded(w, h); + tex->set_size_padded(w, h, tex->get_z_size()); if (tex->get_compression() == Texture::CM_default) { // Unless the user explicitly turned on texture compression, turn @@ -4194,16 +4214,41 @@ framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr, // Sanity check everything. if (z >= 0) { - if (!_supports_cube_map) { + if (z >= tex->get_z_size()) { + // This can happen, when textures with different layer counts + // are attached to a buffer. We simply ignore this if it happens. return false; } - nassertr(z < 6, false); - nassertr(tex->get_texture_type() == Texture::TT_cube_map, false); + if ((w != tex->get_x_size()) || - (h != tex->get_y_size()) || - (w != h)) { + (h != tex->get_y_size())) { return false; } + + if (tex->get_texture_type() == Texture::TT_cube_map) { + if (!_supports_cube_map) { + return false; + } + + nassertr(z < 6, false); + if (w != h) { + return false; + } + + } else if (tex->get_texture_type() == Texture::TT_3d_texture) { + if (!_supports_3d_texture) { + return false; + } + + } else if (tex->get_texture_type() == Texture::TT_2d_texture_array) { + if (!_supports_2d_texture_array) { + return false; + } + + } else { + GLCAT.error() + << "Don't know how to copy framebuffer to texture " << *tex << "\n"; + } } else { nassertr(tex->get_texture_type() == Texture::TT_2d_texture, false); } @@ -4243,6 +4288,7 @@ framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr, GLint internal_format = get_internal_image_format(tex); int width = tex->get_x_size(); int height = tex->get_y_size(); + int depth = tex->get_z_size(); bool uses_mipmaps = tex->uses_mipmaps() && !CLP(ignore_mipmaps); if (uses_mipmaps) { @@ -4260,34 +4306,52 @@ framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr, } bool new_image = needs_reload || gtc->was_image_modified(); + + if (z >= 0) { + if (target == GL_TEXTURE_CUBE_MAP) { + // Copy to a cube map face, which is treated as a 2D texture. + target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + z; + depth = 1; + z = -1; + + // Cube map faces seem to have trouble with CopyTexSubImage, so we + // always reload the image. + new_image = true; + } + } + if (!gtc->_already_applied || internal_format != gtc->_internal_format || uses_mipmaps != gtc->_uses_mipmaps || width != gtc->_width || height != gtc->_height || - 1 != gtc->_depth) { + depth != gtc->_depth) { // If the texture properties have changed, we need to reload the // image. new_image = true; } + if (z >= 0) { - // Copy to a cube map face. - target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + z; + if (new_image) { + // These won't be used because we pass a NULL image, but we still + // have to specify them. Might as well use the actual values. + GLint external_format = get_external_image_format(tex); + GLint component_type = get_component_type(tex->get_component_type()); + _glTexImage3D(target, 0, internal_format, width, height, depth, 0, external_format, component_type, NULL); + } - // Cube map faces seem to have trouble with CopyTexSubImage, so we - // always reload the image. - new_image = true; - } - - if (new_image) { - // We have to create a new image. - // It seems that OpenGL accepts a size higher than the framebuffer, - // but if we run into trouble we'll have to replace this with - // something smarter. - GLP(CopyTexImage2D)(target, 0, internal_format, xo, yo, width, height, 0); + _glCopyTexSubImage3D(target, 0, 0, 0, z, xo, yo, w, h); } else { - // We can overlay the existing image. - GLP(CopyTexSubImage2D)(target, 0, 0, 0, xo, yo, w, h); + if (new_image) { + // We have to create a new image. + // It seems that OpenGL accepts a size higher than the framebuffer, + // but if we run into trouble we'll have to replace this with + // something smarter. + GLP(CopyTexImage2D)(target, 0, internal_format, xo, yo, width, height, 0); + } else { + // We can overlay the existing image. + GLP(CopyTexSubImage2D)(target, 0, 0, 0, xo, yo, w, h); + } } gtc->_already_applied = true; @@ -4295,7 +4359,7 @@ framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr, gtc->_internal_format = internal_format; gtc->_width = width; gtc->_height = height; - gtc->_depth = 1; + gtc->_depth = depth; gtc->mark_loaded(); gtc->enqueue_lru(&_prepared_objects->_graphics_memory_lru); @@ -4373,6 +4437,7 @@ framebuffer_copy_to_ram(Texture *tex, int z, const DisplayRegion *dr, Texture::TextureType texture_type; int z_size; + //TODO: should be extended to support 3D textures and 2D arrays. if (z >= 0) { texture_type = Texture::TT_cube_map; z_size = 6; @@ -4386,6 +4451,7 @@ framebuffer_copy_to_ram(Texture *tex, int z, const DisplayRegion *dr, tex->get_component_type() != component_type || tex->get_format() != format || tex->get_texture_type() != texture_type) { + // Re-setup the texture; its properties have changed. tex->setup_texture(texture_type, w, h, z_size, component_type, format); @@ -5681,6 +5747,7 @@ get_extension_func(const char *prefix, const char *name) { { "DrawRangeElements", (void *)&GLP(DrawRangeElements) }, { "TexImage3D", (void *)&GLP(TexImage3D) }, { "TexSubImage3D", (void *)&GLP(TexSubImage3D) }, + { "CopyTexSubImage3D", (void *)&GLP(CopyTexSubImage3D) }, #endif #ifdef EXPECT_GL_VERSION_1_3 { "ActiveTexture", (void *)&GLP(ActiveTexture) }, @@ -6308,15 +6375,7 @@ get_external_image_format(Texture *tex) const { case Texture::F_depth_component: return GL_DEPTH_COMPONENT; case Texture::F_depth_stencil: -#ifndef OPENGLES_2 - if (CLP(force_depth_stencil)) { - return GL_DEPTH_STENCIL_EXT; - } else { -#endif - return GL_DEPTH_COMPONENT; -#ifndef OPENGLES_2 - } -#endif + return _supports_depth_stencil ? GL_DEPTH_STENCIL_EXT : GL_DEPTH_COMPONENT; #ifndef OPENGLES case Texture::F_red: return GL_RED; @@ -6522,7 +6581,11 @@ get_internal_image_format(Texture *tex) const { return GL_COLOR_INDEX; #endif case Texture::F_depth_component: - return GL_DEPTH_COMPONENT; + if (tex->get_component_type() == Texture::T_float) { + return GL_DEPTH_COMPONENT32F; + } else { + return GL_DEPTH_COMPONENT; + } case Texture::F_depth_component16: #ifdef OPENGLES_1 return GL_DEPTH_COMPONENT16_OES; @@ -6537,7 +6600,11 @@ get_internal_image_format(Texture *tex) const { #else return GL_DEPTH_COMPONENT24; case Texture::F_depth_component32: - return GL_DEPTH_COMPONENT32; + if (tex->get_component_type() == Texture::T_float) { + return GL_DEPTH_COMPONENT32F; + } else { + return GL_DEPTH_COMPONENT32; + } #endif case Texture::F_depth_stencil: #ifndef OPENGLES_2 @@ -7755,15 +7822,15 @@ update_standard_texture_bindings() { TextureContext *tc = texture->prepare_now(view, _prepared_objects, this); if (tc == (TextureContext *)NULL) { // Something wrong with this texture; skip it. - break; + continue; } #ifndef OPENGLES_2 // Then, turn on the current texture mode. GLenum target = get_texture_target(texture->get_texture_type()); - if (target == GL_NONE) { + if (target == GL_NONE || target == GL_TEXTURE_2D_ARRAY_EXT) { // Unsupported texture mode. - break; + continue; } GLP(Enable)(target); #endif @@ -7772,7 +7839,7 @@ update_standard_texture_bindings() { #ifndef OPENGLES_2 GLP(Disable)(target); #endif - break; + continue; } if (stage->involves_color_scale() && _color_scale_enabled) { @@ -8635,7 +8702,7 @@ upload_texture(CLP(TextureContext) *gtc, bool force) { if (!get_supports_compressed_texture_format(image_compression)) { image = tex->get_uncompressed_ram_image(); image_compression = Texture::CM_off; - } + } if (GLCAT.is_debug()) { if (image.is_null()) { @@ -9010,7 +9077,7 @@ upload_texture_image(CLP(TextureContext) *gtc, if (GLCAT.is_debug()) { GLCAT.debug() << "subloading existing texture object, " << width << " x " << height - << " x " << depth << ", mipmaps " << num_ram_mipmap_levels + << " x " << depth << ", z = " << z << ", mipmaps " << num_ram_mipmap_levels << ", uses_mipmaps = " << uses_mipmaps << "\n"; } @@ -9142,31 +9209,37 @@ upload_texture_image(CLP(TextureContext) *gtc, if (GLCAT.is_debug()) { GLCAT.debug() << "loading new texture object, " << width << " x " << height - << " x " << depth << ", mipmaps " << num_ram_mipmap_levels + << " x " << depth << ", z = " << z << ", mipmaps " << num_ram_mipmap_levels << ", uses_mipmaps = " << uses_mipmaps << "\n"; } if (num_ram_mipmap_levels == 0) { #ifndef OPENGLES_2 if ((external_format == GL_DEPTH_STENCIL_EXT) && get_supports_depth_stencil()) { - GLP(TexImage2D)(page_target, 0, GL_DEPTH_STENCIL_EXT, - width, height, 0, GL_DEPTH_STENCIL_EXT, #ifdef OPENGLES_1 - GL_UNSIGNED_INT_24_8_OES, + component_type = GL_UNSIGNED_INT_24_8_OES; #else - GL_UNSIGNED_INT_24_8_EXT, -#endif // OPENGLES_1 - NULL); - } else { -#endif // OPENGLES_2 - GLP(TexImage2D)(page_target, 0, internal_format, - width, height, 0, - external_format, GL_UNSIGNED_BYTE, NULL); -#ifndef OPENGLES_2 + component_type = GL_UNSIGNED_INT_24_8_EXT; +#endif + } +#endif + + // We don't have any RAM mipmap levels, so we create an uninitialized OpenGL + // texture. Presumably this will be used later for render-to-texture or so. + switch (page_target) { + case GL_TEXTURE_1D: + GLP(TexImage1D)(page_target, 0, internal_format, width, 0, external_format, component_type, NULL); + break; + case GL_TEXTURE_3D: + case GL_TEXTURE_2D_ARRAY: + _glTexImage3D(page_target, 0, internal_format, width, height, depth, 0, external_format, component_type, NULL); + break; + default: + GLP(TexImage2D)(page_target, 0, internal_format, width, height, 0, external_format, component_type, NULL); + break; } -#endif // OPENGLES_2 } - + for (int n = mipmap_bias; n < num_ram_mipmap_levels; ++n) { const unsigned char *image_ptr = (unsigned char*)tex->get_ram_mipmap_pointer(n); CPTA_uchar ptimage; @@ -9283,7 +9356,7 @@ upload_texture_image(CLP(TextureContext) *gtc, GLCAT.error() << "GL texture creation failed for " << tex->get_name() << " : " << get_error_string(error_code) << "\n"; - + gtc->_already_applied = false; return false; } @@ -9642,6 +9715,7 @@ do_extract_texture_data(CLP(TextureContext) *gtc) { break; case GL_DEPTH_COMPONENT24: case GL_DEPTH_COMPONENT32: + case GL_DEPTH_COMPONENT32F: type = Texture::T_float; format = Texture::F_depth_component; break; @@ -10034,7 +10108,7 @@ get_supports_cg_profile(const string &name) const { //////////////////////////////////////////////////////////////////// // Function: GLGraphicsStateGuardian::bind_fbo // Access: Protected -// Description: Binds an FBO object. +// Description: Binds a framebuffer object. //////////////////////////////////////////////////////////////////// void CLP(GraphicsStateGuardian):: bind_fbo(GLuint fbo) { diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.h b/panda/src/glstuff/glGraphicsStateGuardian_src.h index d4bfbba3ad..287b7a575c 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.h +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.h @@ -67,6 +67,7 @@ typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSPROC) (GLenum mode, GLuint start, // There is some trivial disagreement between different gl.h headers about this one, so we use our own typename. typedef void (APIENTRYP PFNGLTEXIMAGE3DPROC_P) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture); typedef void (APIENTRYP PFNGLMULTITEXCOORD1FPROC) (GLenum target, const GLfloat s); typedef void (APIENTRYP PFNGLMULTITEXCOORD2FPROC) (GLenum target, const GLfloat s, const GLfloat t); @@ -115,6 +116,8 @@ typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DOES) (GLenum target, GLenum att #else typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); #endif +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREARBPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level); +typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) (GLenum target, GLenum attachment, GLenum pname, GLint *params); typedef void (APIENTRYP PFNGLGENERATEMIPMAPEXTPROC) (GLenum target); @@ -556,6 +559,7 @@ public: PFNGLTEXIMAGE3DPROC_P _glTexImage3D; PFNGLTEXSUBIMAGE3DPROC _glTexSubImage3D; + PFNGLCOPYTEXSUBIMAGE3DPROC _glCopyTexSubImage3D; PFNGLCOMPRESSEDTEXIMAGE1DPROC _glCompressedTexImage1D; PFNGLCOMPRESSEDTEXIMAGE2DPROC _glCompressedTexImage2D; @@ -610,6 +614,8 @@ public: #else PFNGLFRAMEBUFFERTEXTURE3DEXTPROC _glFramebufferTexture3D; #endif + PFNGLFRAMEBUFFERTEXTUREARBPROC _glFramebufferTexture; + PFNGLFRAMEBUFFERTEXTURELAYERPROC _glFramebufferTextureLayer; PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC _glFramebufferRenderbuffer; PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC _glGetFramebufferAttachmentParameteriv; PFNGLGENERATEMIPMAPEXTPROC _glGenerateMipmap; diff --git a/panda/src/glxdisplay/glxGraphicsPipe.cxx b/panda/src/glxdisplay/glxGraphicsPipe.cxx index bb1131ebda..09ea94bea9 100644 --- a/panda/src/glxdisplay/glxGraphicsPipe.cxx +++ b/panda/src/glxdisplay/glxGraphicsPipe.cxx @@ -118,7 +118,8 @@ make_output(const string &name, ((flags&BF_size_track_host)!=0)|| ((flags&BF_rtt_cumulative)!=0)|| ((flags&BF_can_bind_color)!=0)|| - ((flags&BF_can_bind_every)!=0)) { + ((flags&BF_can_bind_every)!=0)|| + ((flags&BF_can_bind_layered)!=0)) { return NULL; } return new glxGraphicsWindow(engine, this, name, fb_prop, win_prop, @@ -168,14 +169,15 @@ make_output(const string &name, if (!glx_support_pbuffer) { return NULL; } - + if (((flags&BF_require_parasite)!=0)|| ((flags&BF_require_window)!=0)|| ((flags&BF_resizeable)!=0)|| - ((flags&BF_size_track_host)!=0)) { + ((flags&BF_size_track_host)!=0)|| + ((flags&BF_can_bind_layered)!=0) { return NULL; } - + if (!support_rtt) { if (((flags&BF_rtt_cumulative)!=0)|| ((flags&BF_can_bind_every)!=0)) { @@ -184,7 +186,7 @@ make_output(const string &name, return NULL; } } - + return new glxGraphicsBuffer(engine, this, name, fb_prop, win_prop, flags, gsg, host); } @@ -199,7 +201,8 @@ make_output(const string &name, if (((flags&BF_require_parasite)!=0)|| ((flags&BF_require_window)!=0)|| ((flags&BF_resizeable)!=0)|| - ((flags&BF_size_track_host)!=0)) { + ((flags&BF_size_track_host)!=0)|| + ((flags&BF_can_bind_layered)!=0) { return NULL; } @@ -211,7 +214,7 @@ make_output(const string &name, return new glxGraphicsPixmap(engine, this, name, fb_prop, win_prop, flags, gsg, host); } - + // Nothing else left to try. return NULL; } diff --git a/panda/src/osxdisplay/osxGraphicsPipe.cxx b/panda/src/osxdisplay/osxGraphicsPipe.cxx index b9efb87ba6..594aed22a5 100644 --- a/panda/src/osxdisplay/osxGraphicsPipe.cxx +++ b/panda/src/osxdisplay/osxGraphicsPipe.cxx @@ -392,7 +392,8 @@ make_output(const string &name, ((flags&BF_resizeable)!=0)|| ((flags&BF_size_track_host)!=0)|| ((flags&BF_can_bind_color)!=0)|| - ((flags&BF_can_bind_every)!=0)) { + ((flags&BF_can_bind_every)!=0)|| + ((flags&BF_can_bind_layered)!=0)) { return NULL; } WindowHandle *window_handle = win_prop.get_parent_window(); @@ -412,7 +413,7 @@ make_output(const string &name, flags, gsg, host); } - // Second thing to try: a glGraphicsBuffer + // Second thing to try: a GLGraphicsBuffer if (retry == 1) { if (!osx_support_gl_buffer) { @@ -453,7 +454,8 @@ make_output(const string &name, ((flags&BF_require_window)!=0)|| ((flags&BF_resizeable)!=0)|| ((flags&BF_size_track_host)!=0)|| - ((flags&BF_can_bind_every)!=0)) { + ((flags&BF_can_bind_every)!=0)|| + ((flags&BF_can_bind_layered)!=0)) { return NULL; } return new osxGraphicsBuffer(engine, this, name, fb_prop, win_prop, diff --git a/panda/src/wgldisplay/wglGraphicsPipe.cxx b/panda/src/wgldisplay/wglGraphicsPipe.cxx index 0e357dfa72..d0af76a204 100644 --- a/panda/src/wgldisplay/wglGraphicsPipe.cxx +++ b/panda/src/wgldisplay/wglGraphicsPipe.cxx @@ -139,7 +139,8 @@ make_output(const string &name, ((flags&BF_size_track_host)!=0)|| ((flags&BF_rtt_cumulative)!=0)|| ((flags&BF_can_bind_color)!=0)|| - ((flags&BF_can_bind_every)!=0)) { + ((flags&BF_can_bind_every)!=0)|| + ((flags&BF_can_bind_layered)!=0)) { return NULL; } if ((flags & BF_fb_props_optional)==0) { @@ -201,7 +202,8 @@ make_output(const string &name, if (retry == 2) { if (((flags&BF_require_parasite)!=0)|| - ((flags&BF_require_window)!=0)) { + ((flags&BF_require_window)!=0)|| + ((flags&BF_can_bind_layered)!=0)) { return NULL; } if ((wglgsg != 0) &&