Commit a1b9d5a2 by Geoff Lang Committed by Commit Bot

Refactor multisample framebuffer completeness checks.

Re-land with protection against div-by-zero in samples compatibility check. BUG=722684 Change-Id: I3d5c310d1f2cb4d8b92d80492435855c3c4ad807 Reviewed-on: https://chromium-review.googlesource.com/517427Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Geoff Lang <geofflang@chromium.org>
parent 95468d17
...@@ -78,6 +78,69 @@ bool CheckAttachmentCompleteness(const Context *context, const FramebufferAttach ...@@ -78,6 +78,69 @@ bool CheckAttachmentCompleteness(const Context *context, const FramebufferAttach
return true; return true;
}; };
bool CheckAttachmentSampleCompleteness(const Context *context,
const FramebufferAttachment &attachment,
bool colorAttachment,
Optional<int> *samples,
Optional<GLboolean> *fixedSampleLocations)
{
ASSERT(attachment.isAttached());
if (attachment.type() == GL_TEXTURE)
{
const Texture *texture = attachment.getTexture();
ASSERT(texture);
const ImageIndex &attachmentImageIndex = attachment.getTextureImageIndex();
// ES3.1 (section 9.4) requires that the value of TEXTURE_FIXED_SAMPLE_LOCATIONS should be
// the same for all attached textures.
GLboolean fixedSampleloc = texture->getFixedSampleLocations(attachmentImageIndex.type,
attachmentImageIndex.mipIndex);
if (fixedSampleLocations->valid() && fixedSampleloc != fixedSampleLocations->value())
{
return false;
}
else
{
*fixedSampleLocations = fixedSampleloc;
}
}
if (samples->valid())
{
if (attachment.getSamples() != samples->value())
{
if (colorAttachment)
{
// APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that
// all color attachments have the same number of samples for the FBO to be complete.
return false;
}
else
{
// CHROMIUM_framebuffer_mixed_samples allows a framebuffer to be considered complete
// when its depth or stencil samples are a multiple of the number of color samples.
if (!context->getExtensions().framebufferMixedSamples)
{
return false;
}
if ((attachment.getSamples() % std::max(samples->value(), 1)) != 0)
{
return false;
}
}
}
}
else
{
*samples = attachment.getSamples();
}
return true;
}
} // anonymous namespace } // anonymous namespace
// This constructor is only used for default framebuffers. // This constructor is only used for default framebuffers.
...@@ -641,9 +704,9 @@ GLenum Framebuffer::checkStatusImpl(const Context *context) ...@@ -641,9 +704,9 @@ GLenum Framebuffer::checkStatusImpl(const Context *context)
ASSERT(mId != 0); ASSERT(mId != 0);
unsigned int colorbufferSize = 0; bool hasAttachments = false;
int samples = -1; Optional<unsigned int> colorbufferSize;
bool missingAttachment = true; Optional<int> samples;
Optional<GLboolean> fixedSampleLocations; Optional<GLboolean> fixedSampleLocations;
bool hasRenderbuffer = false; bool hasRenderbuffer = false;
...@@ -662,51 +725,31 @@ GLenum Framebuffer::checkStatusImpl(const Context *context) ...@@ -662,51 +725,31 @@ GLenum Framebuffer::checkStatusImpl(const Context *context)
return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
} }
if (colorAttachment.type() == GL_TEXTURE) if (!CheckAttachmentSampleCompleteness(context, colorAttachment, true, &samples,
{ &fixedSampleLocations))
// ES3.1 (section 9.4) requires that the value of TEXTURE_FIXED_SAMPLE_LOCATIONS
// should be the same for all attached textures.
GLboolean fixedSampleloc = colorAttachment.getTexture()->getFixedSampleLocations(
colorAttachment.getTextureImageIndex().type, 0);
if (fixedSampleLocations.valid() && fixedSampleloc != fixedSampleLocations.value())
{
return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
}
else
{
fixedSampleLocations = fixedSampleloc;
}
}
else if (colorAttachment.type() == GL_RENDERBUFFER)
{ {
hasRenderbuffer = true; return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
} }
if (!missingAttachment) // in GLES 2.0, all color attachments attachments must have the same number of bitplanes
// in GLES 3.0, there is no such restriction
if (state.getClientMajorVersion() < 3)
{ {
// APPLE_framebuffer_multisample, which EXT_draw_buffers refers to, requires that if (colorbufferSize.valid())
// all color attachments have the same number of samples for the FBO to be complete.
if (colorAttachment.getSamples() != samples)
{ {
return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT; if (format.pixelBytes != colorbufferSize.value())
}
// in GLES 2.0, all color attachments attachments must have the same number of
// bitplanes in GLES 3.0, there is no such restriction
if (state.getClientMajorVersion() < 3)
{
if (format.pixelBytes != colorbufferSize)
{ {
return GL_FRAMEBUFFER_UNSUPPORTED; return GL_FRAMEBUFFER_UNSUPPORTED;
} }
} }
else
{
colorbufferSize = format.pixelBytes;
}
} }
else
{ hasRenderbuffer = hasRenderbuffer || (colorAttachment.type() == GL_RENDERBUFFER);
samples = colorAttachment.getSamples(); hasAttachments = true;
colorbufferSize = format.pixelBytes;
missingAttachment = false;
}
} }
} }
...@@ -724,25 +767,14 @@ GLenum Framebuffer::checkStatusImpl(const Context *context) ...@@ -724,25 +767,14 @@ GLenum Framebuffer::checkStatusImpl(const Context *context)
return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
} }
if (missingAttachment) if (!CheckAttachmentSampleCompleteness(context, depthAttachment, false, &samples,
&fixedSampleLocations))
{ {
samples = depthAttachment.getSamples(); return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
missingAttachment = false;
}
else if (samples != depthAttachment.getSamples())
{
// CHROMIUM_framebuffer_mixed_samples allows a framebuffer to be
// considered complete when its depth or stencil samples are a
// multiple of the number of color samples.
const bool mixedSamples = state.getExtensions().framebufferMixedSamples;
if (!mixedSamples)
return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
const int colorSamples = samples ? samples : 1;
const int depthSamples = depthAttachment.getSamples();
if ((depthSamples % colorSamples) != 0)
return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
} }
hasRenderbuffer = hasRenderbuffer || (depthAttachment.type() == GL_RENDERBUFFER);
hasAttachments = true;
} }
const FramebufferAttachment &stencilAttachment = mState.mStencilAttachment; const FramebufferAttachment &stencilAttachment = mState.mStencilAttachment;
...@@ -759,30 +791,21 @@ GLenum Framebuffer::checkStatusImpl(const Context *context) ...@@ -759,30 +791,21 @@ GLenum Framebuffer::checkStatusImpl(const Context *context)
return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
} }
if (missingAttachment) if (!CheckAttachmentSampleCompleteness(context, stencilAttachment, false, &samples,
{ &fixedSampleLocations))
samples = stencilAttachment.getSamples();
missingAttachment = false;
}
else if (samples != stencilAttachment.getSamples())
{ {
// see the comments in depth attachment check. return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
const bool mixedSamples = state.getExtensions().framebufferMixedSamples;
if (!mixedSamples)
return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
const int colorSamples = samples ? samples : 1;
const int stencilSamples = stencilAttachment.getSamples();
if ((stencilSamples % colorSamples) != 0)
return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
} }
// Starting from ES 3.0 stencil and depth, if present, should be the same image hasRenderbuffer = hasRenderbuffer || (stencilAttachment.type() == GL_RENDERBUFFER);
if (state.getClientMajorVersion() >= 3 && depthAttachment.isAttached() && hasAttachments = true;
stencilAttachment != depthAttachment) }
{
return GL_FRAMEBUFFER_UNSUPPORTED; // Starting from ES 3.0 stencil and depth, if present, should be the same image
} if (state.getClientMajorVersion() >= 3 && depthAttachment.isAttached() &&
stencilAttachment.isAttached() && stencilAttachment != depthAttachment)
{
return GL_FRAMEBUFFER_UNSUPPORTED;
} }
// Special additional validation for WebGL 1 DEPTH/STENCIL/DEPTH_STENCIL. // Special additional validation for WebGL 1 DEPTH/STENCIL/DEPTH_STENCIL.
...@@ -813,14 +836,12 @@ GLenum Framebuffer::checkStatusImpl(const Context *context) ...@@ -813,14 +836,12 @@ GLenum Framebuffer::checkStatusImpl(const Context *context)
} }
} }
// ES3.1(section 9.4) requires that if no image is attached to the // ES3.1(section 9.4) requires that if no image is attached to the framebuffer, and either the
// framebuffer, and either the value of the framebuffer's FRAMEBUFFER_DEFAULT_WIDTH // value of the framebuffer's FRAMEBUFFER_DEFAULT_WIDTH or FRAMEBUFFER_DEFAULT_HEIGHT parameters
// or FRAMEBUFFER_DEFAULT_HEIGHT parameters is zero, the framebuffer is // is zero, the framebuffer is considered incomplete.
// considered incomplete.
GLint defaultWidth = mState.getDefaultWidth(); GLint defaultWidth = mState.getDefaultWidth();
GLint defaultHeight = mState.getDefaultHeight(); GLint defaultHeight = mState.getDefaultHeight();
if (!hasAttachments && (defaultWidth == 0 || defaultHeight == 0))
if (missingAttachment && (defaultWidth == 0 || defaultHeight == 0))
{ {
return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
} }
...@@ -833,9 +854,8 @@ GLenum Framebuffer::checkStatusImpl(const Context *context) ...@@ -833,9 +854,8 @@ GLenum Framebuffer::checkStatusImpl(const Context *context)
return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
} }
// ES3.1(section 9.4) requires that if the attached images are a mix of renderbuffers // ES3.1(section 9.4) requires that if the attached images are a mix of renderbuffers and
// and textures, the value of TEXTURE_FIXED_SAMPLE_LOCATIONS must be TRUE for all // textures, the value of TEXTURE_FIXED_SAMPLE_LOCATIONS must be TRUE for all attached textures.
// attached textures.
if (fixedSampleLocations.valid() && hasRenderbuffer && !fixedSampleLocations.value()) if (fixedSampleLocations.valid() && hasRenderbuffer && !fixedSampleLocations.value())
{ {
return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment