Commit 2a9e107c by Jamie Madill Committed by Commit Bot

Vulkan: Support multiple vertex outputs.

This is a bit of a hack, similar to how D3D11 works. We need to write output locations in the GLSL shader before we send them to glslang, so we wait until the link call, then string-replace some hard-coded identifeir code to the attribute location determined by ANGLE. This CL also fills in some of the vertex format conversion tables in formatutilsvk.cpp. BUG=angleproject:2167 Change-Id: I2424d0d990bdbcd831a4dd130e61e87d8f8f479f Reviewed-on: https://chromium-review.googlesource.com/677555 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarFrank Henigman <fjhenigman@chromium.org>
parent a9c60e9f
...@@ -49,44 +49,6 @@ bool isSingleStatement(TIntermNode *node) ...@@ -49,44 +49,6 @@ bool isSingleStatement(TIntermNode *node)
return true; return true;
} }
// If SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS is enabled, layout qualifiers are spilled whenever
// variables with specified layout qualifiers are copied. Additional checks are needed against the
// type and storage qualifier of the variable to verify that layout qualifiers have to be outputted.
// TODO (mradev): Fix layout qualifier spilling in ScalarizeVecAndMatConstructorArgs and remove
// NeedsToWriteLayoutQualifier.
bool NeedsToWriteLayoutQualifier(const TType &type)
{
if (type.getBasicType() == EbtInterfaceBlock)
{
return false;
}
const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
if ((type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn ||
IsVarying(type.getQualifier())) &&
layoutQualifier.location >= 0)
{
return true;
}
if (type.getQualifier() == EvqFragmentOut && layoutQualifier.yuv == true)
{
return true;
}
if (IsOpaqueType(type.getBasicType()) && layoutQualifier.binding != -1)
{
return true;
}
if (IsImage(type.getBasicType()) && layoutQualifier.imageInternalFormat != EiifUnspecified)
{
return true;
}
return false;
}
class CommaSeparatedListItemPrefixGenerator class CommaSeparatedListItemPrefixGenerator
{ {
public: public:
...@@ -194,8 +156,10 @@ void TOutputGLSLBase::writeBuiltInFunctionTriplet(Visit visit, ...@@ -194,8 +156,10 @@ void TOutputGLSLBase::writeBuiltInFunctionTriplet(Visit visit,
} }
} }
void TOutputGLSLBase::writeLayoutQualifier(const TType &type) void TOutputGLSLBase::writeLayoutQualifier(TIntermTyped *variable)
{ {
const TType &type = variable->getType();
if (!NeedsToWriteLayoutQualifier(type)) if (!NeedsToWriteLayoutQualifier(type))
{ {
return; return;
...@@ -1030,8 +994,8 @@ bool TOutputGLSLBase::visitDeclaration(Visit visit, TIntermDeclaration *node) ...@@ -1030,8 +994,8 @@ bool TOutputGLSLBase::visitDeclaration(Visit visit, TIntermDeclaration *node)
if (visit == PreVisit) if (visit == PreVisit)
{ {
const TIntermSequence &sequence = *(node->getSequence()); const TIntermSequence &sequence = *(node->getSequence());
const TIntermTyped *variable = sequence.front()->getAsTyped(); TIntermTyped *variable = sequence.front()->getAsTyped();
writeLayoutQualifier(variable->getType()); writeLayoutQualifier(variable);
writeVariableType(variable->getType()); writeVariableType(variable->getType());
out << " "; out << " ";
mDeclaringVariables = true; mDeclaringVariables = true;
...@@ -1332,4 +1296,42 @@ void WriteGeometryShaderLayoutQualifiers(TInfoSinkBase &out, ...@@ -1332,4 +1296,42 @@ void WriteGeometryShaderLayoutQualifiers(TInfoSinkBase &out,
} }
} }
// If SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS is enabled, layout qualifiers are spilled whenever
// variables with specified layout qualifiers are copied. Additional checks are needed against the
// type and storage qualifier of the variable to verify that layout qualifiers have to be outputted.
// TODO (mradev): Fix layout qualifier spilling in ScalarizeVecAndMatConstructorArgs and remove
// NeedsToWriteLayoutQualifier.
bool NeedsToWriteLayoutQualifier(const TType &type)
{
if (type.getBasicType() == EbtInterfaceBlock)
{
return false;
}
const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
if ((type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn ||
IsVarying(type.getQualifier())) &&
layoutQualifier.location >= 0)
{
return true;
}
if (type.getQualifier() == EvqFragmentOut && layoutQualifier.yuv == true)
{
return true;
}
if (IsOpaqueType(type.getBasicType()) && layoutQualifier.binding != -1)
{
return true;
}
if (IsImage(type.getBasicType()) && layoutQualifier.imageInternalFormat != EiifUnspecified)
{
return true;
}
return false;
}
} // namespace sh } // namespace sh
...@@ -40,7 +40,7 @@ class TOutputGLSLBase : public TIntermTraverser ...@@ -40,7 +40,7 @@ class TOutputGLSLBase : public TIntermTraverser
TInfoSinkBase &objSink() { return mObjSink; } TInfoSinkBase &objSink() { return mObjSink; }
void writeFloat(TInfoSinkBase &out, float f); void writeFloat(TInfoSinkBase &out, float f);
void writeTriplet(Visit visit, const char *preStr, const char *inStr, const char *postStr); void writeTriplet(Visit visit, const char *preStr, const char *inStr, const char *postStr);
virtual void writeLayoutQualifier(const TType &type); virtual void writeLayoutQualifier(TIntermTyped *variable);
void writeInvariantQualifier(const TType &type); void writeInvariantQualifier(const TType &type);
void writeVariableType(const TType &type); void writeVariableType(const TType &type);
virtual bool writeVariablePrecision(TPrecision precision) = 0; virtual bool writeVariablePrecision(TPrecision precision) = 0;
...@@ -115,6 +115,8 @@ void WriteGeometryShaderLayoutQualifiers(TInfoSinkBase &out, ...@@ -115,6 +115,8 @@ void WriteGeometryShaderLayoutQualifiers(TInfoSinkBase &out,
sh::TLayoutPrimitiveType outputPrimitive, sh::TLayoutPrimitiveType outputPrimitive,
int maxVertices); int maxVertices);
bool NeedsToWriteLayoutQualifier(const TType &type);
} // namespace sh } // namespace sh
#endif // COMPILER_TRANSLATOR_OUTPUTGLSLBASE_H_ #endif // COMPILER_TRANSLATOR_OUTPUTGLSLBASE_H_
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
#include "compiler/translator/OutputVulkanGLSL.h" #include "compiler/translator/OutputVulkanGLSL.h"
#include "compiler/translator/util.h"
namespace sh namespace sh
{ {
...@@ -23,32 +25,42 @@ TOutputVulkanGLSL::TOutputVulkanGLSL(TInfoSinkBase &objSink, ...@@ -23,32 +25,42 @@ TOutputVulkanGLSL::TOutputVulkanGLSL(TInfoSinkBase &objSink,
int shaderVersion, int shaderVersion,
ShShaderOutput output, ShShaderOutput output,
ShCompileOptions compileOptions) ShCompileOptions compileOptions)
: TOutputGLSLBase(objSink, : TOutputGLSL(objSink,
clampingStrategy, clampingStrategy,
hashFunction, hashFunction,
nameMap, nameMap,
symbolTable, symbolTable,
shaderType, shaderType,
shaderVersion, shaderVersion,
output, output,
compileOptions) compileOptions)
{ {
} }
// TODO(jmadill): This is not complete. // TODO(jmadill): This is not complete.
void TOutputVulkanGLSL::writeLayoutQualifier(const TType &type) void TOutputVulkanGLSL::writeLayoutQualifier(TIntermTyped *variable)
{ {
const TType &type = variable->getType();
bool forceLocation =
(type.getQualifier() == EvqAttribute || type.getQualifier() == EvqFragmentOut ||
type.getQualifier() == EvqVertexIn);
if (!NeedsToWriteLayoutQualifier(type) && !forceLocation)
{
return;
}
TInfoSinkBase &out = objSink(); TInfoSinkBase &out = objSink();
const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier(); const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier();
out << "layout("; out << "layout(";
if (type.getQualifier() == EvqAttribute || type.getQualifier() == EvqFragmentOut || // This isn't super clean, but it gets the job done.
type.getQualifier() == EvqVertexIn) // See corresponding code in GlslangWrapper.cpp.
{ // TODO(jmadill): Ensure declarations are separated.
// TODO(jmadill): Multiple output locations. TIntermSymbol *symbol = variable->getAsSymbolNode();
out << "location = " ASSERT(symbol);
<< "0"; out << "location = @@ LOCATION-" << symbol->getName().getString() << " @@";
}
if (IsImage(type.getBasicType()) && layoutQualifier.imageInternalFormat != EiifUnspecified) if (IsImage(type.getBasicType()) && layoutQualifier.imageInternalFormat != EiifUnspecified)
{ {
...@@ -69,23 +81,4 @@ bool TOutputVulkanGLSL::writeVariablePrecision(TPrecision precision) ...@@ -69,23 +81,4 @@ bool TOutputVulkanGLSL::writeVariablePrecision(TPrecision precision)
return true; return true;
} }
void TOutputVulkanGLSL::visitSymbol(TIntermSymbol *node)
{
TInfoSinkBase &out = objSink();
const TString &symbol = node->getSymbol();
if (symbol == "gl_FragColor")
{
out << "webgl_FragColor";
}
else if (symbol == "gl_FragData")
{
out << "webgl_FragData";
}
else
{
TOutputGLSLBase::visitSymbol(node);
}
}
} // namespace sh } // namespace sh
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
namespace sh namespace sh
{ {
class TOutputVulkanGLSL : public TOutputGLSLBase class TOutputVulkanGLSL : public TOutputGLSL
{ {
public: public:
TOutputVulkanGLSL(TInfoSinkBase &objSink, TOutputVulkanGLSL(TInfoSinkBase &objSink,
...@@ -28,9 +28,8 @@ class TOutputVulkanGLSL : public TOutputGLSLBase ...@@ -28,9 +28,8 @@ class TOutputVulkanGLSL : public TOutputGLSLBase
ShCompileOptions compileOptions); ShCompileOptions compileOptions);
protected: protected:
void writeLayoutQualifier(const TType &type) override; void writeLayoutQualifier(TIntermTyped *variable) override;
bool writeVariablePrecision(TPrecision precision) override; bool writeVariablePrecision(TPrecision precision) override;
void visitSymbol(TIntermSymbol *node) override;
}; };
} // namespace sh } // namespace sh
...@@ -63,11 +63,35 @@ GlslangWrapper::~GlslangWrapper() ...@@ -63,11 +63,35 @@ GlslangWrapper::~GlslangWrapper()
ASSERT(result != 0); ASSERT(result != 0);
} }
gl::LinkResult GlslangWrapper::linkProgram(const std::string &vertexSource, gl::LinkResult GlslangWrapper::linkProgram(const gl::Context *glContext,
const std::string &fragmentSource, const gl::ProgramState &programState,
std::vector<uint32_t> *vertexCodeOut, std::vector<uint32_t> *vertexCodeOut,
std::vector<uint32_t> *fragmentCodeOut) std::vector<uint32_t> *fragmentCodeOut)
{ {
std::string vertexSource =
programState.getAttachedVertexShader()->getTranslatedSource(glContext);
const std::string &fragmentSource =
programState.getAttachedFragmentShader()->getTranslatedSource(glContext);
// Parse attribute locations and replace them in the vertex shader.
// See corresponding code in OutputVulkanGLSL.cpp.
// TODO(jmadill): Also do the same for ESSL 3 fragment outputs.
for (const auto &attribute : programState.getAttributes())
{
if (!attribute.staticUse)
continue;
std::stringstream searchStringBuilder;
searchStringBuilder << "@@ LOCATION-" << attribute.name << " @@";
std::string searchString = searchStringBuilder.str();
std::string locationString = Str(attribute.location);
size_t replacePos = vertexSource.find(searchString);
ASSERT(replacePos != std::string::npos);
vertexSource.replace(replacePos, searchString.size(), locationString);
}
std::array<const char *, 2> strings = {{vertexSource.c_str(), fragmentSource.c_str()}}; std::array<const char *, 2> strings = {{vertexSource.c_str(), fragmentSource.c_str()}};
std::array<int, 2> lengths = { std::array<int, 2> lengths = {
......
...@@ -23,8 +23,8 @@ class GlslangWrapper : public gl::RefCountObjectNoID ...@@ -23,8 +23,8 @@ class GlslangWrapper : public gl::RefCountObjectNoID
static GlslangWrapper *GetReference(); static GlslangWrapper *GetReference();
static void ReleaseReference(); static void ReleaseReference();
gl::LinkResult linkProgram(const std::string &vertexSource, gl::LinkResult linkProgram(const gl::Context *glContext,
const std::string &fragmentSource, const gl::ProgramState &programState,
std::vector<uint32_t> *vertexCodeOut, std::vector<uint32_t> *vertexCodeOut,
std::vector<uint32_t> *fragmentCodeOut); std::vector<uint32_t> *fragmentCodeOut);
......
...@@ -66,17 +66,11 @@ gl::LinkResult ProgramVk::link(const gl::Context *glContext, ...@@ -66,17 +66,11 @@ gl::LinkResult ProgramVk::link(const gl::Context *glContext,
RendererVk *renderer = context->getRenderer(); RendererVk *renderer = context->getRenderer();
GlslangWrapper *glslangWrapper = renderer->getGlslangWrapper(); GlslangWrapper *glslangWrapper = renderer->getGlslangWrapper();
const std::string &vertexSource =
mState.getAttachedVertexShader()->getTranslatedSource(glContext);
const std::string &fragmentSource =
mState.getAttachedFragmentShader()->getTranslatedSource(glContext);
std::vector<uint32_t> vertexCode; std::vector<uint32_t> vertexCode;
std::vector<uint32_t> fragmentCode; std::vector<uint32_t> fragmentCode;
bool linkSuccess = false; bool linkSuccess = false;
ANGLE_TRY_RESULT( ANGLE_TRY_RESULT(glslangWrapper->linkProgram(glContext, mState, &vertexCode, &fragmentCode),
glslangWrapper->linkProgram(vertexSource, fragmentSource, &vertexCode, &fragmentCode), linkSuccess);
linkSuccess);
if (!linkSuccess) if (!linkSuccess)
{ {
return false; return false;
......
...@@ -540,6 +540,7 @@ void RendererVk::generateCaps(gl::Caps *outCaps, ...@@ -540,6 +540,7 @@ void RendererVk::generateCaps(gl::Caps *outCaps,
outCaps->maxDrawBuffers = 1; outCaps->maxDrawBuffers = 1;
outCaps->maxVertexAttributes = gl::MAX_VERTEX_ATTRIBS; outCaps->maxVertexAttributes = gl::MAX_VERTEX_ATTRIBS;
outCaps->maxVertexAttribBindings = gl::MAX_VERTEX_ATTRIB_BINDINGS; outCaps->maxVertexAttribBindings = gl::MAX_VERTEX_ATTRIB_BINDINGS;
outCaps->maxVaryingVectors = 16;
// Enable this for simple buffer readback testing, but some functionality is missing. // Enable this for simple buffer readback testing, but some functionality is missing.
// TODO(jmadill): Support full mapBufferRange extension. // TODO(jmadill): Support full mapBufferRange extension.
......
...@@ -35,53 +35,37 @@ VkFormat GetNativeVertexFormat(gl::VertexFormatType vertexFormat) ...@@ -35,53 +35,37 @@ VkFormat GetNativeVertexFormat(gl::VertexFormatType vertexFormat)
UNREACHABLE(); UNREACHABLE();
return VK_FORMAT_UNDEFINED; return VK_FORMAT_UNDEFINED;
case gl::VERTEX_FORMAT_SBYTE1: case gl::VERTEX_FORMAT_SBYTE1:
UNIMPLEMENTED(); return VK_FORMAT_R8_SINT;
return VK_FORMAT_UNDEFINED;
case gl::VERTEX_FORMAT_SBYTE1_NORM: case gl::VERTEX_FORMAT_SBYTE1_NORM:
UNIMPLEMENTED(); return VK_FORMAT_R8_SNORM;
return VK_FORMAT_UNDEFINED;
case gl::VERTEX_FORMAT_SBYTE2: case gl::VERTEX_FORMAT_SBYTE2:
UNIMPLEMENTED(); return VK_FORMAT_R8G8_SINT;
return VK_FORMAT_UNDEFINED;
case gl::VERTEX_FORMAT_SBYTE2_NORM: case gl::VERTEX_FORMAT_SBYTE2_NORM:
UNIMPLEMENTED(); return VK_FORMAT_R8G8_SNORM;
return VK_FORMAT_UNDEFINED;
case gl::VERTEX_FORMAT_SBYTE3: case gl::VERTEX_FORMAT_SBYTE3:
UNIMPLEMENTED(); return VK_FORMAT_R8G8B8_SINT;
return VK_FORMAT_UNDEFINED;
case gl::VERTEX_FORMAT_SBYTE3_NORM: case gl::VERTEX_FORMAT_SBYTE3_NORM:
UNIMPLEMENTED(); return VK_FORMAT_R8G8B8_SNORM;
return VK_FORMAT_UNDEFINED;
case gl::VERTEX_FORMAT_SBYTE4: case gl::VERTEX_FORMAT_SBYTE4:
UNIMPLEMENTED(); return VK_FORMAT_R8G8B8A8_SINT;
return VK_FORMAT_UNDEFINED;
case gl::VERTEX_FORMAT_SBYTE4_NORM: case gl::VERTEX_FORMAT_SBYTE4_NORM:
UNIMPLEMENTED(); return VK_FORMAT_R8G8B8A8_SNORM;
return VK_FORMAT_UNDEFINED;
case gl::VERTEX_FORMAT_UBYTE1: case gl::VERTEX_FORMAT_UBYTE1:
UNIMPLEMENTED(); return VK_FORMAT_R8_UINT;
return VK_FORMAT_UNDEFINED;
case gl::VERTEX_FORMAT_UBYTE1_NORM: case gl::VERTEX_FORMAT_UBYTE1_NORM:
UNIMPLEMENTED(); return VK_FORMAT_R8_UNORM;
return VK_FORMAT_UNDEFINED;
case gl::VERTEX_FORMAT_UBYTE2: case gl::VERTEX_FORMAT_UBYTE2:
UNIMPLEMENTED(); return VK_FORMAT_R8G8_UINT;
return VK_FORMAT_UNDEFINED;
case gl::VERTEX_FORMAT_UBYTE2_NORM: case gl::VERTEX_FORMAT_UBYTE2_NORM:
UNIMPLEMENTED(); return VK_FORMAT_R8G8_UNORM;
return VK_FORMAT_UNDEFINED;
case gl::VERTEX_FORMAT_UBYTE3: case gl::VERTEX_FORMAT_UBYTE3:
UNIMPLEMENTED(); return VK_FORMAT_R8G8B8_UINT;
return VK_FORMAT_UNDEFINED;
case gl::VERTEX_FORMAT_UBYTE3_NORM: case gl::VERTEX_FORMAT_UBYTE3_NORM:
UNIMPLEMENTED(); return VK_FORMAT_R8G8B8_UNORM;
return VK_FORMAT_UNDEFINED;
case gl::VERTEX_FORMAT_UBYTE4: case gl::VERTEX_FORMAT_UBYTE4:
UNIMPLEMENTED(); return VK_FORMAT_R8G8B8A8_UINT;
return VK_FORMAT_UNDEFINED;
case gl::VERTEX_FORMAT_UBYTE4_NORM: case gl::VERTEX_FORMAT_UBYTE4_NORM:
UNIMPLEMENTED(); return VK_FORMAT_R8G8B8A8_UNORM;
return VK_FORMAT_UNDEFINED;
case gl::VERTEX_FORMAT_SSHORT1: case gl::VERTEX_FORMAT_SSHORT1:
UNIMPLEMENTED(); UNIMPLEMENTED();
return VK_FORMAT_UNDEFINED; return VK_FORMAT_UNDEFINED;
......
...@@ -142,13 +142,6 @@ TEST_P(SimpleOperationTest, LinkProgramWithUniforms) ...@@ -142,13 +142,6 @@ TEST_P(SimpleOperationTest, LinkProgramWithUniforms)
TEST_P(SimpleOperationTest, LinkProgramWithAttributes) TEST_P(SimpleOperationTest, LinkProgramWithAttributes)
{ {
if (IsVulkan())
{
// TODO(jmadill): Complete Vulkan implementation.
std::cout << "Test skipped on Vulkan." << std::endl;
return;
}
const std::string vsSource = const std::string vsSource =
R"(attribute vec4 a_input; R"(attribute vec4 a_input;
void main() void main()
...@@ -269,6 +262,74 @@ TEST_P(SimpleOperationTest, DrawQuadAndSwap) ...@@ -269,6 +262,74 @@ TEST_P(SimpleOperationTest, DrawQuadAndSwap)
EXPECT_GL_NO_ERROR(); EXPECT_GL_NO_ERROR();
} }
// Tests a shader program with more than one vertex attribute, with vertex buffers.
TEST_P(SimpleOperationTest, ThreeVertexAttributes)
{
const std::string vertexShader =
R"(attribute vec2 position;
attribute vec4 color1;
attribute vec4 color2;
varying vec4 color;
void main()
{
gl_Position = vec4(position, 0, 1);
color = color1 + color2;
})";
const std::string fragmentShader =
R"(precision mediump float;
varying vec4 color;
void main()
{
gl_FragColor = color;
}
)";
ANGLE_GL_PROGRAM(program, vertexShader, fragmentShader);
glUseProgram(program);
GLint color1Loc = glGetAttribLocation(program, "color1");
GLint color2Loc = glGetAttribLocation(program, "color2");
ASSERT_NE(-1, color1Loc);
ASSERT_NE(-1, color2Loc);
const auto &indices = GetQuadIndices();
// Make colored corners with red == x or 1 -x , and green = y or 1 - y.
std::array<GLColor, 4> baseColors1 = {
{GLColor::black, GLColor::red, GLColor::green, GLColor::yellow}};
std::array<GLColor, 4> baseColors2 = {
{GLColor::yellow, GLColor::green, GLColor::red, GLColor::black}};
std::vector<GLColor> colors1;
std::vector<GLColor> colors2;
for (GLushort index : indices)
{
colors1.push_back(baseColors1[index]);
colors2.push_back(baseColors2[index]);
}
GLBuffer color1Buffer;
glBindBuffer(GL_ARRAY_BUFFER, color1Buffer);
glBufferData(GL_ARRAY_BUFFER, colors1.size() * sizeof(GLColor), colors1.data(), GL_STATIC_DRAW);
glVertexAttribPointer(color1Loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, nullptr);
glEnableVertexAttribArray(color1Loc);
GLBuffer color2Buffer;
glBindBuffer(GL_ARRAY_BUFFER, color2Buffer);
glBufferData(GL_ARRAY_BUFFER, colors2.size() * sizeof(GLColor), colors2.data(), GL_STATIC_DRAW);
glVertexAttribPointer(color2Loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, nullptr);
glEnableVertexAttribArray(color2Loc);
// Draw a non-indexed quad with all vertex buffers. Should draw yellow to the entire window.
drawQuad(program, "position", 0.5f, 1.0f, true);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth(), getWindowHeight(), GLColor::yellow);
}
// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against. // Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
ANGLE_INSTANTIATE_TEST(SimpleOperationTest, ANGLE_INSTANTIATE_TEST(SimpleOperationTest,
ES2_D3D9(), ES2_D3D9(),
......
...@@ -89,7 +89,7 @@ std::array<angle::Vector3, 4> GetIndexedQuadVertices() ...@@ -89,7 +89,7 @@ std::array<angle::Vector3, 4> GetIndexedQuadVertices()
return vertices; return vertices;
} }
static constexpr GLushort IndexedQuadIndices[6] = {0, 1, 2, 0, 2, 3}; static constexpr std::array<GLushort, 6> IndexedQuadIndices = {{0, 1, 2, 0, 2, 3}};
} // anonymous namespace } // anonymous namespace
...@@ -192,6 +192,12 @@ std::array<angle::Vector3, 6> ANGLETestBase::GetQuadVertices() ...@@ -192,6 +192,12 @@ std::array<angle::Vector3, 6> ANGLETestBase::GetQuadVertices()
return vertices; return vertices;
} }
// static
std::array<GLushort, 6> ANGLETestBase::GetQuadIndices()
{
return angle::IndexedQuadIndices;
}
ANGLETestBase::ANGLETestBase(const angle::PlatformParameters &params) ANGLETestBase::ANGLETestBase(const angle::PlatformParameters &params)
: mEGLWindow(nullptr), : mEGLWindow(nullptr),
mWidth(16), mWidth(16),
...@@ -383,7 +389,7 @@ void ANGLETestBase::setupIndexedQuadIndexBuffer() ...@@ -383,7 +389,7 @@ void ANGLETestBase::setupIndexedQuadIndexBuffer()
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mQuadIndexBuffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mQuadIndexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(angle::IndexedQuadIndices), glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(angle::IndexedQuadIndices),
angle::IndexedQuadIndices, GL_STATIC_DRAW); angle::IndexedQuadIndices.data(), GL_STATIC_DRAW);
} }
// static // static
...@@ -552,7 +558,7 @@ void ANGLETestBase::drawIndexedQuad(GLuint program, ...@@ -552,7 +558,7 @@ void ANGLETestBase::drawIndexedQuad(GLuint program,
} }
else else
{ {
indices = angle::IndexedQuadIndices; indices = angle::IndexedQuadIndices.data();
} }
if (!restrictedRange) if (!restrictedRange)
......
...@@ -152,6 +152,16 @@ GLColor32F ReadColor32F(GLint x, GLint y); ...@@ -152,6 +152,16 @@ GLColor32F ReadColor32F(GLint x, GLint y);
#define EXPECT_PIXEL_COLOR32F_EQ(x, y, angleColor) EXPECT_EQ(angleColor, angle::ReadColor32F(x, y)) #define EXPECT_PIXEL_COLOR32F_EQ(x, y, angleColor) EXPECT_EQ(angleColor, angle::ReadColor32F(x, y))
#define EXPECT_PIXEL_RECT_EQ(x, y, width, height, color) \
\
{ \
std::vector<GLColor> actualColors(width *height); \
glReadPixels((x), (y), (width), (height), GL_RGBA, GL_UNSIGNED_BYTE, actualColors.data()); \
std::vector<GLColor> expectedColors(width *height, color); \
EXPECT_EQ(expectedColors, actualColors); \
\
}
#define EXPECT_PIXEL_NEAR(x, y, r, g, b, a, abs_error) \ #define EXPECT_PIXEL_NEAR(x, y, r, g, b, a, abs_error) \
{ \ { \
GLubyte pixel[4]; \ GLubyte pixel[4]; \
...@@ -258,6 +268,7 @@ class ANGLETestBase ...@@ -258,6 +268,7 @@ class ANGLETestBase
GLuint numInstances); GLuint numInstances);
static std::array<angle::Vector3, 6> GetQuadVertices(); static std::array<angle::Vector3, 6> GetQuadVertices();
static std::array<GLushort, 6> GetQuadIndices();
void drawIndexedQuad(GLuint program, void drawIndexedQuad(GLuint program,
const std::string &positionAttribName, const std::string &positionAttribName,
GLfloat positionAttribZ); GLfloat positionAttribZ);
......
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