Skip noop draws in the frontend
If a draw does not have enough vertices for its primitive count to
produce a primitive then skip it. If an instanced draw has 0 instances
or not have enough vertices for its primitive count to
produce a primitive then skip it.
This means a Point with 0 vertices, a Line w/ 0-1 vertices, or a tri
with 0-2 primitives.
Updated some redundant code in the D3D11 backend. Draws below the
minDrawCount will no longer be passed to the backend so updated the
associated state in StateManager11 to only track the case where all
primitives should be culled due to GL state settings.
BUG=angleproject:2568
TEST=functional_transform_feedback_basic_types_interleaved_lines_lowp_int
Change-Id: I9faa767c12004fcdec923ec70a8ee5615d789813
Reviewed-on: https://chromium-review.googlesource.com/1120849
Commit-Queue: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libANGLE/Context.cpp b/src/libANGLE/Context.cpp
index c3bc863..be15449 100644
--- a/src/libANGLE/Context.cpp
+++ b/src/libANGLE/Context.cpp
@@ -14,6 +14,7 @@
#include <sstream>
#include <vector>
+#include "common/PackedEnums.h"
#include "common/matrix_utils.h"
#include "common/platform.h"
#include "common/utilities.h"
@@ -254,6 +255,46 @@
*cap = std::min(*cap, static_cast<CapT>(maximum));
}
+constexpr angle::PackedEnumMap<gl::PrimitiveMode, GLsizei> kMinimumPrimitiveCounts = {{
+ /* Points */ 1,
+ /* Lines */ 2,
+ /* LineLoop */ 2,
+ /* LineStrip */ 2,
+ /* Triangles */ 3,
+ /* TriangleStrip */ 3,
+ /* TriangleFan */ 3,
+ /* LinesAdjacency */ 2,
+ /* LineStripAdjacency */ 2,
+ /* TrianglesAdjacency */ 3,
+ /* TriangleStripAdjacency */ 3,
+}};
+// Indices above are code-gen'd so make sure they don't change
+// if any of these static asserts are hit, must update kMinimumPrimitiveCounts abouve
+static_assert(static_cast<gl::PrimitiveMode>(0) == gl::PrimitiveMode::Points,
+ "gl::PrimitiveMode enum values have changed, update kMinimumPrimitiveCounts.");
+static_assert(static_cast<gl::PrimitiveMode>(1) == gl::PrimitiveMode::Lines,
+ "gl::PrimitiveMode enum values have changed, update kMinimumPrimitiveCounts.");
+static_assert(static_cast<gl::PrimitiveMode>(2) == gl::PrimitiveMode::LineLoop,
+ "gl::PrimitiveMode enum values have changed, update kMinimumPrimitiveCounts.");
+static_assert(static_cast<gl::PrimitiveMode>(3) == gl::PrimitiveMode::LineStrip,
+ "gl::PrimitiveMode enum values have changed, update kMinimumPrimitiveCounts.");
+static_assert(static_cast<gl::PrimitiveMode>(4) == gl::PrimitiveMode::Triangles,
+ "gl::PrimitiveMode enum values have changed, update kMinimumPrimitiveCounts.");
+static_assert(static_cast<gl::PrimitiveMode>(5) == gl::PrimitiveMode::TriangleStrip,
+ "gl::PrimitiveMode enum values have changed, update kMinimumPrimitiveCounts.");
+static_assert(static_cast<gl::PrimitiveMode>(6) == gl::PrimitiveMode::TriangleFan,
+ "gl::PrimitiveMode enum values have changed, update kMinimumPrimitiveCounts.");
+static_assert(static_cast<gl::PrimitiveMode>(7) == gl::PrimitiveMode::LinesAdjacency,
+ "gl::PrimitiveMode enum values have changed, update kMinimumPrimitiveCounts.");
+static_assert(static_cast<gl::PrimitiveMode>(8) == gl::PrimitiveMode::LineStripAdjacency,
+ "gl::PrimitiveMode enum values have changed, update kMinimumPrimitiveCounts.");
+static_assert(static_cast<gl::PrimitiveMode>(9) == gl::PrimitiveMode::TrianglesAdjacency,
+ "gl::PrimitiveMode enum values have changed, update kMinimumPrimitiveCounts.");
+static_assert(static_cast<gl::PrimitiveMode>(10) == gl::PrimitiveMode::TriangleStripAdjacency,
+ "gl::PrimitiveMode enum values have changed, update kMinimumPrimitiveCounts.");
+static_assert(static_cast<gl::PrimitiveMode>(11) == gl::PrimitiveMode::EnumCount,
+ "gl::PrimitiveMode enum values have changed, update kMinimumPrimitiveCounts.");
+
} // anonymous namespace
namespace gl
@@ -2090,8 +2131,8 @@
void Context::drawArrays(PrimitiveMode mode, GLint first, GLsizei count)
{
- // No-op if zero count
- if (count == 0)
+ // No-op if count draws no primitives for given mode
+ if (noopDraw(mode, count))
{
return;
}
@@ -2106,8 +2147,8 @@
GLsizei count,
GLsizei instanceCount)
{
- // No-op if zero count
- if (count == 0 || instanceCount == 0)
+ // No-op if count draws no primitives for given mode
+ if (noopDrawInstanced(mode, count, instanceCount))
{
return;
}
@@ -2121,8 +2162,8 @@
void Context::drawElements(PrimitiveMode mode, GLsizei count, GLenum type, const void *indices)
{
- // No-op if zero count
- if (count == 0)
+ // No-op if count draws no primitives for given mode
+ if (noopDraw(mode, count))
{
return;
}
@@ -2137,8 +2178,8 @@
const void *indices,
GLsizei instances)
{
- // No-op if zero count
- if (count == 0 || instances == 0)
+ // No-op if count draws no primitives for given mode
+ if (noopDrawInstanced(mode, count, instances))
{
return;
}
@@ -2155,8 +2196,8 @@
GLenum type,
const void *indices)
{
- // No-op if zero count
- if (count == 0)
+ // No-op if count draws no primitives for given mode
+ if (noopDraw(mode, count))
{
return;
}
@@ -3331,6 +3372,19 @@
mWorkarounds.loseContextOnOutOfMemory = (mResetStrategy == GL_LOSE_CONTEXT_ON_RESET_EXT);
}
+// 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).
+bool Context::noopDraw(PrimitiveMode mode, GLsizei count)
+{
+ return count < kMinimumPrimitiveCounts[mode];
+}
+
+bool Context::noopDrawInstanced(PrimitiveMode mode, GLsizei count, GLsizei instanceCount)
+{
+ return (instanceCount == 0) || noopDraw(mode, count);
+}
+
Error Context::prepareForDraw(PrimitiveMode mode)
{
if (mGLES1Renderer)
diff --git a/src/libANGLE/Context.h b/src/libANGLE/Context.h
index 9335439..d1b2e1a 100644
--- a/src/libANGLE/Context.h
+++ b/src/libANGLE/Context.h
@@ -1475,6 +1475,9 @@
private:
void initialize();
+ bool noopDraw(PrimitiveMode mode, GLsizei count);
+ bool noopDrawInstanced(PrimitiveMode mode, GLsizei count, GLsizei instanceCount);
+
Error prepareForDraw(PrimitiveMode mode);
Error prepareForClear(GLbitfield mask);
Error prepareForClearBuffer(GLenum buffer, GLint drawbuffer);
diff --git a/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp b/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
index 4a41a4f..56d44ed 100644
--- a/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
@@ -1458,7 +1458,7 @@
gl::Error Renderer11::drawArrays(const gl::Context *context, const gl::DrawCallParams ¶ms)
{
- if (params.vertexCount() < static_cast<size_t>(mStateManager.getCurrentMinimumDrawCount()))
+ if (mStateManager.getCullEverything())
{
return gl::NoError();
}
@@ -1541,7 +1541,7 @@
gl::Error Renderer11::drawElements(const gl::Context *context, const gl::DrawCallParams ¶ms)
{
- if (params.indexCount() < mStateManager.getCurrentMinimumDrawCount())
+ if (mStateManager.getCullEverything())
{
return gl::NoError();
}
@@ -1624,7 +1624,7 @@
gl::Error Renderer11::drawArraysIndirect(const gl::Context *context,
const gl::DrawCallParams ¶ms)
{
- if (std::numeric_limits<GLsizei>::max() == mStateManager.getCurrentMinimumDrawCount())
+ if (mStateManager.getCullEverything())
{
return gl::NoError();
}
@@ -1647,7 +1647,7 @@
gl::Error Renderer11::drawElementsIndirect(const gl::Context *context,
const gl::DrawCallParams ¶ms)
{
- if (std::numeric_limits<GLsizei>::max() == mStateManager.getCurrentMinimumDrawCount())
+ if (mStateManager.getCullEverything())
{
return gl::NoError();
}
diff --git a/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp b/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp
index ac9a1be..335b4e8 100644
--- a/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/StateManager11.cpp
@@ -549,7 +549,7 @@
mDirtyVertexBufferRange(gl::MAX_VERTEX_ATTRIBS, 0),
mCurrentPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_UNDEFINED),
mLastAppliedDrawMode(gl::PrimitiveMode::InvalidEnum),
- mCurrentMinimumDrawCount(0),
+ mCullEverything(false),
mDirtySwizzles(false),
mAppliedIB(nullptr),
mAppliedIBFormat(DXGI_FORMAT_UNKNOWN),
@@ -3400,6 +3400,8 @@
gl::PrimitiveMode currentDrawMode)
{
D3D11_PRIMITIVE_TOPOLOGY primitiveTopology = D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED;
+ // Don't cull everything by default, this also resets if we were previously culling
+ mCullEverything = false;
switch (currentDrawMode)
{
@@ -3414,7 +3416,7 @@
{
// Notify developers of risking undefined behavior.
WARN() << "Point rendering without writing to gl_PointSize.";
- mCurrentMinimumDrawCount = std::numeric_limits<GLsizei>::max();
+ mCullEverything = true;
return;
}
@@ -3428,36 +3430,29 @@
{
primitiveTopology = D3D11_PRIMITIVE_TOPOLOGY_POINTLIST;
}
- mCurrentMinimumDrawCount = 1;
break;
}
case gl::PrimitiveMode::Lines:
primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_LINELIST;
- mCurrentMinimumDrawCount = 2;
break;
case gl::PrimitiveMode::LineLoop:
primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP;
- mCurrentMinimumDrawCount = 2;
break;
case gl::PrimitiveMode::LineStrip:
primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP;
- mCurrentMinimumDrawCount = 2;
break;
case gl::PrimitiveMode::Triangles:
primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
- mCurrentMinimumDrawCount =
- CullsEverything(glState) ? std::numeric_limits<GLsizei>::max() : 3;
+ mCullEverything = CullsEverything(glState);
break;
case gl::PrimitiveMode::TriangleStrip:
primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
- mCurrentMinimumDrawCount =
- CullsEverything(glState) ? std::numeric_limits<GLsizei>::max() : 3;
+ mCullEverything = CullsEverything(glState);
break;
// emulate fans via rewriting index buffer
case gl::PrimitiveMode::TriangleFan:
primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
- mCurrentMinimumDrawCount =
- CullsEverything(glState) ? std::numeric_limits<GLsizei>::max() : 3;
+ mCullEverything = CullsEverything(glState);
break;
default:
UNREACHABLE();
diff --git a/src/libANGLE/renderer/d3d/d3d11/StateManager11.h b/src/libANGLE/renderer/d3d/d3d11/StateManager11.h
index 798210c..5cab0b6 100644
--- a/src/libANGLE/renderer/d3d/d3d11/StateManager11.h
+++ b/src/libANGLE/renderer/d3d/d3d11/StateManager11.h
@@ -243,7 +243,7 @@
// Only used in testing.
InputLayoutCache *getInputLayoutCache() { return &mInputLayoutCache; }
- GLsizei getCurrentMinimumDrawCount() const { return mCurrentMinimumDrawCount; }
+ bool getCullEverything() const { return mCullEverything; }
VertexDataManager *getVertexDataManager() { return &mVertexDataManager; }
ProgramD3D *getProgramD3D() const { return mProgramD3D; }
@@ -487,7 +487,7 @@
// Currently applied primitive topology
D3D11_PRIMITIVE_TOPOLOGY mCurrentPrimitiveTopology;
gl::PrimitiveMode mLastAppliedDrawMode;
- GLsizei mCurrentMinimumDrawCount;
+ bool mCullEverything;
// Currently applied shaders
gl::ShaderMap<ResourceSerial> mAppliedShaders;