Commit eaf56133 by Jonah Ryan-Davis Committed by Commit Bot

gl_VertexID is incorrect if offset argument to glDrawArrays is non-zero

On D3D the vertex ID is always indexed from 0, unlike GL. The D3D backend had assumed the wrong behavior. This forwards the true offset to D3D by using the ConstantsBuffer. Bug: angleproject:3090 Change-Id: Ia19e3490503c97541af14979b75af0c94c67ab6b Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1520988 Commit-Queue: Jonah Ryan-Davis <jonahr@google.com> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent e3dc0dfa
...@@ -849,6 +849,11 @@ void OutputHLSL::header(TInfoSinkBase &out, ...@@ -849,6 +849,11 @@ void OutputHLSL::header(TInfoSinkBase &out,
mResourcesHLSL->samplerMetadataUniforms(out, 4); mResourcesHLSL->samplerMetadataUniforms(out, 4);
} }
if (mUsesVertexID)
{
out << " uint dx_VertexID : packoffset(c3.w);\n";
}
out << "};\n" out << "};\n"
"\n"; "\n";
} }
...@@ -977,6 +982,11 @@ void OutputHLSL::header(TInfoSinkBase &out, ...@@ -977,6 +982,11 @@ void OutputHLSL::header(TInfoSinkBase &out,
out << "#define GL_ANGLE_MULTIVIEW_ENABLED\n"; out << "#define GL_ANGLE_MULTIVIEW_ENABLED\n";
} }
if (mUsesVertexID)
{
out << "#define GL_USES_VERTEX_ID\n";
}
if (mUsesViewID) if (mUsesViewID)
{ {
out << "#define GL_USES_VIEW_ID\n"; out << "#define GL_USES_VIEW_ID\n";
......
...@@ -244,6 +244,12 @@ std::string DynamicHLSL::generateVertexShaderForInputLayout( ...@@ -244,6 +244,12 @@ std::string DynamicHLSL::generateVertexShaderForInputLayout(
initStream << "input." << DecorateVariable(shaderAttribute.name); initStream << "input." << DecorateVariable(shaderAttribute.name);
} }
if (shaderAttribute.name == "gl_VertexID")
{
// dx_VertexID contains the firstVertex offset
initStream << " + dx_VertexID";
}
initStream << ";\n"; initStream << ";\n";
inputIndex += VariableRowCount(TransposeMatrixType(shaderAttribute.type)); inputIndex += VariableRowCount(TransposeMatrixType(shaderAttribute.type));
......
...@@ -513,6 +513,11 @@ bool ProgramD3DMetadata::hasANGLEMultiviewEnabled() const ...@@ -513,6 +513,11 @@ bool ProgramD3DMetadata::hasANGLEMultiviewEnabled() const
return mAttachedShaders[gl::ShaderType::Vertex]->hasANGLEMultiviewEnabled(); return mAttachedShaders[gl::ShaderType::Vertex]->hasANGLEMultiviewEnabled();
} }
bool ProgramD3DMetadata::usesVertexID() const
{
return mAttachedShaders[gl::ShaderType::Vertex]->usesVertexID();
}
bool ProgramD3DMetadata::usesViewID() const bool ProgramD3DMetadata::usesViewID() const
{ {
return mAttachedShaders[gl::ShaderType::Fragment]->usesViewID(); return mAttachedShaders[gl::ShaderType::Fragment]->usesViewID();
...@@ -1148,6 +1153,7 @@ std::unique_ptr<rx::LinkEvent> ProgramD3D::load(const gl::Context *context, ...@@ -1148,6 +1153,7 @@ std::unique_ptr<rx::LinkEvent> ProgramD3D::load(const gl::Context *context,
stream->readBool(&mUsesFragDepth); stream->readBool(&mUsesFragDepth);
stream->readBool(&mHasANGLEMultiviewEnabled); stream->readBool(&mHasANGLEMultiviewEnabled);
stream->readBool(&mUsesVertexID);
stream->readBool(&mUsesViewID); stream->readBool(&mUsesViewID);
stream->readBool(&mUsesPointSize); stream->readBool(&mUsesPointSize);
stream->readBool(&mUsesFlatInterpolation); stream->readBool(&mUsesFlatInterpolation);
...@@ -1429,6 +1435,7 @@ void ProgramD3D::save(const gl::Context *context, gl::BinaryOutputStream *stream ...@@ -1429,6 +1435,7 @@ void ProgramD3D::save(const gl::Context *context, gl::BinaryOutputStream *stream
stream->writeInt(mUsesFragDepth); stream->writeInt(mUsesFragDepth);
stream->writeInt(mHasANGLEMultiviewEnabled); stream->writeInt(mHasANGLEMultiviewEnabled);
stream->writeInt(mUsesVertexID);
stream->writeInt(mUsesViewID); stream->writeInt(mUsesViewID);
stream->writeInt(mUsesPointSize); stream->writeInt(mUsesPointSize);
stream->writeInt(mUsesFlatInterpolation); stream->writeInt(mUsesFlatInterpolation);
...@@ -2018,6 +2025,7 @@ std::unique_ptr<LinkEvent> ProgramD3D::link(const gl::Context *context, ...@@ -2018,6 +2025,7 @@ std::unique_ptr<LinkEvent> ProgramD3D::link(const gl::Context *context,
mUsesPointSize = shadersD3D[gl::ShaderType::Vertex]->usesPointSize(); mUsesPointSize = shadersD3D[gl::ShaderType::Vertex]->usesPointSize();
mDynamicHLSL->getPixelShaderOutputKey(data, mState, metadata, &mPixelShaderKey); mDynamicHLSL->getPixelShaderOutputKey(data, mState, metadata, &mPixelShaderKey);
mUsesFragDepth = metadata.usesFragDepth(); mUsesFragDepth = metadata.usesFragDepth();
mUsesVertexID = metadata.usesVertexID();
mUsesViewID = metadata.usesViewID(); mUsesViewID = metadata.usesViewID();
mHasANGLEMultiviewEnabled = metadata.hasANGLEMultiviewEnabled(); mHasANGLEMultiviewEnabled = metadata.hasANGLEMultiviewEnabled();
...@@ -2866,6 +2874,7 @@ void ProgramD3D::reset() ...@@ -2866,6 +2874,7 @@ void ProgramD3D::reset()
mUsesFragDepth = false; mUsesFragDepth = false;
mHasANGLEMultiviewEnabled = false; mHasANGLEMultiviewEnabled = false;
mUsesVertexID = false;
mUsesViewID = false; mUsesViewID = false;
mPixelShaderKey.clear(); mPixelShaderKey.clear();
mUsesPointSize = false; mUsesPointSize = false;
......
...@@ -129,6 +129,7 @@ class ProgramD3DMetadata final : angle::NonCopyable ...@@ -129,6 +129,7 @@ class ProgramD3DMetadata final : angle::NonCopyable
bool usesInsertedPointCoordValue() const; bool usesInsertedPointCoordValue() const;
bool usesViewScale() const; bool usesViewScale() const;
bool hasANGLEMultiviewEnabled() const; bool hasANGLEMultiviewEnabled() const;
bool usesVertexID() const;
bool usesViewID() const; bool usesViewID() const;
bool canSelectViewInVertexShader() const; bool canSelectViewInVertexShader() const;
bool addsPointCoordToVertexShader() const; bool addsPointCoordToVertexShader() const;
...@@ -324,6 +325,8 @@ class ProgramD3D : public ProgramImpl ...@@ -324,6 +325,8 @@ class ProgramD3D : public ProgramImpl
bool readonly); bool readonly);
bool hasNamedUniform(const std::string &name); bool hasNamedUniform(const std::string &name);
bool usesVertexID() const { return mUsesVertexID; }
private: private:
// These forward-declared tasks are used for multi-thread shader compiles. // These forward-declared tasks are used for multi-thread shader compiles.
class GetExecutableTask; class GetExecutableTask;
...@@ -512,6 +515,7 @@ class ProgramD3D : public ProgramImpl ...@@ -512,6 +515,7 @@ class ProgramD3D : public ProgramImpl
bool mUsesFragDepth; bool mUsesFragDepth;
bool mHasANGLEMultiviewEnabled; bool mHasANGLEMultiviewEnabled;
bool mUsesVertexID;
bool mUsesViewID; bool mUsesViewID;
std::vector<PixelShaderOutputVariable> mPixelShaderKey; std::vector<PixelShaderOutputVariable> mPixelShaderKey;
......
...@@ -87,6 +87,7 @@ void ShaderD3D::uncompile() ...@@ -87,6 +87,7 @@ void ShaderD3D::uncompile()
mUsesDepthRange = false; mUsesDepthRange = false;
mUsesFragDepth = false; mUsesFragDepth = false;
mHasANGLEMultiviewEnabled = false; mHasANGLEMultiviewEnabled = false;
mUsesVertexID = false;
mUsesViewID = false; mUsesViewID = false;
mUsesDiscardRewriting = false; mUsesDiscardRewriting = false;
mUsesNestedBreak = false; mUsesNestedBreak = false;
...@@ -216,6 +217,7 @@ bool ShaderD3D::postTranslateCompile(gl::ShCompilerInstance *compiler, std::stri ...@@ -216,6 +217,7 @@ bool ShaderD3D::postTranslateCompile(gl::ShCompilerInstance *compiler, std::stri
mUsesFragDepth = translatedSource.find("GL_USES_FRAG_DEPTH") != std::string::npos; mUsesFragDepth = translatedSource.find("GL_USES_FRAG_DEPTH") != std::string::npos;
mHasANGLEMultiviewEnabled = mHasANGLEMultiviewEnabled =
translatedSource.find("GL_ANGLE_MULTIVIEW_ENABLED") != std::string::npos; translatedSource.find("GL_ANGLE_MULTIVIEW_ENABLED") != std::string::npos;
mUsesVertexID = translatedSource.find("GL_USES_VERTEX_ID") != std::string::npos;
mUsesViewID = translatedSource.find("GL_USES_VIEW_ID") != std::string::npos; mUsesViewID = translatedSource.find("GL_USES_VIEW_ID") != std::string::npos;
mUsesDiscardRewriting = mUsesDiscardRewriting =
translatedSource.find("ANGLE_USES_DISCARD_REWRITING") != std::string::npos; translatedSource.find("ANGLE_USES_DISCARD_REWRITING") != std::string::npos;
......
...@@ -72,6 +72,7 @@ class ShaderD3D : public ShaderImpl ...@@ -72,6 +72,7 @@ class ShaderD3D : public ShaderImpl
bool usesPointCoord() const { return mUsesPointCoord; } bool usesPointCoord() const { return mUsesPointCoord; }
bool usesDepthRange() const { return mUsesDepthRange; } bool usesDepthRange() const { return mUsesDepthRange; }
bool usesFragDepth() const { return mUsesFragDepth; } bool usesFragDepth() const { return mUsesFragDepth; }
bool usesVertexID() const { return mUsesVertexID; }
bool usesViewID() const { return mUsesViewID; } bool usesViewID() const { return mUsesViewID; }
bool hasANGLEMultiviewEnabled() const { return mHasANGLEMultiviewEnabled; } bool hasANGLEMultiviewEnabled() const { return mHasANGLEMultiviewEnabled; }
...@@ -88,6 +89,7 @@ class ShaderD3D : public ShaderImpl ...@@ -88,6 +89,7 @@ class ShaderD3D : public ShaderImpl
bool mUsesDepthRange; bool mUsesDepthRange;
bool mUsesFragDepth; bool mUsesFragDepth;
bool mHasANGLEMultiviewEnabled; bool mHasANGLEMultiviewEnabled;
bool mUsesVertexID;
bool mUsesViewID; bool mUsesViewID;
bool mUsesDiscardRewriting; bool mUsesDiscardRewriting;
bool mUsesNestedBreak; bool mUsesNestedBreak;
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "libANGLE/renderer/d3d/d3d11/StateManager11.h" #include "libANGLE/renderer/d3d/d3d11/StateManager11.h"
#include "common/angleutils.h"
#include "common/bitset_utils.h" #include "common/bitset_utils.h"
#include "common/mathutil.h" #include "common/mathutil.h"
#include "common/utilities.h" #include "common/utilities.h"
...@@ -489,6 +490,19 @@ void ShaderConstants11::onViewportChange(const gl::Rectangle &glViewport, ...@@ -489,6 +490,19 @@ void ShaderConstants11::onViewportChange(const gl::Rectangle &glViewport,
mVertex.viewScale[1] = mPixel.viewScale[1]; mVertex.viewScale[1] = mPixel.viewScale[1];
} }
// Update the ShaderConstants with a new first vertex and return whether the update dirties them.
ANGLE_INLINE bool ShaderConstants11::onFirstVertexChange(GLint firstVertex)
{
uint32_t newFirstVertex = static_cast<uint32_t>(firstVertex);
bool firstVertexDirty = (mVertex.firstVertex != newFirstVertex);
if (firstVertexDirty)
{
mVertex.firstVertex = newFirstVertex;
mShaderConstantsDirty.set(gl::ShaderType::Vertex);
}
return firstVertexDirty;
}
void ShaderConstants11::onSamplerChange(gl::ShaderType shaderType, void ShaderConstants11::onSamplerChange(gl::ShaderType shaderType,
unsigned int samplerIndex, unsigned int samplerIndex,
const gl::Texture &texture, const gl::Texture &texture,
...@@ -2172,6 +2186,15 @@ angle::Result StateManager11::updateState(const gl::Context *context, ...@@ -2172,6 +2186,15 @@ angle::Result StateManager11::updateState(const gl::Context *context,
invalidateInputLayout(); invalidateInputLayout();
} }
// The ShaderConstants only need to be updated when the program uses vertexID
if (mProgramD3D->usesVertexID())
{
if (mShaderConstants.onFirstVertexChange(firstVertex))
{
mInternalDirtyBits.set(DIRTY_BIT_PROGRAM_UNIFORM_BUFFERS);
}
}
if (indexTypeOrInvalid != gl::DrawElementsType::InvalidEnum) if (indexTypeOrInvalid != gl::DrawElementsType::InvalidEnum)
{ {
ANGLE_TRY(applyIndexBuffer(context, vertexOrIndexCount, indexTypeOrInvalid, indices)); ANGLE_TRY(applyIndexBuffer(context, vertexOrIndexCount, indexTypeOrInvalid, indices));
......
...@@ -44,6 +44,7 @@ class ShaderConstants11 : angle::NonCopyable ...@@ -44,6 +44,7 @@ class ShaderConstants11 : angle::NonCopyable
const D3D11_VIEWPORT &dxViewport, const D3D11_VIEWPORT &dxViewport,
bool is9_3, bool is9_3,
bool presentPathFast); bool presentPathFast);
bool onFirstVertexChange(GLint firstVertex);
void onImageLayerChange(gl::ShaderType shaderType, unsigned int imageIndex, int layer); void onImageLayerChange(gl::ShaderType shaderType, unsigned int imageIndex, int layer);
void onSamplerChange(gl::ShaderType shaderType, void onSamplerChange(gl::ShaderType shaderType,
unsigned int samplerIndex, unsigned int samplerIndex,
...@@ -68,7 +69,7 @@ class ShaderConstants11 : angle::NonCopyable ...@@ -68,7 +69,7 @@ class ShaderConstants11 : angle::NonCopyable
viewCoords{.0f}, viewCoords{.0f},
viewScale{.0f}, viewScale{.0f},
multiviewWriteToViewportIndex{.0f}, multiviewWriteToViewportIndex{.0f},
padding{.0f} firstVertex{0}
{} {}
float depthRange[4]; float depthRange[4];
...@@ -80,8 +81,7 @@ class ShaderConstants11 : angle::NonCopyable ...@@ -80,8 +81,7 @@ class ShaderConstants11 : angle::NonCopyable
// whenever a multi-view draw framebuffer is made active. // whenever a multi-view draw framebuffer is made active.
float multiviewWriteToViewportIndex; float multiviewWriteToViewportIndex;
// Added here to manually pad the struct. uint32_t firstVertex;
float padding;
}; };
struct Pixel struct Pixel
......
...@@ -609,6 +609,78 @@ void main() ...@@ -609,6 +609,78 @@ void main()
ANGLE_GL_PROGRAM(program, kVS, kFS); ANGLE_GL_PROGRAM(program, kVS, kFS);
} }
// Draw an array of points with the first vertex offset at 0 using gl_VertexID
TEST_P(GLSLTest_ES3, GLVertexIDOffsetZeroDrawArray)
{
constexpr int kStartIndex = 0;
constexpr int kArrayLength = 5;
constexpr char kVS[] = R"(#version 300 es
precision highp float;
void main() {
gl_Position = vec4(float(gl_VertexID)/10.0, 0, 0, 1);
gl_PointSize = 3.0;
})";
constexpr char kFS[] = R"(#version 300 es
precision highp float;
out vec4 outColor;
void main() {
outColor = vec4(255.0, 0.0, 0.0, 1.0);
})";
ANGLE_GL_PROGRAM(program, kVS, kFS);
glUseProgram(program);
glDrawArrays(GL_POINTS, kStartIndex, kArrayLength);
double pointCenterX = static_cast<double>(getWindowWidth()) / 2.0;
double pointCenterY = static_cast<double>(getWindowHeight()) / 2.0;
for (int i = kStartIndex; i < kStartIndex + kArrayLength; i++)
{
double pointOffsetX = static_cast<double>(i * getWindowWidth()) / 20.0;
EXPECT_PIXEL_COLOR_EQ(static_cast<int>(pointCenterX + pointOffsetX),
static_cast<int>(pointCenterY), GLColor::red);
}
}
// Draw an array of points with the first vertex offset at 5 using gl_VertexID
TEST_P(GLSLTest_ES3, GLVertexIDOffsetFiveDrawArray)
{
// TODO(jonahr): Remove test suppression once Nexus 5X is removed from bots
// (http://anglebug.com/3264)
ANGLE_SKIP_TEST_IF(IsAndroid() && IsOpenGLES());
constexpr int kStartIndex = 5;
constexpr int kArrayLength = 5;
constexpr char kVS[] = R"(#version 300 es
precision highp float;
void main() {
gl_Position = vec4(float(gl_VertexID)/10.0, 0, 0, 1);
gl_PointSize = 3.0;
})";
constexpr char kFS[] = R"(#version 300 es
precision highp float;
out vec4 outColor;
void main() {
outColor = vec4(255.0, 0.0, 0.0, 1.0);
})";
ANGLE_GL_PROGRAM(program, kVS, kFS);
glUseProgram(program);
glDrawArrays(GL_POINTS, kStartIndex, kArrayLength);
double pointCenterX = static_cast<double>(getWindowWidth()) / 2.0;
double pointCenterY = static_cast<double>(getWindowHeight()) / 2.0;
for (int i = kStartIndex; i < kStartIndex + kArrayLength; i++)
{
double pointOffsetX = static_cast<double>(i * getWindowWidth()) / 20.0;
EXPECT_PIXEL_COLOR_EQ(static_cast<int>(pointCenterX + pointOffsetX),
static_cast<int>(pointCenterY), GLColor::red);
}
}
TEST_P(GLSLTest, ElseIfRewriting) TEST_P(GLSLTest, ElseIfRewriting)
{ {
constexpr char kVS[] = constexpr char kVS[] =
......
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