Make output variables part of Program's shared data.
Also initialize this structure within Program instead of DynamicHLSL.
This should have benefits for other back-ends. Also these variables
weren't being serialized and de-serialized with the program binary,
which could mess up WebGL apps that use MRT.
BUG=angleproject:1123
Change-Id: Ic0dd4840f26441a1bee8527dfa178b24daf82f8a
Reviewed-on: https://chromium-review.googlesource.com/294571
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Tested-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/Program.cpp b/src/libANGLE/Program.cpp
index 44e2e67..ff67dc1 100644
--- a/src/libANGLE/Program.cpp
+++ b/src/libANGLE/Program.cpp
@@ -11,6 +11,7 @@
#include <algorithm>
+#include "common/BitSetIterator.h"
#include "common/debug.h"
#include "common/platform.h"
#include "common/utilities.h"
@@ -309,8 +310,10 @@
return Error(GL_NO_ERROR);
}
- rx::LinkResult result = mProgram->link(data, mInfoLog, mData.mAttachedFragmentShader,
- mData.mAttachedVertexShader, &mOutputVariables);
+ linkOutputVariables();
+
+ rx::LinkResult result =
+ mProgram->link(data, mInfoLog, mData.mAttachedFragmentShader, mData.mAttachedVertexShader);
if (result.error.isError() || !result.linkSuccess)
{
@@ -357,6 +360,7 @@
mData.mAttributes.clear();
mData.mActiveAttribLocationsMask.reset();
mData.mTransformFeedbackVaryingVars.clear();
+ mData.mOutputVariables.clear();
mProgram->reset();
@@ -424,6 +428,17 @@
stream.readInt(&mData.mTransformFeedbackBufferMode);
+ unsigned int outputVarCount = stream.readInt<unsigned int>();
+ for (unsigned int outputIndex = 0; outputIndex < outputVarCount; ++outputIndex)
+ {
+ int locationIndex = stream.readInt<int>();
+ VariableLocation locationData;
+ locationData.element = stream.readInt<unsigned int>();
+ locationData.index = stream.readInt<unsigned int>();
+ locationData.name = stream.readString();
+ mData.mOutputVariables[locationIndex] = locationData;
+ }
+
rx::LinkResult result = mProgram->load(mInfoLog, &stream);
if (result.error.isError() || !result.linkSuccess)
{
@@ -464,6 +479,15 @@
stream.writeInt(mData.mTransformFeedbackBufferMode);
+ stream.writeInt(mData.mOutputVariables.size());
+ for (const auto &outputPair : mData.mOutputVariables)
+ {
+ stream.writeInt(outputPair.first);
+ stream.writeInt(outputPair.second.element);
+ stream.writeInt(outputPair.second.index);
+ stream.writeString(outputPair.second.name);
+ }
+
gl::Error error = mProgram->save(&stream);
if (error.isError())
{
@@ -692,7 +716,7 @@
{
std::string baseName(name);
unsigned int arrayIndex = ParseAndStripArrayIndex(&baseName);
- for (auto outputPair : mOutputVariables)
+ for (auto outputPair : mData.mOutputVariables)
{
const VariableLocation &outputVariable = outputPair.second;
if (outputVariable.name == baseName && (arrayIndex == GL_INVALID_INDEX || arrayIndex == outputVariable.element))
@@ -1663,4 +1687,43 @@
return varyings;
}
+
+void Program::linkOutputVariables()
+{
+ const Shader *fragmentShader = mData.mAttachedFragmentShader;
+ ASSERT(fragmentShader != nullptr);
+
+ // Skip this step for GLES2 shaders.
+ if (fragmentShader->getShaderVersion() == 100)
+ return;
+
+ const std::vector<sh::Attribute> &shaderOutputVars = fragmentShader->getActiveOutputVariables();
+
+ // TODO(jmadill): any caps validation here?
+
+ for (unsigned int outputVariableIndex = 0; outputVariableIndex < shaderOutputVars.size();
+ outputVariableIndex++)
+ {
+ const sh::Attribute &outputVariable = shaderOutputVars[outputVariableIndex];
+
+ // Don't store outputs for gl_FragDepth, gl_FragColor, etc.
+ if (outputVariable.isBuiltIn())
+ continue;
+
+ // Since multiple output locations must be specified, use 0 for non-specified locations.
+ int baseLocation = (outputVariable.location == -1 ? 0 : outputVariable.location);
+
+ ASSERT(outputVariable.staticUse);
+
+ for (unsigned int elementIndex = 0; elementIndex < outputVariable.elementCount();
+ elementIndex++)
+ {
+ const int location = baseLocation + elementIndex;
+ ASSERT(mData.mOutputVariables.count(location) == 0);
+ unsigned int element = outputVariable.isArray() ? elementIndex : GL_INVALID_INDEX;
+ mData.mOutputVariables[location] =
+ VariableLocation(outputVariable.name, element, outputVariableIndex);
+ }
+ }
+}
}