Commit 192745a7 by Jamie Madill Committed by Commit Bot

Add varying packing validation for WebGL.

This CL moves the varying packing from the D3D layer up to Program. This is necessary for WebGL validation, and gives us consistency for the various back-ends. There may be some additional cleanup work on the VaryingPacking class, because it does some work that is D3D- specific. WebGL requires strict varying packing. Instead of allowing success unconditionally, it's an explicit error to succeed to pack a set of varyings that the sample algorithm would fail to pack. Introduce a new packing mode option to the varying packing class to handle this different packing style, while keeping our old more relaxed packing method for ES code. BUG=angleproject:1675 Change-Id: I674ae685ba573cc2ad7d9dfb7441efa8cb2d55fc Reviewed-on: https://chromium-review.googlesource.com/423254 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org>
parent 4eee74de
...@@ -313,10 +313,6 @@ static_library("libANGLE") { ...@@ -313,10 +313,6 @@ static_library("libANGLE") {
defines += [ "ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES={ " + "\"d3dcompiler_47.dll\", \"d3dcompiler_46.dll\", \"d3dcompiler_43.dll\" }" ] defines += [ "ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES={ " + "\"d3dcompiler_47.dll\", \"d3dcompiler_46.dll\", \"d3dcompiler_43.dll\" }" ]
} }
if (angle_enable_hlsl) {
sources += rebase_path(gles_gypi.libangle_d3d_hlsl_sources, ".", "src")
}
if (angle_enable_d3d9) { if (angle_enable_d3d9) {
sources += rebase_path(gles_gypi.libangle_d3d9_sources, ".", "src") sources += rebase_path(gles_gypi.libangle_d3d9_sources, ".", "src")
libs += [ "d3d9.lib" ] libs += [ "d3d9.lib" ]
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "libANGLE/features.h" #include "libANGLE/features.h"
#include "libANGLE/renderer/GLImplFactory.h" #include "libANGLE/renderer/GLImplFactory.h"
#include "libANGLE/renderer/ProgramImpl.h" #include "libANGLE/renderer/ProgramImpl.h"
#include "libANGLE/VaryingPacking.h"
#include "libANGLE/queryconversions.h" #include "libANGLE/queryconversions.h"
#include "libANGLE/Uniform.h" #include "libANGLE/Uniform.h"
...@@ -135,6 +136,12 @@ bool UniformInList(const std::vector<LinkedUniform> &list, const std::string &na ...@@ -135,6 +136,12 @@ bool UniformInList(const std::vector<LinkedUniform> &list, const std::string &na
return false; return false;
} }
// true if varying x has a higher priority in packing than y
bool ComparePackedVarying(const PackedVarying &x, const PackedVarying &y)
{
return gl::CompareShaderVar(*x.varying, *y.varying);
}
} // anonymous namespace } // anonymous namespace
const char *const g_fakepath = "C:\\fakepath"; const char *const g_fakepath = "C:\\fakepath";
...@@ -556,9 +563,12 @@ Error Program::link(const ContextState &data) ...@@ -556,9 +563,12 @@ Error Program::link(const ContextState &data)
const Caps &caps = data.getCaps(); const Caps &caps = data.getCaps();
bool isComputeShaderAttached = (mState.mAttachedComputeShader != nullptr); auto vertexShader = mState.mAttachedVertexShader;
bool nonComputeShadersAttached = auto fragmentShader = mState.mAttachedFragmentShader;
(mState.mAttachedVertexShader != nullptr || mState.mAttachedFragmentShader != nullptr); auto computeShader = mState.mAttachedComputeShader;
bool isComputeShaderAttached = (computeShader != nullptr);
bool nonComputeShadersAttached = (vertexShader != nullptr || fragmentShader != nullptr);
// Check whether we both have a compute and non-compute shaders attached. // Check whether we both have a compute and non-compute shaders attached.
// If there are of both types attached, then linking should fail. // If there are of both types attached, then linking should fail.
// OpenGL ES 3.10, 7.3 Program Objects, under LinkProgram // OpenGL ES 3.10, 7.3 Program Objects, under LinkProgram
...@@ -568,16 +578,16 @@ Error Program::link(const ContextState &data) ...@@ -568,16 +578,16 @@ Error Program::link(const ContextState &data)
return NoError(); return NoError();
} }
if (mState.mAttachedComputeShader) if (computeShader)
{ {
if (!mState.mAttachedComputeShader->isCompiled()) if (!computeShader->isCompiled())
{ {
mInfoLog << "Attached compute shader is not compiled."; mInfoLog << "Attached compute shader is not compiled.";
return NoError(); return NoError();
} }
ASSERT(mState.mAttachedComputeShader->getType() == GL_COMPUTE_SHADER); ASSERT(computeShader->getType() == GL_COMPUTE_SHADER);
mState.mComputeShaderLocalSize = mState.mAttachedComputeShader->getWorkGroupSize(); mState.mComputeShaderLocalSize = computeShader->getWorkGroupSize();
// GLSL ES 3.10, 4.4.1.1 Compute Shader Inputs // GLSL ES 3.10, 4.4.1.1 Compute Shader Inputs
// If the work group size is not specified, a link time error should occur. // If the work group size is not specified, a link time error should occur.
...@@ -597,7 +607,8 @@ Error Program::link(const ContextState &data) ...@@ -597,7 +607,8 @@ Error Program::link(const ContextState &data)
return NoError(); return NoError();
} }
ANGLE_TRY_RESULT(mProgram->link(data, mInfoLog), mLinked); gl::VaryingPacking noVaryingPacking(0, PackMode::ANGLE_RELAXED);
ANGLE_TRY_RESULT(mProgram->link(data, noVaryingPacking, mInfoLog), mLinked);
if (!mLinked) if (!mLinked)
{ {
return NoError(); return NoError();
...@@ -605,20 +616,19 @@ Error Program::link(const ContextState &data) ...@@ -605,20 +616,19 @@ Error Program::link(const ContextState &data)
} }
else else
{ {
if (!mState.mAttachedFragmentShader || !mState.mAttachedFragmentShader->isCompiled()) if (!fragmentShader || !fragmentShader->isCompiled())
{ {
return NoError(); return NoError();
} }
ASSERT(mState.mAttachedFragmentShader->getType() == GL_FRAGMENT_SHADER); ASSERT(fragmentShader->getType() == GL_FRAGMENT_SHADER);
if (!mState.mAttachedVertexShader || !mState.mAttachedVertexShader->isCompiled()) if (!vertexShader || !vertexShader->isCompiled())
{ {
return NoError(); return NoError();
} }
ASSERT(mState.mAttachedVertexShader->getType() == GL_VERTEX_SHADER); ASSERT(vertexShader->getType() == GL_VERTEX_SHADER);
if (mState.mAttachedFragmentShader->getShaderVersion() != if (fragmentShader->getShaderVersion() != vertexShader->getShaderVersion())
mState.mAttachedVertexShader->getShaderVersion())
{ {
mInfoLog << "Fragment shader version does not match vertex shader version."; mInfoLog << "Fragment shader version does not match vertex shader version.";
return NoError(); return NoError();
...@@ -629,7 +639,7 @@ Error Program::link(const ContextState &data) ...@@ -629,7 +639,7 @@ Error Program::link(const ContextState &data)
return NoError(); return NoError();
} }
if (!linkVaryings(mInfoLog, mState.mAttachedVertexShader, mState.mAttachedFragmentShader)) if (!linkVaryings(mInfoLog))
{ {
return NoError(); return NoError();
} }
...@@ -653,7 +663,21 @@ Error Program::link(const ContextState &data) ...@@ -653,7 +663,21 @@ Error Program::link(const ContextState &data)
linkOutputVariables(); linkOutputVariables();
ANGLE_TRY_RESULT(mProgram->link(data, mInfoLog), mLinked); // Validate we can pack the varyings.
std::vector<PackedVarying> packedVaryings = getPackedVaryings(mergedVaryings);
// Map the varyings to the register file
// In WebGL, we use a slightly different handling for packing variables.
auto packMode = data.getExtensions().webglCompatibility ? PackMode::WEBGL_STRICT
: PackMode::ANGLE_RELAXED;
VaryingPacking varyingPacking(data.getCaps().maxVaryingVectors, packMode);
if (!varyingPacking.packUserVaryings(mInfoLog, packedVaryings,
mState.getTransformFeedbackVaryingNames()))
{
return NoError();
}
ANGLE_TRY_RESULT(mProgram->link(data, varyingPacking, mInfoLog), mLinked);
if (!mLinked) if (!mLinked)
{ {
return NoError(); return NoError();
...@@ -1789,10 +1813,11 @@ GLenum Program::getTransformFeedbackBufferMode() const ...@@ -1789,10 +1813,11 @@ GLenum Program::getTransformFeedbackBufferMode() const
return mState.mTransformFeedbackBufferMode; return mState.mTransformFeedbackBufferMode;
} }
bool Program::linkVaryings(InfoLog &infoLog, bool Program::linkVaryings(InfoLog &infoLog) const
const Shader *vertexShader,
const Shader *fragmentShader) const
{ {
const Shader *vertexShader = mState.mAttachedVertexShader;
const Shader *fragmentShader = mState.mAttachedFragmentShader;
ASSERT(vertexShader->getShaderVersion() == fragmentShader->getShaderVersion()); ASSERT(vertexShader->getShaderVersion() == fragmentShader->getShaderVersion());
const std::vector<sh::Varying> &vertexVaryings = vertexShader->getVaryings(); const std::vector<sh::Varying> &vertexVaryings = vertexShader->getVaryings();
...@@ -2372,7 +2397,7 @@ bool Program::linkValidateVaryings(InfoLog &infoLog, ...@@ -2372,7 +2397,7 @@ bool Program::linkValidateVaryings(InfoLog &infoLog,
} }
bool Program::linkValidateTransformFeedback(InfoLog &infoLog, bool Program::linkValidateTransformFeedback(InfoLog &infoLog,
const std::vector<const sh::Varying *> &varyings, const Program::MergedVaryings &varyings,
const Caps &caps) const const Caps &caps) const
{ {
size_t totalComponents = 0; size_t totalComponents = 0;
...@@ -2382,8 +2407,10 @@ bool Program::linkValidateTransformFeedback(InfoLog &infoLog, ...@@ -2382,8 +2407,10 @@ bool Program::linkValidateTransformFeedback(InfoLog &infoLog,
for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames) for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
{ {
bool found = false; bool found = false;
for (const sh::Varying *varying : varyings) for (const auto &ref : varyings)
{ {
const sh::Varying *varying = ref.second.get();
if (tfVaryingName == varying->name) if (tfVaryingName == varying->name)
{ {
if (uniqueNames.count(tfVaryingName) > 0) if (uniqueNames.count(tfVaryingName) > 0)
...@@ -2439,14 +2466,15 @@ bool Program::linkValidateTransformFeedback(InfoLog &infoLog, ...@@ -2439,14 +2466,15 @@ bool Program::linkValidateTransformFeedback(InfoLog &infoLog,
return true; return true;
} }
void Program::gatherTransformFeedbackVaryings(const std::vector<const sh::Varying *> &varyings) void Program::gatherTransformFeedbackVaryings(const Program::MergedVaryings &varyings)
{ {
// Gather the linked varyings that are used for transform feedback, they should all exist. // Gather the linked varyings that are used for transform feedback, they should all exist.
mState.mTransformFeedbackVaryingVars.clear(); mState.mTransformFeedbackVaryingVars.clear();
for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames) for (const std::string &tfVaryingName : mState.mTransformFeedbackVaryingNames)
{ {
for (const sh::Varying *varying : varyings) for (const auto &ref : varyings)
{ {
const sh::Varying *varying = ref.second.get();
if (tfVaryingName == varying->name) if (tfVaryingName == varying->name)
{ {
mState.mTransformFeedbackVaryingVars.push_back(*varying); mState.mTransformFeedbackVaryingVars.push_back(*varying);
...@@ -2456,30 +2484,83 @@ void Program::gatherTransformFeedbackVaryings(const std::vector<const sh::Varyin ...@@ -2456,30 +2484,83 @@ void Program::gatherTransformFeedbackVaryings(const std::vector<const sh::Varyin
} }
} }
std::vector<const sh::Varying *> Program::getMergedVaryings() const Program::MergedVaryings Program::getMergedVaryings() const
{ {
std::set<std::string> uniqueNames; MergedVaryings merged;
std::vector<const sh::Varying *> varyings;
for (const sh::Varying &varying : mState.mAttachedVertexShader->getVaryings()) for (const sh::Varying &varying : mState.mAttachedVertexShader->getVaryings())
{ {
if (uniqueNames.count(varying.name) == 0) merged[varying.name].vertex = &varying;
{
uniqueNames.insert(varying.name);
varyings.push_back(&varying);
}
} }
for (const sh::Varying &varying : mState.mAttachedFragmentShader->getVaryings()) for (const sh::Varying &varying : mState.mAttachedFragmentShader->getVaryings())
{ {
if (uniqueNames.count(varying.name) == 0) merged[varying.name].fragment = &varying;
}
return merged;
}
std::vector<PackedVarying> Program::getPackedVaryings(
const Program::MergedVaryings &mergedVaryings) const
{
const std::vector<std::string> &tfVaryings = mState.getTransformFeedbackVaryingNames();
std::vector<PackedVarying> packedVaryings;
for (const auto &ref : mergedVaryings)
{
const sh::Varying *input = ref.second.vertex;
const sh::Varying *output = ref.second.fragment;
// Only pack varyings that have a matched input or output, plus special builtins.
if ((input && output) || (output && output->isBuiltIn()))
{ {
uniqueNames.insert(varying.name); // Will get the vertex shader interpolation by default.
varyings.push_back(&varying); auto interpolation = ref.second.get()->interpolation;
// Interpolation qualifiers must match.
if (output->isStruct())
{
ASSERT(!output->isArray());
for (const auto &field : output->fields)
{
ASSERT(!field.isStruct() && !field.isArray());
packedVaryings.push_back(PackedVarying(field, interpolation, output->name));
}
}
else
{
packedVaryings.push_back(PackedVarying(*output, interpolation));
}
continue;
}
// Keep Transform FB varyings in the merged list always.
if (!input)
{
continue;
}
for (const std::string &tfVarying : tfVaryings)
{
if (tfVarying == input->name)
{
// Transform feedback for varying structs is underspecified.
// See Khronos bug 9856.
// TODO(jmadill): Figure out how to be spec-compliant here.
if (!input->isStruct())
{
packedVaryings.push_back(PackedVarying(*input, input->interpolation));
packedVaryings.back().vertexOnly = true;
}
break;
}
} }
} }
return varyings; std::sort(packedVaryings.begin(), packedVaryings.end(), ComparePackedVarying);
return packedVaryings;
} }
void Program::linkOutputVariables() void Program::linkOutputVariables()
......
...@@ -49,6 +49,7 @@ class Buffer; ...@@ -49,6 +49,7 @@ class Buffer;
class Framebuffer; class Framebuffer;
struct UniformBlock; struct UniformBlock;
struct LinkedUniform; struct LinkedUniform;
struct PackedVarying;
extern const char * const g_fakepath; extern const char * const g_fakepath;
...@@ -386,6 +387,16 @@ class Program final : angle::NonCopyable, public LabeledObject ...@@ -386,6 +387,16 @@ class Program final : angle::NonCopyable, public LabeledObject
std::unordered_map<std::string, GLuint> mBindings; std::unordered_map<std::string, GLuint> mBindings;
}; };
struct VaryingRef
{
const sh::Varying *get() const { return vertex ? vertex : fragment; }
const sh::Varying *vertex = nullptr;
const sh::Varying *fragment = nullptr;
};
using MergedVaryings = std::map<std::string, VaryingRef>;
void unlink(bool destroy = false); void unlink(bool destroy = false);
void resetUniformBlockBindings(); void resetUniformBlockBindings();
...@@ -399,7 +410,7 @@ class Program final : angle::NonCopyable, public LabeledObject ...@@ -399,7 +410,7 @@ class Program final : angle::NonCopyable, public LabeledObject
const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks, const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks,
InfoLog &infoLog) const; InfoLog &infoLog) const;
bool linkUniformBlocks(InfoLog &infoLog, const Caps &caps); bool linkUniformBlocks(InfoLog &infoLog, const Caps &caps);
bool linkVaryings(InfoLog &infoLog, const Shader *vertexShader, const Shader *fragmentShader) const; bool linkVaryings(InfoLog &infoLog) const;
bool validateVertexAndFragmentUniforms(InfoLog &infoLog) const; bool validateVertexAndFragmentUniforms(InfoLog &infoLog) const;
bool linkUniforms(InfoLog &infoLog, const Caps &caps, const Bindings &uniformBindings); bool linkUniforms(InfoLog &infoLog, const Caps &caps, const Bindings &uniformBindings);
bool indexUniforms(InfoLog &infoLog, const Caps &caps, const Bindings &uniformBindings); bool indexUniforms(InfoLog &infoLog, const Caps &caps, const Bindings &uniformBindings);
...@@ -419,14 +430,15 @@ class Program final : angle::NonCopyable, public LabeledObject ...@@ -419,14 +430,15 @@ class Program final : angle::NonCopyable, public LabeledObject
const sh::Varying &fragmentVarying, const sh::Varying &fragmentVarying,
int shaderVersion); int shaderVersion);
bool linkValidateTransformFeedback(InfoLog &infoLog, bool linkValidateTransformFeedback(InfoLog &infoLog,
const std::vector<const sh::Varying *> &linkedVaryings, const MergedVaryings &linkedVaryings,
const Caps &caps) const; const Caps &caps) const;
void gatherTransformFeedbackVaryings(const std::vector<const sh::Varying *> &varyings); void gatherTransformFeedbackVaryings(const MergedVaryings &varyings);
bool assignUniformBlockRegister(InfoLog &infoLog, UniformBlock *uniformBlock, GLenum shader, unsigned int registerIndex, const Caps &caps); bool assignUniformBlockRegister(InfoLog &infoLog, UniformBlock *uniformBlock, GLenum shader, unsigned int registerIndex, const Caps &caps);
void defineOutputVariables(Shader *fragmentShader); void defineOutputVariables(Shader *fragmentShader);
std::vector<const sh::Varying *> getMergedVaryings() const; MergedVaryings getMergedVaryings() const;
std::vector<PackedVarying> getPackedVaryings(const MergedVaryings &mergedVaryings) const;
void linkOutputVariables(); void linkOutputVariables();
bool flattenUniformsAndCheckCapsForShader(const Shader &shader, bool flattenUniformsAndCheckCapsForShader(const Shader &shader,
......
...@@ -4,46 +4,22 @@ ...@@ -4,46 +4,22 @@
// found in the LICENSE file. // found in the LICENSE file.
// //
// VaryingPacking: // VaryingPacking:
// Class which describes a mapping from varyings to registers in D3D // Class which describes a mapping from varyings to registers, according
// for linking between shader stages. // to the spec, or using custom packing algorithms. We also keep a register
// allocation list for the D3D renderer.
// //
#include "libANGLE/renderer/d3d/hlsl/VaryingPacking.h" #include "libANGLE/VaryingPacking.h"
#include "common/utilities.h" #include "common/utilities.h"
#include "compiler/translator/blocklayoutHLSL.h"
#include "libANGLE/Program.h" #include "libANGLE/Program.h"
namespace rx namespace gl
{ {
// Implementation of VaryingPacking::BuiltinVarying
VaryingPacking::BuiltinVarying::BuiltinVarying() : enabled(false), index(0), systemValue(false)
{
}
std::string VaryingPacking::BuiltinVarying::str() const
{
return (systemValue ? semantic : (semantic + Str(index)));
}
void VaryingPacking::BuiltinVarying::enableSystem(const std::string &systemValueSemantic)
{
enabled = true;
semantic = systemValueSemantic;
systemValue = true;
}
void VaryingPacking::BuiltinVarying::enable(const std::string &semanticVal, unsigned int indexVal)
{
enabled = true;
semantic = semanticVal;
index = indexVal;
}
// Implementation of VaryingPacking // Implementation of VaryingPacking
VaryingPacking::VaryingPacking(GLuint maxVaryingVectors) VaryingPacking::VaryingPacking(GLuint maxVaryingVectors, PackMode packMode)
: mRegisterMap(maxVaryingVectors), mBuiltinInfo(SHADER_TYPE_MAX) : mRegisterMap(maxVaryingVectors), mPackMode(packMode)
{ {
} }
...@@ -56,7 +32,7 @@ bool VaryingPacking::packVarying(const PackedVarying &packedVarying) ...@@ -56,7 +32,7 @@ bool VaryingPacking::packVarying(const PackedVarying &packedVarying)
const auto &varying = *packedVarying.varying; const auto &varying = *packedVarying.varying;
// "Non - square matrices of type matCxR consume the same space as a square matrix of type matN // "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." // where N is the greater of C and R."
// Here we are a bit more conservative and allow packing non-square matrices more tightly. // 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. // Make sure we use transposed matrix types to count registers correctly.
ASSERT(!varying.isStruct()); ASSERT(!varying.isStruct());
...@@ -64,6 +40,13 @@ bool VaryingPacking::packVarying(const PackedVarying &packedVarying) ...@@ -64,6 +40,13 @@ bool VaryingPacking::packVarying(const PackedVarying &packedVarying)
unsigned int varyingRows = gl::VariableRowCount(transposedType); unsigned int varyingRows = gl::VariableRowCount(transposedType);
unsigned int varyingColumns = gl::VariableColumnCount(transposedType); unsigned int varyingColumns = gl::VariableColumnCount(transposedType);
// "Variables of type mat2 occupies 2 complete rows."
// For non-WebGL contexts, we allow mat2 to occupy only two columns per row.
if (mPackMode == PackMode::WEBGL_STRICT && varying.type == GL_FLOAT_MAT2)
{
varyingColumns = 4;
}
// "Arrays of size N are assumed to take N times the size of the base type" // "Arrays of size N are assumed to take N times the size of the base type"
varyingRows *= varying.elementCount(); varyingRows *= varying.elementCount();
...@@ -161,7 +144,12 @@ bool VaryingPacking::packVarying(const PackedVarying &packedVarying) ...@@ -161,7 +144,12 @@ bool VaryingPacking::packVarying(const PackedVarying &packedVarying)
registerInfo.registerColumn = bestColumn; registerInfo.registerColumn = bestColumn;
registerInfo.varyingArrayIndex = arrayIndex; registerInfo.varyingArrayIndex = arrayIndex;
registerInfo.varyingRowIndex = 0; registerInfo.varyingRowIndex = 0;
mRegisterList.push_back(registerInfo); // Do not record register info for builtins.
// TODO(jmadill): Clean this up.
if (!packedVarying.varying->isBuiltIn())
{
mRegisterList.push_back(registerInfo);
}
mRegisterMap[row + arrayIndex][bestColumn] = true; mRegisterMap[row + arrayIndex][bestColumn] = true;
} }
break; break;
...@@ -218,7 +206,12 @@ void VaryingPacking::insert(unsigned int registerRow, ...@@ -218,7 +206,12 @@ void VaryingPacking::insert(unsigned int registerRow,
registerInfo.registerRow = registerRow + (arrayElement * varyingRows) + varyingRow; registerInfo.registerRow = registerRow + (arrayElement * varyingRows) + varyingRow;
registerInfo.varyingRowIndex = varyingRow; registerInfo.varyingRowIndex = varyingRow;
registerInfo.varyingArrayIndex = arrayElement; registerInfo.varyingArrayIndex = arrayElement;
mRegisterList.push_back(registerInfo); // Do not record register info for builtins.
// TODO(jmadill): Clean this up.
if (!packedVarying.varying->isBuiltIn())
{
mRegisterList.push_back(registerInfo);
}
for (unsigned int columnIndex = 0; columnIndex < varyingColumns; ++columnIndex) for (unsigned int columnIndex = 0; columnIndex < varyingColumns; ++columnIndex)
{ {
...@@ -242,7 +235,7 @@ bool VaryingPacking::packUserVaryings(gl::InfoLog &infoLog, ...@@ -242,7 +235,7 @@ bool VaryingPacking::packUserVaryings(gl::InfoLog &infoLog,
const auto &varying = *packedVarying.varying; const auto &varying = *packedVarying.varying;
// Do not assign registers to built-in or unreferenced varyings // Do not assign registers to built-in or unreferenced varyings
if (varying.isBuiltIn() || (!varying.staticUse && !packedVarying.isStructField())) if (!varying.staticUse && !packedVarying.isStructField())
{ {
continue; continue;
} }
...@@ -315,11 +308,6 @@ bool VaryingPacking::packUserVaryings(gl::InfoLog &infoLog, ...@@ -315,11 +308,6 @@ bool VaryingPacking::packUserVaryings(gl::InfoLog &infoLog,
return true; return true;
} }
bool VaryingPacking::validateBuiltins() const
{
return (static_cast<size_t>(getRegisterCount()) <= mRegisterMap.size());
}
unsigned int VaryingPacking::getRegisterCount() const unsigned int VaryingPacking::getRegisterCount() const
{ {
unsigned int count = 0; unsigned int count = 0;
...@@ -332,16 +320,6 @@ unsigned int VaryingPacking::getRegisterCount() const ...@@ -332,16 +320,6 @@ unsigned int VaryingPacking::getRegisterCount() const
} }
} }
if (mBuiltinInfo[SHADER_PIXEL].glFragCoord.enabled)
{
++count;
}
if (mBuiltinInfo[SHADER_PIXEL].glPointCoord.enabled)
{
++count;
}
return count; return count;
} }
......
...@@ -4,26 +4,23 @@ ...@@ -4,26 +4,23 @@
// found in the LICENSE file. // found in the LICENSE file.
// //
// VaryingPacking: // VaryingPacking:
// Class which describes a mapping from varyings to registers in D3D // Class which describes a mapping from varyings to registers, according
// for linking between shader stages. // to the spec, or using custom packing algorithms. We also keep a register
// allocation list for the D3D renderer.
// //
#ifndef LIBANGLE_RENDERER_D3D_HLSL_VARYINGPACKING_H_ #ifndef LIBANGLE_VARYINGPACKING_H_
#define LIBANGLE_RENDERER_D3D_HLSL_VARYINGPACKING_H_ #define LIBANGLE_VARYINGPACKING_H_
#include <GLSLANG/ShaderVars.h> #include <GLSLANG/ShaderVars.h>
#include "angle_gl.h" #include "angle_gl.h"
#include "common/angleutils.h" #include "common/angleutils.h"
#include "libANGLE/renderer/d3d/hlsl/hlsl_utils.h"
namespace gl namespace gl
{ {
class InfoLog; class InfoLog;
}
namespace rx
{
struct PackedVarying struct PackedVarying
{ {
PackedVarying(const sh::ShaderVariable &varyingIn, sh::InterpolationType interpolationIn) PackedVarying(const sh::ShaderVariable &varyingIn, sh::InterpolationType interpolationIn)
...@@ -103,19 +100,25 @@ struct PackedVaryingRegister final ...@@ -103,19 +100,25 @@ struct PackedVaryingRegister final
std::string structFieldName; std::string structFieldName;
}; };
// Supported packing modes:
enum class PackMode
{
// We treat mat2 arrays as taking two full rows.
WEBGL_STRICT,
// We allow mat2 to take a 2x2 chunk.
ANGLE_RELAXED,
};
class VaryingPacking final : angle::NonCopyable class VaryingPacking final : angle::NonCopyable
{ {
public: public:
VaryingPacking(GLuint maxVaryingVectors); VaryingPacking(GLuint maxVaryingVectors, PackMode packMode);
bool packUserVaryings(gl::InfoLog &infoLog, bool packUserVaryings(gl::InfoLog &infoLog,
const std::vector<PackedVarying> &packedVaryings, const std::vector<PackedVarying> &packedVaryings,
const std::vector<std::string> &transformFeedbackVaryings); const std::vector<std::string> &transformFeedbackVaryings);
// Some built-in varyings require emulation that eats up available registers. This method
// checks that we're within the register limits of the implementation.
bool validateBuiltins() const;
struct Register struct Register
{ {
Register() { data[0] = data[1] = data[2] = data[3] = false; } Register() { data[0] = data[1] = data[2] = data[3] = false; }
...@@ -135,34 +138,7 @@ class VaryingPacking final : angle::NonCopyable ...@@ -135,34 +138,7 @@ class VaryingPacking final : angle::NonCopyable
return static_cast<unsigned int>(mRegisterList.size()); return static_cast<unsigned int>(mRegisterList.size());
} }
unsigned int getRegisterCount() const; unsigned int getRegisterCount() const;
size_t getRegisterMapSize() const { return mRegisterMap.size(); }
struct BuiltinVarying final : angle::NonCopyable
{
BuiltinVarying();
std::string str() const;
void enableSystem(const std::string &systemValueSemantic);
void enable(const std::string &semanticVal, unsigned int indexVal);
bool enabled;
std::string semantic;
unsigned int index;
bool systemValue;
};
struct BuiltinInfo
{
BuiltinVarying dxPosition;
BuiltinVarying glPosition;
BuiltinVarying glFragCoord;
BuiltinVarying glPointCoord;
BuiltinVarying glPointSize;
};
const BuiltinInfo &builtins(ShaderType shaderType) const { return mBuiltinInfo[shaderType]; }
BuiltinInfo &builtins(ShaderType shaderType) { return mBuiltinInfo[shaderType]; }
bool usesPointSize() const { return mBuiltinInfo[SHADER_VERTEX].glPointSize.enabled; }
private: private:
bool packVarying(const PackedVarying &packedVarying); bool packVarying(const PackedVarying &packedVarying);
...@@ -177,9 +153,9 @@ class VaryingPacking final : angle::NonCopyable ...@@ -177,9 +153,9 @@ class VaryingPacking final : angle::NonCopyable
std::vector<Register> mRegisterMap; std::vector<Register> mRegisterMap;
std::vector<PackedVaryingRegister> mRegisterList; std::vector<PackedVaryingRegister> mRegisterList;
std::vector<BuiltinInfo> mBuiltinInfo; PackMode mPackMode;
}; };
} // namespace rx } // namespace gl
#endif // LIBANGLE_RENDERER_D3D_HLSL_VARYINGPACKING_H_ #endif // LIBANGLE_VARYINGPACKING_H_
...@@ -7,12 +7,14 @@ ...@@ -7,12 +7,14 @@
// Tests for ANGLE's internal varying packing algorithm. // Tests for ANGLE's internal varying packing algorithm.
// //
#include "libANGLE/renderer/d3d/hlsl/VaryingPacking.h" #include "libANGLE/VaryingPacking.h"
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include "libANGLE/Program.h" #include "libANGLE/Program.h"
using namespace gl;
namespace namespace
{ {
...@@ -22,26 +24,31 @@ class VaryingPackingTest : public ::testing::TestWithParam<GLuint> ...@@ -22,26 +24,31 @@ class VaryingPackingTest : public ::testing::TestWithParam<GLuint>
VaryingPackingTest() {} VaryingPackingTest() {}
bool testVaryingPacking(const std::vector<sh::Varying> &shVaryings, bool testVaryingPacking(const std::vector<sh::Varying> &shVaryings,
rx::VaryingPacking *varyingPacking) VaryingPacking *varyingPacking)
{ {
std::vector<rx::PackedVarying> packedVaryings; std::vector<PackedVarying> packedVaryings;
for (const auto &shVarying : shVaryings) for (const auto &shVarying : shVaryings)
{ {
packedVaryings.push_back(rx::PackedVarying(shVarying, shVarying.interpolation)); packedVaryings.push_back(PackedVarying(shVarying, shVarying.interpolation));
} }
gl::InfoLog infoLog; InfoLog infoLog;
std::vector<std::string> transformFeedbackVaryings; std::vector<std::string> transformFeedbackVaryings;
if (!varyingPacking->packUserVaryings(infoLog, packedVaryings, transformFeedbackVaryings)) return varyingPacking->packUserVaryings(infoLog, packedVaryings, transformFeedbackVaryings);
return false;
return varyingPacking->validateBuiltins();
} }
// Uses the "relaxed" ANGLE packing mode.
bool packVaryings(GLuint maxVaryings, const std::vector<sh::Varying> &shVaryings) bool packVaryings(GLuint maxVaryings, const std::vector<sh::Varying> &shVaryings)
{ {
rx::VaryingPacking varyingPacking(maxVaryings); VaryingPacking varyingPacking(maxVaryings, PackMode::ANGLE_RELAXED);
return testVaryingPacking(shVaryings, &varyingPacking);
}
// Uses the stricter WebGL style packing rules.
bool packVaryingsStrict(GLuint maxVaryings, const std::vector<sh::Varying> &shVaryings)
{
VaryingPacking varyingPacking(maxVaryings, PackMode::WEBGL_STRICT);
return testVaryingPacking(shVaryings, &varyingPacking); return testVaryingPacking(shVaryings, &varyingPacking);
} }
...@@ -85,38 +92,6 @@ TEST_P(VaryingPackingTest, OneVaryingLargerThanMax) ...@@ -85,38 +92,6 @@ TEST_P(VaryingPackingTest, OneVaryingLargerThanMax)
ASSERT_FALSE(packVaryings(1, MakeVaryings(GL_FLOAT_MAT4, 1, 0))); ASSERT_FALSE(packVaryings(1, MakeVaryings(GL_FLOAT_MAT4, 1, 0)));
} }
// Tests that using FragCoord as a user varying will eat up a register.
TEST_P(VaryingPackingTest, MaxVaryingVec4PlusFragCoord)
{
const std::string &userSemantic = rx::GetVaryingSemantic(4, false);
rx::VaryingPacking varyingPacking(kMaxVaryings);
unsigned int reservedSemanticIndex = varyingPacking.getMaxSemanticIndex();
varyingPacking.builtins(rx::SHADER_PIXEL)
.glFragCoord.enable(userSemantic, reservedSemanticIndex);
const auto &varyings = MakeVaryings(GL_FLOAT_VEC4, kMaxVaryings, 0);
ASSERT_FALSE(testVaryingPacking(varyings, &varyingPacking));
}
// Tests that using PointCoord as a user varying will eat up a register.
TEST_P(VaryingPackingTest, MaxVaryingVec4PlusPointCoord)
{
const std::string &userSemantic = rx::GetVaryingSemantic(4, false);
rx::VaryingPacking varyingPacking(kMaxVaryings);
unsigned int reservedSemanticIndex = varyingPacking.getMaxSemanticIndex();
varyingPacking.builtins(rx::SHADER_PIXEL)
.glPointCoord.enable(userSemantic, reservedSemanticIndex);
const auto &varyings = MakeVaryings(GL_FLOAT_VEC4, kMaxVaryings, 0);
ASSERT_FALSE(testVaryingPacking(varyings, &varyingPacking));
}
// This will overflow the available varying space. // This will overflow the available varying space.
TEST_P(VaryingPackingTest, MaxPlusOneVaryingVec3) TEST_P(VaryingPackingTest, MaxPlusOneVaryingVec3)
{ {
...@@ -172,6 +147,13 @@ TEST_P(VaryingPackingTest, MaxVaryingVec3ArrayAndMaxPlusOneFloatArray) ...@@ -172,6 +147,13 @@ TEST_P(VaryingPackingTest, MaxVaryingVec3ArrayAndMaxPlusOneFloatArray)
ASSERT_FALSE(packVaryings(kMaxVaryings, varyings)); ASSERT_FALSE(packVaryings(kMaxVaryings, varyings));
} }
// WebGL should fail to pack max+1 vec2 arrays, unlike our more relaxed packing.
TEST_P(VaryingPackingTest, MaxPlusOneMat2VaryingsFailsWebGL)
{
auto varyings = MakeVaryings(GL_FLOAT_MAT2, kMaxVaryings / 2 + 1, 0);
ASSERT_FALSE(packVaryingsStrict(kMaxVaryings, varyings));
}
// Makes separate tests for different values of kMaxVaryings. // Makes separate tests for different values of kMaxVaryings.
INSTANTIATE_TEST_CASE_P(, VaryingPackingTest, ::testing::Values(1, 4, 8)); INSTANTIATE_TEST_CASE_P(, VaryingPackingTest, ::testing::Values(1, 4, 8));
......
...@@ -17,6 +17,11 @@ ...@@ -17,6 +17,11 @@
#include <map> #include <map>
namespace gl
{
class VaryingPacking;
}
namespace sh namespace sh
{ {
struct BlockMemberInfo; struct BlockMemberInfo;
...@@ -40,7 +45,9 @@ class ProgramImpl : angle::NonCopyable ...@@ -40,7 +45,9 @@ class ProgramImpl : angle::NonCopyable
virtual gl::Error save(gl::BinaryOutputStream *stream) = 0; virtual gl::Error save(gl::BinaryOutputStream *stream) = 0;
virtual void setBinaryRetrievableHint(bool retrievable) = 0; virtual void setBinaryRetrievableHint(bool retrievable) = 0;
virtual LinkResult link(const gl::ContextState &data, gl::InfoLog &infoLog) = 0; virtual LinkResult link(const gl::ContextState &data,
const gl::VaryingPacking &packing,
gl::InfoLog &infoLog) = 0;
virtual GLboolean validate(const gl::Caps &caps, gl::InfoLog *infoLog) = 0; virtual GLboolean validate(const gl::Caps &caps, gl::InfoLog *infoLog) = 0;
virtual void setUniform1fv(GLint location, GLsizei count, const GLfloat *v) = 0; virtual void setUniform1fv(GLint location, GLsizei count, const GLfloat *v) = 0;
......
...@@ -27,7 +27,8 @@ class MockProgramImpl : public rx::ProgramImpl ...@@ -27,7 +27,8 @@ class MockProgramImpl : public rx::ProgramImpl
MOCK_METHOD1(save, gl::Error(gl::BinaryOutputStream *)); MOCK_METHOD1(save, gl::Error(gl::BinaryOutputStream *));
MOCK_METHOD1(setBinaryRetrievableHint, void(bool)); MOCK_METHOD1(setBinaryRetrievableHint, void(bool));
MOCK_METHOD2(link, LinkResult(const gl::ContextState &, gl::InfoLog &)); MOCK_METHOD3(link,
LinkResult(const gl::ContextState &, const gl::VaryingPacking &, gl::InfoLog &));
MOCK_METHOD2(validate, GLboolean(const gl::Caps &, gl::InfoLog *)); MOCK_METHOD2(validate, GLboolean(const gl::Caps &, gl::InfoLog *));
MOCK_METHOD3(setUniform1fv, void(GLint, GLsizei, const GLfloat *)); MOCK_METHOD3(setUniform1fv, void(GLint, GLsizei, const GLfloat *));
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
#include "libANGLE/renderer/d3d/ProgramD3D.h" #include "libANGLE/renderer/d3d/ProgramD3D.h"
#include "libANGLE/renderer/d3d/RendererD3D.h" #include "libANGLE/renderer/d3d/RendererD3D.h"
#include "libANGLE/renderer/d3d/ShaderD3D.h" #include "libANGLE/renderer/d3d/ShaderD3D.h"
#include "libANGLE/renderer/d3d/hlsl/VaryingPacking.h" #include "libANGLE/VaryingPacking.h"
using namespace gl; using namespace gl;
...@@ -127,48 +127,6 @@ DynamicHLSL::DynamicHLSL(RendererD3D *const renderer) : mRenderer(renderer) ...@@ -127,48 +127,6 @@ DynamicHLSL::DynamicHLSL(RendererD3D *const renderer) : mRenderer(renderer)
{ {
} }
void DynamicHLSL::generateVaryingHLSL(const VaryingPacking &varyingPacking,
std::stringstream &hlslStream) const
{
std::string varyingSemantic =
GetVaryingSemantic(mRenderer->getMajorShaderModel(), varyingPacking.usesPointSize());
for (const PackedVaryingRegister &registerInfo : varyingPacking.getRegisterList())
{
const auto &varying = *registerInfo.packedVarying->varying;
ASSERT(!varying.isStruct());
// TODO: Add checks to ensure D3D interpolation modifiers don't result in too many
// registers being used.
// For example, if there are N registers, and we have N vec3 varyings and 1 float
// varying, then D3D will pack them into N registers.
// If the float varying has the 'nointerpolation' modifier on it then we would need
// N + 1 registers, and D3D compilation will fail.
switch (registerInfo.packedVarying->interpolation)
{
case sh::INTERPOLATION_SMOOTH:
hlslStream << " ";
break;
case sh::INTERPOLATION_FLAT:
hlslStream << " nointerpolation ";
break;
case sh::INTERPOLATION_CENTROID:
hlslStream << " centroid ";
break;
default:
UNREACHABLE();
}
GLenum transposedType = gl::TransposeMatrixType(varying.type);
GLenum componentType = gl::VariableComponentType(transposedType);
int columnCount = gl::VariableColumnCount(transposedType);
hlslStream << HLSLComponentTypeString(componentType, columnCount);
unsigned int semanticIndex = registerInfo.semanticIndex;
hlslStream << " v" << semanticIndex << " : " << varyingSemantic << semanticIndex << ";\n";
}
}
std::string DynamicHLSL::generateVertexShaderForInputLayout( std::string DynamicHLSL::generateVertexShaderForInputLayout(
const std::string &sourceShader, const std::string &sourceShader,
const InputLayout &inputLayout, const InputLayout &inputLayout,
...@@ -359,46 +317,81 @@ std::string DynamicHLSL::generatePixelShaderForOutputSignature( ...@@ -359,46 +317,81 @@ std::string DynamicHLSL::generatePixelShaderForOutputSignature(
return pixelHLSL; return pixelHLSL;
} }
void DynamicHLSL::generateVaryingLinkHLSL(ShaderType shaderType, void DynamicHLSL::generateVaryingLinkHLSL(const VaryingPacking &varyingPacking,
const VaryingPacking &varyingPacking, const BuiltinInfo &builtins,
std::stringstream &linkStream) const bool programUsesPointSize,
std::stringstream &hlslStream) const
{ {
const auto &builtins = varyingPacking.builtins(shaderType);
ASSERT(builtins.dxPosition.enabled); ASSERT(builtins.dxPosition.enabled);
linkStream << "{\n" hlslStream << "{\n"
<< " float4 dx_Position : " << builtins.dxPosition.str() << ";\n"; << " float4 dx_Position : " << builtins.dxPosition.str() << ";\n";
if (builtins.glPosition.enabled) if (builtins.glPosition.enabled)
{ {
linkStream << " float4 gl_Position : " << builtins.glPosition.str() << ";\n"; hlslStream << " float4 gl_Position : " << builtins.glPosition.str() << ";\n";
} }
if (builtins.glFragCoord.enabled) if (builtins.glFragCoord.enabled)
{ {
linkStream << " float4 gl_FragCoord : " << builtins.glFragCoord.str() << ";\n"; hlslStream << " float4 gl_FragCoord : " << builtins.glFragCoord.str() << ";\n";
} }
if (builtins.glPointCoord.enabled) if (builtins.glPointCoord.enabled)
{ {
linkStream << " float2 gl_PointCoord : " << builtins.glPointCoord.str() << ";\n"; hlslStream << " float2 gl_PointCoord : " << builtins.glPointCoord.str() << ";\n";
} }
if (builtins.glPointSize.enabled) if (builtins.glPointSize.enabled)
{ {
linkStream << " float gl_PointSize : " << builtins.glPointSize.str() << ";\n"; hlslStream << " float gl_PointSize : " << builtins.glPointSize.str() << ";\n";
} }
// Do this after gl_PointSize, to potentially combine gl_PointCoord and gl_PointSize into the std::string varyingSemantic =
// same register. GetVaryingSemantic(mRenderer->getMajorShaderModel(), programUsesPointSize);
generateVaryingHLSL(varyingPacking, linkStream);
for (const PackedVaryingRegister &registerInfo : varyingPacking.getRegisterList())
{
const auto &varying = *registerInfo.packedVarying->varying;
ASSERT(!varying.isStruct());
// TODO: Add checks to ensure D3D interpolation modifiers don't result in too many
// registers being used.
// For example, if there are N registers, and we have N vec3 varyings and 1 float
// varying, then D3D will pack them into N registers.
// If the float varying has the 'nointerpolation' modifier on it then we would need
// N + 1 registers, and D3D compilation will fail.
linkStream << "};\n"; switch (registerInfo.packedVarying->interpolation)
{
case sh::INTERPOLATION_SMOOTH:
hlslStream << " ";
break;
case sh::INTERPOLATION_FLAT:
hlslStream << " nointerpolation ";
break;
case sh::INTERPOLATION_CENTROID:
hlslStream << " centroid ";
break;
default:
UNREACHABLE();
}
GLenum transposedType = gl::TransposeMatrixType(varying.type);
GLenum componentType = gl::VariableComponentType(transposedType);
int columnCount = gl::VariableColumnCount(transposedType);
hlslStream << HLSLComponentTypeString(componentType, columnCount);
unsigned int semanticIndex = registerInfo.semanticIndex;
hlslStream << " v" << semanticIndex << " : " << varyingSemantic << semanticIndex << ";\n";
}
hlslStream << "};\n";
} }
bool DynamicHLSL::generateShaderLinkHLSL(const gl::ContextState &data, void DynamicHLSL::generateShaderLinkHLSL(const gl::ContextState &data,
const gl::ProgramState &programData, const gl::ProgramState &programData,
const ProgramD3DMetadata &programMetadata, const ProgramD3DMetadata &programMetadata,
const VaryingPacking &varyingPacking, const VaryingPacking &varyingPacking,
const BuiltinVaryingsD3D &builtinsD3D,
std::string *pixelHLSL, std::string *pixelHLSL,
std::string *vertexHLSL) const std::string *vertexHLSL) const
{ {
...@@ -435,9 +428,12 @@ bool DynamicHLSL::generateShaderLinkHLSL(const gl::ContextState &data, ...@@ -435,9 +428,12 @@ bool DynamicHLSL::generateShaderLinkHLSL(const gl::ContextState &data,
// Add stub string to be replaced when shader is dynamically defined by its layout // Add stub string to be replaced when shader is dynamically defined by its layout
vertexStream << "\n" << std::string(VERTEX_ATTRIBUTE_STUB_STRING) << "\n"; vertexStream << "\n" << std::string(VERTEX_ATTRIBUTE_STUB_STRING) << "\n";
const auto &vertexBuiltins = builtinsD3D[SHADER_VERTEX];
// Write the HLSL input/output declarations // Write the HLSL input/output declarations
vertexStream << "struct VS_OUTPUT\n"; vertexStream << "struct VS_OUTPUT\n";
generateVaryingLinkHLSL(SHADER_VERTEX, varyingPacking, vertexStream); generateVaryingLinkHLSL(varyingPacking, vertexBuiltins, builtinsD3D.usesPointSize(),
vertexStream);
vertexStream << "\n" vertexStream << "\n"
<< "VS_OUTPUT main(VS_INPUT input)\n" << "VS_OUTPUT main(VS_INPUT input)\n"
<< "{\n" << "{\n"
...@@ -448,8 +444,6 @@ bool DynamicHLSL::generateShaderLinkHLSL(const gl::ContextState &data, ...@@ -448,8 +444,6 @@ bool DynamicHLSL::generateShaderLinkHLSL(const gl::ContextState &data,
<< "\n" << "\n"
<< " VS_OUTPUT output;\n"; << " VS_OUTPUT output;\n";
const auto &vertexBuiltins = varyingPacking.builtins(SHADER_VERTEX);
if (vertexBuiltins.glPosition.enabled) if (vertexBuiltins.glPosition.enabled)
{ {
vertexStream << " output.gl_Position = gl_Position;\n"; vertexStream << " output.gl_Position = gl_Position;\n";
...@@ -584,10 +578,13 @@ bool DynamicHLSL::generateShaderLinkHLSL(const gl::ContextState &data, ...@@ -584,10 +578,13 @@ bool DynamicHLSL::generateShaderLinkHLSL(const gl::ContextState &data,
<< " return output;\n" << " return output;\n"
<< "}\n"; << "}\n";
const auto &pixelBuiltins = builtinsD3D[SHADER_PIXEL];
std::stringstream pixelStream; std::stringstream pixelStream;
pixelStream << fragmentShaderGL->getTranslatedSource(); pixelStream << fragmentShaderGL->getTranslatedSource();
pixelStream << "struct PS_INPUT\n"; pixelStream << "struct PS_INPUT\n";
generateVaryingLinkHLSL(SHADER_PIXEL, varyingPacking, pixelStream); generateVaryingLinkHLSL(varyingPacking, pixelBuiltins, builtinsD3D.usesPointSize(),
pixelStream);
pixelStream << "\n"; pixelStream << "\n";
pixelStream << std::string(PIXEL_OUTPUT_STUB_STRING) << "\n"; pixelStream << std::string(PIXEL_OUTPUT_STUB_STRING) << "\n";
...@@ -611,8 +608,6 @@ bool DynamicHLSL::generateShaderLinkHLSL(const gl::ContextState &data, ...@@ -611,8 +608,6 @@ bool DynamicHLSL::generateShaderLinkHLSL(const gl::ContextState &data,
<< "{\n"; << "{\n";
} }
const auto &pixelBuiltins = varyingPacking.builtins(SHADER_PIXEL);
if (pixelBuiltins.glFragCoord.enabled) if (pixelBuiltins.glFragCoord.enabled)
{ {
pixelStream << " float rhw = 1.0 / input.gl_FragCoord.w;\n"; pixelStream << " float rhw = 1.0 / input.gl_FragCoord.w;\n";
...@@ -767,30 +762,31 @@ bool DynamicHLSL::generateShaderLinkHLSL(const gl::ContextState &data, ...@@ -767,30 +762,31 @@ bool DynamicHLSL::generateShaderLinkHLSL(const gl::ContextState &data,
*vertexHLSL = vertexStream.str(); *vertexHLSL = vertexStream.str();
*pixelHLSL = pixelStream.str(); *pixelHLSL = pixelStream.str();
return true;
} }
std::string DynamicHLSL::generateGeometryShaderPreamble(const VaryingPacking &varyingPacking) const std::string DynamicHLSL::generateGeometryShaderPreamble(const VaryingPacking &varyingPacking,
const BuiltinVaryingsD3D &builtinsD3D) const
{ {
ASSERT(mRenderer->getMajorShaderModel() >= 4); ASSERT(mRenderer->getMajorShaderModel() >= 4);
std::stringstream preambleStream; std::stringstream preambleStream;
const auto &builtins = varyingPacking.builtins(SHADER_VERTEX); const auto &vertexBuiltins = builtinsD3D[SHADER_VERTEX];
preambleStream << "struct GS_INPUT\n"; preambleStream << "struct GS_INPUT\n";
generateVaryingLinkHLSL(SHADER_VERTEX, varyingPacking, preambleStream); generateVaryingLinkHLSL(varyingPacking, vertexBuiltins, builtinsD3D.usesPointSize(),
preambleStream);
preambleStream << "\n" preambleStream << "\n"
<< "struct GS_OUTPUT\n"; << "struct GS_OUTPUT\n";
generateVaryingLinkHLSL(SHADER_GEOMETRY, varyingPacking, preambleStream); generateVaryingLinkHLSL(varyingPacking, builtinsD3D[SHADER_GEOMETRY],
builtinsD3D.usesPointSize(), preambleStream);
preambleStream preambleStream
<< "\n" << "\n"
<< "void copyVertex(inout GS_OUTPUT output, GS_INPUT input, GS_INPUT flatinput)\n" << "void copyVertex(inout GS_OUTPUT output, GS_INPUT input, GS_INPUT flatinput)\n"
<< "{\n" << "{\n"
<< " output.gl_Position = input.gl_Position;\n"; << " output.gl_Position = input.gl_Position;\n";
if (builtins.glPointSize.enabled) if (vertexBuiltins.glPointSize.enabled)
{ {
preambleStream << " output.gl_PointSize = input.gl_PointSize;\n"; preambleStream << " output.gl_PointSize = input.gl_PointSize;\n";
} }
...@@ -805,7 +801,7 @@ std::string DynamicHLSL::generateGeometryShaderPreamble(const VaryingPacking &va ...@@ -805,7 +801,7 @@ std::string DynamicHLSL::generateGeometryShaderPreamble(const VaryingPacking &va
preambleStream << "input.v" << varyingRegister.semanticIndex << "; \n"; preambleStream << "input.v" << varyingRegister.semanticIndex << "; \n";
} }
if (builtins.glFragCoord.enabled) if (vertexBuiltins.glFragCoord.enabled)
{ {
preambleStream << " output.gl_FragCoord = input.gl_FragCoord;\n"; preambleStream << " output.gl_FragCoord = input.gl_FragCoord;\n";
} }
...@@ -1077,4 +1073,97 @@ void DynamicHLSL::getPixelShaderOutputKey(const gl::ContextState &data, ...@@ -1077,4 +1073,97 @@ void DynamicHLSL::getPixelShaderOutputKey(const gl::ContextState &data,
} }
} }
// BuiltinVarying Implementation.
BuiltinVarying::BuiltinVarying() : enabled(false), index(0), systemValue(false)
{
}
std::string BuiltinVarying::str() const
{
return (systemValue ? semantic : (semantic + Str(index)));
}
void BuiltinVarying::enableSystem(const std::string &systemValueSemantic)
{
enabled = true;
semantic = systemValueSemantic;
systemValue = true;
}
void BuiltinVarying::enable(const std::string &semanticVal, unsigned int indexVal)
{
enabled = true;
semantic = semanticVal;
index = indexVal;
}
// BuiltinVaryingsD3D Implementation.
BuiltinVaryingsD3D::BuiltinVaryingsD3D(const ProgramD3DMetadata &metadata,
const VaryingPacking &packing)
{
updateBuiltins(SHADER_VERTEX, metadata, packing);
updateBuiltins(SHADER_PIXEL, metadata, packing);
if (metadata.getRendererMajorShaderModel() >= 4)
{
updateBuiltins(SHADER_GEOMETRY, metadata, packing);
}
}
void BuiltinVaryingsD3D::updateBuiltins(ShaderType shaderType,
const ProgramD3DMetadata &metadata,
const VaryingPacking &packing)
{
const std::string &userSemantic = GetVaryingSemantic(metadata.getRendererMajorShaderModel(),
metadata.usesSystemValuePointSize());
unsigned int reservedSemanticIndex = packing.getMaxSemanticIndex();
BuiltinInfo *builtins = &mBuiltinInfo[shaderType];
if (metadata.getRendererMajorShaderModel() >= 4)
{
builtins->dxPosition.enableSystem("SV_Position");
}
else if (shaderType == SHADER_PIXEL)
{
builtins->dxPosition.enableSystem("VPOS");
}
else
{
builtins->dxPosition.enableSystem("POSITION");
}
if (metadata.usesTransformFeedbackGLPosition())
{
builtins->glPosition.enable(userSemantic, reservedSemanticIndex++);
}
if (metadata.usesFragCoord())
{
builtins->glFragCoord.enable(userSemantic, reservedSemanticIndex++);
}
if (shaderType == SHADER_VERTEX ? metadata.addsPointCoordToVertexShader()
: metadata.usesPointCoord())
{
// SM3 reserves the TEXCOORD semantic for point sprite texcoords (gl_PointCoord)
// In D3D11 we manually compute gl_PointCoord in the GS.
if (metadata.getRendererMajorShaderModel() >= 4)
{
builtins->glPointCoord.enable(userSemantic, reservedSemanticIndex++);
}
else
{
builtins->glPointCoord.enable("TEXCOORD", 0);
}
}
// Special case: do not include PSIZE semantic in HLSL 3 pixel shaders
if (metadata.usesSystemValuePointSize() &&
(shaderType != SHADER_PIXEL || metadata.getRendererMajorShaderModel() >= 4))
{
builtins->glPointSize.enableSystem("PSIZE");
}
}
} // namespace rx } // namespace rx
...@@ -29,15 +29,14 @@ namespace gl ...@@ -29,15 +29,14 @@ namespace gl
{ {
class InfoLog; class InfoLog;
struct VariableLocation; struct VariableLocation;
class VaryingPacking;
struct VertexAttribute; struct VertexAttribute;
} }
namespace rx namespace rx
{ {
struct PackedVarying;
class ProgramD3DMetadata; class ProgramD3DMetadata;
class ShaderD3D; class ShaderD3D;
class VaryingPacking;
struct PixelShaderOutputVariable struct PixelShaderOutputVariable
{ {
...@@ -47,6 +46,54 @@ struct PixelShaderOutputVariable ...@@ -47,6 +46,54 @@ struct PixelShaderOutputVariable
size_t outputIndex; size_t outputIndex;
}; };
struct BuiltinVarying final : angle::NonCopyable
{
BuiltinVarying();
std::string str() const;
void enableSystem(const std::string &systemValueSemantic);
void enable(const std::string &semanticVal, unsigned int indexVal);
bool enabled;
std::string semantic;
unsigned int index;
bool systemValue;
};
struct BuiltinInfo
{
BuiltinVarying dxPosition;
BuiltinVarying glPosition;
BuiltinVarying glFragCoord;
BuiltinVarying glPointCoord;
BuiltinVarying glPointSize;
};
inline std::string GetVaryingSemantic(int majorShaderModel, bool programUsesPointSize)
{
// SM3 reserves the TEXCOORD semantic for point sprite texcoords (gl_PointCoord)
// In D3D11 we manually compute gl_PointCoord in the GS.
return ((programUsesPointSize && majorShaderModel < 4) ? "COLOR" : "TEXCOORD");
}
class BuiltinVaryingsD3D
{
public:
BuiltinVaryingsD3D(const ProgramD3DMetadata &metadata, const gl::VaryingPacking &packing);
bool usesPointSize() const { return mBuiltinInfo[SHADER_VERTEX].glPointSize.enabled; }
const BuiltinInfo &operator[](ShaderType shaderType) const { return mBuiltinInfo[shaderType]; }
BuiltinInfo &operator[](ShaderType shaderType) { return mBuiltinInfo[shaderType]; }
private:
void updateBuiltins(ShaderType shaderType,
const ProgramD3DMetadata &metadata,
const gl::VaryingPacking &packing);
std::array<BuiltinInfo, SHADER_TYPE_MAX> mBuiltinInfo;
};
class DynamicHLSL : angle::NonCopyable class DynamicHLSL : angle::NonCopyable
{ {
public: public:
...@@ -61,14 +108,16 @@ class DynamicHLSL : angle::NonCopyable ...@@ -61,14 +108,16 @@ class DynamicHLSL : angle::NonCopyable
const std::vector<PixelShaderOutputVariable> &outputVariables, const std::vector<PixelShaderOutputVariable> &outputVariables,
bool usesFragDepth, bool usesFragDepth,
const std::vector<GLenum> &outputLayout) const; const std::vector<GLenum> &outputLayout) const;
bool generateShaderLinkHLSL(const gl::ContextState &data, void generateShaderLinkHLSL(const gl::ContextState &data,
const gl::ProgramState &programData, const gl::ProgramState &programData,
const ProgramD3DMetadata &programMetadata, const ProgramD3DMetadata &programMetadata,
const VaryingPacking &varyingPacking, const gl::VaryingPacking &varyingPacking,
const BuiltinVaryingsD3D &builtinsD3D,
std::string *pixelHLSL, std::string *pixelHLSL,
std::string *vertexHLSL) const; std::string *vertexHLSL) const;
std::string generateGeometryShaderPreamble(const VaryingPacking &varyingPacking) const; std::string generateGeometryShaderPreamble(const gl::VaryingPacking &varyingPacking,
const BuiltinVaryingsD3D &builtinsD3D) const;
std::string generateGeometryShaderHLSL(gl::PrimitiveType primitiveType, std::string generateGeometryShaderHLSL(gl::PrimitiveType primitiveType,
const gl::ContextState &data, const gl::ContextState &data,
...@@ -84,11 +133,10 @@ class DynamicHLSL : angle::NonCopyable ...@@ -84,11 +133,10 @@ class DynamicHLSL : angle::NonCopyable
private: private:
RendererD3D *const mRenderer; RendererD3D *const mRenderer;
void generateVaryingLinkHLSL(ShaderType shaderType, void generateVaryingLinkHLSL(const gl::VaryingPacking &varyingPacking,
const VaryingPacking &varyingPacking, const BuiltinInfo &builtins,
std::stringstream &linkStream) const; bool programUsesPointSize,
void generateVaryingHLSL(const VaryingPacking &varyingPacking, std::stringstream &hlslStream) const;
std::stringstream &hlslStream) const;
// Prepend an underscore // Prepend an underscore
static std::string decorateVariable(const std::string &name); static std::string decorateVariable(const std::string &name);
...@@ -97,6 +145,6 @@ class DynamicHLSL : angle::NonCopyable ...@@ -97,6 +145,6 @@ class DynamicHLSL : angle::NonCopyable
const sh::ShaderVariable &shaderAttrib) const; const sh::ShaderVariable &shaderAttrib) const;
}; };
} } // namespace rx
#endif // LIBANGLE_RENDERER_D3D_DYNAMICHLSL_H_ #endif // LIBANGLE_RENDERER_D3D_DYNAMICHLSL_H_
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "libANGLE/FramebufferAttachment.h" #include "libANGLE/FramebufferAttachment.h"
#include "libANGLE/Program.h" #include "libANGLE/Program.h"
#include "libANGLE/Uniform.h" #include "libANGLE/Uniform.h"
#include "libANGLE/VaryingPacking.h"
#include "libANGLE/VertexArray.h" #include "libANGLE/VertexArray.h"
#include "libANGLE/features.h" #include "libANGLE/features.h"
#include "libANGLE/renderer/d3d/DynamicHLSL.h" #include "libANGLE/renderer/d3d/DynamicHLSL.h"
...@@ -22,7 +23,6 @@ ...@@ -22,7 +23,6 @@
#include "libANGLE/renderer/d3d/ShaderD3D.h" #include "libANGLE/renderer/d3d/ShaderD3D.h"
#include "libANGLE/renderer/d3d/ShaderExecutableD3D.h" #include "libANGLE/renderer/d3d/ShaderExecutableD3D.h"
#include "libANGLE/renderer/d3d/VertexDataManager.h" #include "libANGLE/renderer/d3d/VertexDataManager.h"
#include "libANGLE/renderer/d3d/hlsl/VaryingPacking.h"
using namespace angle; using namespace angle;
...@@ -82,77 +82,6 @@ bool IsRowMajorLayout(const sh::ShaderVariable &var) ...@@ -82,77 +82,6 @@ bool IsRowMajorLayout(const sh::ShaderVariable &var)
return false; return false;
} }
// true if varying x has a higher priority in packing than y
bool ComparePackedVarying(const PackedVarying &x, const PackedVarying &y)
{
return gl::CompareShaderVar(*x.varying, *y.varying);
}
std::vector<PackedVarying> MergeVaryings(const gl::Shader &vertexShader,
const gl::Shader &fragmentShader,
const std::vector<std::string> &tfVaryings)
{
std::vector<PackedVarying> packedVaryings;
for (const sh::Varying &output : vertexShader.getVaryings())
{
bool packed = false;
// Built-in varyings obey special rules
if (output.isBuiltIn())
{
continue;
}
for (const sh::Varying &input : fragmentShader.getVaryings())
{
if (output.name == input.name)
{
if (output.isStruct())
{
ASSERT(!output.isArray());
for (const auto &field : output.fields)
{
ASSERT(!field.isStruct() && !field.isArray());
packedVaryings.push_back(
PackedVarying(field, input.interpolation, input.name));
}
}
else
{
packedVaryings.push_back(PackedVarying(input, input.interpolation));
}
packed = true;
break;
}
}
// Keep Transform FB varyings in the merged list always.
if (!packed)
{
for (const std::string &tfVarying : tfVaryings)
{
if (tfVarying == output.name)
{
// Transform feedback for varying structs is underspecified.
// See Khronos bug 9856.
// TODO(jmadill): Figure out how to be spec-compliant here.
if (!output.isStruct())
{
packedVaryings.push_back(PackedVarying(output, output.interpolation));
packedVaryings.back().vertexOnly = true;
}
break;
}
}
}
}
std::sort(packedVaryings.begin(), packedVaryings.end(), ComparePackedVarying);
return packedVaryings;
}
template <typename VarT> template <typename VarT>
void GetUniformBlockInfo(const std::vector<VarT> &fields, void GetUniformBlockInfo(const std::vector<VarT> &fields,
const std::string &prefix, const std::string &prefix,
...@@ -288,6 +217,20 @@ gl::PrimitiveType GetGeometryShaderTypeFromDrawMode(GLenum drawMode) ...@@ -288,6 +217,20 @@ gl::PrimitiveType GetGeometryShaderTypeFromDrawMode(GLenum drawMode)
} }
} }
bool FindFlatInterpolationVarying(const std::vector<sh::Varying> &varyings)
{
// Note: this assumes nested structs can only be packed with one interpolation.
for (const auto &varying : varyings)
{
if (varying.interpolation == sh::INTERPOLATION_FLAT)
{
return true;
}
}
return false;
}
} // anonymous namespace } // anonymous namespace
// D3DUniform Implementation // D3DUniform Implementation
...@@ -453,60 +396,6 @@ const ShaderD3D *ProgramD3DMetadata::getFragmentShader() const ...@@ -453,60 +396,6 @@ const ShaderD3D *ProgramD3DMetadata::getFragmentShader() const
return mFragmentShader; return mFragmentShader;
} }
void ProgramD3DMetadata::updatePackingBuiltins(ShaderType shaderType, VaryingPacking *packing)
{
const std::string &userSemantic =
GetVaryingSemantic(mRendererMajorShaderModel, usesSystemValuePointSize());
unsigned int reservedSemanticIndex = packing->getMaxSemanticIndex();
VaryingPacking::BuiltinInfo *builtins = &packing->builtins(shaderType);
if (mRendererMajorShaderModel >= 4)
{
builtins->dxPosition.enableSystem("SV_Position");
}
else if (shaderType == SHADER_PIXEL)
{
builtins->dxPosition.enableSystem("VPOS");
}
else
{
builtins->dxPosition.enableSystem("POSITION");
}
if (usesTransformFeedbackGLPosition())
{
builtins->glPosition.enable(userSemantic, reservedSemanticIndex++);
}
if (usesFragCoord())
{
builtins->glFragCoord.enable(userSemantic, reservedSemanticIndex++);
}
if (shaderType == SHADER_VERTEX ? addsPointCoordToVertexShader() : usesPointCoord())
{
// SM3 reserves the TEXCOORD semantic for point sprite texcoords (gl_PointCoord)
// In D3D11 we manually compute gl_PointCoord in the GS.
if (mRendererMajorShaderModel >= 4)
{
builtins->glPointCoord.enable(userSemantic, reservedSemanticIndex++);
}
else
{
builtins->glPointCoord.enable("TEXCOORD", 0);
}
}
// Special case: do not include PSIZE semantic in HLSL 3 pixel shaders
if (usesSystemValuePointSize() &&
(shaderType != SHADER_PIXEL || mRendererMajorShaderModel >= 4))
{
builtins->glPointSize.enableSystem("PSIZE");
}
}
// ProgramD3D Implementation // ProgramD3D Implementation
ProgramD3D::VertexExecutable::VertexExecutable(const gl::InputLayout &inputLayout, ProgramD3D::VertexExecutable::VertexExecutable(const gl::InputLayout &inputLayout,
...@@ -1448,7 +1337,9 @@ LinkResult ProgramD3D::compileProgramExecutables(const gl::ContextState &context ...@@ -1448,7 +1337,9 @@ LinkResult ProgramD3D::compileProgramExecutables(const gl::ContextState &context
(!usesGeometryShader(GL_POINTS) || pointGS)); (!usesGeometryShader(GL_POINTS) || pointGS));
} }
LinkResult ProgramD3D::link(const gl::ContextState &data, gl::InfoLog &infoLog) LinkResult ProgramD3D::link(const gl::ContextState &data,
const gl::VaryingPacking &packing,
gl::InfoLog &infoLog)
{ {
reset(); reset();
...@@ -1473,70 +1364,40 @@ LinkResult ProgramD3D::link(const gl::ContextState &data, gl::InfoLog &infoLog) ...@@ -1473,70 +1364,40 @@ LinkResult ProgramD3D::link(const gl::ContextState &data, gl::InfoLog &infoLog)
} }
} }
std::vector<PackedVarying> packedVaryings =
MergeVaryings(*vertexShader, *fragmentShader, mState.getTransformFeedbackVaryingNames());
// Map the varyings to the register file
VaryingPacking varyingPacking(data.getCaps().maxVaryingVectors);
if (!varyingPacking.packUserVaryings(infoLog, packedVaryings,
mState.getTransformFeedbackVaryingNames()))
{
return false;
}
ProgramD3DMetadata metadata(mRenderer, vertexShaderD3D, fragmentShaderD3D);
metadata.updatePackingBuiltins(SHADER_VERTEX, &varyingPacking);
metadata.updatePackingBuiltins(SHADER_PIXEL, &varyingPacking);
if (!varyingPacking.validateBuiltins())
{
infoLog << "No varying registers left to support gl_FragCoord/gl_PointCoord";
return false;
}
// TODO(jmadill): Implement more sophisticated component packing in D3D9. // 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 // We can fail here because we use one semantic per GLSL varying. D3D11 can pack varyings
// intelligently, but D3D9 assumes one semantic per register. // intelligently, but D3D9 assumes one semantic per register.
if (mRenderer->getRendererClass() == RENDERER_D3D9 && if (mRenderer->getRendererClass() == RENDERER_D3D9 &&
varyingPacking.getMaxSemanticIndex() > data.getCaps().maxVaryingVectors) packing.getMaxSemanticIndex() > data.getCaps().maxVaryingVectors)
{ {
infoLog << "Cannot pack these varyings on D3D9."; infoLog << "Cannot pack these varyings on D3D9.";
return false; return false;
} }
if (!mDynamicHLSL->generateShaderLinkHLSL(data, mState, metadata, varyingPacking, &mPixelHLSL, ProgramD3DMetadata metadata(mRenderer, vertexShaderD3D, fragmentShaderD3D);
&mVertexHLSL)) BuiltinVaryingsD3D builtins(metadata, packing);
{
return false; mDynamicHLSL->generateShaderLinkHLSL(data, mState, metadata, packing, builtins, &mPixelHLSL,
} &mVertexHLSL);
mUsesPointSize = vertexShaderD3D->usesPointSize(); mUsesPointSize = vertexShaderD3D->usesPointSize();
mDynamicHLSL->getPixelShaderOutputKey(data, mState, metadata, &mPixelShaderKey); mDynamicHLSL->getPixelShaderOutputKey(data, mState, metadata, &mPixelShaderKey);
mUsesFragDepth = metadata.usesFragDepth(); mUsesFragDepth = metadata.usesFragDepth();
// Cache if we use flat shading // Cache if we use flat shading
mUsesFlatInterpolation = false; mUsesFlatInterpolation = (FindFlatInterpolationVarying(fragmentShader->getVaryings()) ||
for (const auto &varying : packedVaryings) FindFlatInterpolationVarying(vertexShader->getVaryings()));
{
if (varying.interpolation == sh::INTERPOLATION_FLAT)
{
mUsesFlatInterpolation = true;
break;
}
}
if (mRenderer->getMajorShaderModel() >= 4) if (mRenderer->getMajorShaderModel() >= 4)
{ {
metadata.updatePackingBuiltins(SHADER_GEOMETRY, &varyingPacking); mGeometryShaderPreamble = mDynamicHLSL->generateGeometryShaderPreamble(packing, builtins);
mGeometryShaderPreamble = mDynamicHLSL->generateGeometryShaderPreamble(varyingPacking);
} }
initAttribLocationsToD3DSemantic(); initAttribLocationsToD3DSemantic();
defineUniformsAndAssignRegisters(); defineUniformsAndAssignRegisters();
gatherTransformFeedbackVaryings(varyingPacking); gatherTransformFeedbackVaryings(packing, builtins[SHADER_VERTEX]);
LinkResult result = compileProgramExecutables(data, infoLog); LinkResult result = compileProgramExecutables(data, infoLog);
if (result.isError()) if (result.isError())
...@@ -2312,10 +2173,9 @@ void ProgramD3D::updateCachedInputLayout(const gl::State &state) ...@@ -2312,10 +2173,9 @@ void ProgramD3D::updateCachedInputLayout(const gl::State &state)
} }
} }
void ProgramD3D::gatherTransformFeedbackVaryings(const VaryingPacking &varyingPacking) void ProgramD3D::gatherTransformFeedbackVaryings(const gl::VaryingPacking &varyingPacking,
const BuiltinInfo &builtins)
{ {
const auto &builtins = varyingPacking.builtins(SHADER_VERTEX);
const std::string &varyingSemantic = const std::string &varyingSemantic =
GetVaryingSemantic(mRenderer->getMajorShaderModel(), usesPointSize()); GetVaryingSemantic(mRenderer->getMajorShaderModel(), usesPointSize());
...@@ -2352,7 +2212,7 @@ void ProgramD3D::gatherTransformFeedbackVaryings(const VaryingPacking &varyingPa ...@@ -2352,7 +2212,7 @@ void ProgramD3D::gatherTransformFeedbackVaryings(const VaryingPacking &varyingPa
} }
else else
{ {
for (const PackedVaryingRegister &registerInfo : varyingPacking.getRegisterList()) for (const auto &registerInfo : varyingPacking.getRegisterList())
{ {
const auto &varying = *registerInfo.packedVarying->varying; const auto &varying = *registerInfo.packedVarying->varying;
GLenum transposedType = gl::TransposeMatrixType(varying.type); GLenum transposedType = gl::TransposeMatrixType(varying.type);
......
...@@ -119,9 +119,6 @@ class ProgramD3DMetadata final : angle::NonCopyable ...@@ -119,9 +119,6 @@ class ProgramD3DMetadata final : angle::NonCopyable
GLint getMajorShaderVersion() const; GLint getMajorShaderVersion() const;
const ShaderD3D *getFragmentShader() const; const ShaderD3D *getFragmentShader() const;
// Applies the metadata structure to the varying packing.
void updatePackingBuiltins(ShaderType shaderType, VaryingPacking *packing);
private: private:
const int mRendererMajorShaderModel; const int mRendererMajorShaderModel;
const std::string mShaderModelSuffix; const std::string mShaderModelSuffix;
...@@ -170,7 +167,9 @@ class ProgramD3D : public ProgramImpl ...@@ -170,7 +167,9 @@ class ProgramD3D : public ProgramImpl
ShaderExecutableD3D **outExecutable, ShaderExecutableD3D **outExecutable,
gl::InfoLog *infoLog); gl::InfoLog *infoLog);
LinkResult link(const gl::ContextState &data, gl::InfoLog &infoLog) override; LinkResult link(const gl::ContextState &data,
const gl::VaryingPacking &packing,
gl::InfoLog &infoLog) override;
GLboolean validate(const gl::Caps &caps, gl::InfoLog *infoLog) override; GLboolean validate(const gl::Caps &caps, gl::InfoLog *infoLog) override;
bool getUniformBlockSize(const std::string &blockName, size_t *sizeOut) const override; bool getUniformBlockSize(const std::string &blockName, size_t *sizeOut) const override;
...@@ -354,7 +353,8 @@ class ProgramD3D : public ProgramImpl ...@@ -354,7 +353,8 @@ class ProgramD3D : public ProgramImpl
LinkResult compileProgramExecutables(const gl::ContextState &data, gl::InfoLog &infoLog); LinkResult compileProgramExecutables(const gl::ContextState &data, gl::InfoLog &infoLog);
void gatherTransformFeedbackVaryings(const VaryingPacking &varyings); void gatherTransformFeedbackVaryings(const gl::VaryingPacking &varyings,
const BuiltinInfo &builtins);
D3DUniform *getD3DUniformByName(const std::string &name); D3DUniform *getD3DUniformByName(const std::string &name);
D3DUniform *getD3DUniformFromLocation(GLint location); D3DUniform *getD3DUniformFromLocation(GLint location);
......
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
#include "libANGLE/Device.h" #include "libANGLE/Device.h"
#include "libANGLE/formatutils.h" #include "libANGLE/formatutils.h"
#include "libANGLE/renderer/d3d/VertexDataManager.h" #include "libANGLE/renderer/d3d/VertexDataManager.h"
#include "libANGLE/renderer/d3d/hlsl/hlsl_utils.h"
#include "libANGLE/renderer/d3d/formatutilsD3D.h" #include "libANGLE/renderer/d3d/formatutilsD3D.h"
#include "libANGLE/Version.h" #include "libANGLE/Version.h"
#include "libANGLE/WorkerThread.h" #include "libANGLE/WorkerThread.h"
...@@ -71,6 +70,14 @@ enum RendererClass ...@@ -71,6 +70,14 @@ enum RendererClass
RENDERER_D3D9 RENDERER_D3D9
}; };
enum ShaderType
{
SHADER_VERTEX,
SHADER_PIXEL,
SHADER_GEOMETRY,
SHADER_TYPE_MAX
};
// Useful for unit testing // Useful for unit testing
class BufferFactoryD3D : angle::NonCopyable class BufferFactoryD3D : angle::NonCopyable
{ {
......
//
// Copyright 2015 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// hlsl_utils: Helper functions for HLSL.
#ifndef LIBANGLE_RENDERER_D3D_HLSL_HLSL_UTILS_H_
#define LIBANGLE_RENDERER_D3D_HLSL_HLSL_UTILS_H_
#include <string>
namespace rx
{
enum ShaderType
{
SHADER_VERTEX,
SHADER_PIXEL,
SHADER_GEOMETRY,
SHADER_TYPE_MAX
};
inline std::string GetVaryingSemantic(int majorShaderModel, bool programUsesPointSize)
{
// SM3 reserves the TEXCOORD semantic for point sprite texcoords (gl_PointCoord)
// In D3D11 we manually compute gl_PointCoord in the GS.
return ((programUsesPointSize && majorShaderModel < 4) ? "COLOR" : "TEXCOORD");
}
} // namespace rx
#endif // LIBANGLE_RENDERER_D3D_HLSL_HLSL_UTILS_H_
...@@ -111,7 +111,9 @@ void ProgramGL::setBinaryRetrievableHint(bool retrievable) ...@@ -111,7 +111,9 @@ void ProgramGL::setBinaryRetrievableHint(bool retrievable)
} }
} }
LinkResult ProgramGL::link(const gl::ContextState &data, gl::InfoLog &infoLog) LinkResult ProgramGL::link(const gl::ContextState &data,
const gl::VaryingPacking &packing,
gl::InfoLog &infoLog)
{ {
preLink(); preLink();
......
...@@ -43,7 +43,9 @@ class ProgramGL : public ProgramImpl ...@@ -43,7 +43,9 @@ class ProgramGL : public ProgramImpl
gl::Error save(gl::BinaryOutputStream *stream) override; gl::Error save(gl::BinaryOutputStream *stream) override;
void setBinaryRetrievableHint(bool retrievable) override; void setBinaryRetrievableHint(bool retrievable) override;
LinkResult link(const gl::ContextState &data, gl::InfoLog &infoLog) override; LinkResult link(const gl::ContextState &data,
const gl::VaryingPacking &packing,
gl::InfoLog &infoLog) override;
GLboolean validate(const gl::Caps &caps, gl::InfoLog *infoLog) override; GLboolean validate(const gl::Caps &caps, gl::InfoLog *infoLog) override;
void setUniform1fv(GLint location, GLsizei count, const GLfloat *v) override; void setUniform1fv(GLint location, GLsizei count, const GLfloat *v) override;
......
...@@ -38,7 +38,9 @@ void ProgramNULL::setBinaryRetrievableHint(bool retrievable) ...@@ -38,7 +38,9 @@ void ProgramNULL::setBinaryRetrievableHint(bool retrievable)
{ {
} }
LinkResult ProgramNULL::link(const gl::ContextState &data, gl::InfoLog &infoLog) LinkResult ProgramNULL::link(const gl::ContextState &data,
const gl::VaryingPacking &packing,
gl::InfoLog &infoLog)
{ {
return true; return true;
} }
......
...@@ -27,7 +27,9 @@ class ProgramNULL : public ProgramImpl ...@@ -27,7 +27,9 @@ class ProgramNULL : public ProgramImpl
gl::Error save(gl::BinaryOutputStream *stream) override; gl::Error save(gl::BinaryOutputStream *stream) override;
void setBinaryRetrievableHint(bool retrievable) override; void setBinaryRetrievableHint(bool retrievable) override;
LinkResult link(const gl::ContextState &data, gl::InfoLog &infoLog) override; LinkResult link(const gl::ContextState &data,
const gl::VaryingPacking &packing,
gl::InfoLog &infoLog) override;
GLboolean validate(const gl::Caps &caps, gl::InfoLog *infoLog) override; GLboolean validate(const gl::Caps &caps, gl::InfoLog *infoLog) override;
void setUniform1fv(GLint location, GLsizei count, const GLfloat *v) override; void setUniform1fv(GLint location, GLsizei count, const GLfloat *v) override;
......
...@@ -41,7 +41,9 @@ void ProgramVk::setBinaryRetrievableHint(bool retrievable) ...@@ -41,7 +41,9 @@ void ProgramVk::setBinaryRetrievableHint(bool retrievable)
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
LinkResult ProgramVk::link(const gl::ContextState &data, gl::InfoLog &infoLog) LinkResult ProgramVk::link(const gl::ContextState &data,
const gl::VaryingPacking &packing,
gl::InfoLog &infoLog)
{ {
UNIMPLEMENTED(); UNIMPLEMENTED();
return gl::Error(GL_INVALID_OPERATION); return gl::Error(GL_INVALID_OPERATION);
......
...@@ -27,7 +27,9 @@ class ProgramVk : public ProgramImpl ...@@ -27,7 +27,9 @@ class ProgramVk : public ProgramImpl
gl::Error save(gl::BinaryOutputStream *stream) override; gl::Error save(gl::BinaryOutputStream *stream) override;
void setBinaryRetrievableHint(bool retrievable) override; void setBinaryRetrievableHint(bool retrievable) override;
LinkResult link(const gl::ContextState &data, gl::InfoLog &infoLog) override; LinkResult link(const gl::ContextState &data,
const gl::VaryingPacking &packing,
gl::InfoLog &infoLog) override;
GLboolean validate(const gl::Caps &caps, gl::InfoLog *infoLog) override; GLboolean validate(const gl::Caps &caps, gl::InfoLog *infoLog) override;
void setUniform1fv(GLint location, GLsizei count, const GLfloat *v) override; void setUniform1fv(GLint location, GLsizei count, const GLfloat *v) override;
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include "libANGLE/ContextState.h" #include "libANGLE/ContextState.h"
#include "libANGLE/VaryingPacking.h"
#include "libANGLE/renderer/FramebufferImpl_mock.h" #include "libANGLE/renderer/FramebufferImpl_mock.h"
#include "libANGLE/renderer/ProgramImpl_mock.h" #include "libANGLE/renderer/ProgramImpl_mock.h"
#include "libANGLE/renderer/TextureImpl_mock.h" #include "libANGLE/renderer/TextureImpl_mock.h"
......
...@@ -146,6 +146,8 @@ ...@@ -146,6 +146,8 @@
'libANGLE/TransformFeedback.h', 'libANGLE/TransformFeedback.h',
'libANGLE/Uniform.cpp', 'libANGLE/Uniform.cpp',
'libANGLE/Uniform.h', 'libANGLE/Uniform.h',
'libANGLE/VaryingPacking.cpp',
'libANGLE/VaryingPacking.h',
'libANGLE/Version.h', 'libANGLE/Version.h',
'libANGLE/Version.inl', 'libANGLE/Version.inl',
'libANGLE/VertexArray.cpp', 'libANGLE/VertexArray.cpp',
...@@ -271,12 +273,6 @@ ...@@ -271,12 +273,6 @@
'libANGLE/renderer/d3d/VertexDataManager.cpp', 'libANGLE/renderer/d3d/VertexDataManager.cpp',
'libANGLE/renderer/d3d/VertexDataManager.h', 'libANGLE/renderer/d3d/VertexDataManager.h',
], ],
'libangle_d3d_hlsl_sources':
[
'libANGLE/renderer/d3d/hlsl/VaryingPacking.cpp',
'libANGLE/renderer/d3d/hlsl/VaryingPacking.h',
'libANGLE/renderer/d3d/hlsl/hlsl_utils.h',
],
'libangle_d3d9_sources': 'libangle_d3d9_sources':
[ [
'libANGLE/renderer/d3d/d3d9/Blit9.cpp', 'libANGLE/renderer/d3d/d3d9/Blit9.cpp',
...@@ -830,7 +826,6 @@ ...@@ -830,7 +826,6 @@
{ {
'sources': 'sources':
[ [
'<@(libangle_d3d_hlsl_sources)',
'<@(libangle_d3d_shared_sources)', '<@(libangle_d3d_shared_sources)',
], ],
}], }],
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
'<(angle_path)/src/libANGLE/ResourceManager_unittest.cpp', '<(angle_path)/src/libANGLE/ResourceManager_unittest.cpp',
'<(angle_path)/src/libANGLE/Surface_unittest.cpp', '<(angle_path)/src/libANGLE/Surface_unittest.cpp',
'<(angle_path)/src/libANGLE/TransformFeedback_unittest.cpp', '<(angle_path)/src/libANGLE/TransformFeedback_unittest.cpp',
'<(angle_path)/src/libANGLE/VaryingPacking_unittest.cpp',
'<(angle_path)/src/libANGLE/WorkerThread_unittest.cpp', '<(angle_path)/src/libANGLE/WorkerThread_unittest.cpp',
'<(angle_path)/src/libANGLE/renderer/BufferImpl_mock.h', '<(angle_path)/src/libANGLE/renderer/BufferImpl_mock.h',
'<(angle_path)/src/libANGLE/renderer/FramebufferImpl_mock.h', '<(angle_path)/src/libANGLE/renderer/FramebufferImpl_mock.h',
...@@ -103,7 +104,6 @@ ...@@ -103,7 +104,6 @@
# TODO(jmadill): should probably call this windows sources # TODO(jmadill): should probably call this windows sources
'angle_unittests_hlsl_sources': 'angle_unittests_hlsl_sources':
[ [
'<(angle_path)/src/libANGLE/renderer/d3d/VaryingPacking_unittest.cpp',
'<(angle_path)/src/tests/compiler_tests/UnrollFlatten_test.cpp', '<(angle_path)/src/tests/compiler_tests/UnrollFlatten_test.cpp',
], ],
}, },
......
...@@ -1357,7 +1357,12 @@ TEST_P(GLSLTest, MaxVaryingVec2Arrays) ...@@ -1357,7 +1357,12 @@ TEST_P(GLSLTest, MaxVaryingVec2Arrays)
GLint maxVaryings = 0; GLint maxVaryings = 0;
glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings); glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
VaryingTestBase(0, 0, 0, maxVaryings, 0, 0, 0, 0, false, false, false, true); // Special case: because arrays of mat2 are packed as small grids of two rows by two columns,
// we should be aware that when we're packing into an odd number of varying registers the
// last row will be empty and can not fit the final vec2 arrary.
GLint maxVec2Arrays = (maxVaryings >> 1) << 1;
VaryingTestBase(0, 0, 0, maxVec2Arrays, 0, 0, 0, 0, false, false, false, true);
} }
// Verify shader source with a fixed length that is less than the null-terminated length will compile. // Verify shader source with a fixed length that is less than the null-terminated length will compile.
...@@ -2520,6 +2525,73 @@ TEST_P(GLSLTest_ES3, MultipleDeclarationInForLoopEmptyExpression) ...@@ -2520,6 +2525,73 @@ TEST_P(GLSLTest_ES3, MultipleDeclarationInForLoopEmptyExpression)
ANGLE_GL_PROGRAM(program, mSimpleVSSource, fragmentShader); ANGLE_GL_PROGRAM(program, mSimpleVSSource, fragmentShader);
} }
class WebGLGLSLTest : public GLSLTest
{
protected:
WebGLGLSLTest() { setWebGLCompatibilityEnabled(true); }
};
TEST_P(WebGLGLSLTest, MaxVaryingVec4PlusFragCoord)
{
GLint maxVaryings = 0;
glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
// Generate shader code that uses gl_FragCoord, a special fragment shader variables.
// This test should fail, since we are really using (maxVaryings + 1) varyings.
VaryingTestBase(0, 0, 0, 0, 0, 0, maxVaryings, 0, true, false, false, false);
}
TEST_P(WebGLGLSLTest, MaxVaryingVec4PlusPointCoord)
{
GLint maxVaryings = 0;
glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
// Generate shader code that uses gl_FragCoord, a special fragment shader variables.
// This test should fail, since we are really using (maxVaryings + 1) varyings.
VaryingTestBase(0, 0, 0, 0, 0, 0, maxVaryings, 0, false, true, false, false);
}
TEST_P(WebGLGLSLTest, MaxPlusOneVaryingVec3)
{
GLint maxVaryings = 0;
glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
VaryingTestBase(0, 0, 0, 0, maxVaryings + 1, 0, 0, 0, false, false, false, false);
}
TEST_P(WebGLGLSLTest, MaxPlusOneVaryingVec3Array)
{
GLint maxVaryings = 0;
glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
VaryingTestBase(0, 0, 0, 0, 0, maxVaryings / 2 + 1, 0, 0, false, false, false, false);
}
TEST_P(WebGLGLSLTest, MaxVaryingVec3AndOneVec2)
{
GLint maxVaryings = 0;
glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
VaryingTestBase(0, 0, 1, 0, maxVaryings, 0, 0, 0, false, false, false, false);
}
TEST_P(WebGLGLSLTest, MaxPlusOneVaryingVec2)
{
GLint maxVaryings = 0;
glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
VaryingTestBase(0, 0, 2 * maxVaryings + 1, 0, 0, 0, 0, 0, false, false, false, false);
}
TEST_P(WebGLGLSLTest, MaxVaryingVec3ArrayAndMaxPlusOneFloatArray)
{
GLint maxVaryings = 0;
glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
VaryingTestBase(0, maxVaryings / 2 + 1, 0, 0, 0, 0, 0, maxVaryings / 2, false, false, false,
false);
}
} // anonymous namespace } // anonymous namespace
// 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.
...@@ -2534,3 +2606,5 @@ ANGLE_INSTANTIATE_TEST(GLSLTest, ...@@ -2534,3 +2606,5 @@ ANGLE_INSTANTIATE_TEST(GLSLTest,
// 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(GLSLTest_ES3, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES()); ANGLE_INSTANTIATE_TEST(GLSLTest_ES3, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
ANGLE_INSTANTIATE_TEST(WebGLGLSLTest, ES2_D3D11(), ES2_OPENGL(), ES2_OPENGLES());
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