Commit d7890bca by Tobin Ehlis Committed by Commit Bot

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: 's avatarGeoff Lang <geofflang@chromium.org>
parent 44a3cf49
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <sstream> #include <sstream>
#include <vector> #include <vector>
#include "common/PackedEnums.h"
#include "common/matrix_utils.h" #include "common/matrix_utils.h"
#include "common/platform.h" #include "common/platform.h"
#include "common/utilities.h" #include "common/utilities.h"
...@@ -254,6 +255,46 @@ void LimitCap(CapT *cap, MaxT maximum) ...@@ -254,6 +255,46 @@ void LimitCap(CapT *cap, MaxT maximum)
*cap = std::min(*cap, static_cast<CapT>(maximum)); *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 } // anonymous namespace
namespace gl namespace gl
...@@ -2090,8 +2131,8 @@ void Context::texParameterIuivRobust(TextureType target, ...@@ -2090,8 +2131,8 @@ void Context::texParameterIuivRobust(TextureType target,
void Context::drawArrays(PrimitiveMode mode, GLint first, GLsizei count) void Context::drawArrays(PrimitiveMode mode, GLint first, GLsizei count)
{ {
// No-op if zero count // No-op if count draws no primitives for given mode
if (count == 0) if (noopDraw(mode, count))
{ {
return; return;
} }
...@@ -2106,8 +2147,8 @@ void Context::drawArraysInstanced(PrimitiveMode mode, ...@@ -2106,8 +2147,8 @@ void Context::drawArraysInstanced(PrimitiveMode mode,
GLsizei count, GLsizei count,
GLsizei instanceCount) GLsizei instanceCount)
{ {
// No-op if zero count // No-op if count draws no primitives for given mode
if (count == 0 || instanceCount == 0) if (noopDrawInstanced(mode, count, instanceCount))
{ {
return; return;
} }
...@@ -2121,8 +2162,8 @@ void Context::drawArraysInstanced(PrimitiveMode mode, ...@@ -2121,8 +2162,8 @@ void Context::drawArraysInstanced(PrimitiveMode mode,
void Context::drawElements(PrimitiveMode mode, GLsizei count, GLenum type, const void *indices) void Context::drawElements(PrimitiveMode mode, GLsizei count, GLenum type, const void *indices)
{ {
// No-op if zero count // No-op if count draws no primitives for given mode
if (count == 0) if (noopDraw(mode, count))
{ {
return; return;
} }
...@@ -2137,8 +2178,8 @@ void Context::drawElementsInstanced(PrimitiveMode mode, ...@@ -2137,8 +2178,8 @@ void Context::drawElementsInstanced(PrimitiveMode mode,
const void *indices, const void *indices,
GLsizei instances) GLsizei instances)
{ {
// No-op if zero count // No-op if count draws no primitives for given mode
if (count == 0 || instances == 0) if (noopDrawInstanced(mode, count, instances))
{ {
return; return;
} }
...@@ -2155,8 +2196,8 @@ void Context::drawRangeElements(PrimitiveMode mode, ...@@ -2155,8 +2196,8 @@ void Context::drawRangeElements(PrimitiveMode mode,
GLenum type, GLenum type,
const void *indices) const void *indices)
{ {
// No-op if zero count // No-op if count draws no primitives for given mode
if (count == 0) if (noopDraw(mode, count))
{ {
return; return;
} }
...@@ -3331,6 +3372,19 @@ void Context::initWorkarounds() ...@@ -3331,6 +3372,19 @@ void Context::initWorkarounds()
mWorkarounds.loseContextOnOutOfMemory = (mResetStrategy == GL_LOSE_CONTEXT_ON_RESET_EXT); 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) Error Context::prepareForDraw(PrimitiveMode mode)
{ {
if (mGLES1Renderer) if (mGLES1Renderer)
......
...@@ -1475,6 +1475,9 @@ class Context final : public egl::LabeledObject, angle::NonCopyable ...@@ -1475,6 +1475,9 @@ class Context final : public egl::LabeledObject, angle::NonCopyable
private: private:
void initialize(); void initialize();
bool noopDraw(PrimitiveMode mode, GLsizei count);
bool noopDrawInstanced(PrimitiveMode mode, GLsizei count, GLsizei instanceCount);
Error prepareForDraw(PrimitiveMode mode); Error prepareForDraw(PrimitiveMode mode);
Error prepareForClear(GLbitfield mask); Error prepareForClear(GLbitfield mask);
Error prepareForClearBuffer(GLenum buffer, GLint drawbuffer); Error prepareForClearBuffer(GLenum buffer, GLint drawbuffer);
......
...@@ -1458,7 +1458,7 @@ gl::Error Renderer11::drawWithGeometryShaderAndTransformFeedback(const gl::Conte ...@@ -1458,7 +1458,7 @@ gl::Error Renderer11::drawWithGeometryShaderAndTransformFeedback(const gl::Conte
gl::Error Renderer11::drawArrays(const gl::Context *context, const gl::DrawCallParams &params) gl::Error Renderer11::drawArrays(const gl::Context *context, const gl::DrawCallParams &params)
{ {
if (params.vertexCount() < static_cast<size_t>(mStateManager.getCurrentMinimumDrawCount())) if (mStateManager.getCullEverything())
{ {
return gl::NoError(); return gl::NoError();
} }
...@@ -1541,7 +1541,7 @@ gl::Error Renderer11::drawArrays(const gl::Context *context, const gl::DrawCallP ...@@ -1541,7 +1541,7 @@ gl::Error Renderer11::drawArrays(const gl::Context *context, const gl::DrawCallP
gl::Error Renderer11::drawElements(const gl::Context *context, const gl::DrawCallParams &params) gl::Error Renderer11::drawElements(const gl::Context *context, const gl::DrawCallParams &params)
{ {
if (params.indexCount() < mStateManager.getCurrentMinimumDrawCount()) if (mStateManager.getCullEverything())
{ {
return gl::NoError(); return gl::NoError();
} }
...@@ -1624,7 +1624,7 @@ gl::Error Renderer11::drawElements(const gl::Context *context, const gl::DrawCal ...@@ -1624,7 +1624,7 @@ gl::Error Renderer11::drawElements(const gl::Context *context, const gl::DrawCal
gl::Error Renderer11::drawArraysIndirect(const gl::Context *context, gl::Error Renderer11::drawArraysIndirect(const gl::Context *context,
const gl::DrawCallParams &params) const gl::DrawCallParams &params)
{ {
if (std::numeric_limits<GLsizei>::max() == mStateManager.getCurrentMinimumDrawCount()) if (mStateManager.getCullEverything())
{ {
return gl::NoError(); return gl::NoError();
} }
...@@ -1647,7 +1647,7 @@ gl::Error Renderer11::drawArraysIndirect(const gl::Context *context, ...@@ -1647,7 +1647,7 @@ gl::Error Renderer11::drawArraysIndirect(const gl::Context *context,
gl::Error Renderer11::drawElementsIndirect(const gl::Context *context, gl::Error Renderer11::drawElementsIndirect(const gl::Context *context,
const gl::DrawCallParams &params) const gl::DrawCallParams &params)
{ {
if (std::numeric_limits<GLsizei>::max() == mStateManager.getCurrentMinimumDrawCount()) if (mStateManager.getCullEverything())
{ {
return gl::NoError(); return gl::NoError();
} }
......
...@@ -549,7 +549,7 @@ StateManager11::StateManager11(Renderer11 *renderer) ...@@ -549,7 +549,7 @@ StateManager11::StateManager11(Renderer11 *renderer)
mDirtyVertexBufferRange(gl::MAX_VERTEX_ATTRIBS, 0), mDirtyVertexBufferRange(gl::MAX_VERTEX_ATTRIBS, 0),
mCurrentPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_UNDEFINED), mCurrentPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_UNDEFINED),
mLastAppliedDrawMode(gl::PrimitiveMode::InvalidEnum), mLastAppliedDrawMode(gl::PrimitiveMode::InvalidEnum),
mCurrentMinimumDrawCount(0), mCullEverything(false),
mDirtySwizzles(false), mDirtySwizzles(false),
mAppliedIB(nullptr), mAppliedIB(nullptr),
mAppliedIBFormat(DXGI_FORMAT_UNKNOWN), mAppliedIBFormat(DXGI_FORMAT_UNKNOWN),
...@@ -3400,6 +3400,8 @@ void StateManager11::syncPrimitiveTopology(const gl::State &glState, ...@@ -3400,6 +3400,8 @@ void StateManager11::syncPrimitiveTopology(const gl::State &glState,
gl::PrimitiveMode currentDrawMode) gl::PrimitiveMode currentDrawMode)
{ {
D3D11_PRIMITIVE_TOPOLOGY primitiveTopology = D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED; 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) switch (currentDrawMode)
{ {
...@@ -3414,7 +3416,7 @@ void StateManager11::syncPrimitiveTopology(const gl::State &glState, ...@@ -3414,7 +3416,7 @@ void StateManager11::syncPrimitiveTopology(const gl::State &glState,
{ {
// Notify developers of risking undefined behavior. // Notify developers of risking undefined behavior.
WARN() << "Point rendering without writing to gl_PointSize."; WARN() << "Point rendering without writing to gl_PointSize.";
mCurrentMinimumDrawCount = std::numeric_limits<GLsizei>::max(); mCullEverything = true;
return; return;
} }
...@@ -3428,36 +3430,29 @@ void StateManager11::syncPrimitiveTopology(const gl::State &glState, ...@@ -3428,36 +3430,29 @@ void StateManager11::syncPrimitiveTopology(const gl::State &glState,
{ {
primitiveTopology = D3D11_PRIMITIVE_TOPOLOGY_POINTLIST; primitiveTopology = D3D11_PRIMITIVE_TOPOLOGY_POINTLIST;
} }
mCurrentMinimumDrawCount = 1;
break; break;
} }
case gl::PrimitiveMode::Lines: case gl::PrimitiveMode::Lines:
primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_LINELIST; primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_LINELIST;
mCurrentMinimumDrawCount = 2;
break; break;
case gl::PrimitiveMode::LineLoop: case gl::PrimitiveMode::LineLoop:
primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP; primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP;
mCurrentMinimumDrawCount = 2;
break; break;
case gl::PrimitiveMode::LineStrip: case gl::PrimitiveMode::LineStrip:
primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP; primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP;
mCurrentMinimumDrawCount = 2;
break; break;
case gl::PrimitiveMode::Triangles: case gl::PrimitiveMode::Triangles:
primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
mCurrentMinimumDrawCount = mCullEverything = CullsEverything(glState);
CullsEverything(glState) ? std::numeric_limits<GLsizei>::max() : 3;
break; break;
case gl::PrimitiveMode::TriangleStrip: case gl::PrimitiveMode::TriangleStrip:
primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
mCurrentMinimumDrawCount = mCullEverything = CullsEverything(glState);
CullsEverything(glState) ? std::numeric_limits<GLsizei>::max() : 3;
break; break;
// emulate fans via rewriting index buffer // emulate fans via rewriting index buffer
case gl::PrimitiveMode::TriangleFan: case gl::PrimitiveMode::TriangleFan:
primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; primitiveTopology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
mCurrentMinimumDrawCount = mCullEverything = CullsEverything(glState);
CullsEverything(glState) ? std::numeric_limits<GLsizei>::max() : 3;
break; break;
default: default:
UNREACHABLE(); UNREACHABLE();
......
...@@ -243,7 +243,7 @@ class StateManager11 final : angle::NonCopyable ...@@ -243,7 +243,7 @@ class StateManager11 final : angle::NonCopyable
// Only used in testing. // Only used in testing.
InputLayoutCache *getInputLayoutCache() { return &mInputLayoutCache; } InputLayoutCache *getInputLayoutCache() { return &mInputLayoutCache; }
GLsizei getCurrentMinimumDrawCount() const { return mCurrentMinimumDrawCount; } bool getCullEverything() const { return mCullEverything; }
VertexDataManager *getVertexDataManager() { return &mVertexDataManager; } VertexDataManager *getVertexDataManager() { return &mVertexDataManager; }
ProgramD3D *getProgramD3D() const { return mProgramD3D; } ProgramD3D *getProgramD3D() const { return mProgramD3D; }
...@@ -487,7 +487,7 @@ class StateManager11 final : angle::NonCopyable ...@@ -487,7 +487,7 @@ class StateManager11 final : angle::NonCopyable
// Currently applied primitive topology // Currently applied primitive topology
D3D11_PRIMITIVE_TOPOLOGY mCurrentPrimitiveTopology; D3D11_PRIMITIVE_TOPOLOGY mCurrentPrimitiveTopology;
gl::PrimitiveMode mLastAppliedDrawMode; gl::PrimitiveMode mLastAppliedDrawMode;
GLsizei mCurrentMinimumDrawCount; bool mCullEverything;
// Currently applied shaders // Currently applied shaders
gl::ShaderMap<ResourceSerial> mAppliedShaders; gl::ShaderMap<ResourceSerial> mAppliedShaders;
......
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