Commit c3abb7f1 by Shahbaz Youssefi Committed by Commit Bot

Fix MultiDraw shaders when loaded from cache

State updates that need to be done after linking vs. deserializing can get out of sync, as was the case for mDrawIDLocation (introduced in 1bf18ce9). This commit introduces a common function that's called from both paths to hopefully avoid such issues in the future. The serialize/deserialize functions are moved from MemoryProgramCache to the Program itself. Bug: 890539,angleproject:2516 Change-Id: Idc5b87de53298aacbb1884e79e721b876281fb13 Reviewed-on: https://chromium-review.googlesource.com/c/1417970 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 6ae34889
...@@ -28,121 +28,6 @@ namespace ...@@ -28,121 +28,6 @@ namespace
{ {
constexpr unsigned int kWarningLimit = 3; constexpr unsigned int kWarningLimit = 3;
void WriteShaderVar(BinaryOutputStream *stream, const sh::ShaderVariable &var)
{
stream->writeInt(var.type);
stream->writeInt(var.precision);
stream->writeString(var.name);
stream->writeString(var.mappedName);
stream->writeIntVector(var.arraySizes);
stream->writeInt(var.staticUse);
stream->writeInt(var.active);
stream->writeString(var.structName);
ASSERT(var.fields.empty());
}
void LoadShaderVar(BinaryInputStream *stream, sh::ShaderVariable *var)
{
var->type = stream->readInt<GLenum>();
var->precision = stream->readInt<GLenum>();
var->name = stream->readString();
var->mappedName = stream->readString();
stream->readIntVector<unsigned int>(&var->arraySizes);
var->staticUse = stream->readBool();
var->active = stream->readBool();
var->structName = stream->readString();
}
void WriteShaderVariableBuffer(BinaryOutputStream *stream, const ShaderVariableBuffer &var)
{
stream->writeInt(var.binding);
stream->writeInt(var.dataSize);
for (ShaderType shaderType : AllShaderTypes())
{
stream->writeInt(var.isActive(shaderType));
}
stream->writeInt(var.memberIndexes.size());
for (unsigned int memberCounterIndex : var.memberIndexes)
{
stream->writeInt(memberCounterIndex);
}
}
void LoadShaderVariableBuffer(BinaryInputStream *stream, ShaderVariableBuffer *var)
{
var->binding = stream->readInt<int>();
var->dataSize = stream->readInt<unsigned int>();
for (ShaderType shaderType : AllShaderTypes())
{
var->setActive(shaderType, stream->readBool());
}
unsigned int numMembers = stream->readInt<unsigned int>();
for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
{
var->memberIndexes.push_back(stream->readInt<unsigned int>());
}
}
void WriteBufferVariable(BinaryOutputStream *stream, const BufferVariable &var)
{
WriteShaderVar(stream, var);
stream->writeInt(var.bufferIndex);
stream->writeInt(var.blockInfo.offset);
stream->writeInt(var.blockInfo.arrayStride);
stream->writeInt(var.blockInfo.matrixStride);
stream->writeInt(var.blockInfo.isRowMajorMatrix);
stream->writeInt(var.blockInfo.topLevelArrayStride);
stream->writeInt(var.topLevelArraySize);
for (ShaderType shaderType : AllShaderTypes())
{
stream->writeInt(var.isActive(shaderType));
}
}
void LoadBufferVariable(BinaryInputStream *stream, BufferVariable *var)
{
LoadShaderVar(stream, var);
var->bufferIndex = stream->readInt<int>();
var->blockInfo.offset = stream->readInt<int>();
var->blockInfo.arrayStride = stream->readInt<int>();
var->blockInfo.matrixStride = stream->readInt<int>();
var->blockInfo.isRowMajorMatrix = stream->readBool();
var->blockInfo.topLevelArrayStride = stream->readInt<int>();
var->topLevelArraySize = stream->readInt<int>();
for (ShaderType shaderType : AllShaderTypes())
{
var->setActive(shaderType, stream->readBool());
}
}
void WriteInterfaceBlock(BinaryOutputStream *stream, const InterfaceBlock &block)
{
stream->writeString(block.name);
stream->writeString(block.mappedName);
stream->writeInt(block.isArray);
stream->writeInt(block.arrayElement);
WriteShaderVariableBuffer(stream, block);
}
void LoadInterfaceBlock(BinaryInputStream *stream, InterfaceBlock *block)
{
block->name = stream->readString();
block->mappedName = stream->readString();
block->isArray = stream->readBool();
block->arrayElement = stream->readInt<unsigned int>();
LoadShaderVariableBuffer(stream, block);
}
class HashStream final : angle::NonCopyable class HashStream final : angle::NonCopyable
{ {
public: public:
...@@ -205,443 +90,6 @@ MemoryProgramCache::MemoryProgramCache(egl::BlobCache &blobCache) ...@@ -205,443 +90,6 @@ MemoryProgramCache::MemoryProgramCache(egl::BlobCache &blobCache)
MemoryProgramCache::~MemoryProgramCache() {} MemoryProgramCache::~MemoryProgramCache() {}
// static
angle::Result MemoryProgramCache::Deserialize(const Context *context,
const Program *program,
ProgramState *state,
const uint8_t *binary,
size_t length,
InfoLog &infoLog)
{
BinaryInputStream stream(binary, length);
unsigned char commitString[ANGLE_COMMIT_HASH_SIZE];
stream.readBytes(commitString, ANGLE_COMMIT_HASH_SIZE);
if (memcmp(commitString, ANGLE_COMMIT_HASH, sizeof(unsigned char) * ANGLE_COMMIT_HASH_SIZE) !=
0)
{
infoLog << "Invalid program binary version.";
return angle::Result::Incomplete;
}
int majorVersion = stream.readInt<int>();
int minorVersion = stream.readInt<int>();
if (majorVersion != context->getClientMajorVersion() ||
minorVersion != context->getClientMinorVersion())
{
infoLog << "Cannot load program binaries across different ES context versions.";
return angle::Result::Incomplete;
}
state->mComputeShaderLocalSize[0] = stream.readInt<int>();
state->mComputeShaderLocalSize[1] = stream.readInt<int>();
state->mComputeShaderLocalSize[2] = stream.readInt<int>();
state->mGeometryShaderInputPrimitiveType = stream.readEnum<PrimitiveMode>();
state->mGeometryShaderOutputPrimitiveType = stream.readEnum<PrimitiveMode>();
state->mGeometryShaderInvocations = stream.readInt<int>();
state->mGeometryShaderMaxVertices = stream.readInt<int>();
state->mNumViews = stream.readInt<int>();
static_assert(MAX_VERTEX_ATTRIBS * 2 <= sizeof(uint32_t) * 8,
"All bits of mAttributesTypeMask types and mask fit into 32 bits each");
state->mAttributesTypeMask = gl::ComponentTypeMask(stream.readInt<uint32_t>());
state->mAttributesMask = stream.readInt<gl::AttributesMask>();
static_assert(MAX_VERTEX_ATTRIBS <= sizeof(unsigned long) * 8,
"Too many vertex attribs for mask");
state->mActiveAttribLocationsMask = stream.readInt<gl::AttributesMask>();
unsigned int attribCount = stream.readInt<unsigned int>();
ASSERT(state->mAttributes.empty());
for (unsigned int attribIndex = 0; attribIndex < attribCount; ++attribIndex)
{
sh::Attribute attrib;
LoadShaderVar(&stream, &attrib);
attrib.location = stream.readInt<int>();
state->mAttributes.push_back(attrib);
}
unsigned int uniformCount = stream.readInt<unsigned int>();
ASSERT(state->mUniforms.empty());
for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex)
{
LinkedUniform uniform;
LoadShaderVar(&stream, &uniform);
uniform.bufferIndex = stream.readInt<int>();
uniform.blockInfo.offset = stream.readInt<int>();
uniform.blockInfo.arrayStride = stream.readInt<int>();
uniform.blockInfo.matrixStride = stream.readInt<int>();
uniform.blockInfo.isRowMajorMatrix = stream.readBool();
uniform.typeInfo = &GetUniformTypeInfo(uniform.type);
state->mUniforms.push_back(uniform);
}
const unsigned int uniformIndexCount = stream.readInt<unsigned int>();
ASSERT(state->mUniformLocations.empty());
for (unsigned int uniformIndexIndex = 0; uniformIndexIndex < uniformIndexCount;
uniformIndexIndex++)
{
VariableLocation variable;
stream.readInt(&variable.arrayIndex);
stream.readInt(&variable.index);
stream.readBool(&variable.ignored);
state->mUniformLocations.push_back(variable);
}
unsigned int uniformBlockCount = stream.readInt<unsigned int>();
ASSERT(state->mUniformBlocks.empty());
for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount;
++uniformBlockIndex)
{
InterfaceBlock uniformBlock;
LoadInterfaceBlock(&stream, &uniformBlock);
state->mUniformBlocks.push_back(uniformBlock);
state->mActiveUniformBlockBindings.set(uniformBlockIndex, uniformBlock.binding != 0);
}
unsigned int bufferVariableCount = stream.readInt<unsigned int>();
ASSERT(state->mBufferVariables.empty());
for (unsigned int index = 0; index < bufferVariableCount; ++index)
{
BufferVariable bufferVariable;
LoadBufferVariable(&stream, &bufferVariable);
state->mBufferVariables.push_back(bufferVariable);
}
unsigned int shaderStorageBlockCount = stream.readInt<unsigned int>();
ASSERT(state->mShaderStorageBlocks.empty());
for (unsigned int shaderStorageBlockIndex = 0;
shaderStorageBlockIndex < shaderStorageBlockCount; ++shaderStorageBlockIndex)
{
InterfaceBlock shaderStorageBlock;
LoadInterfaceBlock(&stream, &shaderStorageBlock);
state->mShaderStorageBlocks.push_back(shaderStorageBlock);
}
unsigned int atomicCounterBufferCount = stream.readInt<unsigned int>();
ASSERT(state->mAtomicCounterBuffers.empty());
for (unsigned int bufferIndex = 0; bufferIndex < atomicCounterBufferCount; ++bufferIndex)
{
AtomicCounterBuffer atomicCounterBuffer;
LoadShaderVariableBuffer(&stream, &atomicCounterBuffer);
state->mAtomicCounterBuffers.push_back(atomicCounterBuffer);
}
unsigned int transformFeedbackVaryingCount = stream.readInt<unsigned int>();
// Reject programs that use transform feedback varyings if the hardware cannot support them.
if (transformFeedbackVaryingCount > 0 &&
context->getWorkarounds().disableProgramCachingForTransformFeedback)
{
infoLog << "Current driver does not support transform feedback in binary programs.";
return angle::Result::Incomplete;
}
ASSERT(state->mLinkedTransformFeedbackVaryings.empty());
for (unsigned int transformFeedbackVaryingIndex = 0;
transformFeedbackVaryingIndex < transformFeedbackVaryingCount;
++transformFeedbackVaryingIndex)
{
sh::Varying varying;
stream.readIntVector<unsigned int>(&varying.arraySizes);
stream.readInt(&varying.type);
stream.readString(&varying.name);
GLuint arrayIndex = stream.readInt<GLuint>();
state->mLinkedTransformFeedbackVaryings.emplace_back(varying, arrayIndex);
}
stream.readInt(&state->mTransformFeedbackBufferMode);
unsigned int outputCount = stream.readInt<unsigned int>();
ASSERT(state->mOutputVariables.empty());
for (unsigned int outputIndex = 0; outputIndex < outputCount; ++outputIndex)
{
sh::OutputVariable output;
LoadShaderVar(&stream, &output);
output.location = stream.readInt<int>();
output.index = stream.readInt<int>();
state->mOutputVariables.push_back(output);
}
unsigned int outputVarCount = stream.readInt<unsigned int>();
ASSERT(state->mOutputLocations.empty());
for (unsigned int outputIndex = 0; outputIndex < outputVarCount; ++outputIndex)
{
VariableLocation locationData;
stream.readInt(&locationData.arrayIndex);
stream.readInt(&locationData.index);
stream.readBool(&locationData.ignored);
state->mOutputLocations.push_back(locationData);
}
unsigned int secondaryOutputVarCount = stream.readInt<unsigned int>();
ASSERT(state->mSecondaryOutputLocations.empty());
for (unsigned int outputIndex = 0; outputIndex < secondaryOutputVarCount; ++outputIndex)
{
VariableLocation locationData;
stream.readInt(&locationData.arrayIndex);
stream.readInt(&locationData.index);
stream.readBool(&locationData.ignored);
state->mSecondaryOutputLocations.push_back(locationData);
}
unsigned int outputTypeCount = stream.readInt<unsigned int>();
for (unsigned int outputIndex = 0; outputIndex < outputTypeCount; ++outputIndex)
{
state->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");
state->mDrawBufferTypeMask = gl::ComponentTypeMask(stream.readInt<uint32_t>());
state->mActiveOutputVariables = stream.readInt<gl::DrawBufferMask>();
unsigned int samplerRangeLow = stream.readInt<unsigned int>();
unsigned int samplerRangeHigh = stream.readInt<unsigned int>();
state->mSamplerUniformRange = RangeUI(samplerRangeLow, samplerRangeHigh);
unsigned int samplerCount = stream.readInt<unsigned int>();
for (unsigned int samplerIndex = 0; samplerIndex < samplerCount; ++samplerIndex)
{
TextureType textureType = stream.readEnum<TextureType>();
SamplerFormat format = stream.readEnum<SamplerFormat>();
size_t bindingCount = stream.readInt<size_t>();
bool unreferenced = stream.readBool();
state->mSamplerBindings.emplace_back(textureType, format, bindingCount, unreferenced);
}
unsigned int imageRangeLow = stream.readInt<unsigned int>();
unsigned int imageRangeHigh = stream.readInt<unsigned int>();
state->mImageUniformRange = RangeUI(imageRangeLow, imageRangeHigh);
unsigned int imageBindingCount = stream.readInt<unsigned int>();
for (unsigned int imageIndex = 0; imageIndex < imageBindingCount; ++imageIndex)
{
unsigned int elementCount = stream.readInt<unsigned int>();
ImageBinding imageBinding(elementCount);
for (unsigned int i = 0; i < elementCount; ++i)
{
imageBinding.boundImageUnits[i] = stream.readInt<unsigned int>();
}
state->mImageBindings.emplace_back(imageBinding);
}
unsigned int atomicCounterRangeLow = stream.readInt<unsigned int>();
unsigned int atomicCounterRangeHigh = stream.readInt<unsigned int>();
state->mAtomicCounterUniformRange = RangeUI(atomicCounterRangeLow, atomicCounterRangeHigh);
static_assert(static_cast<unsigned long>(ShaderType::EnumCount) <= sizeof(unsigned long) * 8,
"Too many shader types");
state->mLinkedShaderStages = ShaderBitSet(stream.readInt<uint8_t>());
state->updateTransformFeedbackStrides();
state->updateActiveSamplers();
state->updateActiveImages();
return program->getImplementation()->load(context, infoLog, &stream);
}
// static
void MemoryProgramCache::Serialize(const Context *context,
const gl::Program *program,
angle::MemoryBuffer *binaryOut)
{
BinaryOutputStream stream;
stream.writeBytes(reinterpret_cast<const unsigned char *>(ANGLE_COMMIT_HASH),
ANGLE_COMMIT_HASH_SIZE);
// nullptr context is supported when computing binary length.
if (context)
{
stream.writeInt(context->getClientVersion().major);
stream.writeInt(context->getClientVersion().minor);
}
else
{
stream.writeInt(2);
stream.writeInt(0);
}
const auto &state = program->getState();
const auto &computeLocalSize = state.getComputeShaderLocalSize();
stream.writeInt(computeLocalSize[0]);
stream.writeInt(computeLocalSize[1]);
stream.writeInt(computeLocalSize[2]);
ASSERT(state.mGeometryShaderInvocations >= 1 && state.mGeometryShaderMaxVertices >= 0);
stream.writeEnum(state.mGeometryShaderInputPrimitiveType);
stream.writeEnum(state.mGeometryShaderOutputPrimitiveType);
stream.writeInt(state.mGeometryShaderInvocations);
stream.writeInt(state.mGeometryShaderMaxVertices);
stream.writeInt(state.mNumViews);
static_assert(MAX_VERTEX_ATTRIBS * 2 <= sizeof(uint32_t) * 8,
"All bits of mAttributesTypeMask types and mask fit into 32 bits each");
stream.writeInt(static_cast<int>(state.mAttributesTypeMask.to_ulong()));
stream.writeInt(static_cast<int>(state.mAttributesMask.to_ulong()));
stream.writeInt(state.getActiveAttribLocationsMask().to_ulong());
stream.writeInt(state.getAttributes().size());
for (const sh::Attribute &attrib : state.getAttributes())
{
WriteShaderVar(&stream, attrib);
stream.writeInt(attrib.location);
}
stream.writeInt(state.getUniforms().size());
for (const LinkedUniform &uniform : state.getUniforms())
{
WriteShaderVar(&stream, uniform);
// FIXME: referenced
stream.writeInt(uniform.bufferIndex);
stream.writeInt(uniform.blockInfo.offset);
stream.writeInt(uniform.blockInfo.arrayStride);
stream.writeInt(uniform.blockInfo.matrixStride);
stream.writeInt(uniform.blockInfo.isRowMajorMatrix);
}
stream.writeInt(state.getUniformLocations().size());
for (const auto &variable : state.getUniformLocations())
{
stream.writeInt(variable.arrayIndex);
stream.writeIntOrNegOne(variable.index);
stream.writeInt(variable.ignored);
}
stream.writeInt(state.getUniformBlocks().size());
for (const InterfaceBlock &uniformBlock : state.getUniformBlocks())
{
WriteInterfaceBlock(&stream, uniformBlock);
}
stream.writeInt(state.getBufferVariables().size());
for (const BufferVariable &bufferVariable : state.getBufferVariables())
{
WriteBufferVariable(&stream, bufferVariable);
}
stream.writeInt(state.getShaderStorageBlocks().size());
for (const InterfaceBlock &shaderStorageBlock : state.getShaderStorageBlocks())
{
WriteInterfaceBlock(&stream, shaderStorageBlock);
}
stream.writeInt(state.mAtomicCounterBuffers.size());
for (const auto &atomicCounterBuffer : state.mAtomicCounterBuffers)
{
WriteShaderVariableBuffer(&stream, atomicCounterBuffer);
}
// Warn the app layer if saving a binary with unsupported transform feedback.
if (!state.getLinkedTransformFeedbackVaryings().empty() &&
context->getWorkarounds().disableProgramCachingForTransformFeedback)
{
WARN() << "Saving program binary with transform feedback, which is not supported on this "
"driver.";
}
stream.writeInt(state.getLinkedTransformFeedbackVaryings().size());
for (const auto &var : state.getLinkedTransformFeedbackVaryings())
{
stream.writeIntVector(var.arraySizes);
stream.writeInt(var.type);
stream.writeString(var.name);
stream.writeIntOrNegOne(var.arrayIndex);
}
stream.writeInt(state.getTransformFeedbackBufferMode());
stream.writeInt(state.getOutputVariables().size());
for (const sh::OutputVariable &output : state.getOutputVariables())
{
WriteShaderVar(&stream, output);
stream.writeInt(output.location);
stream.writeInt(output.index);
}
stream.writeInt(state.getOutputLocations().size());
for (const auto &outputVar : state.getOutputLocations())
{
stream.writeInt(outputVar.arrayIndex);
stream.writeIntOrNegOne(outputVar.index);
stream.writeInt(outputVar.ignored);
}
stream.writeInt(state.getSecondaryOutputLocations().size());
for (const auto &outputVar : state.getSecondaryOutputLocations())
{
stream.writeInt(outputVar.arrayIndex);
stream.writeIntOrNegOne(outputVar.index);
stream.writeInt(outputVar.ignored);
}
stream.writeInt(state.mOutputVariableTypes.size());
for (const auto &outputVariableType : state.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>(state.mDrawBufferTypeMask.to_ulong()));
stream.writeInt(static_cast<int>(state.mActiveOutputVariables.to_ulong()));
stream.writeInt(state.getSamplerUniformRange().low());
stream.writeInt(state.getSamplerUniformRange().high());
stream.writeInt(state.getSamplerBindings().size());
for (const auto &samplerBinding : state.getSamplerBindings())
{
stream.writeEnum(samplerBinding.textureType);
stream.writeEnum(samplerBinding.format);
stream.writeInt(samplerBinding.boundTextureUnits.size());
stream.writeInt(samplerBinding.unreferenced);
}
stream.writeInt(state.getImageUniformRange().low());
stream.writeInt(state.getImageUniformRange().high());
stream.writeInt(state.getImageBindings().size());
for (const auto &imageBinding : state.getImageBindings())
{
stream.writeInt(imageBinding.boundImageUnits.size());
for (size_t i = 0; i < imageBinding.boundImageUnits.size(); ++i)
{
stream.writeInt(imageBinding.boundImageUnits[i]);
}
}
stream.writeInt(state.getAtomicCounterUniformRange().low());
stream.writeInt(state.getAtomicCounterUniformRange().high());
stream.writeInt(state.getLinkedShaderStages().to_ulong());
program->getImplementation()->save(context, &stream);
ASSERT(binaryOut);
binaryOut->resize(stream.length());
memcpy(binaryOut->data(), stream.data(), stream.length());
}
// static
void MemoryProgramCache::ComputeHash(const Context *context, void MemoryProgramCache::ComputeHash(const Context *context,
const Program *program, const Program *program,
egl::BlobCache::Key *hashOut) egl::BlobCache::Key *hashOut)
...@@ -672,8 +120,7 @@ void MemoryProgramCache::ComputeHash(const Context *context, ...@@ -672,8 +120,7 @@ void MemoryProgramCache::ComputeHash(const Context *context,
} }
angle::Result MemoryProgramCache::getProgram(const Context *context, angle::Result MemoryProgramCache::getProgram(const Context *context,
const Program *program, Program *program,
ProgramState *state,
egl::BlobCache::Key *hashOut) egl::BlobCache::Key *hashOut)
{ {
ComputeHash(context, program, hashOut); ComputeHash(context, program, hashOut);
...@@ -681,8 +128,8 @@ angle::Result MemoryProgramCache::getProgram(const Context *context, ...@@ -681,8 +128,8 @@ angle::Result MemoryProgramCache::getProgram(const Context *context,
if (get(context, *hashOut, &binaryProgram)) if (get(context, *hashOut, &binaryProgram))
{ {
InfoLog infoLog; InfoLog infoLog;
angle::Result result = Deserialize(context, program, state, binaryProgram.data(), angle::Result result =
binaryProgram.size(), infoLog); program->deserialize(context, binaryProgram.data(), binaryProgram.size(), infoLog);
ANGLE_HISTOGRAM_BOOLEAN("GPU.ANGLE.ProgramCache.LoadBinarySuccess", ANGLE_HISTOGRAM_BOOLEAN("GPU.ANGLE.ProgramCache.LoadBinarySuccess",
result == angle::Result::Continue); result == angle::Result::Continue);
ANGLE_TRY(result); ANGLE_TRY(result);
...@@ -730,7 +177,7 @@ void MemoryProgramCache::putProgram(const egl::BlobCache::Key &programHash, ...@@ -730,7 +177,7 @@ void MemoryProgramCache::putProgram(const egl::BlobCache::Key &programHash,
const Program *program) const Program *program)
{ {
angle::MemoryBuffer serializedProgram; angle::MemoryBuffer serializedProgram;
Serialize(context, program, &serializedProgram); program->serialize(context, &serializedProgram);
ANGLE_HISTOGRAM_COUNTS("GPU.ANGLE.ProgramCache.ProgramBinarySizeBytes", ANGLE_HISTOGRAM_COUNTS("GPU.ANGLE.ProgramCache.ProgramBinarySizeBytes",
static_cast<int>(serializedProgram.size())); static_cast<int>(serializedProgram.size()));
......
...@@ -19,7 +19,6 @@ ...@@ -19,7 +19,6 @@
namespace gl namespace gl
{ {
class Context; class Context;
class InfoLog;
class Program; class Program;
class ProgramState; class ProgramState;
...@@ -29,19 +28,6 @@ class MemoryProgramCache final : angle::NonCopyable ...@@ -29,19 +28,6 @@ class MemoryProgramCache final : angle::NonCopyable
explicit MemoryProgramCache(egl::BlobCache &blobCache); explicit MemoryProgramCache(egl::BlobCache &blobCache);
~MemoryProgramCache(); ~MemoryProgramCache();
// Writes a program's binary to the output memory buffer.
static void Serialize(const Context *context,
const Program *program,
angle::MemoryBuffer *binaryOut);
// Loads program state according to the specified binary blob.
static angle::Result Deserialize(const Context *context,
const Program *program,
ProgramState *state,
const uint8_t *binary,
size_t length,
InfoLog &infoLog);
static void ComputeHash(const Context *context, static void ComputeHash(const Context *context,
const Program *program, const Program *program,
egl::BlobCache::Key *hashOut); egl::BlobCache::Key *hashOut);
...@@ -74,8 +60,7 @@ class MemoryProgramCache final : angle::NonCopyable ...@@ -74,8 +60,7 @@ class MemoryProgramCache final : angle::NonCopyable
// Check the cache, and deserialize and load the program if found. Evict existing hash if load // Check the cache, and deserialize and load the program if found. Evict existing hash if load
// fails. // fails.
angle::Result getProgram(const Context *context, angle::Result getProgram(const Context *context,
const Program *program, Program *program,
ProgramState *state,
egl::BlobCache::Key *hashOut); egl::BlobCache::Key *hashOut);
// Empty the cache. // Empty the cache.
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "common/platform.h" #include "common/platform.h"
#include "common/string_utils.h" #include "common/string_utils.h"
#include "common/utilities.h" #include "common/utilities.h"
#include "common/version.h"
#include "compiler/translator/blocklayout.h" #include "compiler/translator/blocklayout.h"
#include "libANGLE/Context.h" #include "libANGLE/Context.h"
#include "libANGLE/MemoryProgramCache.h" #include "libANGLE/MemoryProgramCache.h"
...@@ -593,6 +594,121 @@ bool ValidateInterfaceBlocksMatch( ...@@ -593,6 +594,121 @@ bool ValidateInterfaceBlocksMatch(
return true; return true;
} }
void WriteShaderVar(BinaryOutputStream *stream, const sh::ShaderVariable &var)
{
stream->writeInt(var.type);
stream->writeInt(var.precision);
stream->writeString(var.name);
stream->writeString(var.mappedName);
stream->writeIntVector(var.arraySizes);
stream->writeInt(var.staticUse);
stream->writeInt(var.active);
stream->writeString(var.structName);
ASSERT(var.fields.empty());
}
void LoadShaderVar(BinaryInputStream *stream, sh::ShaderVariable *var)
{
var->type = stream->readInt<GLenum>();
var->precision = stream->readInt<GLenum>();
var->name = stream->readString();
var->mappedName = stream->readString();
stream->readIntVector<unsigned int>(&var->arraySizes);
var->staticUse = stream->readBool();
var->active = stream->readBool();
var->structName = stream->readString();
}
void WriteShaderVariableBuffer(BinaryOutputStream *stream, const ShaderVariableBuffer &var)
{
stream->writeInt(var.binding);
stream->writeInt(var.dataSize);
for (ShaderType shaderType : AllShaderTypes())
{
stream->writeInt(var.isActive(shaderType));
}
stream->writeInt(var.memberIndexes.size());
for (unsigned int memberCounterIndex : var.memberIndexes)
{
stream->writeInt(memberCounterIndex);
}
}
void LoadShaderVariableBuffer(BinaryInputStream *stream, ShaderVariableBuffer *var)
{
var->binding = stream->readInt<int>();
var->dataSize = stream->readInt<unsigned int>();
for (ShaderType shaderType : AllShaderTypes())
{
var->setActive(shaderType, stream->readBool());
}
unsigned int numMembers = stream->readInt<unsigned int>();
for (unsigned int blockMemberIndex = 0; blockMemberIndex < numMembers; blockMemberIndex++)
{
var->memberIndexes.push_back(stream->readInt<unsigned int>());
}
}
void WriteBufferVariable(BinaryOutputStream *stream, const BufferVariable &var)
{
WriteShaderVar(stream, var);
stream->writeInt(var.bufferIndex);
stream->writeInt(var.blockInfo.offset);
stream->writeInt(var.blockInfo.arrayStride);
stream->writeInt(var.blockInfo.matrixStride);
stream->writeInt(var.blockInfo.isRowMajorMatrix);
stream->writeInt(var.blockInfo.topLevelArrayStride);
stream->writeInt(var.topLevelArraySize);
for (ShaderType shaderType : AllShaderTypes())
{
stream->writeInt(var.isActive(shaderType));
}
}
void LoadBufferVariable(BinaryInputStream *stream, BufferVariable *var)
{
LoadShaderVar(stream, var);
var->bufferIndex = stream->readInt<int>();
var->blockInfo.offset = stream->readInt<int>();
var->blockInfo.arrayStride = stream->readInt<int>();
var->blockInfo.matrixStride = stream->readInt<int>();
var->blockInfo.isRowMajorMatrix = stream->readBool();
var->blockInfo.topLevelArrayStride = stream->readInt<int>();
var->topLevelArraySize = stream->readInt<int>();
for (ShaderType shaderType : AllShaderTypes())
{
var->setActive(shaderType, stream->readBool());
}
}
void WriteInterfaceBlock(BinaryOutputStream *stream, const InterfaceBlock &block)
{
stream->writeString(block.name);
stream->writeString(block.mappedName);
stream->writeInt(block.isArray);
stream->writeInt(block.arrayElement);
WriteShaderVariableBuffer(stream, block);
}
void LoadInterfaceBlock(BinaryInputStream *stream, InterfaceBlock *block)
{
block->name = stream->readString();
block->mappedName = stream->readString();
block->isArray = stream->readBool();
block->arrayElement = stream->readInt<unsigned int>();
LoadShaderVariableBuffer(stream, block);
}
} // anonymous namespace } // anonymous namespace
// Saves the linking context for later use in resolveLink(). // Saves the linking context for later use in resolveLink().
...@@ -1118,7 +1234,7 @@ angle::Result Program::link(const Context *context) ...@@ -1118,7 +1234,7 @@ angle::Result Program::link(const Context *context)
if (cache) if (cache)
{ {
angle::Result result = cache->getProgram(context, this, &mState, &programHash); angle::Result result = cache->getProgram(context, this, &programHash);
mLinked = (result == angle::Result::Continue); mLinked = (result == angle::Result::Continue);
ANGLE_TRY(result); ANGLE_TRY(result);
} }
...@@ -1298,16 +1414,12 @@ void Program::resolveLinkImpl(const Context *context) ...@@ -1298,16 +1414,12 @@ void Program::resolveLinkImpl(const Context *context)
&mState.mImageBindings); &mState.mImageBindings);
// Must be called after markUnusedUniformLocations. // Must be called after markUnusedUniformLocations.
mState.updateActiveSamplers(); postResolveLink(context);
mState.updateActiveImages();
// TODO(syoussefi): this might need to be moved to postResolveLink() so it will be called from
// deserialize() as well. http://anglebug.com/3089
setUniformValuesFromBindingQualifiers(); setUniformValuesFromBindingQualifiers();
if (context->getExtensions().multiDraw)
{
mState.mDrawIDLocation = getUniformLocation("gl_DrawID");
}
// Save to the program cache. // Save to the program cache.
auto *cache = linkingState->context->getMemoryProgramCache(); auto *cache = linkingState->context->getMemoryProgramCache();
if (cache && if (cache &&
...@@ -1456,8 +1568,7 @@ angle::Result Program::loadBinary(const Context *context, ...@@ -1456,8 +1568,7 @@ angle::Result Program::loadBinary(const Context *context,
} }
const uint8_t *bytes = reinterpret_cast<const uint8_t *>(binary); const uint8_t *bytes = reinterpret_cast<const uint8_t *>(binary);
angle::Result result = angle::Result result = deserialize(context, bytes, length, mInfoLog);
MemoryProgramCache::Deserialize(context, this, &mState, bytes, length, mInfoLog);
mLinked = result == angle::Result::Continue; mLinked = result == angle::Result::Continue;
ANGLE_TRY(result); ANGLE_TRY(result);
...@@ -1487,7 +1598,7 @@ angle::Result Program::saveBinary(Context *context, ...@@ -1487,7 +1598,7 @@ angle::Result Program::saveBinary(Context *context,
} }
angle::MemoryBuffer memoryBuf; angle::MemoryBuffer memoryBuf;
MemoryProgramCache::Serialize(context, this, &memoryBuf); serialize(context, &memoryBuf);
GLsizei streamLength = static_cast<GLsizei>(memoryBuf.size()); GLsizei streamLength = static_cast<GLsizei>(memoryBuf.size());
const uint8_t *streamState = memoryBuf.data(); const uint8_t *streamState = memoryBuf.data();
...@@ -3551,7 +3662,6 @@ void Program::gatherTransformFeedbackVaryings(const ProgramMergedVaryings &varyi ...@@ -3551,7 +3662,6 @@ void Program::gatherTransformFeedbackVaryings(const ProgramMergedVaryings &varyi
} }
} }
} }
mState.updateTransformFeedbackStrides();
} }
ProgramMergedVaryings Program::getMergedVaryings() const ProgramMergedVaryings Program::getMergedVaryings() const
...@@ -4144,4 +4254,447 @@ angle::Result Program::syncState(const Context *context) ...@@ -4144,4 +4254,447 @@ angle::Result Program::syncState(const Context *context)
return angle::Result::Continue; return angle::Result::Continue;
} }
void Program::serialize(const Context *context, angle::MemoryBuffer *binaryOut) const
{
BinaryOutputStream stream;
stream.writeBytes(reinterpret_cast<const unsigned char *>(ANGLE_COMMIT_HASH),
ANGLE_COMMIT_HASH_SIZE);
// nullptr context is supported when computing binary length.
if (context)
{
stream.writeInt(context->getClientVersion().major);
stream.writeInt(context->getClientVersion().minor);
}
else
{
stream.writeInt(2);
stream.writeInt(0);
}
const auto &computeLocalSize = mState.getComputeShaderLocalSize();
stream.writeInt(computeLocalSize[0]);
stream.writeInt(computeLocalSize[1]);
stream.writeInt(computeLocalSize[2]);
ASSERT(mState.mGeometryShaderInvocations >= 1 && mState.mGeometryShaderMaxVertices >= 0);
stream.writeEnum(mState.mGeometryShaderInputPrimitiveType);
stream.writeEnum(mState.mGeometryShaderOutputPrimitiveType);
stream.writeInt(mState.mGeometryShaderInvocations);
stream.writeInt(mState.mGeometryShaderMaxVertices);
stream.writeInt(mState.mNumViews);
static_assert(MAX_VERTEX_ATTRIBS * 2 <= sizeof(uint32_t) * 8,
"All bits of mAttributesTypeMask types and mask fit into 32 bits each");
stream.writeInt(static_cast<int>(mState.mAttributesTypeMask.to_ulong()));
stream.writeInt(static_cast<int>(mState.mAttributesMask.to_ulong()));
stream.writeInt(mState.getActiveAttribLocationsMask().to_ulong());
stream.writeInt(mState.getAttributes().size());
for (const sh::Attribute &attrib : mState.getAttributes())
{
WriteShaderVar(&stream, attrib);
stream.writeInt(attrib.location);
}
stream.writeInt(mState.getUniforms().size());
for (const LinkedUniform &uniform : mState.getUniforms())
{
WriteShaderVar(&stream, uniform);
// FIXME: referenced
stream.writeInt(uniform.bufferIndex);
stream.writeInt(uniform.blockInfo.offset);
stream.writeInt(uniform.blockInfo.arrayStride);
stream.writeInt(uniform.blockInfo.matrixStride);
stream.writeInt(uniform.blockInfo.isRowMajorMatrix);
}
stream.writeInt(mState.getUniformLocations().size());
for (const auto &variable : mState.getUniformLocations())
{
stream.writeInt(variable.arrayIndex);
stream.writeIntOrNegOne(variable.index);
stream.writeInt(variable.ignored);
}
stream.writeInt(mState.getUniformBlocks().size());
for (const InterfaceBlock &uniformBlock : mState.getUniformBlocks())
{
WriteInterfaceBlock(&stream, uniformBlock);
}
stream.writeInt(mState.getBufferVariables().size());
for (const BufferVariable &bufferVariable : mState.getBufferVariables())
{
WriteBufferVariable(&stream, bufferVariable);
}
stream.writeInt(mState.getShaderStorageBlocks().size());
for (const InterfaceBlock &shaderStorageBlock : mState.getShaderStorageBlocks())
{
WriteInterfaceBlock(&stream, shaderStorageBlock);
}
stream.writeInt(mState.mAtomicCounterBuffers.size());
for (const auto &atomicCounterBuffer : mState.mAtomicCounterBuffers)
{
WriteShaderVariableBuffer(&stream, atomicCounterBuffer);
}
// Warn the app layer if saving a binary with unsupported transform feedback.
if (!mState.getLinkedTransformFeedbackVaryings().empty() &&
context->getWorkarounds().disableProgramCachingForTransformFeedback)
{
WARN() << "Saving program binary with transform feedback, which is not supported on this "
"driver.";
}
stream.writeInt(mState.getLinkedTransformFeedbackVaryings().size());
for (const auto &var : mState.getLinkedTransformFeedbackVaryings())
{
stream.writeIntVector(var.arraySizes);
stream.writeInt(var.type);
stream.writeString(var.name);
stream.writeIntOrNegOne(var.arrayIndex);
}
stream.writeInt(mState.getTransformFeedbackBufferMode());
stream.writeInt(mState.getOutputVariables().size());
for (const sh::OutputVariable &output : mState.getOutputVariables())
{
WriteShaderVar(&stream, output);
stream.writeInt(output.location);
stream.writeInt(output.index);
}
stream.writeInt(mState.getOutputLocations().size());
for (const auto &outputVar : mState.getOutputLocations())
{
stream.writeInt(outputVar.arrayIndex);
stream.writeIntOrNegOne(outputVar.index);
stream.writeInt(outputVar.ignored);
}
stream.writeInt(mState.getSecondaryOutputLocations().size());
for (const auto &outputVar : mState.getSecondaryOutputLocations())
{
stream.writeInt(outputVar.arrayIndex);
stream.writeIntOrNegOne(outputVar.index);
stream.writeInt(outputVar.ignored);
}
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.writeInt(mState.getSamplerUniformRange().low());
stream.writeInt(mState.getSamplerUniformRange().high());
stream.writeInt(mState.getSamplerBindings().size());
for (const auto &samplerBinding : mState.getSamplerBindings())
{
stream.writeEnum(samplerBinding.textureType);
stream.writeEnum(samplerBinding.format);
stream.writeInt(samplerBinding.boundTextureUnits.size());
stream.writeInt(samplerBinding.unreferenced);
}
stream.writeInt(mState.getImageUniformRange().low());
stream.writeInt(mState.getImageUniformRange().high());
stream.writeInt(mState.getImageBindings().size());
for (const auto &imageBinding : mState.getImageBindings())
{
stream.writeInt(imageBinding.boundImageUnits.size());
for (size_t i = 0; i < imageBinding.boundImageUnits.size(); ++i)
{
stream.writeInt(imageBinding.boundImageUnits[i]);
}
}
stream.writeInt(mState.getAtomicCounterUniformRange().low());
stream.writeInt(mState.getAtomicCounterUniformRange().high());
stream.writeInt(mState.getLinkedShaderStages().to_ulong());
mProgram->save(context, &stream);
ASSERT(binaryOut);
binaryOut->resize(stream.length());
memcpy(binaryOut->data(), stream.data(), stream.length());
}
angle::Result Program::deserialize(const Context *context,
const uint8_t *binary,
size_t length,
InfoLog &infoLog)
{
BinaryInputStream stream(binary, length);
unsigned char commitString[ANGLE_COMMIT_HASH_SIZE];
stream.readBytes(commitString, ANGLE_COMMIT_HASH_SIZE);
if (memcmp(commitString, ANGLE_COMMIT_HASH, sizeof(unsigned char) * ANGLE_COMMIT_HASH_SIZE) !=
0)
{
infoLog << "Invalid program binary version.";
return angle::Result::Incomplete;
}
int majorVersion = stream.readInt<int>();
int minorVersion = stream.readInt<int>();
if (majorVersion != context->getClientMajorVersion() ||
minorVersion != context->getClientMinorVersion())
{
infoLog << "Cannot load program binaries across different ES context versions.";
return angle::Result::Incomplete;
}
mState.mComputeShaderLocalSize[0] = stream.readInt<int>();
mState.mComputeShaderLocalSize[1] = stream.readInt<int>();
mState.mComputeShaderLocalSize[2] = stream.readInt<int>();
mState.mGeometryShaderInputPrimitiveType = stream.readEnum<PrimitiveMode>();
mState.mGeometryShaderOutputPrimitiveType = stream.readEnum<PrimitiveMode>();
mState.mGeometryShaderInvocations = stream.readInt<int>();
mState.mGeometryShaderMaxVertices = stream.readInt<int>();
mState.mNumViews = stream.readInt<int>();
static_assert(MAX_VERTEX_ATTRIBS * 2 <= sizeof(uint32_t) * 8,
"All bits of mAttributesTypeMask types and mask fit into 32 bits each");
mState.mAttributesTypeMask = gl::ComponentTypeMask(stream.readInt<uint32_t>());
mState.mAttributesMask = stream.readInt<gl::AttributesMask>();
static_assert(MAX_VERTEX_ATTRIBS <= sizeof(unsigned long) * 8,
"Too many vertex attribs for mask");
mState.mActiveAttribLocationsMask = stream.readInt<gl::AttributesMask>();
unsigned int attribCount = stream.readInt<unsigned int>();
ASSERT(mState.mAttributes.empty());
for (unsigned int attribIndex = 0; attribIndex < attribCount; ++attribIndex)
{
sh::Attribute attrib;
LoadShaderVar(&stream, &attrib);
attrib.location = stream.readInt<int>();
mState.mAttributes.push_back(attrib);
}
unsigned int uniformCount = stream.readInt<unsigned int>();
ASSERT(mState.mUniforms.empty());
for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; ++uniformIndex)
{
LinkedUniform uniform;
LoadShaderVar(&stream, &uniform);
uniform.bufferIndex = stream.readInt<int>();
uniform.blockInfo.offset = stream.readInt<int>();
uniform.blockInfo.arrayStride = stream.readInt<int>();
uniform.blockInfo.matrixStride = stream.readInt<int>();
uniform.blockInfo.isRowMajorMatrix = stream.readBool();
uniform.typeInfo = &GetUniformTypeInfo(uniform.type);
mState.mUniforms.push_back(uniform);
}
const unsigned int uniformIndexCount = stream.readInt<unsigned int>();
ASSERT(mState.mUniformLocations.empty());
for (unsigned int uniformIndexIndex = 0; uniformIndexIndex < uniformIndexCount;
uniformIndexIndex++)
{
VariableLocation variable;
stream.readInt(&variable.arrayIndex);
stream.readInt(&variable.index);
stream.readBool(&variable.ignored);
mState.mUniformLocations.push_back(variable);
}
unsigned int uniformBlockCount = stream.readInt<unsigned int>();
ASSERT(mState.mUniformBlocks.empty());
for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount;
++uniformBlockIndex)
{
InterfaceBlock uniformBlock;
LoadInterfaceBlock(&stream, &uniformBlock);
mState.mUniformBlocks.push_back(uniformBlock);
mState.mActiveUniformBlockBindings.set(uniformBlockIndex, uniformBlock.binding != 0);
}
unsigned int bufferVariableCount = stream.readInt<unsigned int>();
ASSERT(mState.mBufferVariables.empty());
for (unsigned int index = 0; index < bufferVariableCount; ++index)
{
BufferVariable bufferVariable;
LoadBufferVariable(&stream, &bufferVariable);
mState.mBufferVariables.push_back(bufferVariable);
}
unsigned int shaderStorageBlockCount = stream.readInt<unsigned int>();
ASSERT(mState.mShaderStorageBlocks.empty());
for (unsigned int shaderStorageBlockIndex = 0;
shaderStorageBlockIndex < shaderStorageBlockCount; ++shaderStorageBlockIndex)
{
InterfaceBlock shaderStorageBlock;
LoadInterfaceBlock(&stream, &shaderStorageBlock);
mState.mShaderStorageBlocks.push_back(shaderStorageBlock);
}
unsigned int atomicCounterBufferCount = stream.readInt<unsigned int>();
ASSERT(mState.mAtomicCounterBuffers.empty());
for (unsigned int bufferIndex = 0; bufferIndex < atomicCounterBufferCount; ++bufferIndex)
{
AtomicCounterBuffer atomicCounterBuffer;
LoadShaderVariableBuffer(&stream, &atomicCounterBuffer);
mState.mAtomicCounterBuffers.push_back(atomicCounterBuffer);
}
unsigned int transformFeedbackVaryingCount = stream.readInt<unsigned int>();
// Reject programs that use transform feedback varyings if the hardware cannot support them.
if (transformFeedbackVaryingCount > 0 &&
context->getWorkarounds().disableProgramCachingForTransformFeedback)
{
infoLog << "Current driver does not support transform feedback in binary programs.";
return angle::Result::Incomplete;
}
ASSERT(mState.mLinkedTransformFeedbackVaryings.empty());
for (unsigned int transformFeedbackVaryingIndex = 0;
transformFeedbackVaryingIndex < transformFeedbackVaryingCount;
++transformFeedbackVaryingIndex)
{
sh::Varying varying;
stream.readIntVector<unsigned int>(&varying.arraySizes);
stream.readInt(&varying.type);
stream.readString(&varying.name);
GLuint arrayIndex = stream.readInt<GLuint>();
mState.mLinkedTransformFeedbackVaryings.emplace_back(varying, arrayIndex);
}
stream.readInt(&mState.mTransformFeedbackBufferMode);
unsigned int outputCount = stream.readInt<unsigned int>();
ASSERT(mState.mOutputVariables.empty());
for (unsigned int outputIndex = 0; outputIndex < outputCount; ++outputIndex)
{
sh::OutputVariable output;
LoadShaderVar(&stream, &output);
output.location = stream.readInt<int>();
output.index = stream.readInt<int>();
mState.mOutputVariables.push_back(output);
}
unsigned int outputVarCount = stream.readInt<unsigned int>();
ASSERT(mState.mOutputLocations.empty());
for (unsigned int outputIndex = 0; outputIndex < outputVarCount; ++outputIndex)
{
VariableLocation locationData;
stream.readInt(&locationData.arrayIndex);
stream.readInt(&locationData.index);
stream.readBool(&locationData.ignored);
mState.mOutputLocations.push_back(locationData);
}
unsigned int secondaryOutputVarCount = stream.readInt<unsigned int>();
ASSERT(mState.mSecondaryOutputLocations.empty());
for (unsigned int outputIndex = 0; outputIndex < secondaryOutputVarCount; ++outputIndex)
{
VariableLocation locationData;
stream.readInt(&locationData.arrayIndex);
stream.readInt(&locationData.index);
stream.readBool(&locationData.ignored);
mState.mSecondaryOutputLocations.push_back(locationData);
}
unsigned int outputTypeCount = stream.readInt<unsigned int>();
for (unsigned int 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 = stream.readInt<gl::DrawBufferMask>();
unsigned int samplerRangeLow = stream.readInt<unsigned int>();
unsigned int samplerRangeHigh = stream.readInt<unsigned int>();
mState.mSamplerUniformRange = RangeUI(samplerRangeLow, samplerRangeHigh);
unsigned int samplerCount = stream.readInt<unsigned int>();
for (unsigned int samplerIndex = 0; samplerIndex < samplerCount; ++samplerIndex)
{
TextureType textureType = stream.readEnum<TextureType>();
SamplerFormat format = stream.readEnum<SamplerFormat>();
size_t bindingCount = stream.readInt<size_t>();
bool unreferenced = stream.readBool();
mState.mSamplerBindings.emplace_back(textureType, format, bindingCount, unreferenced);
}
unsigned int imageRangeLow = stream.readInt<unsigned int>();
unsigned int imageRangeHigh = stream.readInt<unsigned int>();
mState.mImageUniformRange = RangeUI(imageRangeLow, imageRangeHigh);
unsigned int imageBindingCount = stream.readInt<unsigned int>();
for (unsigned int imageIndex = 0; imageIndex < imageBindingCount; ++imageIndex)
{
unsigned int elementCount = stream.readInt<unsigned int>();
ImageBinding imageBinding(elementCount);
for (unsigned int i = 0; i < elementCount; ++i)
{
imageBinding.boundImageUnits[i] = stream.readInt<unsigned int>();
}
mState.mImageBindings.emplace_back(imageBinding);
}
unsigned int atomicCounterRangeLow = stream.readInt<unsigned int>();
unsigned int atomicCounterRangeHigh = stream.readInt<unsigned int>();
mState.mAtomicCounterUniformRange = RangeUI(atomicCounterRangeLow, atomicCounterRangeHigh);
static_assert(static_cast<unsigned long>(ShaderType::EnumCount) <= sizeof(unsigned long) * 8,
"Too many shader types");
mState.mLinkedShaderStages = ShaderBitSet(stream.readInt<uint8_t>());
postResolveLink(context);
return mProgram->load(context, infoLog, &stream);
}
void Program::postResolveLink(const gl::Context *context)
{
if (!mState.mAttachedShaders[ShaderType::Compute])
{
mState.updateTransformFeedbackStrides();
}
mState.updateActiveSamplers();
mState.updateActiveImages();
if (context->getExtensions().multiDraw)
{
mState.mDrawIDLocation = getUniformLocation("gl_DrawID");
}
}
} // namespace gl } // namespace gl
...@@ -878,6 +878,15 @@ class Program final : angle::NonCopyable, public LabeledObject ...@@ -878,6 +878,15 @@ class Program final : angle::NonCopyable, public LabeledObject
ANGLE_INLINE bool hasAnyDirtyBit() const { return mDirtyBits.any(); } ANGLE_INLINE bool hasAnyDirtyBit() const { return mDirtyBits.any(); }
// Writes a program's binary to the output memory buffer.
void serialize(const Context *context, angle::MemoryBuffer *binaryOut) const;
// Loads program state according to the specified binary blob.
angle::Result deserialize(const Context *context,
const uint8_t *binary,
size_t length,
InfoLog &infoLog);
private: private:
struct LinkingState; struct LinkingState;
...@@ -980,6 +989,8 @@ class Program final : angle::NonCopyable, public LabeledObject ...@@ -980,6 +989,8 @@ class Program final : angle::NonCopyable, public LabeledObject
// Block until linking is finished and resolve it. // Block until linking is finished and resolve it.
void resolveLinkImpl(const gl::Context *context); void resolveLinkImpl(const gl::Context *context);
void postResolveLink(const gl::Context *context);
ProgramState mState; ProgramState mState;
rx::ProgramImpl *mProgram; rx::ProgramImpl *mProgram;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment