diff options
Diffstat (limited to 'src/3rdparty/angle/src/libANGLE/MemoryProgramCache.cpp')
-rw-r--r-- | src/3rdparty/angle/src/libANGLE/MemoryProgramCache.cpp | 772 |
1 files changed, 772 insertions, 0 deletions
diff --git a/src/3rdparty/angle/src/libANGLE/MemoryProgramCache.cpp b/src/3rdparty/angle/src/libANGLE/MemoryProgramCache.cpp new file mode 100644 index 0000000000..9eec12e3ea --- /dev/null +++ b/src/3rdparty/angle/src/libANGLE/MemoryProgramCache.cpp @@ -0,0 +1,772 @@ +// +// Copyright 2017 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// MemoryProgramCache: Stores compiled and linked programs in memory so they don't +// always have to be re-compiled. Can be used in conjunction with the platform +// layer to warm up the cache from disk. + +#include "libANGLE/MemoryProgramCache.h" + +#include <GLSLANG/ShaderVars.h> +#include <anglebase/sha1.h> + +#include "common/utilities.h" +#include "common/version.h" +#include "libANGLE/BinaryStream.h" +#include "libANGLE/Context.h" +#include "libANGLE/Uniform.h" +#include "libANGLE/histogram_macros.h" +#include "libANGLE/renderer/ProgramImpl.h" +#include "platform/Platform.h" + +namespace gl +{ + +namespace +{ +enum CacheResult +{ + kCacheMiss, + kCacheHitMemory, + kCacheHitDisk, + kCacheResultMax, +}; + +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->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->structName = stream->readString(); +} + +void WriteShaderVariableBuffer(BinaryOutputStream *stream, const ShaderVariableBuffer &var) +{ + stream->writeInt(var.binding); + stream->writeInt(var.dataSize); + + stream->writeInt(var.vertexStaticUse); + stream->writeInt(var.fragmentStaticUse); + stream->writeInt(var.computeStaticUse); + + 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>(); + var->vertexStaticUse = stream->readBool(); + var->fragmentStaticUse = stream->readBool(); + var->computeStaticUse = 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); + stream->writeInt(var.vertexStaticUse); + stream->writeInt(var.fragmentStaticUse); + stream->writeInt(var.computeStaticUse); +} + +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>(); + var->vertexStaticUse = stream->readBool(); + var->fragmentStaticUse = stream->readBool(); + var->computeStaticUse = 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 +{ + public: + std::string str() { return mStringStream.str(); } + + template <typename T> + HashStream &operator<<(T value) + { + mStringStream << value << kSeparator; + return *this; + } + + private: + static constexpr char kSeparator = ':'; + std::ostringstream mStringStream; +}; + +HashStream &operator<<(HashStream &stream, const Shader *shader) +{ + if (shader) + { + stream << shader->getSourceString().c_str() << shader->getSourceString().length() + << shader->getCompilerResourcesString().c_str(); + } + return stream; +} + +HashStream &operator<<(HashStream &stream, const Program::Bindings &bindings) +{ + for (const auto &binding : bindings) + { + stream << binding.first << binding.second; + } + return stream; +} + +HashStream &operator<<(HashStream &stream, const std::vector<std::string> &strings) +{ + for (const auto &str : strings) + { + stream << str; + } + return stream; +} + +} // anonymous namespace + +MemoryProgramCache::MemoryProgramCache(size_t maxCacheSizeBytes) + : mProgramBinaryCache(maxCacheSizeBytes), mIssuedWarnings(0) +{ +} + +MemoryProgramCache::~MemoryProgramCache() +{ +} + +// static +LinkResult 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 false; + } + + 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 false; + } + + state->mComputeShaderLocalSize[0] = stream.readInt<int>(); + state->mComputeShaderLocalSize[1] = stream.readInt<int>(); + state->mComputeShaderLocalSize[2] = stream.readInt<int>(); + + state->mNumViews = stream.readInt<int>(); + + static_assert(MAX_VERTEX_ATTRIBS <= sizeof(unsigned long) * 8, + "Too many vertex attribs for mask"); + state->mActiveAttribLocationsMask = stream.readInt<unsigned long>(); + + 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 false; + } + + 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>(); + 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 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 < 8 * sizeof(uint32_t), + "All bits of DrawBufferMask can be contained in an uint32_t"); + state->mActiveOutputVariables = stream.readInt<uint32_t>(); + + 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) + { + GLenum textureType = stream.readInt<GLenum>(); + size_t bindingCount = stream.readInt<size_t>(); + bool unreferenced = stream.readBool(); + state->mSamplerBindings.emplace_back( + SamplerBinding(textureType, 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(SHADER_TYPE_MAX <= sizeof(unsigned long) * 8, "Too many shader types"); + state->mLinkedShaderStages = stream.readInt<unsigned long>(); + + 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]); + + stream.writeInt(state.mNumViews); + + 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(state.getOutputLocations().size()); + for (const auto &outputVar : state.getOutputLocations()) + { + 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 < 8 * sizeof(uint32_t), + "All bits of DrawBufferMask can be contained in an uint32_t"); + stream.writeInt(static_cast<uint32_t>(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.writeInt(samplerBinding.textureType); + 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, + const Program *program, + ProgramHash *hashOut) +{ + const Shader *vertexShader = program->getAttachedVertexShader(); + const Shader *fragmentShader = program->getAttachedFragmentShader(); + const Shader *computeShader = program->getAttachedComputeShader(); + + // Compute the program hash. Start with the shader hashes and resource strings. + HashStream hashStream; + hashStream << vertexShader << fragmentShader << computeShader; + + // Add some ANGLE metadata and Context properties, such as version and back-end. + hashStream << ANGLE_COMMIT_HASH << context->getClientMajorVersion() + << context->getClientMinorVersion() << context->getString(GL_RENDERER); + + // Hash pre-link program properties. + hashStream << program->getAttributeBindings() << program->getUniformLocationBindings() + << program->getFragmentInputBindings() + << program->getState().getTransformFeedbackVaryingNames() + << program->getState().getTransformFeedbackBufferMode(); + + // Call the secure SHA hashing function. + const std::string &programKey = hashStream.str(); + angle::base::SHA1HashBytes(reinterpret_cast<const unsigned char *>(programKey.c_str()), + programKey.length(), hashOut->data()); +} + +LinkResult MemoryProgramCache::getProgram(const Context *context, + const Program *program, + ProgramState *state, + ProgramHash *hashOut) +{ + ComputeHash(context, program, hashOut); + const angle::MemoryBuffer *binaryProgram = nullptr; + LinkResult result(false); + if (get(*hashOut, &binaryProgram)) + { + InfoLog infoLog; + ANGLE_TRY_RESULT(Deserialize(context, program, state, binaryProgram->data(), + binaryProgram->size(), infoLog), + result); + ANGLE_HISTOGRAM_BOOLEAN("GPU.ANGLE.ProgramCache.LoadBinarySuccess", result.getResult()); + if (!result.getResult()) + { + // Cache load failed, evict. + if (mIssuedWarnings++ < kWarningLimit) + { + WARN() << "Failed to load binary from cache: " << infoLog.str(); + + if (mIssuedWarnings == kWarningLimit) + { + WARN() << "Reaching warning limit for cache load failures, silencing " + "subsequent warnings."; + } + } + remove(*hashOut); + } + } + return result; +} + +bool MemoryProgramCache::get(const ProgramHash &programHash, const angle::MemoryBuffer **programOut) +{ + const CacheEntry *entry = nullptr; + if (!mProgramBinaryCache.get(programHash, &entry)) + { + ANGLE_HISTOGRAM_ENUMERATION("GPU.ANGLE.ProgramCache.CacheResult", kCacheMiss, + kCacheResultMax); + return false; + } + + if (entry->second == CacheSource::PutProgram) + { + ANGLE_HISTOGRAM_ENUMERATION("GPU.ANGLE.ProgramCache.CacheResult", kCacheHitMemory, + kCacheResultMax); + } + else + { + ANGLE_HISTOGRAM_ENUMERATION("GPU.ANGLE.ProgramCache.CacheResult", kCacheHitDisk, + kCacheResultMax); + } + + *programOut = &entry->first; + return true; +} + +bool MemoryProgramCache::getAt(size_t index, + ProgramHash *hashOut, + const angle::MemoryBuffer **programOut) +{ + const CacheEntry *entry = nullptr; + if (!mProgramBinaryCache.getAt(index, hashOut, &entry)) + { + return false; + } + + *programOut = &entry->first; + return true; +} + +void MemoryProgramCache::remove(const ProgramHash &programHash) +{ + bool result = mProgramBinaryCache.eraseByKey(programHash); + ASSERT(result); +} + +void MemoryProgramCache::putProgram(const ProgramHash &programHash, + const Context *context, + const Program *program) +{ + CacheEntry newEntry; + Serialize(context, program, &newEntry.first); + newEntry.second = CacheSource::PutProgram; + + ANGLE_HISTOGRAM_COUNTS("GPU.ANGLE.ProgramCache.ProgramBinarySizeBytes", + static_cast<int>(newEntry.first.size())); + + const CacheEntry *result = + mProgramBinaryCache.put(programHash, std::move(newEntry), newEntry.first.size()); + if (!result) + { + ERR() << "Failed to store binary program in memory cache, program is too large."; + } + else + { + auto *platform = ANGLEPlatformCurrent(); + platform->cacheProgram(platform, programHash, result->first.size(), result->first.data()); + } +} + +void MemoryProgramCache::updateProgram(const Context *context, const Program *program) +{ + gl::ProgramHash programHash; + ComputeHash(context, program, &programHash); + putProgram(programHash, context, program); +} + +void MemoryProgramCache::putBinary(const ProgramHash &programHash, + const uint8_t *binary, + size_t length) +{ + // Copy the binary. + CacheEntry newEntry; + newEntry.first.resize(length); + memcpy(newEntry.first.data(), binary, length); + newEntry.second = CacheSource::PutBinary; + + // Store the binary. + const CacheEntry *result = mProgramBinaryCache.put(programHash, std::move(newEntry), length); + if (!result) + { + ERR() << "Failed to store binary program in memory cache, program is too large."; + } +} + +void MemoryProgramCache::clear() +{ + mProgramBinaryCache.clear(); + mIssuedWarnings = 0; +} + +void MemoryProgramCache::resize(size_t maxCacheSizeBytes) +{ + mProgramBinaryCache.resize(maxCacheSizeBytes); +} + +size_t MemoryProgramCache::entryCount() const +{ + return mProgramBinaryCache.entryCount(); +} + +size_t MemoryProgramCache::trim(size_t limit) +{ + return mProgramBinaryCache.shrinkToSize(limit); +} + +size_t MemoryProgramCache::size() const +{ + return mProgramBinaryCache.size(); +} + +size_t MemoryProgramCache::maxSize() const +{ + return mProgramBinaryCache.maxSize(); +} + +} // namespace gl |