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,
mResourcesHLSL->samplerMetadataUniforms(out, 4);
}
if (mUsesVertexID)
{
out << " uint dx_VertexID : packoffset(c3.w);\n";
}
out << "};\n"
"\n";
}
......@@ -977,6 +982,11 @@ void OutputHLSL::header(TInfoSinkBase &out,
out << "#define GL_ANGLE_MULTIVIEW_ENABLED\n";
}
if (mUsesVertexID)
{
out << "#define GL_USES_VERTEX_ID\n";
}
if (mUsesViewID)
{
out << "#define GL_USES_VIEW_ID\n";
......
......@@ -244,6 +244,12 @@ std::string DynamicHLSL::generateVertexShaderForInputLayout(
initStream << "input." << DecorateVariable(shaderAttribute.name);
}
if (shaderAttribute.name == "gl_VertexID")
{
// dx_VertexID contains the firstVertex offset
initStream << " + dx_VertexID";
}
initStream << ";\n";
inputIndex += VariableRowCount(TransposeMatrixType(shaderAttribute.type));
......
......@@ -513,6 +513,11 @@ bool ProgramD3DMetadata::hasANGLEMultiviewEnabled() const
return mAttachedShaders[gl::ShaderType::Vertex]->hasANGLEMultiviewEnabled();
}
bool ProgramD3DMetadata::usesVertexID() const
{
return mAttachedShaders[gl::ShaderType::Vertex]->usesVertexID();
}
bool ProgramD3DMetadata::usesViewID() const
{
return mAttachedShaders[gl::ShaderType::Fragment]->usesViewID();
......@@ -1148,6 +1153,7 @@ std::unique_ptr<rx::LinkEvent> ProgramD3D::load(const gl::Context *context,
stream->readBool(&mUsesFragDepth);
stream->readBool(&mHasANGLEMultiviewEnabled);
stream->readBool(&mUsesVertexID);
stream->readBool(&mUsesViewID);
stream->readBool(&mUsesPointSize);
stream->readBool(&mUsesFlatInterpolation);
......@@ -1429,6 +1435,7 @@ void ProgramD3D::save(const gl::Context *context, gl::BinaryOutputStream *stream
stream->writeInt(mUsesFragDepth);
stream->writeInt(mHasANGLEMultiviewEnabled);
stream->writeInt(mUsesVertexID);
stream->writeInt(mUsesViewID);
stream->writeInt(mUsesPointSize);
stream->writeInt(mUsesFlatInterpolation);
......@@ -2018,6 +2025,7 @@ std::unique_ptr<LinkEvent> ProgramD3D::link(const gl::Context *context,
mUsesPointSize = shadersD3D[gl::ShaderType::Vertex]->usesPointSize();
mDynamicHLSL->getPixelShaderOutputKey(data, mState, metadata, &mPixelShaderKey);
mUsesFragDepth = metadata.usesFragDepth();
mUsesVertexID = metadata.usesVertexID();
mUsesViewID = metadata.usesViewID();
mHasANGLEMultiviewEnabled = metadata.hasANGLEMultiviewEnabled();
......@@ -2866,6 +2874,7 @@ void ProgramD3D::reset()
mUsesFragDepth = false;
mHasANGLEMultiviewEnabled = false;
mUsesVertexID = false;
mUsesViewID = false;
mPixelShaderKey.clear();
mUsesPointSize = false;
......
......@@ -129,6 +129,7 @@ class ProgramD3DMetadata final : angle::NonCopyable
bool usesInsertedPointCoordValue() const;
bool usesViewScale() const;
bool hasANGLEMultiviewEnabled() const;
bool usesVertexID() const;
bool usesViewID() const;
bool canSelectViewInVertexShader() const;
bool addsPointCoordToVertexShader() const;
......@@ -324,6 +325,8 @@ class ProgramD3D : public ProgramImpl
bool readonly);
bool hasNamedUniform(const std::string &name);
bool usesVertexID() const { return mUsesVertexID; }
private:
// These forward-declared tasks are used for multi-thread shader compiles.
class GetExecutableTask;
......@@ -512,6 +515,7 @@ class ProgramD3D : public ProgramImpl
bool mUsesFragDepth;
bool mHasANGLEMultiviewEnabled;
bool mUsesVertexID;
bool mUsesViewID;
std::vector<PixelShaderOutputVariable> mPixelShaderKey;
......
......@@ -87,6 +87,7 @@ void ShaderD3D::uncompile()
mUsesDepthRange = false;
mUsesFragDepth = false;
mHasANGLEMultiviewEnabled = false;
mUsesVertexID = false;
mUsesViewID = false;
mUsesDiscardRewriting = false;
mUsesNestedBreak = false;
......@@ -216,6 +217,7 @@ bool ShaderD3D::postTranslateCompile(gl::ShCompilerInstance *compiler, std::stri
mUsesFragDepth = translatedSource.find("GL_USES_FRAG_DEPTH") != std::string::npos;
mHasANGLEMultiviewEnabled =
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;
mUsesDiscardRewriting =
translatedSource.find("ANGLE_USES_DISCARD_REWRITING") != std::string::npos;
......
......@@ -72,6 +72,7 @@ class ShaderD3D : public ShaderImpl
bool usesPointCoord() const { return mUsesPointCoord; }
bool usesDepthRange() const { return mUsesDepthRange; }
bool usesFragDepth() const { return mUsesFragDepth; }
bool usesVertexID() const { return mUsesVertexID; }
bool usesViewID() const { return mUsesViewID; }
bool hasANGLEMultiviewEnabled() const { return mHasANGLEMultiviewEnabled; }
......@@ -88,6 +89,7 @@ class ShaderD3D : public ShaderImpl
bool mUsesDepthRange;
bool mUsesFragDepth;
bool mHasANGLEMultiviewEnabled;
bool mUsesVertexID;
bool mUsesViewID;
bool mUsesDiscardRewriting;
bool mUsesNestedBreak;
......
......@@ -8,6 +8,7 @@
#include "libANGLE/renderer/d3d/d3d11/StateManager11.h"
#include "common/angleutils.h"
#include "common/bitset_utils.h"
#include "common/mathutil.h"
#include "common/utilities.h"
......@@ -489,6 +490,19 @@ void ShaderConstants11::onViewportChange(const gl::Rectangle &glViewport,
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,
unsigned int samplerIndex,
const gl::Texture &texture,
......@@ -2172,6 +2186,15 @@ angle::Result StateManager11::updateState(const gl::Context *context,
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)
{
ANGLE_TRY(applyIndexBuffer(context, vertexOrIndexCount, indexTypeOrInvalid, indices));
......
......@@ -44,6 +44,7 @@ class ShaderConstants11 : angle::NonCopyable
const D3D11_VIEWPORT &dxViewport,
bool is9_3,
bool presentPathFast);
bool onFirstVertexChange(GLint firstVertex);
void onImageLayerChange(gl::ShaderType shaderType, unsigned int imageIndex, int layer);
void onSamplerChange(gl::ShaderType shaderType,
unsigned int samplerIndex,
......@@ -68,7 +69,7 @@ class ShaderConstants11 : angle::NonCopyable
viewCoords{.0f},
viewScale{.0f},
multiviewWriteToViewportIndex{.0f},
padding{.0f}
firstVertex{0}
{}
float depthRange[4];
......@@ -80,8 +81,7 @@ class ShaderConstants11 : angle::NonCopyable
// whenever a multi-view draw framebuffer is made active.
float multiviewWriteToViewportIndex;
// Added here to manually pad the struct.
float padding;
uint32_t firstVertex;
};
struct Pixel
......
......@@ -609,6 +609,78 @@ void main()
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)
{
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