non-sampleable textures didn't support "magic resolve"
There was an inconsistency in the gles backend where non-sampleable, non-MS textures failed (assert) if they were used with a render target with MS (i.e. "magic resolve" case). We fix this by taking the same code path for textures and renderbuffers, the only difference being the calls to glFrameBufferRenderbuffer instead of glFramebufferTexture2D.
This commit is contained in:
committed by
Mathias Agopian
parent
86125ca72a
commit
090c02b2cf
@@ -789,8 +789,8 @@ void OpenGLDriver::framebufferTexture(backend::TargetBufferInfo const& binfo,
|
||||
|
||||
auto& gl = mContext;
|
||||
|
||||
GLenum target = GL_TEXTURE_2D;
|
||||
if (any(t->usage & TextureUsage::SAMPLEABLE)) {
|
||||
GLenum target = GL_TEXTURE_2D;
|
||||
switch (t->target) {
|
||||
case SamplerType::SAMPLER_2D:
|
||||
case SamplerType::SAMPLER_2D_ARRAY:
|
||||
@@ -805,128 +805,131 @@ void OpenGLDriver::framebufferTexture(backend::TargetBufferInfo const& binfo,
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rt->gl.samples <= 1 ||
|
||||
(rt->gl.samples > 1 && t->samples > 1 && gl.features.multisample_texture)) {
|
||||
// on GL3.2 / GLES3.1 and above multisample is handled when creating the texture.
|
||||
// If multisampled textures are not supported and we end-up here, things should
|
||||
// still work, albeit without MSAA.
|
||||
gl.bindFramebuffer(GL_FRAMEBUFFER, rt->gl.fbo);
|
||||
switch (target) {
|
||||
case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
|
||||
case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
|
||||
case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
|
||||
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
|
||||
case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
|
||||
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
|
||||
case GL_TEXTURE_2D:
|
||||
case GL_TEXTURE_2D_MULTISAMPLE:
|
||||
if (rt->gl.samples <= 1 ||
|
||||
(rt->gl.samples > 1 && t->samples > 1 && gl.features.multisample_texture)) {
|
||||
// on GL3.2 / GLES3.1 and above multisample is handled when creating the texture.
|
||||
// If multisampled textures are not supported and we end-up here, things should
|
||||
// still work, albeit without MSAA.
|
||||
gl.bindFramebuffer(GL_FRAMEBUFFER, rt->gl.fbo);
|
||||
switch (target) {
|
||||
case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
|
||||
case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
|
||||
case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
|
||||
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
|
||||
case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
|
||||
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
|
||||
case GL_TEXTURE_2D:
|
||||
case GL_TEXTURE_2D_MULTISAMPLE:
|
||||
if (any(t->usage & TextureUsage::SAMPLEABLE)) {
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, attachment,
|
||||
target, t->gl.id, binfo.level);
|
||||
break;
|
||||
case GL_TEXTURE_2D_ARRAY:
|
||||
// GL_TEXTURE_2D_MULTISAMPLE_ARRAY is not supported in GLES
|
||||
glFramebufferTextureLayer(GL_FRAMEBUFFER, attachment,
|
||||
t->gl.id, binfo.level, binfo.layer);
|
||||
break;
|
||||
default:
|
||||
// we shouldn't be here
|
||||
break;
|
||||
}
|
||||
CHECK_GL_ERROR(utils::slog.e)
|
||||
} else
|
||||
} else {
|
||||
assert(target == GL_TEXTURE_2D);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment,
|
||||
GL_RENDERBUFFER, t->gl.id);
|
||||
}
|
||||
break;
|
||||
case GL_TEXTURE_2D_ARRAY:
|
||||
// GL_TEXTURE_2D_MULTISAMPLE_ARRAY is not supported in GLES
|
||||
glFramebufferTextureLayer(GL_FRAMEBUFFER, attachment,
|
||||
t->gl.id, binfo.level, binfo.layer);
|
||||
break;
|
||||
default:
|
||||
// we shouldn't be here
|
||||
break;
|
||||
}
|
||||
CHECK_GL_ERROR(utils::slog.e)
|
||||
} else
|
||||
#ifdef GL_EXT_multisampled_render_to_texture
|
||||
// EXT_multisampled_render_to_texture only support GL_COLOR_ATTACHMENT0
|
||||
if (!attachmentTypeNotSupportedByMSRTT && (t->depth <= 1)
|
||||
&& ((gl.ext.EXT_multisampled_render_to_texture && attachment == GL_COLOR_ATTACHMENT0)
|
||||
|| gl.ext.EXT_multisampled_render_to_texture2)) {
|
||||
assert(rt->gl.samples > 1);
|
||||
// We have a multi-sample rendertarget and we have EXT_multisampled_render_to_texture,
|
||||
// so, we can directly use a 1-sample texture as attachment, multi-sample resolve,
|
||||
// will happen automagically and efficiently in the driver.
|
||||
// This extension only exists on OpenGL ES.
|
||||
gl.bindFramebuffer(GL_FRAMEBUFFER, rt->gl.fbo);
|
||||
// EXT_multisampled_render_to_texture only support GL_COLOR_ATTACHMENT0
|
||||
if (!attachmentTypeNotSupportedByMSRTT && (t->depth <= 1)
|
||||
&& ((gl.ext.EXT_multisampled_render_to_texture && attachment == GL_COLOR_ATTACHMENT0)
|
||||
|| gl.ext.EXT_multisampled_render_to_texture2)) {
|
||||
assert(rt->gl.samples > 1);
|
||||
// We have a multi-sample rendertarget and we have EXT_multisampled_render_to_texture,
|
||||
// so, we can directly use a 1-sample texture as attachment, multi-sample resolve,
|
||||
// will happen automagically and efficiently in the driver.
|
||||
// This extension only exists on OpenGL ES.
|
||||
gl.bindFramebuffer(GL_FRAMEBUFFER, rt->gl.fbo);
|
||||
if (any(t->usage & TextureUsage::SAMPLEABLE)) {
|
||||
glext::glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER,
|
||||
attachment, target, t->gl.id, binfo.level, rt->gl.samples);
|
||||
} else
|
||||
} else {
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment,
|
||||
GL_RENDERBUFFER, t->gl.id);
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{ // here we emulate ext.EXT_multisampled_render_to_texture
|
||||
assert(rt->gl.samples > 1);
|
||||
{ // here we emulate ext.EXT_multisampled_render_to_texture
|
||||
assert(rt->gl.samples > 1);
|
||||
|
||||
// If the texture doesn't already have one, create a sidecar multi-sampled renderbuffer,
|
||||
// which is where drawing will actually take place, make that our attachment.
|
||||
gl.bindFramebuffer(GL_FRAMEBUFFER, rt->gl.fbo);
|
||||
if (t->gl.rb == 0) {
|
||||
glGenRenderbuffers(1, &t->gl.rb);
|
||||
renderBufferStorage(t->gl.rb,
|
||||
t->gl.internalFormat, rt->width, rt->height, rt->gl.samples);
|
||||
}
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, t->gl.rb);
|
||||
// If the texture doesn't already have one, create a sidecar multi-sampled renderbuffer,
|
||||
// which is where drawing will actually take place, make that our attachment.
|
||||
gl.bindFramebuffer(GL_FRAMEBUFFER, rt->gl.fbo);
|
||||
if (t->gl.rb == 0) {
|
||||
glGenRenderbuffers(1, &t->gl.rb);
|
||||
renderBufferStorage(t->gl.rb,
|
||||
t->gl.internalFormat, rt->width, rt->height, rt->gl.samples);
|
||||
}
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, t->gl.rb);
|
||||
|
||||
// We also need a "read" sidecar fbo, used later for the resolve, which takes place in
|
||||
// endRenderPass().
|
||||
if (!rt->gl.fbo_read) {
|
||||
glGenFramebuffers(1, &rt->gl.fbo_read);
|
||||
}
|
||||
gl.bindFramebuffer(GL_FRAMEBUFFER, rt->gl.fbo_read);
|
||||
switch (target) {
|
||||
case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
|
||||
case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
|
||||
case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
|
||||
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
|
||||
case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
|
||||
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
|
||||
case GL_TEXTURE_2D:
|
||||
// We also need a "read" sidecar fbo, used later for the resolve, which takes place in
|
||||
// endRenderPass().
|
||||
if (!rt->gl.fbo_read) {
|
||||
glGenFramebuffers(1, &rt->gl.fbo_read);
|
||||
}
|
||||
gl.bindFramebuffer(GL_FRAMEBUFFER, rt->gl.fbo_read);
|
||||
switch (target) {
|
||||
case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
|
||||
case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
|
||||
case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
|
||||
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
|
||||
case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
|
||||
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
|
||||
case GL_TEXTURE_2D:
|
||||
if (any(t->usage & TextureUsage::SAMPLEABLE)) {
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, attachment,
|
||||
target, t->gl.id, binfo.level);
|
||||
break;
|
||||
case GL_TEXTURE_2D_ARRAY:
|
||||
glFramebufferTextureLayer(GL_FRAMEBUFFER, attachment,
|
||||
t->gl.id, binfo.level, binfo.layer);
|
||||
break;
|
||||
default:
|
||||
// we shouldn't be here
|
||||
break;
|
||||
}
|
||||
|
||||
CHECK_GL_ERROR(utils::slog.e)
|
||||
|
||||
switch (attachment) {
|
||||
case GL_COLOR_ATTACHMENT0:
|
||||
rt->gl.resolve |= TargetBufferFlags::COLOR0;
|
||||
break;
|
||||
case GL_COLOR_ATTACHMENT1:
|
||||
rt->gl.resolve |= TargetBufferFlags::COLOR1;
|
||||
break;
|
||||
case GL_COLOR_ATTACHMENT2:
|
||||
rt->gl.resolve |= TargetBufferFlags::COLOR2;
|
||||
break;
|
||||
case GL_COLOR_ATTACHMENT3:
|
||||
rt->gl.resolve |= TargetBufferFlags::COLOR3;
|
||||
break;
|
||||
case GL_DEPTH_ATTACHMENT:
|
||||
rt->gl.resolve |= TargetBufferFlags::DEPTH;
|
||||
break;
|
||||
case GL_STENCIL_ATTACHMENT:
|
||||
rt->gl.resolve |= TargetBufferFlags::STENCIL;
|
||||
break;
|
||||
case GL_DEPTH_STENCIL_ATTACHMENT:
|
||||
rt->gl.resolve |= TargetBufferFlags::DEPTH;
|
||||
rt->gl.resolve |= TargetBufferFlags::STENCIL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
assert(target == GL_TEXTURE_2D);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment,
|
||||
GL_RENDERBUFFER, t->gl.id);
|
||||
}
|
||||
break;
|
||||
case GL_TEXTURE_2D_ARRAY:
|
||||
glFramebufferTextureLayer(GL_FRAMEBUFFER, attachment,
|
||||
t->gl.id, binfo.level, binfo.layer);
|
||||
break;
|
||||
default:
|
||||
// we shouldn't be here
|
||||
break;
|
||||
}
|
||||
|
||||
CHECK_GL_ERROR(utils::slog.e)
|
||||
|
||||
switch (attachment) {
|
||||
case GL_COLOR_ATTACHMENT0: rt->gl.resolve |= TargetBufferFlags::COLOR0; break;
|
||||
case GL_COLOR_ATTACHMENT1: rt->gl.resolve |= TargetBufferFlags::COLOR1; break;
|
||||
case GL_COLOR_ATTACHMENT2: rt->gl.resolve |= TargetBufferFlags::COLOR2; break;
|
||||
case GL_COLOR_ATTACHMENT3: rt->gl.resolve |= TargetBufferFlags::COLOR3; break;
|
||||
case GL_DEPTH_ATTACHMENT: rt->gl.resolve |= TargetBufferFlags::DEPTH; break;
|
||||
case GL_STENCIL_ATTACHMENT: rt->gl.resolve |= TargetBufferFlags::STENCIL; break;
|
||||
case GL_DEPTH_STENCIL_ATTACHMENT:
|
||||
rt->gl.resolve |= TargetBufferFlags::DEPTH;
|
||||
rt->gl.resolve |= TargetBufferFlags::STENCIL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (any(t->usage & TextureUsage::SAMPLEABLE)) {
|
||||
// In a sense, drawing to a texture level is similar to calling setTextureData on it; in
|
||||
// both cases, we update the base/max LOD to give shaders access to levels as they become
|
||||
// available.
|
||||
updateTextureLodRange(t, binfo.level);
|
||||
} else {
|
||||
assert(std::max(uint8_t(1), t->samples) == std::max(uint8_t(1), rt->gl.samples));
|
||||
gl.bindFramebuffer(GL_FRAMEBUFFER, rt->gl.fbo);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, t->gl.id);
|
||||
}
|
||||
|
||||
CHECK_GL_ERROR(utils::slog.e)
|
||||
@@ -1143,7 +1146,7 @@ void OpenGLDriver::destroyVertexBuffer(Handle<HwVertexBuffer> vbh) {
|
||||
auto& gl = mContext;
|
||||
GLVertexBuffer const* eb = handle_cast<const GLVertexBuffer*>(vbh);
|
||||
GLsizei n = GLsizei(eb->bufferCount);
|
||||
auto& buffers = eb->gl.buffers;
|
||||
const auto& buffers = eb->gl.buffers;
|
||||
gl.deleteBuffers(n, buffers.data(), GL_ARRAY_BUFFER);
|
||||
destruct(vbh, eb);
|
||||
}
|
||||
@@ -1219,7 +1222,9 @@ void OpenGLDriver::destroyTexture(Handle<HwTexture> th) {
|
||||
}
|
||||
} else {
|
||||
assert(t->gl.target == GL_RENDERBUFFER);
|
||||
assert(t->gl.rb == 0);
|
||||
if (t->gl.rb) {
|
||||
glDeleteRenderbuffers(1, &t->gl.rb);
|
||||
}
|
||||
glDeleteRenderbuffers(1, &t->gl.id);
|
||||
}
|
||||
if (t->gl.fence) {
|
||||
|
||||
Reference in New Issue
Block a user