Refactor program pipeline handling.

In preparation for moving more code from gl::Program to
gl::ProgramExecutable so it can be shared with ProgramPipeline.

Bug: angleproject:6566
Change-Id: Icb7ecccb37ae8e0d7d5fef8968f0dd7ef6fe6150
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3226305
Reviewed-by: Tim Van Patten <timvp@google.com>
Reviewed-by: Cody Northrop <cnorthrop@google.com>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
This commit is contained in:
Jamie Madill 2021-10-18 10:44:38 -04:00 коммит произвёл Angle LUCI CQ
Родитель 577cfeff92
Коммит 3a9f18f135
23 изменённых файлов: 566 добавлений и 610 удалений

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

@ -281,7 +281,8 @@ enum SubjectIndexes : angle::SubjectIndex
kSamplerMaxSubjectIndex = kSampler0SubjectIndex + IMPLEMENTATION_MAX_ACTIVE_TEXTURES,
kVertexArraySubjectIndex = kSamplerMaxSubjectIndex,
kReadFramebufferSubjectIndex,
kDrawFramebufferSubjectIndex
kDrawFramebufferSubjectIndex,
kProgramPipelineSubjectIndex,
};
bool IsClearBufferEnabled(const FramebufferState &fbState, GLenum buffer, GLint drawbuffer)
@ -316,7 +317,6 @@ bool GetSaveAndRestoreState(const egl::AttributeMap &attribs)
{
return (attribs.get(EGL_EXTERNAL_CONTEXT_SAVE_STATE_ANGLE, EGL_FALSE) == EGL_TRUE);
}
} // anonymous namespace
#if defined(ANGLE_PLATFORM_APPLE)
@ -400,6 +400,7 @@ Context::Context(egl::Display *display,
mVertexArrayObserverBinding(this, kVertexArraySubjectIndex),
mDrawFramebufferObserverBinding(this, kDrawFramebufferSubjectIndex),
mReadFramebufferObserverBinding(this, kReadFramebufferSubjectIndex),
mProgramPipelineObserverBinding(this, kProgramPipelineSubjectIndex),
mThreadPool(nullptr),
mFrameCapture(new angle::FrameCapture),
mRefCount(0),
@ -1293,8 +1294,7 @@ void Context::useProgramStages(ProgramPipelineID pipeline,
pipeline);
ASSERT(programPipeline);
ANGLE_CONTEXT_TRY(mState.useProgramStages(this, programPipeline, stages, shaderProgram));
mStateCache.onProgramExecutableChange(this);
ANGLE_CONTEXT_TRY(programPipeline->useProgramStages(this, stages, shaderProgram));
}
void Context::bindTransformFeedback(GLenum target, TransformFeedbackID transformFeedbackHandle)
@ -1310,7 +1310,12 @@ void Context::bindProgramPipeline(ProgramPipelineID pipelineHandle)
ProgramPipeline *pipeline = mState.mProgramPipelineManager->checkProgramPipelineAllocation(
mImplementation.get(), pipelineHandle);
ANGLE_CONTEXT_TRY(mState.setProgramPipelineBinding(this, pipeline));
if (pipeline && pipeline->isLinked())
{
ANGLE_CONTEXT_TRY(mState.onProgramPipelineExecutableChange(this));
}
mStateCache.onProgramExecutableChange(this);
mProgramPipelineObserverBinding.bind(pipeline);
}
void Context::beginQuery(QueryType target, QueryID query)
@ -8924,6 +8929,22 @@ void Context::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMess
}
break;
case kProgramPipelineSubjectIndex:
switch (message)
{
case angle::SubjectMessage::SubjectChanged:
ANGLE_CONTEXT_TRY(mState.onProgramPipelineExecutableChange(this));
mStateCache.onProgramExecutableChange(this);
break;
case angle::SubjectMessage::ProgramRelinked:
ANGLE_CONTEXT_TRY(mState.mProgramPipeline->link(this));
break;
default:
UNREACHABLE();
break;
}
break;
default:
if (index < kTextureMaxSubjectIndex)
{

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

@ -775,6 +775,7 @@ class Context final : public egl::LabeledObject, angle::NonCopyable, public angl
angle::ObserverBinding mVertexArrayObserverBinding;
angle::ObserverBinding mDrawFramebufferObserverBinding;
angle::ObserverBinding mReadFramebufferObserverBinding;
angle::ObserverBinding mProgramPipelineObserverBinding;
std::vector<angle::ObserverBinding> mUniformBufferObserverBindings;
std::vector<angle::ObserverBinding> mAtomicCounterBufferObserverBindings;
std::vector<angle::ObserverBinding> mShaderStorageBufferObserverBindings;

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

@ -1222,7 +1222,6 @@ ProgramState::ProgramState()
mAttachedShaders{},
mLocationsUsedForXfbExtension(0),
mAtomicCounterUniformRange(0, 0),
mYUVOutput(false),
mBinaryRetrieveableHint(false),
mSeparable(false),
mNumViews(-1),
@ -1631,13 +1630,6 @@ angle::Result Program::linkImpl(const Context *context)
return angle::Result::Continue;
}
if (!linkOutputVariables(context->getCaps(), context->getExtensions(),
context->getClientVersion(), combinedImageUniforms,
combinedShaderStorageBlocks))
{
return angle::Result::Continue;
}
gl::Shader *vertexShader = mState.mAttachedShaders[ShaderType::Vertex];
if (vertexShader)
{
@ -1648,6 +1640,15 @@ angle::Result Program::linkImpl(const Context *context)
gl::Shader *fragmentShader = mState.mAttachedShaders[ShaderType::Fragment];
if (fragmentShader)
{
if (!mState.mExecutable->linkValidateOutputVariables(
context->getCaps(), context->getExtensions(), context->getClientVersion(),
combinedImageUniforms, combinedShaderStorageBlocks,
fragmentShader->getActiveOutputVariables(), fragmentShader->getShaderVersion(),
mFragmentOutputLocations, mFragmentOutputIndexes))
{
return angle::Result::Continue;
}
mState.mEarlyFramentTestsOptimization =
fragmentShader->hasEarlyFragmentTestsOptimization();
mState.mSpecConstUsageBits |= fragmentShader->getSpecConstUsageBits();
@ -1838,10 +1839,6 @@ void Program::unlink()
mState.mUniformLocations.clear();
mState.mBufferVariables.clear();
mState.mOutputVariableTypes.clear();
mState.mDrawBufferTypeMask.reset();
mState.mYUVOutput = false;
mState.mActiveOutputVariables.reset();
mState.mComputeShaderLocalSize.fill(1);
mState.mNumViews = -1;
mState.mDrawIDLocation = -1;
@ -2326,12 +2323,6 @@ size_t Program::getOutputResourceCount() const
return (mLinked ? mState.mExecutable->getOutputVariables().size() : 0);
}
const std::vector<GLenum> &Program::getOutputVariableTypes() const
{
ASSERT(!mLinkingState);
return mState.mOutputVariableTypes;
}
void Program::getResourceName(const std::string name,
GLsizei bufSize,
GLsizei *length,
@ -2453,12 +2444,6 @@ const gl::ProgramAliasedBindings &Program::getFragmentOutputIndexes() const
return mFragmentOutputIndexes;
}
ComponentTypeMask Program::getDrawBufferTypeMask() const
{
ASSERT(!mLinkingState);
return mState.mDrawBufferTypeMask;
}
const std::vector<GLsizei> &Program::getTransformFeedbackStrides() const
{
ASSERT(!mLinkingState);
@ -3999,367 +3984,6 @@ bool Program::linkInterfaceBlocks(const Caps &caps,
return true;
}
int Program::getOutputLocationForLink(const sh::ShaderVariable &outputVariable) const
{
if (outputVariable.location != -1)
{
return outputVariable.location;
}
int apiLocation = mFragmentOutputLocations.getBinding(outputVariable);
if (apiLocation != -1)
{
return apiLocation;
}
return -1;
}
bool Program::isOutputSecondaryForLink(const sh::ShaderVariable &outputVariable) const
{
if (outputVariable.index != -1)
{
ASSERT(outputVariable.index == 0 || outputVariable.index == 1);
return (outputVariable.index == 1);
}
int apiIndex = mFragmentOutputIndexes.getBinding(outputVariable);
if (apiIndex != -1)
{
// Index layout qualifier from the shader takes precedence, so the index from the API is
// checked only if the index was not set in the shader. This is not specified in the EXT
// spec, but is specified in desktop OpenGL specs.
return (apiIndex == 1);
}
// EXT_blend_func_extended: Outputs get index 0 by default.
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()
? static_cast<unsigned int>(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,
sh::ShaderVariable &outputVariable)
{
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())
{
outputVariable.location = baseLocation;
const unsigned int location = baseLocation + elementIndex;
outputLocations[location] = locationInfo;
}
}
}
} // anonymous namespace
bool Program::linkOutputVariables(const Caps &caps,
const Extensions &extensions,
const Version &version,
GLuint combinedImageUniformsCount,
GLuint combinedShaderStorageBlocksCount)
{
InfoLog &infoLog = mState.mExecutable->getInfoLog();
Shader *fragmentShader = mState.mAttachedShaders[ShaderType::Fragment];
ASSERT(mState.mOutputVariableTypes.empty());
ASSERT(mState.mActiveOutputVariables.none());
ASSERT(mState.mDrawBufferTypeMask.none());
ASSERT(!mState.mYUVOutput);
if (!fragmentShader)
{
// No fragment shader, so nothing to link
return true;
}
const std::vector<sh::ShaderVariable> &outputVariables =
fragmentShader->getActiveOutputVariables();
// Gather output variable types
for (const sh::ShaderVariable &outputVariable : outputVariables)
{
if (outputVariable.isBuiltIn() && outputVariable.name != "gl_FragColor" &&
outputVariable.name != "gl_FragData")
{
continue;
}
unsigned int baseLocation =
(outputVariable.location == -1 ? 0u
: static_cast<unsigned int>(outputVariable.location));
// 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();
for (unsigned int elementIndex = 0; elementIndex < elementCount; elementIndex++)
{
const unsigned int location = baseLocation + elementIndex;
if (location >= mState.mOutputVariableTypes.size())
{
mState.mOutputVariableTypes.resize(location + 1, GL_NONE);
}
ASSERT(location < mState.mActiveOutputVariables.size());
mState.mActiveOutputVariables.set(location);
mState.mOutputVariableTypes[location] = VariableComponentType(outputVariable.type);
ComponentType componentType =
GLenumToComponentType(mState.mOutputVariableTypes[location]);
SetComponentTypeMask(componentType, location, &mState.mDrawBufferTypeMask);
}
if (outputVariable.yuv)
{
ASSERT(outputVariables.size() == 1);
mState.mYUVOutput = true;
}
}
if (version >= ES_3_1)
{
// [OpenGL ES 3.1] Chapter 8.22 Page 203:
// A link error will be generated if the sum of the number of active image uniforms used in
// all shaders, the number of active shader storage blocks, and the number of active
// fragment shader outputs exceeds the implementation-dependent value of
// MAX_COMBINED_SHADER_OUTPUT_RESOURCES.
if (combinedImageUniformsCount + combinedShaderStorageBlocksCount +
mState.mActiveOutputVariables.count() >
static_cast<GLuint>(caps.maxCombinedShaderOutputResources))
{
infoLog
<< "The sum of the number of active image uniforms, active shader storage blocks "
"and active fragment shader outputs exceeds "
"MAX_COMBINED_SHADER_OUTPUT_RESOURCES ("
<< caps.maxCombinedShaderOutputResources << ")";
return false;
}
}
// Skip this step for GLES2 shaders.
if (fragmentShader && fragmentShader->getShaderVersion() == 100)
return true;
mState.mExecutable->mOutputVariables = outputVariables;
mState.mExecutable->mYUVOutput = mState.mYUVOutput;
// TODO(jmadill): any caps validation here?
// 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.mExecutable->getOutputVariables().size();
outputVariableIndex++)
{
const sh::ShaderVariable &outputVariable =
mState.mExecutable->getOutputVariables()[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.mExecutable->mSecondaryOutputLocations
: mState.mExecutable->mOutputLocations;
unsigned int location = binding.second.location;
VariableLocation locationInfo(arrayIndex, outputVariableIndex);
if (location >= outputLocations.size())
{
outputLocations.resize(location + 1);
}
if (outputLocations[location].used())
{
infoLog << "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. Otherwise, the remaining unallocated outputs will be processed later.
for (unsigned int outputVariableIndex = 0;
outputVariableIndex < mState.mExecutable->getOutputVariables().size();
outputVariableIndex++)
{
const sh::ShaderVariable &outputVariable =
mState.mExecutable->getOutputVariables()[outputVariableIndex];
// Don't store outputs for gl_FragDepth, gl_FragColor, etc.
if (outputVariable.isBuiltIn())
continue;
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 = isOutputSecondaryForLink(outputVariable)
? mState.mExecutable->mSecondaryOutputLocations
: mState.mExecutable->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();
if (FindUsedOutputLocation(outputLocations, baseLocation, elementCount, reservedLocations,
outputVariableIndex))
{
infoLog << "Location of variable " << outputVariable.name
<< " conflicts with another variable.";
return false;
}
AssignOutputLocations(outputLocations, baseLocation, elementCount, reservedLocations,
outputVariableIndex,
mState.mExecutable->mOutputVariables[outputVariableIndex]);
}
// Here we assign locations for the output variables that don't yet have them. Note that we're
// not necessarily able to fit the variables optimally, since then we might have to try
// different arrangements of output arrays. Now we just assign the locations in the order that
// 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 = static_cast<GLuint>(caps.maxDrawBuffers);
if (!mState.mExecutable->getSecondaryOutputLocations().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.
maxLocation = caps.maxDualSourceDrawBuffers;
}
for (unsigned int outputVariableIndex = 0;
outputVariableIndex < mState.mExecutable->getOutputVariables().size();
outputVariableIndex++)
{
const sh::ShaderVariable &outputVariable =
mState.mExecutable->getOutputVariables()[outputVariableIndex];
// Don't store outputs for gl_FragDepth, gl_FragColor, etc.
if (outputVariable.isBuiltIn())
continue;
int fixedLocation = getOutputLocationForLink(outputVariable);
auto &outputLocations = isOutputSecondaryForLink(outputVariable)
? mState.mExecutable->mSecondaryOutputLocations
: mState.mExecutable->mOutputLocations;
unsigned int baseLocation = 0;
unsigned int elementCount = outputVariable.getBasicTypeElementCount();
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.
while (FindUsedOutputLocation(outputLocations, baseLocation, elementCount,
reservedLocations, outputVariableIndex))
{
baseLocation++;
}
AssignOutputLocations(outputLocations, baseLocation, elementCount, reservedLocations,
outputVariableIndex,
mState.mExecutable->mOutputVariables[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."
infoLog << "Could not fit output variable into available locations: "
<< outputVariable.name;
return false;
}
}
return true;
}
void Program::setUniformValuesFromBindingQualifiers()
{
for (unsigned int samplerIndex : mState.mExecutable->getSamplerUniformRange())
@ -4670,20 +4294,6 @@ angle::Result Program::serialize(const Context *context, angle::MemoryBuffer *bi
"driver.";
}
stream.writeInt(mState.mOutputVariableTypes.size());
for (const auto &outputVariableType : mState.mOutputVariableTypes)
{
stream.writeInt(outputVariableType);
}
static_assert(
IMPLEMENTATION_MAX_DRAW_BUFFERS * 2 <= 8 * sizeof(uint32_t),
"All bits of mDrawBufferTypeMask and mActiveOutputVariables can be contained in 32 bits");
stream.writeInt(static_cast<int>(mState.mDrawBufferTypeMask.to_ulong()));
stream.writeInt(static_cast<int>(mState.mActiveOutputVariables.to_ulong()));
stream.writeBool(mState.isYUVOutput());
stream.writeInt(mState.getAtomicCounterUniformRange().low());
stream.writeInt(mState.getAtomicCounterUniformRange().high());
@ -4778,21 +4388,6 @@ angle::Result Program::deserialize(const Context *context,
mState.mBufferVariables.push_back(bufferVariable);
}
size_t outputTypeCount = stream.readInt<size_t>();
for (size_t outputIndex = 0; outputIndex < outputTypeCount; ++outputIndex)
{
mState.mOutputVariableTypes.push_back(stream.readInt<GLenum>());
}
static_assert(IMPLEMENTATION_MAX_DRAW_BUFFERS * 2 <= 8 * sizeof(uint32_t),
"All bits of mDrawBufferTypeMask and mActiveOutputVariables types and mask fit "
"into 32 bits each");
mState.mDrawBufferTypeMask = gl::ComponentTypeMask(stream.readInt<uint32_t>());
mState.mActiveOutputVariables =
gl::DrawBufferMask(stream.readInt<gl::DrawBufferMask::value_type>());
stream.readBool(&mState.mYUVOutput);
unsigned int atomicCounterRangeLow = stream.readInt<unsigned int>();
unsigned int atomicCounterRangeHigh = stream.readInt<unsigned int>();
mState.mAtomicCounterUniformRange = RangeUI(atomicCounterRangeLow, atomicCounterRangeHigh);

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

@ -252,7 +252,6 @@ class ProgramState final : angle::NonCopyable
{
return mExecutable->getProgramInputs();
}
DrawBufferMask getActiveOutputVariables() const { return mActiveOutputVariables; }
const std::vector<sh::ShaderVariable> &getOutputVariables() const
{
return mExecutable->getOutputVariables();
@ -352,12 +351,6 @@ class ProgramState final : angle::NonCopyable
uint32_t getLocationsUsedForXfbExtension() const { return mLocationsUsedForXfbExtension; }
const std::vector<GLenum> &getOutputVariableTypes() const { return mOutputVariableTypes; }
ComponentTypeMask getDrawBufferTypeMask() const { return mDrawBufferTypeMask; }
bool isYUVOutput() const { return mYUVOutput; }
bool hasBinaryRetrieveableHint() const { return mBinaryRetrieveableHint; }
bool isSeparable() const { return mSeparable; }
@ -394,16 +387,6 @@ class ProgramState final : angle::NonCopyable
std::vector<BufferVariable> mBufferVariables;
RangeUI mAtomicCounterUniformRange;
DrawBufferMask mActiveOutputVariables;
// Fragment output variable base types: FLOAT, INT, or UINT. Ordered by location.
std::vector<GLenum> mOutputVariableTypes;
ComponentTypeMask mDrawBufferTypeMask;
// GL_EXT_YUV_target. YUV output shaders can only have one ouput and can only write to YUV
// framebuffers.
bool mYUVOutput;
bool mBinaryRetrieveableHint;
bool mSeparable;
bool mEarlyFramentTestsOptimization;
@ -479,7 +462,7 @@ class Program final : public LabeledObject, public angle::Subject
void bindFragmentOutputIndex(GLuint index, const char *name);
// KHR_parallel_shader_compile
// Try to link the program asynchrously. As a result, background threads may be launched to
// Try to link the program asynchronously. As a result, background threads may be launched to
// execute the linking tasks concurrently.
angle::Result link(const Context *context);
@ -525,12 +508,6 @@ class Program final : public LabeledObject, public angle::Subject
GLint getFragDataLocation(const std::string &name) const;
size_t getOutputResourceCount() const;
const std::vector<GLenum> &getOutputVariableTypes() const;
DrawBufferMask getActiveOutputVariables() const
{
ASSERT(!mLinkingState);
return mState.mActiveOutputVariables;
}
// EXT_blend_func_extended
GLint getFragDataIndex(const std::string &name) const;
@ -768,14 +745,6 @@ class Program final : public LabeledObject, public angle::Subject
bool usesMultiview() const { return mState.usesMultiview(); }
ComponentTypeMask getDrawBufferTypeMask() const;
bool isYUVOutput() const
{
ASSERT(!mLinkingState);
return mState.isYUVOutput();
}
const std::vector<GLsizei> &getTransformFeedbackStrides() const;
// Program dirty bits.
@ -844,14 +813,6 @@ class Program final : public LabeledObject, public angle::Subject
void updateLinkedShaderStages();
int getOutputLocationForLink(const sh::ShaderVariable &outputVariable) const;
bool isOutputSecondaryForLink(const sh::ShaderVariable &outputVariable) const;
bool linkOutputVariables(const Caps &caps,
const Extensions &extensions,
const Version &version,
GLuint combinedImageUniformsCount,
GLuint combinedShaderStorageBlocksCount);
void setUniformValuesFromBindingQualifiers();
bool shouldIgnoreUniform(UniformLocation location) const;

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

@ -8,6 +8,7 @@
#include "libANGLE/ProgramExecutable.h"
#include "common/string_utils.h"
#include "libANGLE/Context.h"
#include "libANGLE/Program.h"
#include "libANGLE/Shader.h"
@ -61,6 +62,94 @@ const sh::ShaderVariable *FindOutputVaryingOrField(const ProgramMergedVaryings &
}
return var;
}
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()
? static_cast<unsigned int>(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,
sh::ShaderVariable &outputVariable)
{
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())
{
outputVariable.location = baseLocation;
const unsigned int location = baseLocation + elementIndex;
outputLocations[location] = locationInfo;
}
}
}
int GetOutputLocationForLink(const ProgramAliasedBindings &fragmentOutputLocations,
const sh::ShaderVariable &outputVariable)
{
if (outputVariable.location != -1)
{
return outputVariable.location;
}
int apiLocation = fragmentOutputLocations.getBinding(outputVariable);
if (apiLocation != -1)
{
return apiLocation;
}
return -1;
}
bool IsOutputSecondaryForLink(const ProgramAliasedBindings &fragmentOutputIndexes,
const sh::ShaderVariable &outputVariable)
{
if (outputVariable.index != -1)
{
ASSERT(outputVariable.index == 0 || outputVariable.index == 1);
return (outputVariable.index == 1);
}
int apiIndex = fragmentOutputIndexes.getBinding(outputVariable);
if (apiIndex != -1)
{
// Index layout qualifier from the shader takes precedence, so the index from the API is
// checked only if the index was not set in the shader. This is not specified in the EXT
// spec, but is specified in desktop OpenGL specs.
return (apiIndex == 1);
}
// EXT_blend_func_extended: Outputs get index 0 by default.
return false;
}
} // anonymous namespace
ProgramExecutable::ProgramExecutable()
@ -165,6 +254,7 @@ void ProgramExecutable::reset()
mAtomicCounterBuffers.clear();
mOutputVariables.clear();
mOutputLocations.clear();
mActiveOutputVariablesMask.reset();
mSecondaryOutputLocations.clear();
mYUVOutput = false;
mSamplerBindings.clear();
@ -186,6 +276,9 @@ void ProgramExecutable::reset()
mTessGenSpacing = GL_NONE;
mTessGenVertexOrder = GL_NONE;
mTessGenPointMode = GL_NONE;
mOutputVariableTypes.clear();
mDrawBufferTypeMask.reset();
}
void ProgramExecutable::load(bool isSeparable, gl::BinaryInputStream *stream)
@ -325,6 +418,22 @@ void ProgramExecutable::load(bool isSeparable, gl::BinaryInputStream *stream)
mOutputLocations.push_back(locationData);
}
mActiveOutputVariablesMask =
gl::DrawBufferMask(stream->readInt<gl::DrawBufferMask::value_type>());
size_t outputTypeCount = stream->readInt<size_t>();
for (size_t outputIndex = 0; outputIndex < outputTypeCount; ++outputIndex)
{
mOutputVariableTypes.push_back(stream->readInt<GLenum>());
}
static_assert(IMPLEMENTATION_MAX_DRAW_BUFFERS * 2 <= 8 * sizeof(uint32_t),
"All bits of mDrawBufferTypeMask and mActiveOutputVariables types and mask fit "
"into 32 bits each");
mDrawBufferTypeMask = gl::ComponentTypeMask(stream->readInt<uint32_t>());
stream->readBool(&mYUVOutput);
size_t secondaryOutputVarCount = stream->readInt<size_t>();
ASSERT(getSecondaryOutputLocations().empty());
for (size_t outputIndex = 0; outputIndex < secondaryOutputVarCount; ++outputIndex)
@ -504,6 +613,21 @@ void ProgramExecutable::save(bool isSeparable, gl::BinaryOutputStream *stream) c
stream->writeBool(outputVar.ignored);
}
stream->writeInt(static_cast<int>(mActiveOutputVariablesMask.to_ulong()));
stream->writeInt(mOutputVariableTypes.size());
for (const auto &outputVariableType : mOutputVariableTypes)
{
stream->writeInt(outputVariableType);
}
static_assert(
IMPLEMENTATION_MAX_DRAW_BUFFERS * 2 <= 8 * sizeof(uint32_t),
"All bits of mDrawBufferTypeMask and mActiveOutputVariables can be contained in 32 bits");
stream->writeInt(static_cast<int>(mDrawBufferTypeMask.to_ulong()));
stream->writeBool(mYUVOutput);
stream->writeInt(getSecondaryOutputLocations().size());
for (const auto &outputVar : getSecondaryOutputLocations())
{
@ -1049,4 +1173,260 @@ bool ProgramExecutable::validateSamplersImpl(InfoLog *infoLog, const Caps &caps)
return true;
}
bool ProgramExecutable::linkValidateOutputVariables(
const Caps &caps,
const Extensions &extensions,
const Version &version,
GLuint combinedImageUniformsCount,
GLuint combinedShaderStorageBlocksCount,
const std::vector<sh::ShaderVariable> &outputVariables,
int fragmentShaderVersion,
const ProgramAliasedBindings &fragmentOutputLocations,
const ProgramAliasedBindings &fragmentOutputIndices)
{
ASSERT(mOutputVariableTypes.empty());
ASSERT(mActiveOutputVariablesMask.none());
ASSERT(mDrawBufferTypeMask.none());
ASSERT(!mYUVOutput);
// Gather output variable types
for (const sh::ShaderVariable &outputVariable : outputVariables)
{
if (outputVariable.isBuiltIn() && outputVariable.name != "gl_FragColor" &&
outputVariable.name != "gl_FragData")
{
continue;
}
unsigned int baseLocation =
(outputVariable.location == -1 ? 0u
: static_cast<unsigned int>(outputVariable.location));
// 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();
for (unsigned int elementIndex = 0; elementIndex < elementCount; elementIndex++)
{
const unsigned int location = baseLocation + elementIndex;
if (location >= mOutputVariableTypes.size())
{
mOutputVariableTypes.resize(location + 1, GL_NONE);
}
ASSERT(location < mActiveOutputVariablesMask.size());
mActiveOutputVariablesMask.set(location);
mOutputVariableTypes[location] = VariableComponentType(outputVariable.type);
ComponentType componentType = GLenumToComponentType(mOutputVariableTypes[location]);
SetComponentTypeMask(componentType, location, &mDrawBufferTypeMask);
}
if (outputVariable.yuv)
{
ASSERT(outputVariables.size() == 1);
mYUVOutput = true;
}
}
if (version >= ES_3_1)
{
// [OpenGL ES 3.1] Chapter 8.22 Page 203:
// A link error will be generated if the sum of the number of active image uniforms used in
// all shaders, the number of active shader storage blocks, and the number of active
// fragment shader outputs exceeds the implementation-dependent value of
// MAX_COMBINED_SHADER_OUTPUT_RESOURCES.
if (combinedImageUniformsCount + combinedShaderStorageBlocksCount +
mActiveOutputVariablesMask.count() >
static_cast<GLuint>(caps.maxCombinedShaderOutputResources))
{
mInfoLog
<< "The sum of the number of active image uniforms, active shader storage blocks "
"and active fragment shader outputs exceeds "
"MAX_COMBINED_SHADER_OUTPUT_RESOURCES ("
<< caps.maxCombinedShaderOutputResources << ")";
return false;
}
}
if (fragmentShaderVersion == 100)
return true;
mOutputVariables = outputVariables;
// 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 &bindingPair : fragmentOutputLocations)
{
const std::string &name = bindingPair.first;
const ProgramBinding &binding = bindingPair.second;
size_t nameLengthWithoutArrayIndex;
unsigned int arrayIndex = ParseArrayIndex(name, &nameLengthWithoutArrayIndex);
if (arrayIndex == 0 || arrayIndex == GL_INVALID_INDEX)
{
continue;
}
for (unsigned int outputVariableIndex = 0; outputVariableIndex < mOutputVariables.size();
outputVariableIndex++)
{
const sh::ShaderVariable &outputVariable = 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, name, 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.
std::vector<VariableLocation> &outputLocations =
fragmentOutputIndices.getBindingByName(name) == 1 ? mSecondaryOutputLocations
: mOutputLocations;
unsigned int location = binding.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. Otherwise, the remaining unallocated outputs will be processed later.
for (unsigned int outputVariableIndex = 0; outputVariableIndex < mOutputVariables.size();
outputVariableIndex++)
{
const sh::ShaderVariable &outputVariable = mOutputVariables[outputVariableIndex];
// Don't store outputs for gl_FragDepth, gl_FragColor, etc.
if (outputVariable.isBuiltIn())
continue;
int fixedLocation = GetOutputLocationForLink(fragmentOutputLocations, 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);
std::vector<VariableLocation> &outputLocations =
IsOutputSecondaryForLink(fragmentOutputIndices, outputVariable)
? mSecondaryOutputLocations
: 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();
if (FindUsedOutputLocation(outputLocations, baseLocation, elementCount, reservedLocations,
outputVariableIndex))
{
mInfoLog << "Location of variable " << outputVariable.name
<< " conflicts with another variable.";
return false;
}
AssignOutputLocations(outputLocations, baseLocation, elementCount, reservedLocations,
outputVariableIndex, mOutputVariables[outputVariableIndex]);
}
// Here we assign locations for the output variables that don't yet have them. Note that we're
// not necessarily able to fit the variables optimally, since then we might have to try
// different arrangements of output arrays. Now we just assign the locations in the order that
// 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 = static_cast<GLuint>(caps.maxDrawBuffers);
if (!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.
maxLocation = caps.maxDualSourceDrawBuffers;
}
for (unsigned int outputVariableIndex = 0; outputVariableIndex < mOutputVariables.size();
outputVariableIndex++)
{
const sh::ShaderVariable &outputVariable = mOutputVariables[outputVariableIndex];
// Don't store outputs for gl_FragDepth, gl_FragColor, etc.
if (outputVariable.isBuiltIn())
continue;
int fixedLocation = GetOutputLocationForLink(fragmentOutputLocations, outputVariable);
std::vector<VariableLocation> &outputLocations =
IsOutputSecondaryForLink(fragmentOutputIndices, outputVariable)
? mSecondaryOutputLocations
: mOutputLocations;
unsigned int baseLocation = 0;
unsigned int elementCount = outputVariable.getBasicTypeElementCount();
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.
while (FindUsedOutputLocation(outputLocations, baseLocation, elementCount,
reservedLocations, outputVariableIndex))
{
baseLocation++;
}
AssignOutputLocations(outputLocations, baseLocation, elementCount, reservedLocations,
outputVariableIndex, mOutputVariables[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;
}
}
return true;
}
} // namespace gl

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

@ -316,7 +316,7 @@ class ProgramExecutable final : public angle::Subject
bool validateSamplers(InfoLog *infoLog, const Caps &caps) const
{
// Use the cache if:
// - we aren't using an infolog (which gives the full error).
// - we aren't using an info log (which gives the full error).
// - The sample mapping hasn't changed and we've already validated.
if (infoLog == nullptr && mCachedValidateSamplersResult.valid())
{
@ -326,6 +326,9 @@ class ProgramExecutable final : public angle::Subject
return validateSamplersImpl(infoLog, caps);
}
ComponentTypeMask getFragmentOutputsTypeMask() const { return mDrawBufferTypeMask; }
DrawBufferMask getActiveOutputVariablesMask() const { return mActiveOutputVariablesMask; }
private:
// TODO(timvp): http://anglebug.com/3570: Investigate removing these friend
// class declarations and accessing the necessary members with getters/setters.
@ -361,6 +364,16 @@ class ProgramExecutable final : public angle::Subject
bool validateSamplersImpl(InfoLog *infoLog, const Caps &caps) const;
bool linkValidateOutputVariables(const Caps &caps,
const Extensions &extensions,
const Version &version,
GLuint combinedImageUniformsCount,
GLuint combinedShaderStorageBlocksCount,
const std::vector<sh::ShaderVariable> &outputVariables,
int fragmentShaderVersion,
const ProgramAliasedBindings &fragmentOutputLocations,
const ProgramAliasedBindings &fragmentOutputIndices);
InfoLog mInfoLog;
ShaderBitSet mLinkedShaderStages;
@ -389,6 +402,7 @@ class ProgramExecutable final : public angle::Subject
// to uniforms.
std::vector<sh::ShaderVariable> mOutputVariables;
std::vector<VariableLocation> mOutputLocations;
DrawBufferMask mActiveOutputVariablesMask;
// EXT_blend_func_extended secondary outputs (ones with index 1)
std::vector<VariableLocation> mSecondaryOutputLocations;
bool mYUVOutput;
@ -458,6 +472,10 @@ class ProgramExecutable final : public angle::Subject
GLenum mTessGenVertexOrder;
GLenum mTessGenPointMode;
// Fragment output variable base types: FLOAT, INT, or UINT. Ordered by location.
std::vector<GLenum> mOutputVariableTypes;
ComponentTypeMask mDrawBufferTypeMask;
// Cache for sampler validation
mutable Optional<bool> mCachedValidateSamplersResult;
};

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

@ -1423,7 +1423,7 @@ LinkingVariables::LinkingVariables(const ProgramState &state)
LinkingVariables::LinkingVariables(const ProgramPipelineState &state)
{
for (ShaderType shaderType : state.getProgramExecutable().getLinkedShaderStages())
for (ShaderType shaderType : state.getExecutable().getLinkedShaderStages())
{
const Program *program = state.getShaderProgram(shaderType);
ASSERT(program);

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

@ -124,7 +124,8 @@ void ProgramPipelineState::updateExecutableTextures()
{
const Program *program = getShaderProgram(shaderType);
ASSERT(program);
mExecutable->setActiveTextureMask(program->getExecutable().getActiveSamplersMask());
mExecutable->setActiveTextureMask(mExecutable->getActiveSamplersMask() |
program->getExecutable().getActiveSamplersMask());
mExecutable->setActiveImagesMask(mExecutable->getActiveImagesMask() |
program->getExecutable().getActiveImagesMask());
// Updates mActiveSamplerRefCounts, mActiveSamplerTypes, and mActiveSamplerFormats
@ -197,15 +198,16 @@ void ProgramPipeline::activeShaderProgram(Program *shaderProgram)
mState.activeShaderProgram(shaderProgram);
}
void ProgramPipeline::useProgramStages(const Context *context,
GLbitfield stages,
Program *shaderProgram)
angle::Result ProgramPipeline::useProgramStages(const Context *context,
GLbitfield stages,
Program *shaderProgram)
{
mState.useProgramStages(context, stages, shaderProgram, &mProgramObserverBindings);
updateLinkedShaderStages();
updateExecutable();
mState.mIsLinked = false;
return link(context);
}
void ProgramPipeline::updateLinkedShaderStages()
@ -432,8 +434,6 @@ void ProgramPipeline::updateHasBooleans()
void ProgramPipeline::updateExecutable()
{
mState.mExecutable->reset();
// Vertex Shader ProgramExecutable properties
updateExecutableAttributes();
updateTransformFeedbackMembers();
@ -471,6 +471,8 @@ angle::Result ProgramPipeline::link(const Context *context)
ProgramVaryingPacking varyingPacking;
LinkingVariables linkingVariables(mState);
mState.mExecutable->reset();
if (mState.mExecutable->hasLinkedShaderStage(gl::ShaderType::Vertex))
{
InfoLog &infoLog = mState.mExecutable->getInfoLog();
@ -486,6 +488,23 @@ angle::Result ProgramPipeline::link(const Context *context)
return angle::Result::Stop;
}
Program *fragmentShaderProgram = getShaderProgram(ShaderType::Fragment);
if (fragmentShaderProgram)
{
// We should also be validating image uniforms and SSBOs.
const int combinedImageUniforms = 0;
const int combinedShaderStorageBlocks = 0;
const ProgramExecutable &fragmentExecutable = fragmentShaderProgram->getExecutable();
if (!mState.mExecutable->linkValidateOutputVariables(
context->getCaps(), context->getExtensions(), context->getClientVersion(),
combinedImageUniforms, combinedShaderStorageBlocks,
fragmentExecutable.getOutputVariables(),
fragmentExecutable.getLinkedShaderVersion(ShaderType::Fragment),
ProgramAliasedBindings(), ProgramAliasedBindings()))
{
return angle::Result::Continue;
}
}
mergedVaryings = GetMergedVaryingsFromLinkingVariables(linkingVariables);
// If separable program objects are in use, the set of attributes captured is taken
// from the program object active on the last vertex processing stage.
@ -524,7 +543,11 @@ angle::Result ProgramPipeline::link(const Context *context)
ANGLE_TRY(getImplementation()->link(context, mergedVaryings, varyingPacking));
}
mState.mExecutable->mActiveSamplerRefCounts.fill(0);
updateExecutable();
mState.mIsLinked = true;
onStateChange(angle::SubjectMessage::SubjectChanged);
return angle::Result::Continue;
}
@ -641,16 +664,16 @@ void ProgramPipeline::onSubjectStateChange(angle::SubjectIndex index, angle::Sub
switch (message)
{
case angle::SubjectMessage::ProgramTextureOrImageBindingChanged:
mState.mIsLinked = false;
mState.mExecutable->mActiveSamplerRefCounts.fill(0);
mState.updateExecutableTextures();
break;
case angle::SubjectMessage::ProgramRelinked:
mState.mIsLinked = false;
updateExecutable();
onStateChange(angle::SubjectMessage::ProgramRelinked);
break;
case angle::SubjectMessage::SamplerUniformsUpdated:
getExecutable().resetCachedValidateSamplersResult();
mState.mExecutable->resetCachedValidateSamplersResult();
break;
default:
UNREACHABLE();

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

@ -38,12 +38,7 @@ class ProgramPipelineState final : angle::NonCopyable
const std::string &getLabel() const;
const ProgramExecutable &getProgramExecutable() const
{
ASSERT(mExecutable);
return *mExecutable;
}
ProgramExecutable &getProgramExecutable()
ProgramExecutable &getExecutable() const
{
ASSERT(mExecutable);
return *mExecutable;
@ -91,7 +86,8 @@ class ProgramPipelineState final : angle::NonCopyable
class ProgramPipeline final : public RefCountObject<ProgramPipelineID>,
public LabeledObject,
public angle::ObserverInterface
public angle::ObserverInterface,
public angle::Subject
{
public:
ProgramPipeline(rx::GLImplFactory *factory, ProgramPipelineID handle);
@ -105,8 +101,7 @@ class ProgramPipeline final : public RefCountObject<ProgramPipelineID>,
const ProgramPipelineState &getState() const { return mState; }
ProgramPipelineState &getState() { return mState; }
const ProgramExecutable &getExecutable() const { return mState.getProgramExecutable(); }
ProgramExecutable &getExecutable() { return mState.getProgramExecutable(); }
ProgramExecutable &getExecutable() const { return mState.getExecutable(); }
rx::ProgramPipelineImpl *getImplementation() const;
@ -122,7 +117,9 @@ class ProgramPipeline final : public RefCountObject<ProgramPipelineID>,
return program;
}
void useProgramStages(const Context *context, GLbitfield stages, Program *shaderProgram);
angle::Result useProgramStages(const Context *context,
GLbitfield stages,
Program *shaderProgram);
Program *getShaderProgram(ShaderType shaderType) const { return mState.mPrograms[shaderType]; }
@ -131,6 +128,7 @@ class ProgramPipeline final : public RefCountObject<ProgramPipelineID>,
bool linkVaryings(InfoLog &infoLog) const;
void validate(const gl::Context *context);
GLboolean isValid() const { return mState.isValid(); }
bool isLinked() const { return mState.mIsLinked; }
// ObserverInterface implementation.
void onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message) override;

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

@ -2008,17 +2008,6 @@ bool State::removeTransformFeedbackBinding(const Context *context,
return false;
}
angle::Result State::useProgramStages(const Context *context,
ProgramPipeline *programPipeline,
GLbitfield stages,
Program *shaderProgram)
{
programPipeline->useProgramStages(context, stages, shaderProgram);
ANGLE_TRY(onProgramPipelineExecutableChange(context, programPipeline));
return angle::Result::Continue;
}
angle::Result State::setProgramPipelineBinding(const Context *context, ProgramPipeline *pipeline)
{
if (mProgramPipeline.get() == pipeline)
@ -2048,11 +2037,6 @@ angle::Result State::setProgramPipelineBinding(const Context *context, ProgramPi
}
}
if (mProgramPipeline.get())
{
ANGLE_TRY(onProgramPipelineExecutableChange(context, mProgramPipeline.get()));
}
return angle::Result::Continue;
}
@ -3280,8 +3264,8 @@ void State::getBooleani_v(GLenum target, GLuint index, GLboolean *data) const
}
}
// TODO(https://anglebug.com/3889): Remove this helper function after blink and chromium part
// refactory done.
// TODO(http://anglebug.com/3889): Remove this helper function after blink and chromium part
// refactor done.
Texture *State::getTextureForActiveSampler(TextureType type, size_t index)
{
if (type != TextureType::VideoImage)
@ -3575,15 +3559,15 @@ angle::Result State::onProgramExecutableChange(const Context *context, Program *
return angle::Result::Continue;
}
angle::Result State::onProgramPipelineExecutableChange(const Context *context,
ProgramPipeline *programPipeline)
angle::Result State::onProgramPipelineExecutableChange(const Context *context)
{
mDirtyBits.set(DIRTY_BIT_PROGRAM_EXECUTABLE);
// Set any bound textures.
const ActiveTextureTypeArray &textureTypes =
programPipeline->getExecutable().getActiveSamplerTypes();
for (size_t textureIndex : programPipeline->getExecutable().getActiveSamplersMask())
const ProgramExecutable &executable = mProgramPipeline->getExecutable();
const ActiveTextureTypeArray &textureTypes = executable.getActiveSamplerTypes();
for (size_t textureIndex : executable.getActiveSamplersMask())
{
TextureType type = textureTypes[textureIndex];
@ -3595,7 +3579,7 @@ angle::Result State::onProgramPipelineExecutableChange(const Context *context,
updateTextureBinding(context, textureIndex, texture);
}
for (size_t imageUnitIndex : programPipeline->getExecutable().getActiveImagesMask())
for (size_t imageUnitIndex : executable.getActiveImagesMask())
{
Texture *image = mImageUnits[imageUnitIndex].texture.get();
if (!image)

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

@ -411,10 +411,6 @@ class State : angle::NonCopyable
Query *getActiveQuery(QueryType type) const;
// Program Pipeline binding manipulation
angle::Result useProgramStages(const Context *context,
ProgramPipeline *programPipeline,
GLbitfield stages,
Program *shaderProgram);
angle::Result setProgramPipelineBinding(const Context *context, ProgramPipeline *pipeline);
void detachProgramPipeline(const Context *context, ProgramPipelineID pipeline);
@ -605,8 +601,7 @@ class State : angle::NonCopyable
// Sets the dirty bit for the program executable.
angle::Result onProgramExecutableChange(const Context *context, Program *program);
// Sets the dirty bit for the program pipeline executable.
angle::Result onProgramPipelineExecutableChange(const Context *context,
ProgramPipeline *program);
angle::Result onProgramPipelineExecutableChange(const Context *context);
enum DirtyBitType
{

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

@ -1019,9 +1019,6 @@ void SerializeProgramState(JsonSerializer *json, const gl::ProgramState &program
SerializeRange(json, programState.getAtomicCounterUniformRange());
SerializeVariableLocationsVector(json, "SecondaryOutputLocations",
programState.getSecondaryOutputLocations());
json->addScalar("ActiveOutputVariables", programState.getActiveOutputVariables().to_ulong());
json->addVector("OutputVariableTypes", programState.getOutputVariableTypes());
json->addScalar("DrawBufferTypeMask", programState.getDrawBufferTypeMask().to_ulong());
json->addScalar("BinaryRetrieveableHint", programState.hasBinaryRetrieveableHint());
json->addScalar("Separable", programState.isSeparable());
json->addScalar("EarlyFragmentTestsOptimization",

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

@ -311,7 +311,7 @@ angle::Result FramebufferD3D::syncState(const gl::Context *context,
const gl::AttachmentList &FramebufferD3D::getColorAttachmentsForRender(const gl::Context *context)
{
gl::DrawBufferMask activeProgramOutputs =
context->getState().getProgram()->getActiveOutputVariables();
context->getState().getProgram()->getExecutable().getActiveOutputVariablesMask();
if (mColorAttachmentsForRender.valid() && mCurrentActiveProgramOutputs == activeProgramOutputs)
{

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

@ -2003,12 +2003,13 @@ angle::Result StateManager11::syncFramebuffer(const gl::Context *context)
RTVArray framebufferRTVs = {{}};
const auto &colorRTs = mFramebuffer11->getCachedColorRenderTargets();
size_t appliedRTIndex = 0;
bool skipInactiveRTs = mRenderer->getFeatures().mrtPerfWorkaround.enabled;
const auto &drawStates = mFramebuffer11->getState().getDrawBufferStates();
gl::DrawBufferMask activeProgramOutputs = mProgramD3D->getState().getActiveOutputVariables();
UINT maxExistingRT = 0;
const auto &colorAttachments = mFramebuffer11->getState().getColorAttachments();
size_t appliedRTIndex = 0;
bool skipInactiveRTs = mRenderer->getFeatures().mrtPerfWorkaround.enabled;
const auto &drawStates = mFramebuffer11->getState().getDrawBufferStates();
gl::DrawBufferMask activeProgramOutputs =
mProgramD3D->getState().getExecutable().getActiveOutputVariablesMask();
UINT maxExistingRT = 0;
const auto &colorAttachments = mFramebuffer11->getState().getColorAttachments();
for (size_t rtIndex = 0; rtIndex < colorRTs.size(); ++rtIndex)
{

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

@ -835,12 +835,12 @@ angle::Result ContextVk::setupDraw(const gl::Context *context,
mGraphicsDirtyBits.set(DIRTY_BIT_VERTEX_BUFFERS);
}
if (mProgram && mProgram->dirtyUniforms())
if (mProgram && mProgram->hasDirtyUniforms())
{
ANGLE_TRY(mProgram->updateUniforms(this));
mGraphicsDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
}
else if (mProgramPipeline && mProgramPipeline->dirtyUniforms(getState()))
else if (mProgramPipeline && mProgramPipeline->hasDirtyUniforms())
{
ANGLE_TRY(mProgramPipeline->updateUniforms(this));
mGraphicsDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
@ -1076,12 +1076,12 @@ angle::Result ContextVk::setupDispatch(const gl::Context *context)
// TODO: Remove this and fix tests. http://anglebug.com/5070
ANGLE_TRY(flushOutsideRenderPassCommands());
if (mProgram && mProgram->dirtyUniforms())
if (mProgram && mProgram->hasDirtyUniforms())
{
ANGLE_TRY(mProgram->updateUniforms(this));
mComputeDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
}
else if (mProgramPipeline && mProgramPipeline->dirtyUniforms(getState()))
else if (mProgramPipeline && mProgramPipeline->hasDirtyUniforms())
{
ANGLE_TRY(mProgramPipeline->updateUniforms(this));
mComputeDirtyBits.set(DIRTY_BIT_DESCRIPTOR_SETS);
@ -3421,7 +3421,7 @@ void ContextVk::invalidateProgramBindingHelper(const gl::State &glState)
}
else if (mProgramPipeline)
{
mProgramPipeline->onProgramBind(this);
mProgramPipeline->onProgramBind();
}
}
@ -5123,8 +5123,10 @@ angle::Result ContextVk::updateActiveTextures(const gl::Context *context, gl::Co
}
}
recreatePipelineLayout =
textureVk->getAndResetImmutableSamplerDirtyState() || recreatePipelineLayout;
if (textureVk->getAndResetImmutableSamplerDirtyState())
{
recreatePipelineLayout = true;
}
}
if (!mExecutable->isImmutableSamplerFormatCompatible(externalFormatIndexMap, vkFormatIndexMap))
@ -5135,7 +5137,7 @@ angle::Result ContextVk::updateActiveTextures(const gl::Context *context, gl::Co
// Recreate the pipeline layout, if necessary.
if (recreatePipelineLayout)
{
ANGLE_TRY(mExecutable->createPipelineLayout(context, &mActiveTextures));
ANGLE_TRY(mExecutable->createPipelineLayout(this, *executable, &mActiveTextures));
// The default uniforms descriptor set was reset during createPipelineLayout(), so mark them
// dirty to get everything reallocated/rebound before the next draw.
@ -5147,7 +5149,7 @@ angle::Result ContextVk::updateActiveTextures(const gl::Context *context, gl::Co
}
else if (mProgramPipeline)
{
mProgramPipeline->setAllDefaultUniformsDirty(context->getState());
mProgramPipeline->setAllDefaultUniformsDirty();
}
}
}

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

@ -1929,7 +1929,7 @@ angle::Result FramebufferVk::syncState(const gl::Context *context,
// optimize that path which requires modifying the current render pass.
// We're deferring the resolve check to FramebufferVk::blit(), since if the read buffer is
// multisampled-render-to-texture, then srcFramebuffer->getSamples(context) gives > 1, but
// there's no resolve happening as the read buffer's singlesampled image will be used as
// there's no resolve happening as the read buffer's single sampled image will be used as
// blit src. FramebufferVk::blit() will handle those details for us.
ANGLE_TRY(contextVk->flushCommandsAndEndRenderPass());
}

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

@ -395,7 +395,7 @@ ProgramVk *ProgramExecutableVk::getShaderProgram(const gl::State &glState,
}
else if (mProgramPipeline)
{
return mProgramPipeline->getShaderProgram(glState, shaderType);
return mProgramPipeline->getShaderProgram(shaderType);
}
return nullptr;
@ -414,7 +414,7 @@ void ProgramExecutableVk::fillProgramStateMap(
}
else if (mProgramPipeline)
{
mProgramPipeline->fillProgramStateMap(contextVk, programStatesOut);
mProgramPipeline->fillProgramStateMap(programStatesOut);
}
}
@ -425,7 +425,7 @@ const gl::ProgramExecutable &ProgramExecutableVk::getGlExecutable()
{
return mProgram->getState().getExecutable();
}
return mProgramPipeline->getState().getProgramExecutable();
return mProgramPipeline->getState().getExecutable();
}
uint32_t GetInterfaceBlockArraySize(const std::vector<gl::InterfaceBlock> &blocks,
@ -954,13 +954,11 @@ angle::Result ProgramExecutableVk::initDynamicDescriptorPools(
}
angle::Result ProgramExecutableVk::createPipelineLayout(
const gl::Context *glContext,
ContextVk *contextVk,
const gl::ProgramExecutable &glExecutable,
gl::ActiveTextureArray<vk::TextureUnit> *activeTextures)
{
const gl::State &glState = glContext->getState();
ContextVk *contextVk = vk::GetImpl(glContext);
gl::TransformFeedback *transformFeedback = glState.getCurrentTransformFeedback();
const gl::ProgramExecutable &glExecutable = getGlExecutable();
gl::TransformFeedback *transformFeedback = contextVk->getState().getCurrentTransformFeedback();
const gl::ShaderBitSet &linkedShaderStages = glExecutable.getLinkedShaderStages();
gl::ShaderMap<const gl::ProgramState *> programStates;
fillProgramStateMap(contextVk, &programStates);
@ -1179,7 +1177,7 @@ void ProgramExecutableVk::updateDefaultUniformsDescriptorSet(
VkWriteDescriptorSet &writeInfo = contextVk->allocWriteDescriptorSet();
VkDescriptorBufferInfo &bufferInfo = contextVk->allocDescriptorBufferInfo();
// Size is set to the size of the empty buffer for shader statges with no uniform data,
// Size is set to the size of the empty buffer for shader stages with no uniform data,
// otherwise it is set to the total size of the uniform data in the current shader stage
VkDeviceSize size = defaultUniformBlock.uniformData.size();
vk::BufferHelper *bufferHelper = defaultUniformBuffer;

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

@ -153,7 +153,8 @@ class ProgramExecutableVk
angle::Result getComputePipeline(ContextVk *contextVk, vk::PipelineAndSerial **pipelineOut);
const vk::PipelineLayout &getPipelineLayout() const { return mPipelineLayout.get(); }
angle::Result createPipelineLayout(const gl::Context *glContext,
angle::Result createPipelineLayout(ContextVk *contextVk,
const gl::ProgramExecutable &glExecutable,
gl::ActiveTextureArray<vk::TextureUnit> *activeTextures);
angle::Result updateTexturesDescriptorSet(ContextVk *contextVk,

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

@ -37,14 +37,13 @@ void ProgramPipelineVk::reset(ContextVk *contextVk)
// TODO: http://anglebug.com/3570: Move/Copy all of the necessary information into
// the ProgramExecutable, so this function can be removed.
void ProgramPipelineVk::fillProgramStateMap(
const ContextVk *contextVk,
gl::ShaderMap<const gl::ProgramState *> *programStatesOut)
{
for (gl::ShaderType shaderType : gl::AllShaderTypes())
{
(*programStatesOut)[shaderType] = nullptr;
ProgramVk *programVk = getShaderProgram(contextVk->getState(), shaderType);
ProgramVk *programVk = getShaderProgram(shaderType);
if (programVk)
{
(*programStatesOut)[shaderType] = &programVk->getState();
@ -57,9 +56,7 @@ angle::Result ProgramPipelineVk::link(const gl::Context *glContext,
const gl::ProgramVaryingPacking &varyingPacking)
{
ContextVk *contextVk = vk::GetImpl(glContext);
const gl::State &glState = glContext->getState();
const gl::ProgramPipeline *glPipeline = glState.getProgramPipeline();
const gl::ProgramExecutable &glExecutable = glPipeline->getExecutable();
const gl::ProgramExecutable &glExecutable = mState.getExecutable();
GlslangSourceOptions options =
GlslangWrapperVk::CreateSourceOptions(contextVk->getRenderer()->getFeatures());
GlslangProgramInterfaceInfo glslangProgramInterfaceInfo;
@ -72,20 +69,19 @@ angle::Result ProgramPipelineVk::link(const gl::Context *glContext,
const gl::ShaderType linkedTransformFeedbackStage =
glExecutable.getLinkedTransformFeedbackStage();
// This should be done before assigning varying location. Otherwise, We can encounter shader
// interface mismatching problem in case the transformFeedback stage is not Vertex stage.
for (const gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
// This should be done before assigning varying locations. Otherwise, we can encounter shader
// interface mismatching problems when the transform feedback stage is not the vertex stage.
if (options.supportsTransformFeedbackExtension)
{
gl::Program *glProgram =
const_cast<gl::Program *>(glPipeline->getShaderProgram(shaderType));
if (glProgram)
for (const gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
{
const bool isTransformFeedbackStage =
shaderType == linkedTransformFeedbackStage &&
!glProgram->getState().getLinkedTransformFeedbackVaryings().empty();
if (options.supportsTransformFeedbackExtension &&
gl::ShaderTypeSupportsTransformFeedback(shaderType))
const gl::Program *glProgram = mState.getShaderProgram(shaderType);
if (glProgram && gl::ShaderTypeSupportsTransformFeedback(shaderType))
{
const bool isTransformFeedbackStage =
shaderType == linkedTransformFeedbackStage &&
!glProgram->getState().getLinkedTransformFeedbackVaryings().empty();
GlslangAssignTransformFeedbackLocations(
shaderType, glProgram->getState(), isTransformFeedbackStage,
&glslangProgramInterfaceInfo, &mExecutable.mVariableInfoMap);
@ -97,8 +93,7 @@ angle::Result ProgramPipelineVk::link(const gl::Context *glContext,
UniformBindingIndexMap uniformBindingIndexMap;
for (const gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
{
gl::Program *glProgram =
const_cast<gl::Program *>(glPipeline->getShaderProgram(shaderType));
const gl::Program *glProgram = mState.getShaderProgram(shaderType);
if (glProgram)
{
const bool isTransformFeedbackStage =
@ -118,19 +113,17 @@ angle::Result ProgramPipelineVk::link(const gl::Context *glContext,
mExecutable.resolvePrecisionMismatch(mergedVaryings);
}
return mExecutable.createPipelineLayout(glContext, nullptr);
return mExecutable.createPipelineLayout(contextVk, mState.getExecutable(), nullptr);
}
size_t ProgramPipelineVk::calcUniformUpdateRequiredSpace(
ContextVk *contextVk,
const gl::ProgramExecutable &glExecutable,
const gl::State &glState,
gl::ShaderMap<VkDeviceSize> *uniformOffsets) const
{
size_t requiredSpace = 0;
for (const gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
for (const gl::ShaderType shaderType : mState.getExecutable().getLinkedShaderStages())
{
ProgramVk *programVk = getShaderProgram(glState, shaderType);
ProgramVk *programVk = getShaderProgram(shaderType);
ASSERT(programVk);
if (programVk->isShaderUniformDirty(shaderType))
{
@ -143,8 +136,7 @@ size_t ProgramPipelineVk::calcUniformUpdateRequiredSpace(
angle::Result ProgramPipelineVk::updateUniforms(ContextVk *contextVk)
{
const gl::State &glState = contextVk->getState();
const gl::ProgramExecutable &glExecutable = *glState.getProgramExecutable();
const gl::ProgramExecutable &glExecutable = mState.getExecutable();
vk::DynamicBuffer *defaultUniformStorage = contextVk->getDefaultUniformStorage();
uint8_t *bufferData = nullptr;
VkDeviceSize bufferOffset = 0;
@ -155,9 +147,9 @@ angle::Result ProgramPipelineVk::updateUniforms(ContextVk *contextVk)
// We usually only update uniform data for shader stages that are actually dirty. But when the
// buffer for uniform data have switched, because all shader stages are using the same buffer,
// we then must update uniform data for all shader stages to keep all shader stages' unform data
// in the same buffer.
requiredSpace = calcUniformUpdateRequiredSpace(contextVk, glExecutable, glState, &offsets);
// we then must update uniform data for all shader stages to keep all shader stages' uniform
// data in the same buffer.
requiredSpace = calcUniformUpdateRequiredSpace(contextVk, &offsets);
ASSERT(requiredSpace > 0);
// Allocate space from dynamicBuffer. Always try to allocate from the current buffer first.
@ -165,16 +157,16 @@ angle::Result ProgramPipelineVk::updateUniforms(ContextVk *contextVk)
if (!defaultUniformStorage->allocateFromCurrentBuffer(requiredSpace, &bufferData,
&bufferOffset))
{
setAllDefaultUniformsDirty(contextVk->getState());
setAllDefaultUniformsDirty();
requiredSpace = calcUniformUpdateRequiredSpace(contextVk, glExecutable, glState, &offsets);
requiredSpace = calcUniformUpdateRequiredSpace(contextVk, &offsets);
ANGLE_TRY(defaultUniformStorage->allocate(contextVk, requiredSpace, &bufferData, nullptr,
&bufferOffset, &anyNewBufferAllocated));
}
for (const gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
{
ProgramVk *programVk = getShaderProgram(glState, shaderType);
ProgramVk *programVk = getShaderProgram(shaderType);
ASSERT(programVk);
if (programVk->isShaderUniformDirty(shaderType))
{
@ -208,7 +200,7 @@ angle::Result ProgramPipelineVk::updateUniforms(ContextVk *contextVk)
if (glExecutable.hasTransformFeedbackOutput())
{
TransformFeedbackVk *transformFeedbackVk =
vk::GetImpl(glState.getCurrentTransformFeedback());
vk::GetImpl(contextVk->getState().getCurrentTransformFeedback());
uniformsAndXfbBufferDesc = &transformFeedbackVk->getTransformFeedbackDesc();
uniformsAndXfbBufferDesc->updateDefaultUniformBuffer(
defaultUniformBuffer->getBufferSerial());
@ -227,7 +219,7 @@ angle::Result ProgramPipelineVk::updateUniforms(ContextVk *contextVk)
{
for (const gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
{
ProgramVk *programVk = getShaderProgram(glState, shaderType);
ProgramVk *programVk = getShaderProgram(shaderType);
mExecutable.updateDefaultUniformsDescriptorSet(
shaderType, programVk->getDefaultUniformBlocks()[shaderType],
defaultUniformBuffer, contextVk);
@ -240,12 +232,12 @@ angle::Result ProgramPipelineVk::updateUniforms(ContextVk *contextVk)
return angle::Result::Continue;
}
bool ProgramPipelineVk::dirtyUniforms(const gl::State &glState)
bool ProgramPipelineVk::hasDirtyUniforms() const
{
for (const gl::ShaderType shaderType : gl::AllShaderTypes())
{
const ProgramVk *program = getShaderProgram(glState, shaderType);
if (program && program->dirtyUniforms())
const ProgramVk *program = getShaderProgram(shaderType);
if (program && program->hasDirtyUniforms())
{
return true;
}
@ -254,21 +246,21 @@ bool ProgramPipelineVk::dirtyUniforms(const gl::State &glState)
return false;
}
void ProgramPipelineVk::setAllDefaultUniformsDirty(const gl::State &glState)
void ProgramPipelineVk::setAllDefaultUniformsDirty()
{
const gl::ProgramExecutable &glExecutable = *glState.getProgramExecutable();
const gl::ProgramExecutable &glExecutable = mState.getExecutable();
for (const gl::ShaderType shaderType : glExecutable.getLinkedShaderStages())
{
ProgramVk *programVk = getShaderProgram(glState, shaderType);
ProgramVk *programVk = getShaderProgram(shaderType);
ASSERT(programVk);
programVk->setShaderUniformDirtyBit(shaderType);
}
}
void ProgramPipelineVk::onProgramBind(ContextVk *contextVk)
void ProgramPipelineVk::onProgramBind()
{
setAllDefaultUniformsDirty(contextVk->getState());
setAllDefaultUniformsDirty();
}
} // namespace rx

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

@ -31,19 +31,13 @@ class ProgramPipelineVk : public ProgramPipelineImpl
const ProgramExecutableVk &getExecutable() const { return mExecutable; }
ProgramExecutableVk &getExecutable() { return mExecutable; }
ProgramVk *getShaderProgram(const gl::State &glState, gl::ShaderType shaderType) const
ProgramVk *getShaderProgram(gl::ShaderType shaderType) const
{
gl::ProgramPipeline *pipeline = glState.getProgramPipeline();
const gl::Program *program = pipeline->getShaderProgram(shaderType);
if (program)
{
return vk::GetImpl(program);
}
return nullptr;
const gl::Program *program = mState.getShaderProgram(shaderType);
return SafeGetImplAs<ProgramVk>(program);
}
void fillProgramStateMap(const ContextVk *contextVk,
gl::ShaderMap<const gl::ProgramState *> *programStatesOut);
void fillProgramStateMap(gl::ShaderMap<const gl::ProgramState *> *programStatesOut);
angle::Result link(const gl::Context *glContext,
const gl::ProgramMergedVaryings &mergedVaryings,
@ -51,14 +45,12 @@ class ProgramPipelineVk : public ProgramPipelineImpl
angle::Result updateUniforms(ContextVk *contextVk);
void setAllDefaultUniformsDirty(const gl::State &glState);
bool dirtyUniforms(const gl::State &glState);
void onProgramBind(ContextVk *contextVk);
void setAllDefaultUniformsDirty();
bool hasDirtyUniforms() const;
void onProgramBind();
private:
size_t calcUniformUpdateRequiredSpace(ContextVk *contextVk,
const gl::ProgramExecutable &glExecutable,
const gl::State &glState,
gl::ShaderMap<VkDeviceSize> *uniformOffsets) const;
ProgramExecutableVk mExecutable;

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

@ -199,7 +199,7 @@ std::unique_ptr<rx::LinkEvent> ProgramVk::load(const gl::Context *context,
return std::make_unique<LinkEventDone>(status);
}
status = mExecutable.createPipelineLayout(context, nullptr);
status = mExecutable.createPipelineLayout(contextVk, mState.getExecutable(), nullptr);
return std::make_unique<LinkEventDone>(status);
}
@ -294,7 +294,7 @@ std::unique_ptr<LinkEvent> ProgramVk::link(const gl::Context *context,
// TODO(jie.a.chen@intel.com): Parallelize linking.
// http://crbug.com/849576
status = mExecutable.createPipelineLayout(context, nullptr);
status = mExecutable.createPipelineLayout(contextVk, mState.getExecutable(), nullptr);
return std::make_unique<LinkEventDone>(status);
}
@ -715,7 +715,7 @@ size_t ProgramVk::calcUniformUpdateRequiredSpace(ContextVk *contextVk,
angle::Result ProgramVk::updateUniforms(ContextVk *contextVk)
{
ASSERT(dirtyUniforms());
ASSERT(hasDirtyUniforms());
bool anyNewBufferAllocated = false;
uint8_t *bufferData = nullptr;

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

@ -106,7 +106,7 @@ class ProgramVk : public ProgramImpl
angle::Result updateUniforms(ContextVk *contextVk);
void setAllDefaultUniformsDirty();
bool dirtyUniforms() const { return mDefaultUniformBlocksDirty.any(); }
bool hasDirtyUniforms() const { return mDefaultUniformBlocksDirty.any(); }
bool isShaderUniformDirty(gl::ShaderType shaderType) const
{
return mDefaultUniformBlocksDirty[shaderType];

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

@ -461,19 +461,19 @@ bool ValidateFragmentShaderColorBufferMaskMatch(const Context *context)
const Framebuffer *framebuffer = context->getState().getDrawFramebuffer();
auto drawBufferMask = framebuffer->getDrawBufferMask().to_ulong();
auto fragmentOutputMask = program->getActiveOutputVariables().to_ulong();
auto fragmentOutputMask = program->getExecutable().getActiveOutputVariablesMask().to_ulong();
return drawBufferMask == (drawBufferMask & fragmentOutputMask);
}
bool ValidateFragmentShaderColorBufferTypeMatch(const Context *context)
{
const Program *program = context->getActiveLinkedProgram();
const Framebuffer *framebuffer = context->getState().getDrawFramebuffer();
const ProgramExecutable *executable = context->getState().getProgramExecutable();
const Framebuffer *framebuffer = context->getState().getDrawFramebuffer();
return ValidateComponentTypeMasks(program->getDrawBufferTypeMask().to_ulong(),
return ValidateComponentTypeMasks(executable->getFragmentOutputsTypeMask().to_ulong(),
framebuffer->getDrawBufferTypeMask().to_ulong(),
program->getActiveOutputVariables().to_ulong(),
executable->getActiveOutputVariablesMask().to_ulong(),
framebuffer->getDrawBufferMask().to_ulong());
}
@ -4036,7 +4036,7 @@ const char *ValidateDrawStates(const Context *context)
return errorMsg;
}
programIsYUVOutput = program->isYUVOutput();
programIsYUVOutput = executable->isYUVOutput();
}
else if (programPipeline)
{
@ -4052,10 +4052,7 @@ const char *ValidateDrawStates(const Context *context)
return errorMsg;
}
bool goodResult = programPipeline->link(context) == angle::Result::Continue;
ASSERT(executable);
if (!goodResult)
if (!programPipeline->isLinked())
{
return kProgramPipelineLinkFailed;
}