add support for EXT_blend_func_extended to D3D11

Change-Id: Id66868851a490d0a68a7e76280720825c4844a45
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1591192
Commit-Queue: Geoff Lang <geofflang@chromium.org>
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
This commit is contained in:
Lee Salzman 2019-04-30 23:42:31 -04:00 коммит произвёл Commit Bot
Родитель 3e62561c4e
Коммит 8ba78da0b3
14 изменённых файлов: 416 добавлений и 148 удалений

Просмотреть файл

@ -233,6 +233,7 @@ OutputHLSL::OutputHLSL(sh::GLenum shaderType,
const char *sourcePath,
ShShaderOutput outputType,
int numRenderTargets,
int maxDualSourceDrawBuffers,
const std::vector<Uniform> &uniforms,
ShCompileOptions compileOptions,
sh::WorkGroupSize workGroupSize,
@ -249,6 +250,7 @@ OutputHLSL::OutputHLSL(sh::GLenum shaderType,
mInsideFunction(false),
mInsideMain(false),
mNumRenderTargets(numRenderTargets),
mMaxDualSourceDrawBuffers(maxDualSourceDrawBuffers),
mCurrentFunctionMetadata(nullptr),
mWorkGroupSize(workGroupSize),
mPerfDiagnostics(perfDiagnostics)
@ -276,6 +278,7 @@ OutputHLSL::OutputHLSL(sh::GLenum shaderType,
mUsesNestedBreak = false;
mRequiresIEEEStrictCompiling = false;
mUseZeroArray = false;
mUsesSecondaryColor = false;
mUniqueIndex = 0;
@ -630,6 +633,8 @@ void OutputHLSL::header(TInfoSinkBase &out,
{
const bool usingMRTExtension =
IsExtensionEnabled(mExtensionBehavior, TExtension::EXT_draw_buffers);
const bool usingBFEExtension =
IsExtensionEnabled(mExtensionBehavior, TExtension::EXT_blend_func_extended);
out << "// Varyings\n";
writeReferencedVaryings(out);
@ -664,6 +669,23 @@ void OutputHLSL::header(TInfoSinkBase &out,
}
out << "};\n";
if (usingBFEExtension && mUsesSecondaryColor)
{
out << "static float4 gl_SecondaryColor[" << mMaxDualSourceDrawBuffers
<< "] = \n"
"{\n";
for (int i = 0; i < mMaxDualSourceDrawBuffers; i++)
{
out << " float4(0, 0, 0, 0)";
if (i + 1 != mMaxDualSourceDrawBuffers)
{
out << ",";
}
out << "\n";
}
out << "};\n";
}
}
if (mUsesFragDepth)
@ -781,6 +803,11 @@ void OutputHLSL::header(TInfoSinkBase &out,
{
out << "#define GL_USES_FRAG_DATA\n";
}
if (mShaderVersion < 300 && usingBFEExtension && mUsesSecondaryColor)
{
out << "#define GL_USES_SECONDARY_COLOR\n";
}
}
else if (mShaderType == GL_VERTEX_SHADER)
{
@ -1118,6 +1145,16 @@ void OutputHLSL::visitSymbol(TIntermSymbol *node)
out << "gl_Color";
mUsesFragData = true;
}
else if (qualifier == EvqSecondaryFragColorEXT)
{
out << "gl_SecondaryColor[0]";
mUsesSecondaryColor = true;
}
else if (qualifier == EvqSecondaryFragDataEXT)
{
out << "gl_SecondaryColor";
mUsesSecondaryColor = true;
}
else if (qualifier == EvqFragCoord)
{
mUsesFragCoord = true;

Просмотреть файл

@ -43,6 +43,7 @@ class OutputHLSL : public TIntermTraverser
const char *sourcePath,
ShShaderOutput outputType,
int numRenderTargets,
int maxDualSourceDrawBuffers,
const std::vector<Uniform> &uniforms,
ShCompileOptions compileOptions,
sh::WorkGroupSize workGroupSize,
@ -207,8 +208,10 @@ class OutputHLSL : public TIntermTraverser
bool mUsesNestedBreak;
bool mRequiresIEEEStrictCompiling;
mutable bool mUseZeroArray;
bool mUsesSecondaryColor;
int mNumRenderTargets;
int mMaxDualSourceDrawBuffers;
int mUniqueIndex; // For creating unique names

Просмотреть файл

@ -42,6 +42,8 @@ void TranslatorHLSL::translate(TIntermBlock *root,
{
const ShBuiltInResources &resources = getResources();
int numRenderTargets = resources.EXT_draw_buffers ? resources.MaxDrawBuffers : 1;
int maxDualSourceDrawBuffers =
resources.EXT_blend_func_extended ? resources.MaxDualSourceDrawBuffers : 0;
sh::AddDefaultReturnStatements(root);
@ -135,10 +137,10 @@ void TranslatorHLSL::translate(TIntermBlock *root,
sh::RewriteAtomicFunctionExpressions(root, &getSymbolTable(), getShaderVersion());
}
sh::OutputHLSL outputHLSL(getShaderType(), getShaderVersion(), getExtensionBehavior(),
getSourcePath(), getOutputType(), numRenderTargets, getUniforms(),
compileOptions, getComputeShaderLocalSize(), &getSymbolTable(),
perfDiagnostics, mShaderStorageBlocks);
sh::OutputHLSL outputHLSL(
getShaderType(), getShaderVersion(), getExtensionBehavior(), getSourcePath(),
getOutputType(), numRenderTargets, maxDualSourceDrawBuffers, getUniforms(), compileOptions,
getComputeShaderLocalSize(), &getSymbolTable(), perfDiagnostics, mShaderStorageBlocks);
outputHLSL.output(root, getInfoSink().obj);

Просмотреть файл

@ -59,7 +59,7 @@ HashStream &operator<<(HashStream &stream, const ProgramBindings &bindings)
{
for (const auto &binding : bindings)
{
stream << binding.first << binding.second;
stream << binding.first << binding.second.location;
}
return stream;
}

Просмотреть файл

@ -142,7 +142,11 @@ GLint GetVariableLocation(const std::vector<VarT> &list,
const VarT &variable = list[variableLocation.index];
if (angle::BeginsWith(variable.name, name))
// Array output variables may be bound out of order, so we need to ensure we only pick the
// first element if given the base name. Uniforms don't allow this behavior and some code
// seemingly depends on the opposite behavior, so only enable it for output variables.
if (angle::BeginsWith(variable.name, name) &&
(!std::is_base_of<sh::OutputVariable, VarT>::value || variableLocation.arrayIndex == 0))
{
if (name.length() == variable.name.length())
{
@ -863,13 +867,56 @@ ProgramBindings::~ProgramBindings() {}
void ProgramBindings::bindLocation(GLuint index, const std::string &name)
{
mBindings[name] = index;
mBindings[name] = ProgramBinding(index);
// EXT_blend_func_extended spec: "If it specifies the base name of an array,
// it identifies the resources associated with the first element of the array."
//
// Normalize array bindings so that "name" and "name[0]" map to the same entry.
// If this binding is of the form "name[0]", then mark the "name" binding as
// aliased but do not update it yet in case "name" is not actually an array.
size_t nameLengthWithoutArrayIndex;
unsigned int arrayIndex = ParseArrayIndex(name, &nameLengthWithoutArrayIndex);
if (arrayIndex == 0)
{
std::string baseName = name.substr(0u, nameLengthWithoutArrayIndex);
auto iter = mBindings.find(baseName);
if (iter != mBindings.end())
{
iter->second.aliased = true;
}
}
}
int ProgramBindings::getBinding(const std::string &name) const
int ProgramBindings::getBindingByName(const std::string &name) const
{
auto iter = mBindings.find(name);
return (iter != mBindings.end()) ? iter->second : -1;
return (iter != mBindings.end()) ? iter->second.location : -1;
}
int ProgramBindings::getBinding(const sh::VariableWithLocation &variable) const
{
const std::string &name = variable.name;
// Check with the normalized array name if applicable.
if (variable.isArray())
{
size_t nameLengthWithoutArrayIndex;
unsigned int arrayIndex = ParseArrayIndex(name, &nameLengthWithoutArrayIndex);
if (arrayIndex == 0)
{
std::string baseName = name.substr(0u, nameLengthWithoutArrayIndex);
auto iter = mBindings.find(baseName);
// If "name" exists and is not aliased, that means it was modified more
// recently than its "name[0]" form and should be used instead of that.
if (iter != mBindings.end() && !iter->second.aliased)
{
return iter->second.location;
}
}
}
return getBindingByName(name);
}
ProgramBindings::const_iterator ProgramBindings::begin() const
@ -1152,7 +1199,7 @@ BindingInfo Program::getFragmentInputBindingInfo(GLint index) const
for (const auto &binding : mFragmentInputBindings)
{
if (binding.second != static_cast<GLuint>(index))
if (binding.second.location != static_cast<GLuint>(index))
continue;
ret.valid = true;
@ -1540,6 +1587,7 @@ void Program::unlink()
mState.mAtomicCounterBuffers.clear();
mState.mOutputVariables.clear();
mState.mOutputLocations.clear();
mState.mSecondaryOutputLocations.clear();
mState.mOutputVariableTypes.clear();
mState.mDrawBufferTypeMask.reset();
mState.mActiveOutputVariables.reset();
@ -2930,7 +2978,7 @@ bool Program::linkValidateFragmentInputBindings(gl::InfoLog &infoLog) const
continue;
}
const auto inputBinding = mFragmentInputBindings.getBinding(input.name);
const auto inputBinding = mFragmentInputBindings.getBinding(input);
if (inputBinding == -1)
continue;
@ -3121,7 +3169,7 @@ bool Program::linkAttributes(const Caps &caps, InfoLog &infoLog)
// for each member/element (unlike uniforms for example).
ASSERT(!attribute.isArray() && !attribute.isStruct());
int bindingLocation = mAttributeBindings.getBinding(attribute.name);
int bindingLocation = mAttributeBindings.getBinding(attribute);
if (attribute.location == -1 && bindingLocation != -1)
{
attribute.location = bindingLocation;
@ -3710,7 +3758,7 @@ int Program::getOutputLocationForLink(const sh::OutputVariable &outputVariable)
{
return outputVariable.location;
}
int apiLocation = mFragmentOutputLocations.getBinding(outputVariable.name);
int apiLocation = mFragmentOutputLocations.getBinding(outputVariable);
if (apiLocation != -1)
{
return apiLocation;
@ -3725,7 +3773,7 @@ bool Program::isOutputSecondaryForLink(const sh::OutputVariable &outputVariable)
ASSERT(outputVariable.index == 0 || outputVariable.index == 1);
return (outputVariable.index == 1);
}
int apiIndex = mFragmentOutputIndexes.getBinding(outputVariable.name);
int apiIndex = mFragmentOutputIndexes.getBinding(outputVariable);
if (apiIndex != -1)
{
// Index layout qualifier from the shader takes precedence, so the index from the API is
@ -3737,6 +3785,60 @@ bool Program::isOutputSecondaryForLink(const sh::OutputVariable &outputVariable)
return false;
}
namespace
{
bool FindUsedOutputLocation(std::vector<VariableLocation> &outputLocations,
unsigned int baseLocation,
unsigned int elementCount,
const std::vector<VariableLocation> &reservedLocations,
unsigned int variableIndex)
{
if (baseLocation + elementCount > outputLocations.size())
{
elementCount =
baseLocation < outputLocations.size() ? outputLocations.size() - baseLocation : 0;
}
for (unsigned int elementIndex = 0; elementIndex < elementCount; elementIndex++)
{
const unsigned int location = baseLocation + elementIndex;
if (outputLocations[location].used())
{
VariableLocation locationInfo(elementIndex, variableIndex);
if (std::find(reservedLocations.begin(), reservedLocations.end(), locationInfo) ==
reservedLocations.end())
{
return true;
}
}
}
return false;
}
void AssignOutputLocations(std::vector<VariableLocation> &outputLocations,
unsigned int baseLocation,
unsigned int elementCount,
const std::vector<VariableLocation> &reservedLocations,
unsigned int variableIndex)
{
if (baseLocation + elementCount > outputLocations.size())
{
outputLocations.resize(baseLocation + elementCount);
}
for (unsigned int elementIndex = 0; elementIndex < elementCount; elementIndex++)
{
VariableLocation locationInfo(elementIndex, variableIndex);
if (std::find(reservedLocations.begin(), reservedLocations.end(), locationInfo) ==
reservedLocations.end())
{
const unsigned int location = baseLocation + elementIndex;
outputLocations[location] = locationInfo;
}
}
}
} // anonymous namespace
bool Program::linkOutputVariables(const Caps &caps,
const Extensions &extensions,
const Version &version,
@ -3821,10 +3923,77 @@ bool Program::linkOutputVariables(const Caps &caps,
}
}
bool hasSecondaryOutputs = false;
// EXT_blend_func_extended doesn't specify anything related to binding specific elements of an
// output array in explicit terms.
//
// Assuming fragData is an output array, you can defend the position that:
// P1) you must support binding "fragData" because it's specified
// P2) you must support querying "fragData[x]" because it's specified
// P3) you must support binding "fragData[0]" because it's a frequently used pattern
//
// Then you can make the leap of faith:
// P4) you must support binding "fragData[x]" because you support "fragData[0]"
// P5) you must support binding "fragData[x]" because you support querying "fragData[x]"
//
// The spec brings in the "world of arrays" when it mentions binding the arrays and the
// automatic binding. Thus it must be interpreted that the thing is not undefined, rather you
// must infer the only possible interpretation (?). Note again: this need of interpretation
// might be completely off of what GL spec logic is.
//
// The other complexity is that unless you implement this feature, it's hard to understand what
// should happen when the client invokes the feature. You cannot add an additional error as it
// is not specified. One can ignore it, but obviously it creates the discrepancies...
std::vector<VariableLocation> reservedLocations;
// Process any output API bindings for arrays that don't alias to the first element.
for (const auto &binding : mFragmentOutputLocations)
{
size_t nameLengthWithoutArrayIndex;
unsigned int arrayIndex = ParseArrayIndex(binding.first, &nameLengthWithoutArrayIndex);
if (arrayIndex == 0 || arrayIndex == GL_INVALID_INDEX)
{
continue;
}
for (unsigned int outputVariableIndex = 0;
outputVariableIndex < mState.mOutputVariables.size(); outputVariableIndex++)
{
const sh::OutputVariable &outputVariable = mState.mOutputVariables[outputVariableIndex];
// Check that the binding corresponds to an output array and its array index fits.
if (outputVariable.isBuiltIn() || !outputVariable.isArray() ||
!angle::BeginsWith(outputVariable.name, binding.first,
nameLengthWithoutArrayIndex) ||
arrayIndex >= outputVariable.getOutermostArraySize())
{
continue;
}
// Get the API index that corresponds to this exact binding.
// This index may differ from the index used for the array's base.
auto &outputLocations = mFragmentOutputIndexes.getBindingByName(binding.first) == 1
? mState.mSecondaryOutputLocations
: mState.mOutputLocations;
unsigned int location = binding.second.location;
VariableLocation locationInfo(arrayIndex, outputVariableIndex);
if (location >= outputLocations.size())
{
outputLocations.resize(location + 1);
}
if (outputLocations[location].used())
{
mInfoLog << "Location of variable " << outputVariable.name
<< " conflicts with another variable.";
return false;
}
outputLocations[location] = locationInfo;
// Note the array binding location so that it can be skipped later.
reservedLocations.push_back(locationInfo);
}
}
// Reserve locations for output variables whose location is fixed in the shader or through the
// API.
// API. Otherwise, the remaining unallocated outputs will be processed later.
for (unsigned int outputVariableIndex = 0; outputVariableIndex < mState.mOutputVariables.size();
outputVariableIndex++)
{
@ -3834,51 +4003,30 @@ bool Program::linkOutputVariables(const Caps &caps,
if (outputVariable.isBuiltIn())
continue;
int baseLocation = getOutputLocationForLink(outputVariable);
if (baseLocation == -1)
int fixedLocation = getOutputLocationForLink(outputVariable);
if (fixedLocation == -1)
{
// Here we're only reserving locations for variables whose location is fixed.
continue;
}
unsigned int baseLocation = static_cast<unsigned int>(fixedLocation);
auto *outputLocations = &mState.mOutputLocations;
if (isOutputSecondaryForLink(outputVariable))
{
outputLocations = &mState.mSecondaryOutputLocations;
// Note that this check doesn't need to be before checking baseLocation == -1 above. If
// an output has an index specified it will always also have the location specified.
hasSecondaryOutputs = true;
}
auto &outputLocations = isOutputSecondaryForLink(outputVariable)
? mState.mSecondaryOutputLocations
: mState.mOutputLocations;
// GLSL ES 3.10 section 4.3.6: Output variables cannot be arrays of arrays or arrays of
// structures, so we may use getBasicTypeElementCount().
unsigned int elementCount = outputVariable.getBasicTypeElementCount();
unsigned int outputLocationsNeeded = static_cast<unsigned int>(baseLocation) + elementCount;
if (outputLocationsNeeded > outputLocations->size())
if (FindUsedOutputLocation(outputLocations, baseLocation, elementCount, reservedLocations,
outputVariableIndex))
{
outputLocations->resize(outputLocationsNeeded);
}
for (unsigned int elementIndex = 0; elementIndex < elementCount; elementIndex++)
{
const unsigned int location = static_cast<unsigned int>(baseLocation) + elementIndex;
ASSERT(location < outputLocations->size());
if (outputLocations->at(location).used())
{
mInfoLog << "Location of variable " << outputVariable.name
<< " conflicts with another variable.";
return false;
}
if (outputVariable.isArray())
{
(*outputLocations)[location] = VariableLocation(elementIndex, outputVariableIndex);
}
else
{
VariableLocation locationInfo;
locationInfo.index = outputVariableIndex;
(*outputLocations)[location] = locationInfo;
}
mInfoLog << "Location of variable " << outputVariable.name
<< " conflicts with another variable.";
return false;
}
AssignOutputLocations(outputLocations, baseLocation, elementCount, reservedLocations,
outputVariableIndex);
}
// Here we assign locations for the output variables that don't yet have them. Note that we're
@ -3887,7 +4035,7 @@ bool Program::linkOutputVariables(const Caps &caps,
// we got the output variables. The spec isn't clear on what kind of algorithm is required for
// finding locations for the output variables, so this should be acceptable at least for now.
GLuint maxLocation = caps.maxDrawBuffers;
if (hasSecondaryOutputs)
if (!mState.mSecondaryOutputLocations.empty())
{
// EXT_blend_func_extended: Program outputs will be validated against
// MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT if there's even one output with index one.
@ -3903,74 +4051,46 @@ bool Program::linkOutputVariables(const Caps &caps,
if (outputVariable.isBuiltIn())
continue;
if (getOutputLocationForLink(outputVariable) != -1)
{
continue;
}
auto *outputLocations = &mState.mOutputLocations;
if (isOutputSecondaryForLink(outputVariable))
{
outputLocations = &mState.mSecondaryOutputLocations;
}
int baseLocation = 0;
int fixedLocation = getOutputLocationForLink(outputVariable);
auto &outputLocations = isOutputSecondaryForLink(outputVariable)
? mState.mSecondaryOutputLocations
: mState.mOutputLocations;
unsigned int baseLocation = 0;
unsigned int elementCount = outputVariable.getBasicTypeElementCount();
bool elementsFit = false;
while (!elementsFit)
if (fixedLocation != -1)
{
// Secondary inputs might have caused the max location to drop below what has already
// been explicitly assigned locations. Check for any fixed locations above the max
// that should cause linking to fail.
baseLocation = static_cast<unsigned int>(fixedLocation);
}
else
{
// No fixed location, so try to fit the output in unassigned locations.
// Try baseLocations starting from 0 one at a time and see if the variable fits.
elementsFit = true;
if (baseLocation + elementCount > maxLocation)
while (FindUsedOutputLocation(outputLocations, baseLocation, elementCount,
reservedLocations, outputVariableIndex))
{
// EXT_blend_func_extended: Linking can fail:
// "if the explicit binding assignments do not leave enough space for the linker to
// automatically assign a location for a varying out array, which requires multiple
// contiguous locations."
mInfoLog << "Could not fit output variable into available locations: "
<< outputVariable.name;
return false;
}
unsigned int outputLocationsNeeded =
static_cast<unsigned int>(baseLocation) + elementCount;
if (outputLocationsNeeded > outputLocations->size())
{
outputLocations->resize(outputLocationsNeeded);
}
for (unsigned int elementIndex = 0; elementIndex < elementCount; elementIndex++)
{
const unsigned int location =
static_cast<unsigned int>(baseLocation) + elementIndex;
ASSERT(location < outputLocations->size());
if (outputLocations->at(location).used())
{
elementsFit = false;
break;
}
}
if (elementsFit)
{
for (unsigned int elementIndex = 0; elementIndex < elementCount; elementIndex++)
{
const unsigned int location =
static_cast<unsigned int>(baseLocation) + elementIndex;
if (outputVariable.isArray())
{
(*outputLocations)[location] =
VariableLocation(elementIndex, outputVariableIndex);
}
else
{
VariableLocation locationInfo;
locationInfo.index = outputVariableIndex;
(*outputLocations)[location] = locationInfo;
}
}
}
else
{
++baseLocation;
baseLocation++;
}
AssignOutputLocations(outputLocations, baseLocation, elementCount, reservedLocations,
outputVariableIndex);
}
// Check for any elements assigned above the max location that are actually used.
if (baseLocation + elementCount > maxLocation &&
(baseLocation >= maxLocation ||
FindUsedOutputLocation(outputLocations, maxLocation,
baseLocation + elementCount - maxLocation, reservedLocations,
outputVariableIndex)))
{
// EXT_blend_func_extended: Linking can fail:
// "if the explicit binding assignments do not leave enough space for the linker to
// automatically assign a location for a varying out array, which requires multiple
// contiguous locations."
mInfoLog << "Could not fit output variable into available locations: "
<< outputVariable.name;
return false;
}
}

Просмотреть файл

@ -179,6 +179,11 @@ struct VariableLocation
void markUnused() { index = kUnused; }
void markIgnored() { ignored = true; }
bool operator==(const VariableLocation &other) const
{
return arrayIndex == other.arrayIndex && index == other.index;
}
// "arrayIndex" stores the index of the innermost GLSL array. It's zero for non-arrays.
unsigned int arrayIndex;
// "index" is an index of the variable. The variable contains the indices for other than the
@ -473,6 +478,16 @@ class ProgramState final : angle::NonCopyable
ActiveTextureMask mActiveImagesMask;
};
struct ProgramBinding
{
ProgramBinding() : location(GL_INVALID_INDEX), aliased(false) {}
ProgramBinding(GLuint index) : location(index), aliased(false) {}
GLuint location;
// Whether another binding was set that may potentially alias this.
bool aliased;
};
class ProgramBindings final : angle::NonCopyable
{
public:
@ -480,14 +495,15 @@ class ProgramBindings final : angle::NonCopyable
~ProgramBindings();
void bindLocation(GLuint index, const std::string &name);
int getBinding(const std::string &name) const;
int getBindingByName(const std::string &name) const;
int getBinding(const sh::VariableWithLocation &variable) const;
using const_iterator = std::unordered_map<std::string, GLuint>::const_iterator;
using const_iterator = std::unordered_map<std::string, ProgramBinding>::const_iterator;
const_iterator begin() const;
const_iterator end() const;
private:
std::unordered_map<std::string, GLuint> mBindings;
std::unordered_map<std::string, ProgramBinding> mBindings;
};
struct ProgramVaryingRef

Просмотреть файл

@ -32,20 +32,6 @@ LinkedUniform *FindUniform(std::vector<LinkedUniform> &list, const std::string &
return nullptr;
}
int GetUniformLocationBinding(const ProgramBindings &uniformLocationBindings,
const sh::Uniform &uniform)
{
int binding = uniformLocationBindings.getBinding(uniform.name);
if (uniform.isArray() && binding == -1)
{
// Bindings for array uniforms can be set either with or without [0] in the end.
ASSERT(angle::EndsWith(uniform.name, "[0]"));
std::string nameWithoutIndex = uniform.name.substr(0u, uniform.name.length() - 3u);
return uniformLocationBindings.getBinding(nameWithoutIndex);
}
return binding;
}
template <typename VarT>
void SetActive(std::vector<VarT> *list, const std::string &name, ShaderType shaderType, bool active)
{
@ -664,7 +650,7 @@ bool UniformLinker::indexUniforms(InfoLog &infoLog, const ProgramBindings &unifo
continue;
}
int preSetLocation = GetUniformLocationBinding(uniformLocationBindings, uniform);
int preSetLocation = uniformLocationBindings.getBinding(uniform);
int shaderLocation = uniform.location;
if (shaderLocation != -1)
@ -740,7 +726,7 @@ bool UniformLinker::gatherUniformLocationsAndCheckConflicts(
continue;
}
int apiBoundLocation = GetUniformLocationBinding(uniformLocationBindings, uniform);
int apiBoundLocation = uniformLocationBindings.getBinding(uniform);
int shaderLocation = uniform.location;
if (shaderLocation != -1)
@ -785,7 +771,7 @@ bool UniformLinker::gatherUniformLocationsAndCheckConflicts(
// from the shader. Other uniforms should not be assigned to those locations.
for (const auto &locationBinding : uniformLocationBindings)
{
GLuint location = locationBinding.second;
GLuint location = locationBinding.second.location;
if (reservedLocations.find(location) == reservedLocations.end())
{
ignoredLocations->insert(location);

Просмотреть файл

@ -97,13 +97,14 @@ void HLSLTypeString(std::ostringstream &ostream, GLenum type)
const PixelShaderOutputVariable *FindOutputAtLocation(
const std::vector<PixelShaderOutputVariable> &outputVariables,
unsigned int location)
unsigned int location,
size_t index = 0)
{
for (size_t variableIndex = 0; variableIndex < outputVariables.size(); ++variableIndex)
for (auto &outputVar : outputVariables)
{
if (outputVariables[variableIndex].outputIndex == location)
if (outputVar.outputLocation == location && outputVar.outputIndex == index)
{
return &outputVariables[variableIndex];
return &outputVar;
}
}
@ -294,7 +295,9 @@ std::string DynamicHLSL::generatePixelShaderForOutputSignature(
{
numOutputs = 1u;
}
const PixelShaderOutputVariable defaultOutput(GL_FLOAT_VEC4, "dummy", "float4(0, 0, 0, 1)", 0);
const PixelShaderOutputVariable defaultOutput(GL_FLOAT_VEC4, "dummy", "float4(0, 0, 0, 1)", 0,
0);
size_t outputIndex = 0;
for (size_t layoutIndex = 0; layoutIndex < numOutputs; ++layoutIndex)
{
@ -303,15 +306,16 @@ std::string DynamicHLSL::generatePixelShaderForOutputSignature(
if (binding != GL_NONE)
{
unsigned int location = (binding - GL_COLOR_ATTACHMENT0);
outputIndex =
layoutIndex > 0 && binding == outputLayout[layoutIndex - 1] ? outputIndex + 1 : 0;
const PixelShaderOutputVariable *outputVariable =
outputLayout.empty() ? &defaultOutput
: FindOutputAtLocation(outputVariables, location);
: FindOutputAtLocation(outputVariables, location, outputIndex);
// OpenGL ES 3.0 spec $4.2.1
// If [...] not all user-defined output variables are written, the values of fragment
// colors
// corresponding to unwritten variables are similarly undefined.
// colors corresponding to unwritten variables are similarly undefined.
if (outputVariable)
{
declarationStream << " ";
@ -1204,10 +1208,26 @@ void DynamicHLSL::getPixelShaderOutputKey(const gl::State &data,
outputKeyVariable.name = "gl_Color" + Str(renderTargetIndex);
outputKeyVariable.source =
broadcast ? "gl_Color[0]" : "gl_Color[" + Str(renderTargetIndex) + "]";
outputKeyVariable.outputIndex = renderTargetIndex;
outputKeyVariable.outputLocation = renderTargetIndex;
outPixelShaderKey->push_back(outputKeyVariable);
}
if (metadata.usesSecondaryColor())
{
for (unsigned int secondaryIndex = 0;
secondaryIndex < data.getExtensions().maxDualSourceDrawBuffers; secondaryIndex++)
{
PixelShaderOutputVariable outputKeyVariable;
outputKeyVariable.type = GL_FLOAT_VEC4;
outputKeyVariable.name = "gl_SecondaryColor" + Str(secondaryIndex);
outputKeyVariable.source = "gl_SecondaryColor[" + Str(secondaryIndex) + "]";
outputKeyVariable.outputLocation = secondaryIndex;
outputKeyVariable.outputIndex = 1;
outPixelShaderKey->push_back(outputKeyVariable);
}
}
}
else
{
@ -1238,7 +1258,39 @@ void DynamicHLSL::getPixelShaderOutputKey(const gl::State &data,
outputKeyVariable.source =
variableName +
(outputVariable.isArray() ? ArrayString(outputLocation.arrayIndex) : "");
outputKeyVariable.outputIndex = outputLocationIndex;
outputKeyVariable.outputLocation = outputLocationIndex;
outPixelShaderKey->push_back(outputKeyVariable);
}
// Now generate any secondary outputs...
for (size_t outputLocationIndex = 0u;
outputLocationIndex < programData.getSecondaryOutputLocations().size();
++outputLocationIndex)
{
const VariableLocation &outputLocation =
programData.getSecondaryOutputLocations().at(outputLocationIndex);
if (!outputLocation.used())
{
continue;
}
const sh::ShaderVariable &outputVariable = shaderOutputVars[outputLocation.index];
const std::string &variableName = "out_" + outputVariable.name;
// Fragment outputs can't be arrays of arrays. ESSL 3.10 section 4.3.6.
const std::string &elementString =
(outputVariable.isArray() ? Str(outputLocation.arrayIndex) : "");
ASSERT(outputVariable.active);
PixelShaderOutputVariable outputKeyVariable;
outputKeyVariable.type = outputVariable.type;
outputKeyVariable.name = variableName + elementString;
outputKeyVariable.source =
variableName +
(outputVariable.isArray() ? ArrayString(outputLocation.arrayIndex) : "");
outputKeyVariable.outputLocation = outputLocationIndex;
outputKeyVariable.outputIndex = 1;
outPixelShaderKey->push_back(outputKeyVariable);
}

Просмотреть файл

@ -67,13 +67,19 @@ struct PixelShaderOutputVariable
PixelShaderOutputVariable(GLenum typeIn,
const std::string &nameIn,
const std::string &sourceIn,
size_t outputLocationIn,
size_t outputIndexIn)
: type(typeIn), name(nameIn), source(sourceIn), outputIndex(outputIndexIn)
: type(typeIn),
name(nameIn),
source(sourceIn),
outputLocation(outputLocationIn),
outputIndex(outputIndexIn)
{}
GLenum type = GL_NONE;
std::string name;
std::string source;
size_t outputLocation = 0;
size_t outputIndex = 0;
};

Просмотреть файл

@ -67,6 +67,20 @@ void GetDefaultInputLayoutFromShader(gl::Shader *vertexShader, gl::InputLayout *
}
}
size_t GetMaxOutputIndex(const std::vector<PixelShaderOutputVariable> &shaderOutputVars,
size_t location)
{
size_t maxIndex = 0;
for (auto &outputVar : shaderOutputVars)
{
if (outputVar.outputLocation == location)
{
maxIndex = std::max(maxIndex, outputVar.outputIndex);
}
}
return maxIndex;
}
void GetDefaultOutputLayoutFromShader(
const std::vector<PixelShaderOutputVariable> &shaderOutputVars,
std::vector<GLenum> *outputLayoutOut)
@ -75,8 +89,10 @@ void GetDefaultOutputLayoutFromShader(
if (!shaderOutputVars.empty())
{
outputLayoutOut->push_back(GL_COLOR_ATTACHMENT0 +
static_cast<unsigned int>(shaderOutputVars[0].outputIndex));
size_t location = shaderOutputVars[0].outputLocation;
size_t maxIndex = GetMaxOutputIndex(shaderOutputVars, location);
outputLayoutOut->assign(maxIndex + 1,
GL_COLOR_ATTACHMENT0 + static_cast<unsigned int>(location));
}
}
@ -477,6 +493,11 @@ bool ProgramD3DMetadata::usesBroadcast(const gl::State &data) const
data.getClientMajorVersion() < 3);
}
bool ProgramD3DMetadata::usesSecondaryColor() const
{
return mAttachedShaders[gl::ShaderType::Fragment]->usesSecondaryColor();
}
bool ProgramD3DMetadata::usesFragDepth() const
{
return mAttachedShaders[gl::ShaderType::Fragment]->usesFragDepth();
@ -1166,6 +1187,7 @@ std::unique_ptr<rx::LinkEvent> ProgramD3D::load(const gl::Context *context,
stream->readInt(&mPixelShaderKey[pixelShaderKeyIndex].type);
stream->readString(&mPixelShaderKey[pixelShaderKeyIndex].name);
stream->readString(&mPixelShaderKey[pixelShaderKeyIndex].source);
stream->readInt(&mPixelShaderKey[pixelShaderKeyIndex].outputLocation);
stream->readInt(&mPixelShaderKey[pixelShaderKeyIndex].outputIndex);
}
@ -1449,6 +1471,7 @@ void ProgramD3D::save(const gl::Context *context, gl::BinaryOutputStream *stream
stream->writeInt(variable.type);
stream->writeString(variable.name);
stream->writeString(variable.source);
stream->writeInt(variable.outputLocation);
stream->writeInt(variable.outputIndex);
}
@ -3048,7 +3071,11 @@ void ProgramD3D::updateCachedOutputLayout(const gl::Context *context,
{
auto binding = colorbuffer->getBinding() == GL_BACK ? GL_COLOR_ATTACHMENT0
: colorbuffer->getBinding();
mPixelShaderOutputLayoutCache.push_back(binding);
size_t maxIndex = binding != GL_NONE ? GetMaxOutputIndex(mPixelShaderKey,
binding - GL_COLOR_ATTACHMENT0)
: 0;
mPixelShaderOutputLayoutCache.insert(mPixelShaderOutputLayoutCache.end(), maxIndex + 1,
binding);
}
else
{

Просмотреть файл

@ -122,6 +122,7 @@ class ProgramD3DMetadata final : angle::NonCopyable
int getRendererMajorShaderModel() const;
bool usesBroadcast(const gl::State &data) const;
bool usesSecondaryColor() const;
bool usesFragDepth() const;
bool usesPointCoord() const;
bool usesFragCoord() const;

Просмотреть файл

@ -150,6 +150,7 @@ void ShaderD3D::uncompile()
mUsesMultipleRenderTargets = false;
mUsesFragColor = false;
mUsesFragData = false;
mUsesSecondaryColor = false;
mUsesFragCoord = false;
mUsesFrontFacing = false;
mUsesPointSize = false;
@ -272,6 +273,7 @@ std::shared_ptr<WaitableCompileEvent> ShaderD3D::compile(const gl::Context *cont
mUsesMultipleRenderTargets = translatedSource.find("GL_USES_MRT") != std::string::npos;
mUsesFragColor = translatedSource.find("GL_USES_FRAG_COLOR") != std::string::npos;
mUsesFragData = translatedSource.find("GL_USES_FRAG_DATA") != std::string::npos;
mUsesSecondaryColor = translatedSource.find("GL_USES_SECONDARY_COLOR") != std::string::npos;
mUsesFragCoord = translatedSource.find("GL_USES_FRAG_COORD") != std::string::npos;
mUsesFrontFacing = translatedSource.find("GL_USES_FRONT_FACING") != std::string::npos;
mUsesPointSize = translatedSource.find("GL_USES_POINT_SIZE") != std::string::npos;

Просмотреть файл

@ -65,6 +65,7 @@ class ShaderD3D : public ShaderImpl
bool usesMultipleRenderTargets() const { return mUsesMultipleRenderTargets; }
bool usesFragColor() const { return mUsesFragColor; }
bool usesFragData() const { return mUsesFragData; }
bool usesSecondaryColor() const { return mUsesSecondaryColor; }
bool usesFragCoord() const { return mUsesFragCoord; }
bool usesFrontFacing() const { return mUsesFrontFacing; }
bool usesPointSize() const { return mUsesPointSize; }
@ -81,6 +82,7 @@ class ShaderD3D : public ShaderImpl
bool mUsesMultipleRenderTargets;
bool mUsesFragColor;
bool mUsesFragData;
bool mUsesSecondaryColor;
bool mUsesFragCoord;
bool mUsesFrontFacing;
bool mUsesPointSize;

Просмотреть файл

@ -1649,6 +1649,8 @@ void GenerateCaps(ID3D11Device *device,
extensions->textureBorderClamp = true;
extensions->textureMultisample = true;
extensions->provokingVertex = true;
extensions->blendFuncExtended = true;
extensions->maxDualSourceDrawBuffers = 1;
// D3D11 Feature Level 10_0+ uses SV_IsFrontFace in HLSL to emulate gl_FrontFacing.
// D3D11 Feature Level 9_3 doesn't support SV_IsFrontFace, and has no equivalent, so can't
@ -1751,6 +1753,18 @@ D3D11_BLEND ConvertBlendFunc(GLenum glBlend, bool isAlpha)
case GL_SRC_ALPHA_SATURATE:
d3dBlend = D3D11_BLEND_SRC_ALPHA_SAT;
break;
case GL_SRC1_COLOR_EXT:
d3dBlend = (isAlpha ? D3D11_BLEND_SRC1_ALPHA : D3D11_BLEND_SRC1_COLOR);
break;
case GL_SRC1_ALPHA_EXT:
d3dBlend = D3D11_BLEND_SRC1_ALPHA;
break;
case GL_ONE_MINUS_SRC1_COLOR_EXT:
d3dBlend = (isAlpha ? D3D11_BLEND_INV_SRC1_ALPHA : D3D11_BLEND_INV_SRC1_COLOR);
break;
case GL_ONE_MINUS_SRC1_ALPHA_EXT:
d3dBlend = D3D11_BLEND_INV_SRC1_ALPHA;
break;
default:
UNREACHABLE();
}