FBO overhaul: support layered framebuffers (RTM_bind_layered), support render-to-2d-array, better respect FrameBufferProperties, more simple handling of RTP_depth_stencil

This commit is contained in:
rdb 2013-08-13 12:44:27 +00:00
parent a6eeaf42b5
commit 2274f2e651
13 changed files with 656 additions and 326 deletions

View File

@ -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;
}

View File

@ -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;

View File

@ -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() {

View File

@ -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();

View File

@ -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;

View File

@ -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);

View File

@ -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<RTP_COUNT; i++) {
_rb[i] = 0;
_tex[i] = 0;
@ -100,14 +98,14 @@ CLP(GraphicsBuffer)::
CLP(GraphicsBuffer) *graphics_buffer;
list <CLP(GraphicsBuffer) *>::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, &gtc->_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, &gtc->_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;

View File

@ -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<GLuint> _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"

View File

@ -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) {

View File

@ -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;

View File

@ -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;
}

View File

@ -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,

View File

@ -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) &&