Commit 9fc3682c by Jamie Madill

D3D: Rework varying packing code.

In D3D we pack varyings by making a register map, and using the recommended GLSL ES algorithm to reserve register space. We use this map to assign row and column slots to each varying and then produce a semantic index value. The existing scheme had a number of bugs, and was failing several angle_end2end_tests. The new design cleans up the code somewhat and uses a different counting scheme for the semantic indexes: just sort the varyings in packing order and use a simple incrementing semantic index per varying. In SM4+, the HLSL compiler sorts and packs the varyings correctly itself, and in SM3, handle the cases we don't support by returning an error instead of a D3D compiler link error. Also refactor how we store varying information for TF Feedback/ StreamOut. Only store the necessary D3D information, instead of extra information like the name and type. This fixes several tests in GLSLTest/*. This also will allow us to fix interpolation qualifier packing and the structure packing in HLSL, which seems to work differently than the rest of the varying types. BUG=angleproject:1202 TEST=bots,dEQP-GLES3.functional.transform_feedback.* Change-Id: Ie5bfbb4f71d8bf97f39115fc46d2e61b131df639 Reviewed-on: https://chromium-review.googlesource.com/311241Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Tested-by: 's avatarJamie Madill <jmadill@chromium.org>
parent e39a3f0a
......@@ -48,6 +48,8 @@ const std::vector<VarT> &GetShaderVariables(const std::vector<VarT> *variableLis
return *variableList;
}
} // anonymous namespace
// true if varying x has a higher priority in packing than y
bool CompareVarying(const sh::Varying &x, const sh::Varying &y)
{
......@@ -70,8 +72,6 @@ bool CompareVarying(const sh::Varying &x, const sh::Varying &y)
return gl::VariableSortOrder(x.type) < gl::VariableSortOrder(y.type);
}
} // anonymous namespace
Shader::Data::Data(GLenum shaderType) : mShaderType(shaderType), mShaderVersion(100)
{
}
......
......@@ -137,6 +137,7 @@ class Shader : angle::NonCopyable
ResourceManager *mResourceManager;
};
bool CompareVarying(const sh::Varying &x, const sh::Varying &y);
}
#endif // LIBANGLE_SHADER_H_
......@@ -118,24 +118,23 @@ std::string GetVaryingSemantic(int majorShaderModel, bool programUsesPointSize)
return ((programUsesPointSize && majorShaderModel < 4) ? "COLOR" : "TEXCOORD");
}
// DynamicHLSL implementation
DynamicHLSL::DynamicHLSL(RendererD3D *const renderer) : mRenderer(renderer)
{
}
void DynamicHLSL::generateVaryingHLSL(const gl::Caps &caps,
const std::vector<PackedVarying> &varyings,
bool programUsesPointSize,
void DynamicHLSL::generateVaryingHLSL(const VaryingPacking &varyingPacking,
std::stringstream &hlslStream) const
{
std::string varyingSemantic =
GetVaryingSemantic(mRenderer->getMajorShaderModel(), programUsesPointSize);
GetVaryingSemantic(mRenderer->getMajorShaderModel(), varyingPacking.usesPointSize());
for (const PackedVaryingRegister &registerInfo : PackedVaryingIterator(varyings))
for (const PackedVaryingRegister &registerInfo : varyingPacking.getRegisterList())
{
const PackedVarying &packedVarying = varyings[registerInfo.varyingIndex];
const sh::Varying &varying = *packedVarying.varying;
GLenum transposedType = gl::TransposeMatrixType(varying.type);
unsigned int registerIndex = registerInfo.registerIndex(caps, varyings);
const sh::Varying &varying = *registerInfo.packedVarying->varying;
GLenum transposedType = gl::TransposeMatrixType(varying.type);
unsigned int semanticIndex = registerInfo.semanticIndex;
// TODO: Add checks to ensure D3D interpolation modifiers don't result in too many
// registers being used.
......@@ -171,7 +170,7 @@ void DynamicHLSL::generateVaryingHLSL(const gl::Caps &caps,
hlslStream << HLSLComponentTypeString(componentType, columnCount);
}
hlslStream << " v" << registerIndex << " : " << varyingSemantic << registerIndex << ";\n";
hlslStream << " v" << semanticIndex << " : " << varyingSemantic << semanticIndex << ";\n";
}
}
......@@ -360,97 +359,48 @@ std::string DynamicHLSL::generatePixelShaderForOutputSignature(
return pixelHLSL;
}
void DynamicHLSL::generateVaryingLinkHLSL(const gl::Caps &caps,
bool programUsesPointSize,
const SemanticInfo &info,
const std::vector<PackedVarying> &packedVaryings,
void DynamicHLSL::generateVaryingLinkHLSL(ShaderType shaderType,
const VaryingPacking &varyingPacking,
std::stringstream &linkStream) const
{
ASSERT(info.dxPosition.enabled);
const auto &builtins = varyingPacking.builtins(shaderType);
ASSERT(builtins.dxPosition.enabled);
linkStream << "{\n"
<< " float4 dx_Position : " << info.dxPosition.str() << ";\n";
<< " float4 dx_Position : " << builtins.dxPosition.str() << ";\n";
if (info.glPosition.enabled)
if (builtins.glPosition.enabled)
{
linkStream << " float4 gl_Position : " << info.glPosition.str() << ";\n";
linkStream << " float4 gl_Position : " << builtins.glPosition.str() << ";\n";
}
if (info.glFragCoord.enabled)
if (builtins.glFragCoord.enabled)
{
linkStream << " float4 gl_FragCoord : " << info.glFragCoord.str() << ";\n";
linkStream << " float4 gl_FragCoord : " << builtins.glFragCoord.str() << ";\n";
}
if (info.glPointCoord.enabled)
if (builtins.glPointCoord.enabled)
{
linkStream << " float2 gl_PointCoord : " << info.glPointCoord.str() << ";\n";
linkStream << " float2 gl_PointCoord : " << builtins.glPointCoord.str() << ";\n";
}
if (info.glPointSize.enabled)
if (builtins.glPointSize.enabled)
{
linkStream << " float gl_PointSize : " << info.glPointSize.str() << ";\n";
linkStream << " float gl_PointSize : " << builtins.glPointSize.str() << ";\n";
}
// Do this after glPointSize, to potentially combine gl_PointCoord and gl_PointSize into the
// same register.
generateVaryingHLSL(caps, packedVaryings, programUsesPointSize, linkStream);
generateVaryingHLSL(varyingPacking, linkStream);
linkStream << "};\n";
}
void DynamicHLSL::storeBuiltinVaryings(const SemanticInfo &info,
std::vector<D3DVarying> *d3dVaryingsOut) const
{
if (info.glPosition.enabled)
{
d3dVaryingsOut->push_back(D3DVarying("gl_Position", GL_FLOAT_VEC4, 1,
info.glPosition.semantic, info.glPosition.index, 1));
}
if (info.glFragCoord.enabled)
{
d3dVaryingsOut->push_back(D3DVarying("gl_FragCoord", GL_FLOAT_VEC4, 1,
info.glFragCoord.semantic, info.glFragCoord.index, 1));
}
if (info.glPointSize.enabled)
{
d3dVaryingsOut->push_back(D3DVarying("gl_PointSize", GL_FLOAT, 1, "PSIZE", 0, 1));
}
}
void DynamicHLSL::storeUserVaryings(const std::vector<PackedVarying> &packedVaryings,
bool programUsesPointSize,
std::vector<D3DVarying> *d3dVaryingsOut) const
{
const std::string &varyingSemantic =
GetVaryingSemantic(mRenderer->getMajorShaderModel(), programUsesPointSize);
for (const PackedVarying &packedVarying : packedVaryings)
{
if (packedVarying.registerAssigned())
{
const sh::Varying &varying = *packedVarying.varying;
ASSERT(!varying.isBuiltIn());
GLenum transposedType = TransposeMatrixType(varying.type);
int variableRows = (varying.isStruct() ? 1 : VariableRowCount(transposedType));
d3dVaryingsOut->push_back(D3DVarying(varying.name, varying.type, varying.elementCount(),
varyingSemantic, packedVarying.registerIndex,
variableRows * varying.elementCount()));
}
}
}
bool DynamicHLSL::generateShaderLinkHLSL(const gl::Data &data,
const gl::Program::Data &programData,
const ProgramD3DMetadata &programMetadata,
InfoLog &infoLog,
unsigned int registerCount,
const VaryingPacking &varyingPacking,
std::string *pixelHLSL,
std::string *vertexHLSL,
const std::vector<PackedVarying> &packedVaryings,
std::vector<D3DVarying> *d3dVaryingsOut) const
std::string *vertexHLSL) const
{
ASSERT(pixelHLSL->empty() && vertexHLSL->empty());
......@@ -460,9 +410,6 @@ bool DynamicHLSL::generateShaderLinkHLSL(const gl::Data &data,
const ShaderD3D *fragmentShader = GetImplAs<ShaderD3D>(fragmentShaderGL);
const int shaderModel = mRenderer->getMajorShaderModel();
bool usesFragCoord = programMetadata.usesFragCoord();
bool usesPointCoord = fragmentShader->usesPointCoord();
bool usesPointSize = vertexShader->usesPointSize();
bool useInstancedPointSpriteEmulation =
programMetadata.usesPointSize() &&
mRenderer->getWorkarounds().useInstancedPointSpriteEmulation;
......@@ -470,29 +417,6 @@ bool DynamicHLSL::generateShaderLinkHLSL(const gl::Data &data,
// Validation done in the compiler
ASSERT(!fragmentShader->usesFragColor() || !fragmentShader->usesFragData());
// Write the HLSL input/output declarations
const unsigned int registersNeeded =
registerCount + (usesFragCoord ? 1u : 0u) + (usesPointCoord ? 1u : 0u);
if (static_cast<GLuint>(registersNeeded) > data.caps->maxVaryingVectors)
{
infoLog << "No varying registers left to support gl_FragCoord/gl_PointCoord";
return false;
}
// Instanced PointSprite emulation requires that gl_PointCoord is present in the vertex shader
// VS_OUTPUT structure to ensure compatibility with the generated PS_INPUT of the pixel shader.
// GeometryShader PointSprite emulation does not require this additional entry because the
// GS_OUTPUT of the Geometry shader contains the pointCoord value and already matches the
// PS_INPUT of the generated pixel shader. The Geometry Shader point sprite implementation needs
// gl_PointSize to be in VS_OUTPUT and GS_INPUT. Instanced point sprites doesn't need
// gl_PointSize in VS_OUTPUT.
const SemanticInfo &vertexSemantics =
GetSemanticInfo(SHADER_VERTEX, programMetadata, registerCount);
storeUserVaryings(packedVaryings, usesPointSize, d3dVaryingsOut);
storeBuiltinVaryings(vertexSemantics, d3dVaryingsOut);
std::stringstream vertexStream;
vertexStream << vertexShaderGL->getTranslatedSource();
......@@ -507,10 +431,11 @@ bool DynamicHLSL::generateShaderLinkHLSL(const gl::Data &data,
}
// Add stub string to be replaced when shader is dynamically defined by its layout
vertexStream << "\n" << VERTEX_ATTRIBUTE_STUB_STRING + "\n"
<< "struct VS_OUTPUT\n";
generateVaryingLinkHLSL(*data.caps, usesPointSize, vertexSemantics, packedVaryings,
vertexStream);
vertexStream << "\n" << VERTEX_ATTRIBUTE_STUB_STRING + "\n";
// Write the HLSL input/output declarations
vertexStream << "struct VS_OUTPUT\n";
generateVaryingLinkHLSL(SHADER_VERTEX, varyingPacking, vertexStream);
vertexStream << "\n"
<< "VS_OUTPUT main(VS_INPUT input)\n"
<< "{\n"
......@@ -527,7 +452,9 @@ bool DynamicHLSL::generateShaderLinkHLSL(const gl::Data &data,
<< "\n"
<< " VS_OUTPUT output;\n";
if (vertexSemantics.glPosition.enabled)
const auto &vertexBuiltins = varyingPacking.builtins(SHADER_VERTEX);
if (vertexBuiltins.glPosition.enabled)
{
vertexStream << " output.gl_Position = gl_Position;\n";
}
......@@ -551,35 +478,33 @@ bool DynamicHLSL::generateShaderLinkHLSL(const gl::Data &data,
}
// We don't need to output gl_PointSize if we use are emulating point sprites via instancing.
if (usesPointSize && shaderModel >= 3 && !useInstancedPointSpriteEmulation)
if (vertexBuiltins.glPointSize.enabled)
{
vertexStream << " output.gl_PointSize = gl_PointSize;\n";
}
if (usesFragCoord)
if (vertexBuiltins.glFragCoord.enabled)
{
vertexStream << " output.gl_FragCoord = gl_Position;\n";
}
for (const PackedVaryingRegister &registerInfo : PackedVaryingIterator(packedVaryings))
for (const PackedVaryingRegister &registerInfo : varyingPacking.getRegisterList())
{
const PackedVarying &packedVarying = packedVaryings[registerInfo.varyingIndex];
const sh::Varying &varying = *packedVarying.varying;
const sh::Varying &varying = *registerInfo.packedVarying->varying;
GLenum transposedType = TransposeMatrixType(varying.type);
unsigned int variableRows =
static_cast<unsigned int>(varying.isStruct() ? 1 : VariableRowCount(transposedType));
int r = registerInfo.registerIndex(*data.caps, packedVaryings);
vertexStream << " output.v" << r << " = _" + varying.name;
vertexStream << " output.v" << registerInfo.semanticIndex << " = _" + varying.name;
if (varying.isArray())
{
vertexStream << ArrayString(registerInfo.elementIndex);
vertexStream << ArrayString(registerInfo.varyingArrayIndex);
}
if (variableRows > 1)
{
vertexStream << ArrayString(registerInfo.rowIndex);
vertexStream << ArrayString(registerInfo.varyingRowIndex);
}
vertexStream << ";\n";
......@@ -619,12 +544,8 @@ bool DynamicHLSL::generateShaderLinkHLSL(const gl::Data &data,
std::stringstream pixelStream;
pixelStream << fragmentShaderGL->getTranslatedSource();
const SemanticInfo &pixelSemantics =
GetSemanticInfo(SHADER_PIXEL, programMetadata, registerCount);
pixelStream << "struct PS_INPUT\n";
generateVaryingLinkHLSL(*data.caps, usesPointSize, pixelSemantics, packedVaryings, pixelStream);
generateVaryingLinkHLSL(SHADER_PIXEL, varyingPacking, pixelStream);
pixelStream << "\n";
pixelStream << PIXEL_OUTPUT_STUB_STRING + "\n";
......@@ -648,7 +569,9 @@ bool DynamicHLSL::generateShaderLinkHLSL(const gl::Data &data,
<< "{\n";
}
if (usesFragCoord)
const auto &pixelBuiltins = varyingPacking.builtins(SHADER_PIXEL);
if (pixelBuiltins.glFragCoord.enabled)
{
pixelStream << " float rhw = 1.0 / input.gl_FragCoord.w;\n";
......@@ -680,7 +603,7 @@ bool DynamicHLSL::generateShaderLinkHLSL(const gl::Data &data,
<< " gl_FragCoord.w = rhw;\n";
}
if (usesPointCoord && shaderModel >= 3)
if (pixelBuiltins.glPointCoord.enabled && shaderModel >= 3)
{
pixelStream << " gl_PointCoord.x = input.gl_PointCoord.x;\n"
<< " gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n";
......@@ -698,32 +621,30 @@ bool DynamicHLSL::generateShaderLinkHLSL(const gl::Data &data,
}
}
for (const PackedVaryingRegister &registerInfo : PackedVaryingIterator(packedVaryings))
for (const PackedVaryingRegister &registerInfo : varyingPacking.getRegisterList())
{
const PackedVarying &packedVarying = packedVaryings[registerInfo.varyingIndex];
const sh::Varying &varying = *packedVarying.varying;
const sh::Varying &varying = *registerInfo.packedVarying->varying;
// Don't reference VS-only transform feedback varyings in the PS.
if (packedVarying.vertexOnly)
if (registerInfo.packedVarying->vertexOnly)
continue;
ASSERT(!varying.isBuiltIn());
GLenum transposedType = TransposeMatrixType(varying.type);
int variableRows = (varying.isStruct() ? 1 : VariableRowCount(transposedType));
unsigned int registerIndex = registerInfo.registerIndex(*data.caps, packedVaryings);
pixelStream << " _" << varying.name;
if (varying.isArray())
{
pixelStream << ArrayString(registerInfo.elementIndex);
pixelStream << ArrayString(registerInfo.varyingArrayIndex);
}
if (variableRows > 1)
{
pixelStream << ArrayString(registerInfo.rowIndex);
pixelStream << ArrayString(registerInfo.varyingRowIndex);
}
pixelStream << " = input.v" << registerIndex;
pixelStream << " = input.v" << registerInfo.semanticIndex;
if (!varying.isStruct())
{
......@@ -765,64 +686,43 @@ bool DynamicHLSL::generateShaderLinkHLSL(const gl::Data &data,
return true;
}
std::string DynamicHLSL::generateGeometryShaderPreamble(
const gl::Data &data,
const gl::Program::Data &programData,
const ProgramD3DMetadata &programMetadata,
unsigned int registerCount,
const std::vector<PackedVarying> &packedVaryings) const
std::string DynamicHLSL::generateGeometryShaderPreamble(const VaryingPacking &varyingPacking) const
{
int majorShaderModel = mRenderer->getMajorShaderModel();
ASSERT(registerCount >= 0 && registerCount <= data.caps->maxVaryingVectors);
ASSERT(majorShaderModel >= 4);
// Must be called during link, not from a binary load.
const ShaderD3D *vertexShader = GetImplAs<ShaderD3D>(programData.getAttachedVertexShader());
const ShaderD3D *fragmentShader = GetImplAs<ShaderD3D>(programData.getAttachedFragmentShader());
ASSERT(vertexShader && fragmentShader);
bool usesFragCoord = fragmentShader->usesFragCoord();
bool usesPointSize = vertexShader->usesPointSize();
const SemanticInfo &inSemantics =
GetSemanticInfo(SHADER_VERTEX, programMetadata, registerCount);
const SemanticInfo &outSemantics =
GetSemanticInfo(SHADER_GEOMETRY, programMetadata, registerCount);
ASSERT(mRenderer->getMajorShaderModel() >= 4);
std::stringstream preambleStream;
const auto &builtins = varyingPacking.builtins(SHADER_VERTEX);
preambleStream << "struct GS_INPUT\n";
generateVaryingLinkHLSL(*data.caps, usesPointSize, inSemantics, packedVaryings, preambleStream);
generateVaryingLinkHLSL(SHADER_VERTEX, varyingPacking, preambleStream);
preambleStream << "\n"
<< "struct GS_OUTPUT\n";
generateVaryingLinkHLSL(*data.caps, usesPointSize, outSemantics, packedVaryings,
preambleStream);
generateVaryingLinkHLSL(SHADER_GEOMETRY, varyingPacking, preambleStream);
preambleStream
<< "\n"
<< "void copyVertex(inout GS_OUTPUT output, GS_INPUT input, GS_INPUT flatinput)\n"
<< "{\n"
<< " output.gl_Position = input.gl_Position;\n";
if (usesPointSize)
if (builtins.glPointSize.enabled)
{
preambleStream << " output.gl_PointSize = input.gl_PointSize;\n";
}
for (const PackedVaryingRegister &varyingRegister : PackedVaryingIterator(packedVaryings))
for (const PackedVaryingRegister &varyingRegister : varyingPacking.getRegisterList())
{
const sh::Varying &varying = *packedVaryings[varyingRegister.varyingIndex].varying;
unsigned int registerIndex = varyingRegister.registerIndex(*data.caps, packedVaryings);
const sh::Varying &varying = *varyingRegister.packedVarying->varying;
preambleStream << " output.v" << registerIndex << " = ";
preambleStream << " output.v" << varyingRegister.semanticIndex << " = ";
if (varying.interpolation == sh::INTERPOLATION_FLAT)
{
preambleStream << "flat";
}
preambleStream << "input.v" << registerIndex << "; \n";
preambleStream << "input.v" << varyingRegister.semanticIndex << "; \n";
}
if (usesFragCoord)
if (builtins.glFragCoord.enabled)
{
preambleStream << " output.gl_FragCoord = input.gl_FragCoord;\n";
}
......
......@@ -37,8 +37,8 @@ namespace rx
{
struct PackedVarying;
class ProgramD3DMetadata;
struct SemanticInfo;
class ShaderD3D;
class VaryingPacking;
struct PixelShaderOutputVariable
{
......@@ -65,19 +65,11 @@ class DynamicHLSL : angle::NonCopyable
bool generateShaderLinkHLSL(const gl::Data &data,
const gl::Program::Data &programData,
const ProgramD3DMetadata &programMetadata,
gl::InfoLog &infoLog,
unsigned int registerCount,
const VaryingPacking &varyingPacking,
std::string *pixelHLSL,
std::string *vertexHLSL,
const std::vector<PackedVarying> &packedVaryings,
std::vector<D3DVarying> *d3dVaryingsOut) const;
std::string *vertexHLSL) const;
std::string generateGeometryShaderPreamble(
const gl::Data &data,
const gl::Program::Data &programData,
const ProgramD3DMetadata &programMetadata,
unsigned int registers,
const std::vector<PackedVarying> &packedVaryings) const;
std::string generateGeometryShaderPreamble(const VaryingPacking &varyingPacking) const;
std::string generateGeometryShaderHLSL(gl::PrimitiveType primitiveType,
const gl::Data &data,
......@@ -92,20 +84,11 @@ class DynamicHLSL : angle::NonCopyable
private:
RendererD3D *const mRenderer;
void generateVaryingLinkHLSL(const gl::Caps &caps,
bool programUsesPointSize,
const SemanticInfo &info,
const std::vector<PackedVarying> &packedVaryings,
void generateVaryingLinkHLSL(ShaderType shaderType,
const VaryingPacking &varyingPacking,
std::stringstream &linkStream) const;
void generateVaryingHLSL(const gl::Caps &caps,
const std::vector<PackedVarying> &varyings,
bool programUsesPointSize,
void generateVaryingHLSL(const VaryingPacking &varyingPacking,
std::stringstream &hlslStream) const;
void storeUserVaryings(const std::vector<PackedVarying> &packedVaryings,
bool programUsesPointSize,
std::vector<D3DVarying> *d3dVaryingsOut) const;
void storeBuiltinVaryings(const SemanticInfo &info,
std::vector<D3DVarying> *d3dVaryingsOut) const;
// Prepend an underscore
static std::string decorateVariable(const std::string &name);
......
......@@ -101,6 +101,12 @@ struct AttributeSorter
const ProgramD3D::SemanticIndexArray *originalIndices;
};
// true if varying x has a higher priority in packing than y
bool ComparePackedVarying(const PackedVarying &x, const PackedVarying &y)
{
return gl::CompareVarying(*x.varying, *y.varying);
}
std::vector<PackedVarying> MergeVaryings(const gl::Shader &vertexShader,
const gl::Shader &fragmentShader,
const std::vector<std::string> &tfVaryings)
......@@ -142,6 +148,8 @@ std::vector<PackedVarying> MergeVaryings(const gl::Shader &vertexShader,
}
}
std::sort(packedVaryings.begin(), packedVaryings.end(), ComparePackedVarying);
return packedVaryings;
}
......@@ -344,22 +352,18 @@ bool D3DUniform::isReferencedByFragmentShader() const
// D3DVarying Implementation
D3DVarying::D3DVarying()
D3DVarying::D3DVarying() : semanticIndex(0), componentCount(0), outputSlot(0)
{
}
D3DVarying::D3DVarying(const std::string &name,
GLenum type,
GLsizei size,
const std::string &semanticName,
unsigned int semanticIndex,
unsigned int semanticIndexCount)
: name(name),
type(type),
size(size),
semanticName(semanticName),
semanticIndex(semanticIndex),
semanticIndexCount(semanticIndexCount)
D3DVarying::D3DVarying(const std::string &semanticNameIn,
unsigned int semanticIndexIn,
unsigned int componentCountIn,
unsigned int outputSlotIn)
: semanticName(semanticNameIn),
semanticIndex(semanticIndexIn),
componentCount(componentCountIn),
outputSlot(outputSlotIn)
{
}
......@@ -781,19 +785,16 @@ LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream)
mD3DUniformBlocks.push_back(uniformBlock);
}
const unsigned int transformFeedbackVaryingCount = stream->readInt<unsigned int>();
mTransformFeedbackD3DVaryings.resize(transformFeedbackVaryingCount);
for (unsigned int varyingIndex = 0; varyingIndex < transformFeedbackVaryingCount;
varyingIndex++)
const unsigned int streamOutVaryingCount = stream->readInt<unsigned int>();
mStreamOutVaryings.resize(streamOutVaryingCount);
for (unsigned int varyingIndex = 0; varyingIndex < streamOutVaryingCount; ++varyingIndex)
{
D3DVarying *varying = &mTransformFeedbackD3DVaryings[varyingIndex];
D3DVarying *varying = &mStreamOutVaryings[varyingIndex];
stream->readString(&varying->name);
stream->readInt(&varying->type);
stream->readInt(&varying->size);
stream->readString(&varying->semanticName);
stream->readInt(&varying->semanticIndex);
stream->readInt(&varying->semanticIndexCount);
stream->readInt(&varying->componentCount);
stream->readInt(&varying->outputSlot);
}
stream->readString(&mVertexHLSL);
......@@ -839,7 +840,7 @@ LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream)
ShaderExecutableD3D *shaderExecutable = nullptr;
gl::Error error = mRenderer->loadExecutable(
vertexShaderFunction, vertexShaderSize, SHADER_VERTEX, mTransformFeedbackD3DVaryings,
vertexShaderFunction, vertexShaderSize, SHADER_VERTEX, mStreamOutVaryings,
(mData.getTransformFeedbackBufferMode() == GL_SEPARATE_ATTRIBS), &shaderExecutable);
if (error.isError())
{
......@@ -878,7 +879,7 @@ LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream)
ShaderExecutableD3D *shaderExecutable = nullptr;
gl::Error error = mRenderer->loadExecutable(
pixelShaderFunction, pixelShaderSize, SHADER_PIXEL, mTransformFeedbackD3DVaryings,
pixelShaderFunction, pixelShaderSize, SHADER_PIXEL, mStreamOutVaryings,
(mData.getTransformFeedbackBufferMode() == GL_SEPARATE_ATTRIBS), &shaderExecutable);
if (error.isError())
{
......@@ -911,8 +912,8 @@ LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream)
bool splitAttribs = (mData.getTransformFeedbackBufferMode() == GL_SEPARATE_ATTRIBS);
gl::Error error = mRenderer->loadExecutable(
geometryShaderFunction, geometryShaderSize, SHADER_GEOMETRY,
mTransformFeedbackD3DVaryings, splitAttribs, &mGeometryExecutables[geometryExeIndex]);
geometryShaderFunction, geometryShaderSize, SHADER_GEOMETRY, mStreamOutVaryings,
splitAttribs, &mGeometryExecutables[geometryExeIndex]);
if (error.isError())
{
return LinkResult(false, error);
......@@ -985,17 +986,13 @@ gl::Error ProgramD3D::save(gl::BinaryOutputStream *stream)
stream->writeInt(uniformBlock.vsRegisterIndex);
}
stream->writeInt(mTransformFeedbackD3DVaryings.size());
for (size_t i = 0; i < mTransformFeedbackD3DVaryings.size(); i++)
stream->writeInt(mStreamOutVaryings.size());
for (const auto &varying : mStreamOutVaryings)
{
const D3DVarying &varying = mTransformFeedbackD3DVaryings[i];
stream->writeString(varying.name);
stream->writeInt(varying.type);
stream->writeInt(varying.size);
stream->writeString(varying.semanticName);
stream->writeInt(varying.semanticIndex);
stream->writeInt(varying.semanticIndexCount);
stream->writeInt(varying.componentCount);
stream->writeInt(varying.outputSlot);
}
stream->writeString(mVertexHLSL);
......@@ -1130,7 +1127,7 @@ gl::Error ProgramD3D::getPixelExecutableForOutputLayout(const std::vector<GLenum
gl::InfoLog *currentInfoLog = infoLog ? infoLog : &tempInfoLog;
gl::Error error = mRenderer->compileToExecutable(
*currentInfoLog, finalPixelHLSL, SHADER_PIXEL, mTransformFeedbackD3DVaryings,
*currentInfoLog, finalPixelHLSL, SHADER_PIXEL, mStreamOutVaryings,
(mData.getTransformFeedbackBufferMode() == GL_SEPARATE_ATTRIBS), mPixelWorkarounds,
&pixelExecutable);
if (error.isError())
......@@ -1179,7 +1176,7 @@ gl::Error ProgramD3D::getVertexExecutableForInputLayout(const gl::InputLayout &i
gl::InfoLog *currentInfoLog = infoLog ? infoLog : &tempInfoLog;
gl::Error error = mRenderer->compileToExecutable(
*currentInfoLog, finalVertexHLSL, SHADER_VERTEX, mTransformFeedbackD3DVaryings,
*currentInfoLog, finalVertexHLSL, SHADER_VERTEX, mStreamOutVaryings,
(mData.getTransformFeedbackBufferMode() == GL_SEPARATE_ATTRIBS), mVertexWorkarounds,
&vertexExecutable);
if (error.isError())
......@@ -1238,7 +1235,7 @@ gl::Error ProgramD3D::getGeometryExecutableForPrimitiveType(const gl::Data &data
gl::InfoLog *currentInfoLog = infoLog ? infoLog : &tempInfoLog;
gl::Error error = mRenderer->compileToExecutable(
*currentInfoLog, geometryHLSL, SHADER_GEOMETRY, mTransformFeedbackD3DVaryings,
*currentInfoLog, geometryHLSL, SHADER_GEOMETRY, mStreamOutVaryings,
(mData.getTransformFeedbackBufferMode() == GL_SEPARATE_ATTRIBS), D3DCompilerWorkarounds(),
&mGeometryExecutables[geometryShaderType]);
......@@ -1353,9 +1350,9 @@ LinkResult ProgramD3D::link(const gl::Data &data, gl::InfoLog &infoLog)
MergeVaryings(*vertexShader, *fragmentShader, mData.getTransformFeedbackVaryingNames());
// Map the varyings to the register file
unsigned int registerCount = 0;
if (!PackVaryings(*data.caps, infoLog, &packedVaryings,
mData.getTransformFeedbackVaryingNames(), &registerCount))
VaryingPacking varyingPacking(data.caps->maxVaryingVectors);
if (!varyingPacking.packVaryings(infoLog, packedVaryings,
mData.getTransformFeedbackVaryingNames()))
{
return LinkResult(false, gl::Error(GL_NO_ERROR));
}
......@@ -1364,10 +1361,27 @@ LinkResult ProgramD3D::link(const gl::Data &data, gl::InfoLog &infoLog)
usesInstancedPointSpriteEmulation(), vertexShaderD3D,
fragmentShaderD3D);
std::vector<D3DVarying> d3dVaryings;
if (!mDynamicHLSL->generateShaderLinkHLSL(data, mData, metadata, infoLog, registerCount,
&mPixelHLSL, &mVertexHLSL, packedVaryings,
&d3dVaryings))
varyingPacking.enableBuiltins(SHADER_VERTEX, metadata);
varyingPacking.enableBuiltins(SHADER_PIXEL, metadata);
if (static_cast<GLuint>(varyingPacking.getRegisterCount()) > data.caps->maxVaryingVectors)
{
infoLog << "No varying registers left to support gl_FragCoord/gl_PointCoord";
return LinkResult(false, gl::Error(GL_NO_ERROR));
}
// TODO(jmadill): Implement more sophisticated component packing in D3D9.
// We can fail here because we use one semantic per GLSL varying. D3D11 can pack varyings
// intelligently, but D3D9 assumes one semantic per register.
if (mRenderer->getRendererClass() == RENDERER_D3D9 &&
varyingPacking.getMaxSemanticIndex() > data.caps->maxVaryingVectors)
{
infoLog << "Cannot pack these varyings on D3D9.";
return LinkResult(false, gl::Error(GL_NO_ERROR));
}
if (!mDynamicHLSL->generateShaderLinkHLSL(data, mData, metadata, varyingPacking, &mPixelHLSL,
&mVertexHLSL))
{
return LinkResult(false, gl::Error(GL_NO_ERROR));
}
......@@ -1388,15 +1402,15 @@ LinkResult ProgramD3D::link(const gl::Data &data, gl::InfoLog &infoLog)
if (mRenderer->getMajorShaderModel() >= 4)
{
mGeometryShaderPreamble = mDynamicHLSL->generateGeometryShaderPreamble(
data, mData, metadata, registerCount, packedVaryings);
varyingPacking.enableBuiltins(SHADER_GEOMETRY, metadata);
mGeometryShaderPreamble = mDynamicHLSL->generateGeometryShaderPreamble(varyingPacking);
}
initSemanticIndex();
defineUniformsAndAssignRegisters();
gatherTransformFeedbackVaryings(d3dVaryings);
gatherTransformFeedbackVaryings(varyingPacking);
LinkResult result = compileProgramExecutables(data, infoLog);
if (result.error.isError() || !result.linkSuccess)
......@@ -2113,7 +2127,7 @@ void ProgramD3D::reset()
std::fill(mSemanticIndexes, mSemanticIndexes + ArraySize(mSemanticIndexes), -1);
std::fill(mAttributesByLayout, mAttributesByLayout + ArraySize(mAttributesByLayout), -1);
mTransformFeedbackD3DVaryings.clear();
mStreamOutVaryings.clear();
mGeometryShaderPreamble.clear();
}
......@@ -2195,18 +2209,60 @@ void ProgramD3D::updateCachedInputLayout(const gl::State &state)
}
}
void ProgramD3D::gatherTransformFeedbackVaryings(const std::vector<D3DVarying> &d3dVaryings)
void ProgramD3D::gatherTransformFeedbackVaryings(const VaryingPacking &varyingPacking)
{
const auto &builtins = varyingPacking.builtins(SHADER_VERTEX);
const std::string &varyingSemantic =
GetVaryingSemantic(mRenderer->getMajorShaderModel(), usesPointSize());
// Gather the linked varyings that are used for transform feedback, they should all exist.
mTransformFeedbackD3DVaryings.clear();
for (const std::string &tfVaryingName : mData.getTransformFeedbackVaryingNames())
mStreamOutVaryings.clear();
const auto &tfVaryingNames = mData.getTransformFeedbackVaryingNames();
for (unsigned int outputSlot = 0; outputSlot < static_cast<unsigned int>(tfVaryingNames.size());
++outputSlot)
{
for (const D3DVarying &d3dVarying : d3dVaryings)
const auto &tfVaryingName = tfVaryingNames[outputSlot];
if (tfVaryingName == "gl_Position")
{
if (tfVaryingName == d3dVarying.name)
if (builtins.glPosition.enabled)
{
mTransformFeedbackD3DVaryings.push_back(d3dVarying);
break;
mStreamOutVaryings.push_back(D3DVarying(builtins.glPosition.semantic,
builtins.glPosition.index, 4, outputSlot));
}
}
else if (tfVaryingName == "gl_FragCoord")
{
if (builtins.glFragCoord.enabled)
{
mStreamOutVaryings.push_back(D3DVarying(builtins.glFragCoord.semantic,
builtins.glFragCoord.index, 4, outputSlot));
}
}
else if (tfVaryingName == "gl_PointSize")
{
if (builtins.glPointSize.enabled)
{
mStreamOutVaryings.push_back(D3DVarying("PSIZE", 0, 1, outputSlot));
}
}
else
{
for (const PackedVaryingRegister &registerInfo : varyingPacking.getRegisterList())
{
const sh::Varying &varying = *registerInfo.packedVarying->varying;
GLenum transposedType = gl::TransposeMatrixType(varying.type);
int componentCount = gl::VariableColumnCount(transposedType);
ASSERT(!varying.isBuiltIn());
// There can be more than one register assigned to a particular varying, and each
// register needs its own stream out entry.
if (tfVaryingName == varying.name)
{
mStreamOutVaryings.push_back(D3DVarying(
varyingSemantic, registerInfo.semanticIndex, componentCount, outputSlot));
}
}
}
}
......
......@@ -80,26 +80,21 @@ struct D3DUniformBlock
unsigned int psRegisterIndex;
};
struct D3DVarying
struct D3DVarying final
{
D3DVarying();
D3DVarying(const std::string &name,
GLenum type,
GLsizei size,
const std::string &semanticName,
unsigned int semanticIndex,
unsigned int semanticIndexCount);
// Original GL name
std::string name;
D3DVarying(const std::string &semanticNameIn,
unsigned int semanticIndexIn,
unsigned int componentCountIn,
unsigned int outputSlotIn);
GLenum type;
GLsizei size;
D3DVarying(const D3DVarying &) = default;
D3DVarying &operator=(const D3DVarying &) = default;
// DirectX semantic information
std::string semanticName;
unsigned int semanticIndex;
unsigned int semanticIndexCount;
unsigned int componentCount;
unsigned int outputSlot;
};
class ProgramD3DMetadata : angle::NonCopyable
......@@ -336,7 +331,7 @@ class ProgramD3D : public ProgramImpl
LinkResult compileProgramExecutables(const gl::Data &data, gl::InfoLog &infoLog);
void gatherTransformFeedbackVaryings(const std::vector<D3DVarying> &varyings);
void gatherTransformFeedbackVaryings(const VaryingPacking &varyings);
D3DUniform *getD3DUniformByName(const std::string &name);
D3DUniform *getD3DUniformFromLocation(GLint location);
......@@ -394,7 +389,7 @@ class ProgramD3D : public ProgramImpl
VertexExecutable::Signature mCachedVertexSignature;
gl::InputLayout mCachedInputLayout;
std::vector<D3DVarying> mTransformFeedbackD3DVaryings;
std::vector<D3DVarying> mStreamOutVaryings;
std::vector<D3DUniform *> mD3DUniforms;
std::vector<D3DUniformBlock> mD3DUniformBlocks;
......
......@@ -56,7 +56,8 @@ enum ShaderType
{
SHADER_VERTEX,
SHADER_PIXEL,
SHADER_GEOMETRY
SHADER_GEOMETRY,
SHADER_TYPE_MAX
};
struct DeviceIdentifier
......@@ -206,13 +207,13 @@ class RendererD3D : public Renderer, public BufferFactoryD3D
virtual gl::Error loadExecutable(const void *function,
size_t length,
ShaderType type,
const std::vector<D3DVarying> &transformFeedbackVaryings,
const std::vector<D3DVarying> &streamOutVaryings,
bool separatedOutputBuffers,
ShaderExecutableD3D **outExecutable) = 0;
virtual gl::Error compileToExecutable(gl::InfoLog &infoLog,
const std::string &shaderHLSL,
ShaderType type,
const std::vector<D3DVarying> &transformFeedbackVaryings,
const std::vector<D3DVarying> &streamOutVaryings,
bool separatedOutputBuffers,
const D3DCompilerWorkarounds &workarounds,
ShaderExecutableD3D **outExectuable) = 0;
......
......@@ -18,269 +18,238 @@
namespace rx
{
SemanticInfo::BuiltinInfo::BuiltinInfo() : enabled(false), index(0), systemValue(false)
// Implementation of VaryingPacking::BuiltinVarying
VaryingPacking::BuiltinVarying::BuiltinVarying() : enabled(false), index(0), systemValue(false)
{
}
std::string SemanticInfo::BuiltinInfo::str() const
std::string VaryingPacking::BuiltinVarying::str() const
{
return (systemValue ? semantic : (semantic + Str(index)));
}
void SemanticInfo::BuiltinInfo::enableSystem(const std::string &systemValueSemantic)
void VaryingPacking::BuiltinVarying::enableSystem(const std::string &systemValueSemantic)
{
enabled = true;
semantic = systemValueSemantic;
systemValue = true;
}
void SemanticInfo::BuiltinInfo::enable(const std::string &semanticVal, unsigned int indexVal)
void VaryingPacking::BuiltinVarying::enable(const std::string &semanticVal, unsigned int indexVal)
{
enabled = true;
semantic = semanticVal;
index = indexVal;
}
bool PackVarying(PackedVarying *packedVarying, const int maxVaryingVectors, VaryingPacking &packing)
// Implementation of VaryingPacking
VaryingPacking::VaryingPacking(GLuint maxVaryingVectors)
: mRegisterMap(maxVaryingVectors), mBuiltinInfo(SHADER_TYPE_MAX)
{
// Make sure we use transposed matrix types to count registers correctly.
int registers = 0;
int elements = 0;
}
// Packs varyings into generic varying registers, using the algorithm from
// See [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
// Also [OpenGL ES Shading Language 3.00 rev. 4] Section 11 page 119
// Returns false if unsuccessful.
bool VaryingPacking::packVarying(const PackedVarying &packedVarying)
{
unsigned int varyingRows = 0;
unsigned int varyingColumns = 0;
const sh::Varying &varying = *packedVarying->varying;
const sh::Varying &varying = *packedVarying.varying;
if (varying.isStruct())
{
registers = HLSLVariableRegisterCount(varying, true) * varying.elementCount();
elements = 4;
varyingRows = HLSLVariableRegisterCount(varying, true);
varyingColumns = 4;
}
else
{
// "Non - square matrices of type matCxR consume the same space as a square matrix of type
// matN where N is the greater of C and R.Variables of type mat2 occupies 2 complete rows."
// Here we are a bit more conservative and allow packing non-square matrices more tightly.
// Make sure we use transposed matrix types to count registers correctly.
GLenum transposedType = gl::TransposeMatrixType(varying.type);
registers = gl::VariableRowCount(transposedType) * varying.elementCount();
elements = gl::VariableColumnCount(transposedType);
varyingRows = gl::VariableRowCount(transposedType);
varyingColumns = gl::VariableColumnCount(transposedType);
}
if (elements >= 2 && elements <= 4)
{
for (int r = 0; r <= maxVaryingVectors - registers; r++)
{
bool available = true;
// "Arrays of size N are assumed to take N times the size of the base type"
varyingRows *= varying.elementCount();
for (int y = 0; y < registers && available; y++)
{
for (int x = 0; x < elements && available; x++)
{
if (packing[r + y][x])
{
available = false;
}
}
}
unsigned int maxVaryingVectors = static_cast<unsigned int>(mRegisterMap.size());
if (available)
// "For 2, 3 and 4 component variables packing is started using the 1st column of the 1st row.
// Variables are then allocated to successive rows, aligning them to the 1st column."
if (varyingColumns >= 2 && varyingColumns <= 4)
{
for (unsigned int row = 0; row <= maxVaryingVectors - varyingRows; ++row)
{
if (isFree(row, 0, varyingRows, varyingColumns))
{
packedVarying->registerIndex = r;
packedVarying->columnIndex = 0;
for (int y = 0; y < registers; y++)
{
for (int x = 0; x < elements; x++)
{
packing[r + y][x] = packedVarying;
}
}
insert(row, 0, packedVarying);
return true;
}
}
if (elements == 2)
// "For 2 component variables, when there are no spare rows, the strategy is switched to
// using the highest numbered row and the lowest numbered column where the variable will
// fit."
if (varyingColumns == 2)
{
for (int r = maxVaryingVectors - registers; r >= 0; r--)
for (unsigned int r = maxVaryingVectors - varyingRows + 1; r-- >= 1;)
{
bool available = true;
for (int y = 0; y < registers && available; y++)
{
for (int x = 2; x < 4 && available; x++)
{
if (packing[r + y][x])
{
available = false;
}
}
}
if (available)
if (isFree(r, 2, varyingRows, 2))
{
packedVarying->registerIndex = r;
packedVarying->columnIndex = 2;
for (int y = 0; y < registers; y++)
{
for (int x = 2; x < 4; x++)
{
packing[r + y][x] = packedVarying;
}
}
insert(r, 2, packedVarying);
return true;
}
}
}
return false;
}
else if (elements == 1)
{
int space[4] = {0};
for (int y = 0; y < maxVaryingVectors; y++)
// "1 component variables have their own packing rule. They are packed in order of size, largest
// first. Each variable is placed in the column that leaves the least amount of space in the
// column and aligned to the lowest available rows within that column."
ASSERT(varyingColumns == 1);
unsigned int contiguousSpace[4] = {0};
unsigned int bestContiguousSpace[4] = {0};
unsigned int totalSpace[4] = {0};
for (unsigned int row = 0; row < maxVaryingVectors; ++row)
{
for (unsigned int column = 0; column < 4; ++column)
{
for (int x = 0; x < 4; x++)
if (mRegisterMap[row][column])
{
space[x] += packing[y][x] ? 0 : 1;
contiguousSpace[column] = 0;
}
}
else
{
contiguousSpace[column]++;
totalSpace[column]++;
int column = 0;
if (contiguousSpace[column] > bestContiguousSpace[column])
{
bestContiguousSpace[column] = contiguousSpace[column];
}
}
}
}
for (int x = 0; x < 4; x++)
unsigned int bestColumn = 0;
for (unsigned int column = 1; column < 4; ++column)
{
if (bestContiguousSpace[column] >= varyingRows &&
(bestContiguousSpace[bestColumn] < varyingRows ||
totalSpace[column] < totalSpace[bestColumn]))
{
if (space[x] >= registers && (space[column] < registers || space[x] < space[column]))
{
column = x;
}
bestColumn = column;
}
}
if (space[column] >= registers)
if (bestContiguousSpace[bestColumn] >= varyingRows)
{
for (unsigned int row = 0; row < maxVaryingVectors; row++)
{
for (int r = 0; r < maxVaryingVectors; r++)
if (isFree(row, bestColumn, varyingRows, 1))
{
if (!packing[r][column])
for (unsigned int arrayIndex = 0; arrayIndex < varyingRows; ++arrayIndex)
{
packedVarying->registerIndex = r;
packedVarying->columnIndex = column;
for (int y = r; y < r + registers; y++)
{
packing[y][column] = packedVarying;
}
break;
// If varyingRows > 1, it must be an array.
PackedVaryingRegister registerInfo;
registerInfo.packedVarying = &packedVarying;
registerInfo.registerRow = row + arrayIndex;
registerInfo.registerColumn = bestColumn;
registerInfo.varyingArrayIndex = arrayIndex;
registerInfo.varyingRowIndex = 0;
mRegisterList.push_back(registerInfo);
mRegisterMap[row + arrayIndex][bestColumn] = true;
}
break;
}
return true;
}
return true;
}
else
UNREACHABLE();
return false;
}
unsigned int PackedVaryingRegister::registerIndex(
const gl::Caps &caps,
const std::vector<PackedVarying> &packedVaryings) const
bool VaryingPacking::isFree(unsigned int registerRow,
unsigned int registerColumn,
unsigned int varyingRows,
unsigned int varyingColumns) const
{
const PackedVarying &packedVarying = packedVaryings[varyingIndex];
const sh::Varying &varying = *packedVarying.varying;
GLenum transposedType = gl::TransposeMatrixType(varying.type);
unsigned int variableRows =
static_cast<unsigned int>(varying.isStruct() ? 1 : gl::VariableRowCount(transposedType));
return (elementIndex * variableRows + (packedVarying.columnIndex * caps.maxVaryingVectors) +
(packedVarying.registerIndex + rowIndex));
}
PackedVaryingIterator::PackedVaryingIterator(const std::vector<PackedVarying> &packedVaryings)
: mPackedVaryings(packedVaryings), mEnd(*this)
{
mEnd.setEnd();
}
PackedVaryingIterator::Iterator PackedVaryingIterator::begin() const
{
return Iterator(*this);
}
const PackedVaryingIterator::Iterator &PackedVaryingIterator::end() const
{
return mEnd;
}
PackedVaryingIterator::Iterator::Iterator(const PackedVaryingIterator &parent) : mParent(parent)
{
while (mRegister.varyingIndex < mParent.mPackedVaryings.size() &&
!mParent.mPackedVaryings[mRegister.varyingIndex].registerAssigned())
for (unsigned int row = 0; row < varyingRows; ++row)
{
++mRegister.varyingIndex;
ASSERT(registerRow + row < mRegisterMap.size());
for (unsigned int column = 0; column < varyingColumns; ++column)
{
ASSERT(registerColumn + column < 4);
if (mRegisterMap[registerRow + row][registerColumn + column])
{
return false;
}
}
}
return true;
}
PackedVaryingIterator::Iterator &PackedVaryingIterator::Iterator::operator++()
void VaryingPacking::insert(unsigned int registerRow,
unsigned int registerColumn,
const PackedVarying &packedVarying)
{
const sh::Varying *varying = mParent.mPackedVaryings[mRegister.varyingIndex].varying;
GLenum transposedType = gl::TransposeMatrixType(varying->type);
unsigned int variableRows =
static_cast<unsigned int>(varying->isStruct() ? 1 : gl::VariableRowCount(transposedType));
unsigned int varyingRows = 0;
unsigned int varyingColumns = 0;
// Innermost iteration: row count
if (mRegister.rowIndex + 1 < variableRows)
const sh::Varying &varying = *packedVarying.varying;
if (varying.isStruct())
{
++mRegister.rowIndex;
return *this;
varyingRows = HLSLVariableRegisterCount(varying, true);
varyingColumns = 4;
}
mRegister.rowIndex = 0;
// Middle iteration: element count
if (mRegister.elementIndex + 1 < varying->elementCount())
else
{
++mRegister.elementIndex;
return *this;
GLenum transposedType = gl::TransposeMatrixType(varying.type);
varyingRows = gl::VariableRowCount(transposedType);
varyingColumns = gl::VariableColumnCount(transposedType);
}
mRegister.elementIndex = 0;
PackedVaryingRegister registerInfo;
registerInfo.packedVarying = &packedVarying;
registerInfo.registerColumn = registerColumn;
// Outer iteration: the varying itself. Once we pass the last varying, this Iterator will
// equal the end Iterator.
do
for (unsigned int arrayElement = 0; arrayElement < varying.elementCount(); ++arrayElement)
{
++mRegister.varyingIndex;
} while (mRegister.varyingIndex < mParent.mPackedVaryings.size() &&
!mParent.mPackedVaryings[mRegister.varyingIndex].registerAssigned());
return *this;
}
bool PackedVaryingIterator::Iterator::operator==(const Iterator &other) const
{
return mRegister.elementIndex == other.mRegister.elementIndex &&
mRegister.rowIndex == other.mRegister.rowIndex &&
mRegister.varyingIndex == other.mRegister.varyingIndex;
}
for (unsigned int varyingRow = 0; varyingRow < varyingRows; ++varyingRow)
{
registerInfo.registerRow = registerRow + (arrayElement * varyingRows) + varyingRow;
registerInfo.varyingRowIndex = varyingRow;
registerInfo.varyingArrayIndex = arrayElement;
mRegisterList.push_back(registerInfo);
bool PackedVaryingIterator::Iterator::operator!=(const Iterator &other) const
{
return !(*this == other);
for (unsigned int columnIndex = 0; columnIndex < varyingColumns; ++columnIndex)
{
mRegisterMap[registerInfo.registerRow][registerColumn + columnIndex] = true;
}
}
}
}
// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading
// Language 1.00 rev. 17] appendix A section 7 page 111
// Returns the number of used varying registers, or -1 if unsuccesful
bool PackVaryings(const gl::Caps &caps,
gl::InfoLog &infoLog,
std::vector<PackedVarying> *packedVaryings,
const std::vector<std::string> &transformFeedbackVaryings,
unsigned int *registerCountOut)
// See comment on packVarying.
bool VaryingPacking::packVaryings(gl::InfoLog &infoLog,
const std::vector<PackedVarying> &packedVaryings,
const std::vector<std::string> &transformFeedbackVaryings)
{
VaryingPacking packing = {};
*registerCountOut = 0;
std::set<std::string> uniqueVaryingNames;
for (PackedVarying &packedVarying : *packedVaryings)
// "Variables are packed into the registers one at a time so that they each occupy a contiguous
// subrectangle. No splitting of variables is permitted."
for (const PackedVarying &packedVarying : packedVaryings)
{
const sh::Varying &varying = *packedVarying.varying;
......@@ -292,7 +261,7 @@ bool PackVaryings(const gl::Caps &caps,
ASSERT(uniqueVaryingNames.count(varying.name) == 0);
if (PackVarying(&packedVarying, caps.maxVaryingVectors, packing))
if (packVarying(packedVarying))
{
uniqueVaryingNames.insert(varying.name);
}
......@@ -311,7 +280,7 @@ bool PackVaryings(const gl::Caps &caps,
continue;
}
for (PackedVarying &packedVarying : *packedVaryings)
for (const PackedVarying &packedVarying : packedVaryings)
{
const sh::Varying &varying = *packedVarying.varying;
......@@ -321,7 +290,7 @@ bool PackVaryings(const gl::Caps &caps,
bool found = false;
if (transformFeedbackVaryingName == varying.name)
{
if (!PackVarying(&packedVarying, caps.maxVaryingVectors, packing))
if (!packVarying(packedVarying))
{
infoLog << "Could not pack varying " << varying.name;
return false;
......@@ -337,67 +306,84 @@ bool PackVaryings(const gl::Caps &caps,
return false;
}
}
// Add duplicate transform feedback varyings for 'flat' shaded attributes. This is
// necessary because we write out modified vertex data to correct for the provoking
// vertex in D3D11. This extra transform feedback varying is the unmodified stream.
if (varying.interpolation == sh::INTERPOLATION_FLAT)
{
sh::Varying duplicateVarying(varying);
duplicateVarying.name = "StreamOut_" + duplicateVarying.name;
}
}
}
// Return the number of used registers
for (GLuint r = 0; r < caps.maxVaryingVectors; r++)
// Sort the packed register list
std::sort(mRegisterList.begin(), mRegisterList.end());
// Assign semantic indices
for (unsigned int semanticIndex = 0;
semanticIndex < static_cast<unsigned int>(mRegisterList.size()); ++semanticIndex)
{
if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
mRegisterList[semanticIndex].semanticIndex = semanticIndex;
}
return true;
}
unsigned int VaryingPacking::getRegisterCount() const
{
unsigned int count = 0;
for (const Register &reg : mRegisterMap)
{
if (reg.data[0] || reg.data[1] || reg.data[2] || reg.data[3])
{
(*registerCountOut)++;
++count;
}
}
return true;
if (mBuiltinInfo[SHADER_PIXEL].glFragCoord.enabled)
{
++count;
}
if (mBuiltinInfo[SHADER_PIXEL].glPointCoord.enabled)
{
++count;
}
return count;
}
SemanticInfo GetSemanticInfo(ShaderType shaderType,
const ProgramD3DMetadata &programMetadata,
unsigned int startRegisters)
void VaryingPacking::enableBuiltins(ShaderType shaderType,
const ProgramD3DMetadata &programMetadata)
{
int majorShaderModel = programMetadata.getRendererMajorShaderModel();
bool position = programMetadata.usesTransformFeedbackGLPosition();
bool fragCoord = programMetadata.usesFragCoord();
bool pointCoord = shaderType == SHADER_VERTEX ? programMetadata.addsPointCoordToVertexShader()
: programMetadata.usesPointCoord();
bool pointSize = programMetadata.usesSystemValuePointSize();
bool hlsl4 = (majorShaderModel >= 4);
bool pointSize = programMetadata.usesSystemValuePointSize();
bool hlsl4 = (majorShaderModel >= 4);
const std::string &userSemantic = GetVaryingSemantic(majorShaderModel, pointSize);
unsigned int reservedSemanticIndex = getMaxSemanticIndex();
const std::string &userSemantic = GetVaryingSemantic(majorShaderModel, pointSize);
unsigned int reservedRegisterIndex = startRegisters;
BuiltinInfo *builtins = &mBuiltinInfo[shaderType];
SemanticInfo info;
if (hlsl4)
{
info.dxPosition.enableSystem("SV_Position");
builtins->dxPosition.enableSystem("SV_Position");
}
else if (shaderType == SHADER_PIXEL)
{
info.dxPosition.enableSystem("VPOS");
builtins->dxPosition.enableSystem("VPOS");
}
else
{
info.dxPosition.enableSystem("POSITION");
builtins->dxPosition.enableSystem("POSITION");
}
if (position)
{
info.glPosition.enable(userSemantic, reservedRegisterIndex++);
builtins->glPosition.enable(userSemantic, reservedSemanticIndex++);
}
if (fragCoord)
{
info.glFragCoord.enable(userSemantic, reservedRegisterIndex++);
builtins->glFragCoord.enable(userSemantic, reservedSemanticIndex++);
}
if (pointCoord)
......@@ -406,21 +392,19 @@ SemanticInfo GetSemanticInfo(ShaderType shaderType,
// In D3D11 we manually compute gl_PointCoord in the GS.
if (hlsl4)
{
info.glPointCoord.enable(userSemantic, reservedRegisterIndex++);
builtins->glPointCoord.enable(userSemantic, reservedSemanticIndex++);
}
else
{
info.glPointCoord.enable("TEXCOORD", 0);
builtins->glPointCoord.enable("TEXCOORD", 0);
}
}
// Special case: do not include PSIZE semantic in HLSL 3 pixel shaders
if (pointSize && (shaderType != SHADER_PIXEL || hlsl4))
{
info.glPointSize.enableSystem("PSIZE");
builtins->glPointSize.enableSystem("PSIZE");
}
return info;
}
} // namespace rx
......@@ -19,88 +19,92 @@ class ProgramD3DMetadata;
struct PackedVarying
{
PackedVarying(const sh::Varying &varyingIn)
: varying(&varyingIn), registerIndex(GL_INVALID_INDEX), columnIndex(0), vertexOnly(false)
{
}
bool registerAssigned() const { return registerIndex != GL_INVALID_INDEX; }
void resetRegisterAssignment() { registerIndex = GL_INVALID_INDEX; }
PackedVarying(const sh::Varying &varyingIn) : varying(&varyingIn), vertexOnly(false) {}
const sh::Varying *varying;
// Assigned during link
unsigned int registerIndex;
// Assigned during link, Defaults to 0
unsigned int columnIndex;
// Transform feedback varyings can be only referenced in the VS.
bool vertexOnly;
};
struct PackedVaryingRegister final
{
PackedVaryingRegister() : varyingIndex(0), elementIndex(0), rowIndex(0) {}
PackedVaryingRegister()
: packedVarying(nullptr),
varyingArrayIndex(0),
varyingRowIndex(0),
registerRow(0),
registerColumn(0)
{
}
PackedVaryingRegister(const PackedVaryingRegister &) = default;
PackedVaryingRegister &operator=(const PackedVaryingRegister &) = default;
unsigned int registerIndex(const gl::Caps &caps,
const std::vector<PackedVarying> &packedVaryings) const;
bool operator<(const PackedVaryingRegister &other) const
{
return sortOrder() < other.sortOrder();
}
unsigned int sortOrder() const
{
// TODO(jmadill): Handle interpolation types
return registerRow * 4 + registerColumn;
}
// Index to the array of varyings.
const PackedVarying *packedVarying;
// The array element of the packed varying.
unsigned int varyingArrayIndex;
// The row of the array element of the packed varying.
unsigned int varyingRowIndex;
// The register row to which we've assigned this packed varying.
unsigned int registerRow;
size_t varyingIndex;
unsigned int elementIndex;
unsigned int rowIndex;
// The column of the register row into which we've packed this varying.
unsigned int registerColumn;
// Assigned after packing
unsigned int semanticIndex;
};
class PackedVaryingIterator final : public angle::NonCopyable
class VaryingPacking final : angle::NonCopyable
{
public:
PackedVaryingIterator(const std::vector<PackedVarying> &packedVaryings);
class Iterator final
{
public:
Iterator(const PackedVaryingIterator &parent);
VaryingPacking(GLuint maxVaryingVectors);
Iterator(const Iterator &) = default;
Iterator &operator=(const Iterator &) = delete;
bool packVaryings(gl::InfoLog &infoLog,
const std::vector<PackedVarying> &packedVaryings,
const std::vector<std::string> &transformFeedbackVaryings);
Iterator &operator++();
bool operator==(const Iterator &other) const;
bool operator!=(const Iterator &other) const;
struct Register
{
Register() { data[0] = data[1] = data[2] = data[3] = false; }
const PackedVaryingRegister &operator*() const { return mRegister; }
void setEnd() { mRegister.varyingIndex = mParent.mPackedVaryings.size(); }
bool &operator[](unsigned int index) { return data[index]; }
bool operator[](unsigned int index) const { return data[index]; }
private:
const PackedVaryingIterator &mParent;
PackedVaryingRegister mRegister;
bool data[4];
};
Iterator begin() const;
const Iterator &end() const;
Register &operator[](unsigned int index) { return mRegisterMap[index]; }
const Register &operator[](unsigned int index) const { return mRegisterMap[index]; }
private:
const std::vector<PackedVarying> &mPackedVaryings;
Iterator mEnd;
};
typedef const PackedVarying *VaryingPacking[gl::IMPLEMENTATION_MAX_VARYING_VECTORS][4];
const std::vector<PackedVaryingRegister> &getRegisterList() const { return mRegisterList; }
unsigned int getMaxSemanticIndex() const
{
return static_cast<unsigned int>(mRegisterList.size());
}
unsigned int getRegisterCount() const;
bool PackVaryings(const gl::Caps &caps,
gl::InfoLog &infoLog,
std::vector<PackedVarying> *packedVaryings,
const std::vector<std::string> &transformFeedbackVaryings,
unsigned int *registerCountOut);
void enableBuiltins(ShaderType shaderType, const ProgramD3DMetadata &programMetadata);
struct SemanticInfo final
{
struct BuiltinInfo final
struct BuiltinVarying final : angle::NonCopyable
{
BuiltinInfo();
BuiltinVarying();
std::string str() const;
void enableSystem(const std::string &systemValueSemantic);
......@@ -112,16 +116,34 @@ struct SemanticInfo final
bool systemValue;
};
BuiltinInfo dxPosition;
BuiltinInfo glPosition;
BuiltinInfo glFragCoord;
BuiltinInfo glPointCoord;
BuiltinInfo glPointSize;
};
struct BuiltinInfo
{
BuiltinVarying dxPosition;
BuiltinVarying glPosition;
BuiltinVarying glFragCoord;
BuiltinVarying glPointCoord;
BuiltinVarying glPointSize;
};
SemanticInfo GetSemanticInfo(ShaderType shaderType,
const ProgramD3DMetadata &programMetadata,
unsigned int startRegisters);
const BuiltinInfo &builtins(ShaderType shaderType) const { return mBuiltinInfo[shaderType]; }
bool usesPointSize() const { return mBuiltinInfo[SHADER_VERTEX].glPointSize.enabled; }
private:
bool packVarying(const PackedVarying &packedVarying);
bool isFree(unsigned int registerRow,
unsigned int registerColumn,
unsigned int varyingRows,
unsigned int varyingColumns) const;
void insert(unsigned int registerRow,
unsigned int registerColumn,
const PackedVarying &packedVarying);
std::vector<Register> mRegisterMap;
std::vector<PackedVaryingRegister> mRegisterList;
std::vector<BuiltinInfo> mBuiltinInfo;
};
} // namespace rx
......
......@@ -3257,7 +3257,7 @@ ProgramImpl *Renderer11::createProgram(const gl::Program::Data &data)
gl::Error Renderer11::loadExecutable(const void *function,
size_t length,
ShaderType type,
const std::vector<D3DVarying> &transformFeedbackVaryings,
const std::vector<D3DVarying> &streamOutVaryings,
bool separatedOutputBuffers,
ShaderExecutableD3D **outExecutable)
{
......@@ -3275,25 +3275,22 @@ gl::Error Renderer11::loadExecutable(const void *function,
return gl::Error(GL_OUT_OF_MEMORY, "Failed to create vertex shader, result: 0x%X.", result);
}
if (transformFeedbackVaryings.size() > 0)
if (!streamOutVaryings.empty())
{
std::vector<D3D11_SO_DECLARATION_ENTRY> soDeclaration;
for (size_t i = 0; i < transformFeedbackVaryings.size(); i++)
soDeclaration.reserve(streamOutVaryings.size());
for (const auto &streamOutVarying : streamOutVaryings)
{
const D3DVarying &varying = transformFeedbackVaryings[i];
GLenum transposedType = gl::TransposeMatrixType(varying.type);
for (unsigned int j = 0; j < varying.semanticIndexCount; j++)
{
D3D11_SO_DECLARATION_ENTRY entry = { 0 };
entry.Stream = 0;
entry.SemanticName = varying.semanticName.c_str();
entry.SemanticIndex = varying.semanticIndex + j;
entry.StartComponent = 0;
entry.ComponentCount = static_cast<BYTE>(gl::VariableColumnCount(transposedType));
entry.OutputSlot = static_cast<BYTE>((separatedOutputBuffers ? i : 0));
soDeclaration.push_back(entry);
}
D3D11_SO_DECLARATION_ENTRY entry = {0};
entry.Stream = 0;
entry.SemanticName = streamOutVarying.semanticName.c_str();
entry.SemanticIndex = streamOutVarying.semanticIndex;
entry.StartComponent = 0;
entry.ComponentCount = static_cast<BYTE>(streamOutVarying.componentCount);
entry.OutputSlot = static_cast<BYTE>(
(separatedOutputBuffers ? streamOutVarying.outputSlot : 0));
soDeclaration.push_back(entry);
}
result = mDevice->CreateGeometryShaderWithStreamOutput(
......@@ -3349,7 +3346,7 @@ gl::Error Renderer11::loadExecutable(const void *function,
gl::Error Renderer11::compileToExecutable(gl::InfoLog &infoLog,
const std::string &shaderHLSL,
ShaderType type,
const std::vector<D3DVarying> &transformFeedbackVaryings,
const std::vector<D3DVarying> &streamOutVaryings,
bool separatedOutputBuffers,
const D3DCompilerWorkarounds &workarounds,
ShaderExecutableD3D **outExectuable)
......@@ -3422,7 +3419,7 @@ gl::Error Renderer11::compileToExecutable(gl::InfoLog &infoLog,
}
error = loadExecutable(binary->GetBufferPointer(), binary->GetBufferSize(), type,
transformFeedbackVaryings, separatedOutputBuffers, outExectuable);
streamOutVaryings, separatedOutputBuffers, outExectuable);
SafeRelease(binary);
if (error.isError())
......
......@@ -191,13 +191,13 @@ class Renderer11 : public RendererD3D
gl::Error loadExecutable(const void *function,
size_t length,
ShaderType type,
const std::vector<D3DVarying> &transformFeedbackVaryings,
const std::vector<D3DVarying> &streamOutVaryings,
bool separatedOutputBuffers,
ShaderExecutableD3D **outExecutable) override;
gl::Error compileToExecutable(gl::InfoLog &infoLog,
const std::string &shaderHLSL,
ShaderType type,
const std::vector<D3DVarying> &transformFeedbackVaryings,
const std::vector<D3DVarying> &streamOutVaryings,
bool separatedOutputBuffers,
const D3DCompilerWorkarounds &workarounds,
ShaderExecutableD3D **outExectuable) override;
......
......@@ -2735,12 +2735,12 @@ ProgramImpl *Renderer9::createProgram(const gl::Program::Data &data)
gl::Error Renderer9::loadExecutable(const void *function,
size_t length,
ShaderType type,
const std::vector<D3DVarying> &transformFeedbackVaryings,
const std::vector<D3DVarying> &streamOutVaryings,
bool separatedOutputBuffers,
ShaderExecutableD3D **outExecutable)
{
// Transform feedback is not supported in ES2 or D3D9
ASSERT(transformFeedbackVaryings.size() == 0);
ASSERT(streamOutVaryings.empty());
switch (type)
{
......@@ -2777,13 +2777,13 @@ gl::Error Renderer9::loadExecutable(const void *function,
gl::Error Renderer9::compileToExecutable(gl::InfoLog &infoLog,
const std::string &shaderHLSL,
ShaderType type,
const std::vector<D3DVarying> &transformFeedbackVaryings,
const std::vector<D3DVarying> &streamOutVaryings,
bool separatedOutputBuffers,
const D3DCompilerWorkarounds &workarounds,
ShaderExecutableD3D **outExectuable)
{
// Transform feedback is not supported in ES2 or D3D9
ASSERT(transformFeedbackVaryings.size() == 0);
ASSERT(streamOutVaryings.empty());
const char *profileType = NULL;
switch (type)
......@@ -2846,7 +2846,7 @@ gl::Error Renderer9::compileToExecutable(gl::InfoLog &infoLog,
}
error = loadExecutable(binary->GetBufferPointer(), binary->GetBufferSize(), type,
transformFeedbackVaryings, separatedOutputBuffers, outExectuable);
streamOutVaryings, separatedOutputBuffers, outExectuable);
SafeRelease(binary);
if (error.isError())
......
......@@ -179,13 +179,13 @@ class Renderer9 : public RendererD3D
gl::Error loadExecutable(const void *function,
size_t length,
ShaderType type,
const std::vector<D3DVarying> &transformFeedbackVaryings,
const std::vector<D3DVarying> &streamOutVaryings,
bool separatedOutputBuffers,
ShaderExecutableD3D **outExecutable) override;
gl::Error compileToExecutable(gl::InfoLog &infoLog,
const std::string &shaderHLSL,
ShaderType type,
const std::vector<D3DVarying> &transformFeedbackVaryings,
const std::vector<D3DVarying> &streamOutVaryings,
bool separatedOutputBuffers,
const D3DCompilerWorkarounds &workarounds,
ShaderExecutableD3D **outExectuable) override;
......
......@@ -828,8 +828,14 @@ TEST_P(GLSLTest, MaxVaryingVec3Array)
}
// Disabled because of a failure in D3D9
TEST_P(GLSLTest, DISABLED_MaxVaryingVec3AndOneFloat)
TEST_P(GLSLTest, MaxVaryingVec3AndOneFloat)
{
if (isD3D9())
{
std::cout << "Test disabled on D3D9." << std::endl;
return;
}
GLint maxVaryings = 0;
glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
......@@ -837,8 +843,14 @@ TEST_P(GLSLTest, DISABLED_MaxVaryingVec3AndOneFloat)
}
// Disabled because of a failure in D3D9
TEST_P(GLSLTest, DISABLED_MaxVaryingVec3ArrayAndOneFloatArray)
TEST_P(GLSLTest, MaxVaryingVec3ArrayAndOneFloatArray)
{
if (isD3D9())
{
std::cout << "Test disabled on D3D9." << std::endl;
return;
}
GLint maxVaryings = 0;
glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
......@@ -846,8 +858,14 @@ TEST_P(GLSLTest, DISABLED_MaxVaryingVec3ArrayAndOneFloatArray)
}
// Disabled because of a failure in D3D9
TEST_P(GLSLTest, DISABLED_TwiceMaxVaryingVec2)
TEST_P(GLSLTest, TwiceMaxVaryingVec2)
{
if (isD3D9())
{
std::cout << "Test disabled on D3D9." << std::endl;
return;
}
GLint maxVaryings = 0;
glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
......@@ -855,8 +873,14 @@ TEST_P(GLSLTest, DISABLED_TwiceMaxVaryingVec2)
}
// Disabled because of a failure in D3D9
TEST_P(GLSLTest, DISABLED_MaxVaryingVec2Arrays)
TEST_P(GLSLTest, MaxVaryingVec2Arrays)
{
if (isD3DSM3())
{
std::cout << "Test disabled on SM3." << std::endl;
return;
}
GLint maxVaryings = 0;
glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
......
......@@ -5,6 +5,7 @@
//
#include "test_utils/ANGLETest.h"
#include "Vector.h"
using namespace angle;
......@@ -15,6 +16,10 @@ class TransformFeedbackTest : public ANGLETest
{
protected:
TransformFeedbackTest()
: mProgram(0),
mTransformFeedbackBufferSize(0),
mTransformFeedbackBuffer(0),
mTransformFeedback(0)
{
setWindowWidth(128);
setWindowHeight(128);
......@@ -28,6 +33,44 @@ class TransformFeedbackTest : public ANGLETest
{
ANGLETest::SetUp();
glGenBuffers(1, &mTransformFeedbackBuffer);
mTransformFeedbackBufferSize = 1 << 24; // ~16MB
glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, mTransformFeedbackBuffer);
glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, mTransformFeedbackBufferSize, NULL,
GL_STATIC_DRAW);
glGenTransformFeedbacks(1, &mTransformFeedback);
ASSERT_GL_NO_ERROR();
}
void TearDown() override
{
if (mProgram != 0)
{
glDeleteProgram(mProgram);
mProgram = 0;
}
if (mTransformFeedbackBuffer != 0)
{
glDeleteBuffers(1, &mTransformFeedbackBuffer);
mTransformFeedbackBuffer = 0;
}
if (mTransformFeedback != 0)
{
glDeleteTransformFeedbacks(1, &mTransformFeedback);
mTransformFeedback = 0;
}
ANGLETest::TearDown();
}
void compileDefaultProgram(const std::vector<std::string> &tfVaryings, GLenum bufferMode)
{
ASSERT_EQ(0u, mProgram);
const std::string vertexShaderSource = SHADER_SOURCE
(
precision highp float;
......@@ -49,49 +92,24 @@ class TransformFeedbackTest : public ANGLETest
}
);
mProgram = CompileProgram(vertexShaderSource, fragmentShaderSource);
if (mProgram == 0)
{
FAIL() << "shader compilation failed.";
}
glGenBuffers(1, &mTransformFeedbackBuffer);
mTransformFeedbackBufferSize = 1 << 24; // ~16MB
glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, mTransformFeedbackBuffer);
glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, mTransformFeedbackBufferSize, NULL, GL_STATIC_DRAW);
ASSERT_GL_NO_ERROR();
}
void TearDown() override
{
glDeleteProgram(mProgram);
glDeleteBuffers(1, &mTransformFeedbackBuffer);
ANGLETest::TearDown();
mProgram = CompileProgramWithTransformFeedback(vertexShaderSource, fragmentShaderSource,
tfVaryings, bufferMode);
ASSERT_NE(0u, mProgram);
}
GLuint mProgram;
size_t mTransformFeedbackBufferSize;
GLuint mTransformFeedbackBuffer;
GLuint mTransformFeedback;
};
TEST_P(TransformFeedbackTest, ZeroSizedViewport)
{
// Set the program's transform feedback varyings (just gl_Position)
const GLchar* transformFeedbackVaryings[] =
{
"gl_Position"
};
glTransformFeedbackVaryings(mProgram,
static_cast<GLsizei>(ArraySize(transformFeedbackVaryings)),
transformFeedbackVaryings, GL_INTERLEAVED_ATTRIBS);
glLinkProgram(mProgram);
// Re-link the program
GLint linkStatus;
glGetProgramiv(mProgram, GL_LINK_STATUS, &linkStatus);
ASSERT_NE(linkStatus, 0);
std::vector<std::string> tfVaryings;
tfVaryings.push_back("gl_Position");
compileDefaultProgram(tfVaryings, GL_INTERLEAVED_ATTRIBS);
glUseProgram(mProgram);
......@@ -137,19 +155,9 @@ TEST_P(TransformFeedbackTest, RecordAndDraw)
glClear(GL_COLOR_BUFFER_BIT);
// Set the program's transform feedback varyings (just gl_Position)
const GLchar* transformFeedbackVaryings[] =
{
"gl_Position"
};
glTransformFeedbackVaryings(mProgram,
static_cast<GLsizei>(ArraySize(transformFeedbackVaryings)),
transformFeedbackVaryings, GL_INTERLEAVED_ATTRIBS);
glLinkProgram(mProgram);
// Re-link the program
GLint linkStatus;
glGetProgramiv(mProgram, GL_LINK_STATUS, &linkStatus);
ASSERT_NE(linkStatus, 0);
std::vector<std::string> tfVaryings;
tfVaryings.push_back("gl_Position");
compileDefaultProgram(tfVaryings, GL_INTERLEAVED_ATTRIBS);
glUseProgram(mProgram);
......@@ -223,10 +231,7 @@ TEST_P(TransformFeedbackTest, BufferBinding)
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0);
// Generate a new transform feedback and buffer
GLuint transformFeedbackObject = 0;
glGenTransformFeedbacks(1, &transformFeedbackObject);
// Generate a new buffer
GLuint scratchBuffer = 0;
glGenBuffers(1, &scratchBuffer);
......@@ -246,7 +251,7 @@ TEST_P(TransformFeedbackTest, BufferBinding)
EXPECT_GL_NO_ERROR();
// Check that the buffer ID for the newly bound transform feedback is zero
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedbackObject);
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, mTransformFeedback);
glGetIntegerv(GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, &currentBufferBinding);
EXPECT_EQ(0, currentBufferBinding);
......@@ -270,7 +275,6 @@ TEST_P(TransformFeedbackTest, BufferBinding)
EXPECT_GL_NO_ERROR();
// Clean up
glDeleteTransformFeedbacks(1, &transformFeedbackObject);
glDeleteBuffers(1, &scratchBuffer);
}
......@@ -297,13 +301,11 @@ TEST_P(TransformFeedbackTest, VertexOnly)
std::vector<std::string> tfVaryings;
tfVaryings.push_back("varyingAttrib");
GLuint program = CompileProgramWithTransformFeedback(vertexShaderSource, fragmentShaderSource,
tfVaryings, GL_INTERLEAVED_ATTRIBS);
ASSERT_NE(0u, program);
mProgram = CompileProgramWithTransformFeedback(vertexShaderSource, fragmentShaderSource,
tfVaryings, GL_INTERLEAVED_ATTRIBS);
ASSERT_NE(0u, mProgram);
GLuint transformFeedback;
glGenTransformFeedbacks(1, &transformFeedback);
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedback);
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, mTransformFeedback);
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBuffer);
std::vector<float> attribData;
......@@ -312,14 +314,14 @@ TEST_P(TransformFeedbackTest, VertexOnly)
attribData.push_back(static_cast<float>(cnt));
}
GLint attribLocation = glGetAttribLocation(program, "attrib");
GLint attribLocation = glGetAttribLocation(mProgram, "attrib");
ASSERT_NE(-1, attribLocation);
glVertexAttribPointer(attribLocation, 1, GL_FLOAT, GL_FALSE, 4, &attribData[0]);
glEnableVertexAttribArray(attribLocation);
glBeginTransformFeedback(GL_TRIANGLES);
drawQuad(program, "position", 0.5f);
drawQuad(mProgram, "position", 0.5f);
glEndTransformFeedback();
ASSERT_GL_NO_ERROR();
......@@ -333,9 +335,6 @@ TEST_P(TransformFeedbackTest, VertexOnly)
EXPECT_EQ(attribData[cnt], mappedFloats[cnt]);
}
glDeleteTransformFeedbacks(1, &transformFeedback);
glDeleteProgram(program);
EXPECT_GL_NO_ERROR();
}
......@@ -381,16 +380,16 @@ TEST_P(TransformFeedbackTest, MultiplePaused)
std::vector<std::string> tfVaryings;
tfVaryings.push_back("transformFeedbackOutput");
GLuint program = CompileProgramWithTransformFeedback(vertexShaderSource, fragmentShaderSource,
tfVaryings, GL_INTERLEAVED_ATTRIBS);
ASSERT_NE(program, 0u);
glUseProgram(program);
mProgram = CompileProgramWithTransformFeedback(vertexShaderSource, fragmentShaderSource,
tfVaryings, GL_INTERLEAVED_ATTRIBS);
ASSERT_NE(0u, mProgram);
glUseProgram(mProgram);
GLint positionLocation = glGetAttribLocation(program, "position");
GLint positionLocation = glGetAttribLocation(mProgram, "position");
glDisableVertexAttribArray(positionLocation);
glVertexAttrib4f(positionLocation, 0.0f, 0.0f, 0.0f, 1.0f);
GLint tfInputLocation = glGetAttribLocation(program, "transformFeedbackInput");
GLint tfInputLocation = glGetAttribLocation(mProgram, "transformFeedbackInput");
glEnableVertexAttribArray(tfInputLocation);
glVertexAttribPointer(tfInputLocation, 1, GL_FLOAT, false, 0, &transformFeedbackData[0]);
......@@ -628,7 +627,79 @@ TEST_P(TransformFeedbackTest, MultiContext)
}
}
// Test that when two vec2s are packed into the same register, we can still capture both of them.
TEST_P(TransformFeedbackTest, PackingBug)
{
// TODO(jmadill): With points and rasterizer discard?
const std::string &vertexShaderSource =
"#version 300 es\n"
"in vec2 inAttrib1;\n"
"in vec2 inAttrib2;\n"
"out vec2 outAttrib1;\n"
"out vec2 outAttrib2;\n"
"in vec2 position;\n"
"void main() {"
" outAttrib1 = inAttrib1;\n"
" outAttrib2 = inAttrib2;\n"
" gl_Position = vec4(position, 0, 1);\n"
"}";
const std::string &fragmentShaderSource =
"#version 300 es\n"
"precision mediump float;\n"
"out vec4 color;\n"
"void main() {\n"
" color = vec4(0);\n"
"}";
std::vector<std::string> tfVaryings;
tfVaryings.push_back("outAttrib1");
tfVaryings.push_back("outAttrib2");
mProgram = CompileProgramWithTransformFeedback(vertexShaderSource, fragmentShaderSource,
tfVaryings, GL_INTERLEAVED_ATTRIBS);
ASSERT_NE(0u, mProgram);
glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, mTransformFeedbackBuffer);
glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, sizeof(Vector2) * 2 * 6, nullptr, GL_STREAM_DRAW);
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, mTransformFeedback);
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mTransformFeedbackBuffer);
GLint attrib1Loc = glGetAttribLocation(mProgram, "inAttrib1");
GLint attrib2Loc = glGetAttribLocation(mProgram, "inAttrib2");
Vector2 attrib1Data[] = {Vector2(1.0, 2.0), Vector2(3.0, 4.0), Vector2(5.0, 6.0)};
Vector2 attrib2Data[] = {Vector2(11.0, 12.0), Vector2(13.0, 14.0), Vector2(15.0, 16.0)};
glEnableVertexAttribArray(attrib1Loc);
glEnableVertexAttribArray(attrib2Loc);
glVertexAttribPointer(attrib1Loc, 2, GL_FLOAT, GL_FALSE, 0, attrib1Data);
glVertexAttribPointer(attrib2Loc, 2, GL_FLOAT, GL_FALSE, 0, attrib2Data);
glBeginTransformFeedback(GL_TRIANGLES);
drawQuad(mProgram, "position", 0.5f);
glEndTransformFeedback();
ASSERT_GL_NO_ERROR();
const GLvoid *mapPointer =
glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(Vector2) * 2 * 6, GL_MAP_READ_BIT);
ASSERT_NE(nullptr, mapPointer);
const Vector2 *vecPointer = static_cast<const Vector2 *>(mapPointer);
for (unsigned int vectorIndex = 0; vectorIndex < 3; ++vectorIndex)
{
unsigned int stream1Index = vectorIndex * 2;
unsigned int stream2Index = vectorIndex * 2 + 1;
EXPECT_EQ(attrib1Data[vectorIndex], vecPointer[stream1Index]);
EXPECT_EQ(attrib2Data[vectorIndex], vecPointer[stream2Index]);
}
ASSERT_GL_NO_ERROR();
}
// Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
ANGLE_INSTANTIATE_TEST(TransformFeedbackTest, ES3_D3D11(), ES3_OPENGL());
} // namespace
} // anonymous namespace
......@@ -298,6 +298,24 @@ bool ANGLETest::isD3D11() const
return (rendererString.find("Direct3D11 vs_5_0") != std::string::npos);
}
bool ANGLETest::isD3D11_FL93() const
{
std::string rendererString(reinterpret_cast<const char *>(glGetString(GL_RENDERER)));
return (rendererString.find("Direct3D11 vs_4_0_") != std::string::npos);
}
bool ANGLETest::isD3D9() const
{
std::string rendererString(reinterpret_cast<const char *>(glGetString(GL_RENDERER)));
return (rendererString.find("Direct3D9") != std::string::npos);
}
bool ANGLETest::isD3DSM3() const
{
std::string rendererString(reinterpret_cast<const char *>(glGetString(GL_RENDERER)));
return isD3D9() || isD3D11_FL93();
}
EGLint ANGLETest::getPlatformRenderer() const
{
assert(mEGLWindow);
......
......@@ -100,6 +100,11 @@ class ANGLETest : public ::testing::TestWithParam<angle::PlatformParameters>
bool isNVidia() const;
// Note: FL9_3 is explicitly *not* considered D3D11.
bool isD3D11() const;
bool isD3D11_FL93() const;
// Is a D3D9-class renderer.
bool isD3D9() const;
// Is D3D9 or SM9_3 renderer.
bool isD3DSM3() const;
EGLint getPlatformRenderer() const;
private:
......
......@@ -19,6 +19,22 @@ Vector2::Vector2(float x, float y) : x(x), y(y)
{
}
bool Vector2::operator==(const Vector2 &vec) const
{
return x == vec.x && y == vec.y;
}
bool Vector2::operator!=(const Vector2 &vec) const
{
return !(*this == vec);
}
std::ostream &operator<<(std::ostream &stream, const Vector2 &vec)
{
stream << "(" << vec.x << "," << vec.y << ")";
return stream;
}
float Vector2::length(const Vector2 &vec)
{
float lenSquared = lengthSquared(vec);
......
......@@ -10,11 +10,16 @@
#ifndef UTIL_VECTOR_H
#define UTIL_VECTOR_H
#include <ostream>
struct Vector2
{
Vector2();
Vector2(float x, float y);
bool operator==(const Vector2 &vec) const;
bool operator!=(const Vector2 &vec) const;
static float length(const Vector2 &vec);
static float lengthSquared(const Vector2 &vec);
......@@ -26,6 +31,8 @@ struct Vector2
float x, y;
};
std::ostream &operator<<(std::ostream &stream, const Vector2 &vec);
struct Vector3
{
Vector3();
......
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