Commit c77cb596 by Jamie Madill Committed by Commit Bot

No-op draw calls with rendering feedback loops.

This is quite within spec and protects our various back-ends from FB loops. Also makes the check more cached for optimization purposes. Bug: angleproject:4490 Change-Id: Ia82ec88244d07670d68ce53495b5893b8a75ac42 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2118153 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarCody Northrop <cnorthrop@google.com>
parent 38152bda
......@@ -61,9 +61,14 @@ ANGLE_INLINE void MarkShaderStorageBufferUsage(const Context *context)
// Return true if the draw is a no-op, else return false.
// A no-op draw occurs if the count of vertices is less than the minimum required to
// have a valid primitive for this mode (0 for points, 0-1 for lines, 0-2 for tris).
// We also no-op draws that have rendering feedback loops. This is spec:
// "In this scenario, the framebuffer will be considered framebuffer complete
// but the values of fragments rendered while in this state will be undefined."
// From 3.2 spec: 9.3.1 Rendering Feedback Loops
ANGLE_INLINE bool Context::noopDraw(PrimitiveMode mode, GLsizei count)
{
return count < kMinimumPrimitiveCounts[mode];
return count < kMinimumPrimitiveCounts[mode] ||
mState.mDrawFramebuffer->hasRenderingFeedbackLoop();
}
ANGLE_INLINE angle::Result Context::syncDirtyBits()
......
......@@ -318,6 +318,7 @@ FramebufferState::FramebufferState()
mWebGLDepthStencilConsistent(true),
mDepthBufferFeedbackLoop(false),
mStencilBufferFeedbackLoop(false),
mHasRenderingFeedbackLoop(false),
mDefaultFramebufferReadAttachmentInitialized(false)
{
ASSERT(mDrawBufferStates.size() > 0);
......@@ -339,6 +340,7 @@ FramebufferState::FramebufferState(const Caps &caps, FramebufferID id)
mWebGLDepthStencilConsistent(true),
mDepthBufferFeedbackLoop(false),
mStencilBufferFeedbackLoop(false),
mHasRenderingFeedbackLoop(false),
mDefaultFramebufferReadAttachmentInitialized(false)
{
ASSERT(mId != Framebuffer::kDefaultDrawFramebufferHandle);
......@@ -679,22 +681,43 @@ bool FramebufferState::isDefault() const
bool FramebufferState::updateAttachmentFeedbackLoop(size_t dirtyBit)
{
bool loop;
switch (dirtyBit)
{
case Framebuffer::DIRTY_BIT_DEPTH_ATTACHMENT:
mDepthBufferFeedbackLoop = mDepthAttachment.isBoundAsSamplerOrImage();
return mDepthBufferFeedbackLoop;
loop = mDepthAttachment.isBoundAsSamplerOrImage();
mDepthBufferFeedbackLoop = loop;
break;
case Framebuffer::DIRTY_BIT_STENCIL_ATTACHMENT:
mStencilBufferFeedbackLoop = mStencilAttachment.isBoundAsSamplerOrImage();
return mStencilBufferFeedbackLoop;
loop = mStencilAttachment.isBoundAsSamplerOrImage();
mStencilBufferFeedbackLoop = loop;
break;
default:
ASSERT(dirtyBit <= Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX);
mDrawBufferFeedbackLoops[dirtyBit] =
mColorAttachments[dirtyBit].isBoundAsSamplerOrImage();
return mDrawBufferFeedbackLoops.test(dirtyBit);
loop = mColorAttachments[dirtyBit].isBoundAsSamplerOrImage();
mDrawBufferFeedbackLoops[dirtyBit] = loop;
break;
}
updateHasRenderingFeedbackLoop();
return loop;
}
void FramebufferState::updateHasRenderingFeedbackLoop()
{
// We don't handle tricky cases where the default FBO is bound as a sampler.
// We also don't handle tricky cases with EGLImages and mipmap selection.
// TODO(http://anglebug.com/4500): Tricky rendering feedback loop cases.
if (isDefault())
{
return;
}
mHasRenderingFeedbackLoop =
mDrawBufferFeedbackLoops.any() || mDepthBufferFeedbackLoop || mStencilBufferFeedbackLoop;
}
const FramebufferID Framebuffer::kDefaultDrawFramebufferHandle = {0};
......@@ -2003,20 +2026,6 @@ FramebufferAttachment *Framebuffer::getAttachmentFromSubjectIndex(angle::Subject
}
}
bool Framebuffer::formsRenderingFeedbackLoopWith(const Context *context) const
{
// We don't handle tricky cases where the default FBO is bound as a sampler.
// We also don't handle tricky cases with EGLImages and mipmap selection.
// TODO(http://anglebug.com/4500): Tricky rendering feedback loop cases.
if (mState.isDefault())
{
return false;
}
return mState.mDrawBufferFeedbackLoops.any() || mState.mDepthBufferFeedbackLoop ||
mState.mStencilBufferFeedbackLoop;
}
bool Framebuffer::formsCopyingFeedbackLoopWith(TextureID copyTextureID,
GLint copyTextureLevel,
GLint copyTextureLayer) const
......
......@@ -128,6 +128,7 @@ class FramebufferState final : angle::NonCopyable
const FramebufferAttachment *getWebGLDepthAttachment() const;
const FramebufferAttachment *getWebGLStencilAttachment() const;
bool updateAttachmentFeedbackLoop(size_t dirtyBit);
void updateHasRenderingFeedbackLoop();
friend class Framebuffer;
......@@ -160,6 +161,7 @@ class FramebufferState final : angle::NonCopyable
DrawBufferMask mDrawBufferFeedbackLoops;
bool mDepthBufferFeedbackLoop;
bool mStencilBufferFeedbackLoop;
bool mHasRenderingFeedbackLoop;
// Tracks if we need to initialize the resources for each attachment.
angle::BitSet<IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS + 2> mResourceNeedsInit;
......@@ -381,7 +383,7 @@ class Framebuffer final : public angle::ObserverInterface,
// Observer implementation
void onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message) override;
bool formsRenderingFeedbackLoopWith(const Context *context) const;
bool hasRenderingFeedbackLoop() const { return mState.mHasRenderingFeedbackLoop; }
bool formsCopyingFeedbackLoopWith(TextureID copyTextureID,
GLint copyTextureLevel,
GLint copyTextureLayer) const;
......
......@@ -2846,7 +2846,7 @@ const char *ValidateDrawStates(const Context *context)
}
// Detect rendering feedback loops for WebGL.
if (framebuffer->formsRenderingFeedbackLoopWith(context))
if (framebuffer->hasRenderingFeedbackLoop())
{
return kFeedbackLoop;
}
......
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