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) ...@@ -61,9 +61,14 @@ ANGLE_INLINE void MarkShaderStorageBufferUsage(const Context *context)
// Return true if the draw is a no-op, else return false. // 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 // 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). // 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) 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() ANGLE_INLINE angle::Result Context::syncDirtyBits()
......
...@@ -318,6 +318,7 @@ FramebufferState::FramebufferState() ...@@ -318,6 +318,7 @@ FramebufferState::FramebufferState()
mWebGLDepthStencilConsistent(true), mWebGLDepthStencilConsistent(true),
mDepthBufferFeedbackLoop(false), mDepthBufferFeedbackLoop(false),
mStencilBufferFeedbackLoop(false), mStencilBufferFeedbackLoop(false),
mHasRenderingFeedbackLoop(false),
mDefaultFramebufferReadAttachmentInitialized(false) mDefaultFramebufferReadAttachmentInitialized(false)
{ {
ASSERT(mDrawBufferStates.size() > 0); ASSERT(mDrawBufferStates.size() > 0);
...@@ -339,6 +340,7 @@ FramebufferState::FramebufferState(const Caps &caps, FramebufferID id) ...@@ -339,6 +340,7 @@ FramebufferState::FramebufferState(const Caps &caps, FramebufferID id)
mWebGLDepthStencilConsistent(true), mWebGLDepthStencilConsistent(true),
mDepthBufferFeedbackLoop(false), mDepthBufferFeedbackLoop(false),
mStencilBufferFeedbackLoop(false), mStencilBufferFeedbackLoop(false),
mHasRenderingFeedbackLoop(false),
mDefaultFramebufferReadAttachmentInitialized(false) mDefaultFramebufferReadAttachmentInitialized(false)
{ {
ASSERT(mId != Framebuffer::kDefaultDrawFramebufferHandle); ASSERT(mId != Framebuffer::kDefaultDrawFramebufferHandle);
...@@ -679,22 +681,43 @@ bool FramebufferState::isDefault() const ...@@ -679,22 +681,43 @@ bool FramebufferState::isDefault() const
bool FramebufferState::updateAttachmentFeedbackLoop(size_t dirtyBit) bool FramebufferState::updateAttachmentFeedbackLoop(size_t dirtyBit)
{ {
bool loop;
switch (dirtyBit) switch (dirtyBit)
{ {
case Framebuffer::DIRTY_BIT_DEPTH_ATTACHMENT: case Framebuffer::DIRTY_BIT_DEPTH_ATTACHMENT:
mDepthBufferFeedbackLoop = mDepthAttachment.isBoundAsSamplerOrImage(); loop = mDepthAttachment.isBoundAsSamplerOrImage();
return mDepthBufferFeedbackLoop; mDepthBufferFeedbackLoop = loop;
break;
case Framebuffer::DIRTY_BIT_STENCIL_ATTACHMENT: case Framebuffer::DIRTY_BIT_STENCIL_ATTACHMENT:
mStencilBufferFeedbackLoop = mStencilAttachment.isBoundAsSamplerOrImage(); loop = mStencilAttachment.isBoundAsSamplerOrImage();
return mStencilBufferFeedbackLoop; mStencilBufferFeedbackLoop = loop;
break;
default: default:
ASSERT(dirtyBit <= Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX); ASSERT(dirtyBit <= Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX);
mDrawBufferFeedbackLoops[dirtyBit] = loop = mColorAttachments[dirtyBit].isBoundAsSamplerOrImage();
mColorAttachments[dirtyBit].isBoundAsSamplerOrImage(); mDrawBufferFeedbackLoops[dirtyBit] = loop;
return mDrawBufferFeedbackLoops.test(dirtyBit); 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}; const FramebufferID Framebuffer::kDefaultDrawFramebufferHandle = {0};
...@@ -2003,20 +2026,6 @@ FramebufferAttachment *Framebuffer::getAttachmentFromSubjectIndex(angle::Subject ...@@ -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, bool Framebuffer::formsCopyingFeedbackLoopWith(TextureID copyTextureID,
GLint copyTextureLevel, GLint copyTextureLevel,
GLint copyTextureLayer) const GLint copyTextureLayer) const
......
...@@ -128,6 +128,7 @@ class FramebufferState final : angle::NonCopyable ...@@ -128,6 +128,7 @@ class FramebufferState final : angle::NonCopyable
const FramebufferAttachment *getWebGLDepthAttachment() const; const FramebufferAttachment *getWebGLDepthAttachment() const;
const FramebufferAttachment *getWebGLStencilAttachment() const; const FramebufferAttachment *getWebGLStencilAttachment() const;
bool updateAttachmentFeedbackLoop(size_t dirtyBit); bool updateAttachmentFeedbackLoop(size_t dirtyBit);
void updateHasRenderingFeedbackLoop();
friend class Framebuffer; friend class Framebuffer;
...@@ -160,6 +161,7 @@ class FramebufferState final : angle::NonCopyable ...@@ -160,6 +161,7 @@ class FramebufferState final : angle::NonCopyable
DrawBufferMask mDrawBufferFeedbackLoops; DrawBufferMask mDrawBufferFeedbackLoops;
bool mDepthBufferFeedbackLoop; bool mDepthBufferFeedbackLoop;
bool mStencilBufferFeedbackLoop; bool mStencilBufferFeedbackLoop;
bool mHasRenderingFeedbackLoop;
// Tracks if we need to initialize the resources for each attachment. // Tracks if we need to initialize the resources for each attachment.
angle::BitSet<IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS + 2> mResourceNeedsInit; angle::BitSet<IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS + 2> mResourceNeedsInit;
...@@ -381,7 +383,7 @@ class Framebuffer final : public angle::ObserverInterface, ...@@ -381,7 +383,7 @@ class Framebuffer final : public angle::ObserverInterface,
// Observer implementation // Observer implementation
void onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message) override; 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, bool formsCopyingFeedbackLoopWith(TextureID copyTextureID,
GLint copyTextureLevel, GLint copyTextureLevel,
GLint copyTextureLayer) const; GLint copyTextureLayer) const;
......
...@@ -2846,7 +2846,7 @@ const char *ValidateDrawStates(const Context *context) ...@@ -2846,7 +2846,7 @@ const char *ValidateDrawStates(const Context *context)
} }
// Detect rendering feedback loops for WebGL. // Detect rendering feedback loops for WebGL.
if (framebuffer->formsRenderingFeedbackLoopWith(context)) if (framebuffer->hasRenderingFeedbackLoop())
{ {
return kFeedbackLoop; 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