Commit 3244736a by Jamie Madill Committed by Commit Bot

Use MemoryProgramCache.

Add the member functions for saving and loading from the binary cache, and hook them into the Program class. Requires that the Renderer supports the program binary extension. BUG=angleproject:1897 Change-Id: I2dc8d21b02da705ded58c5cd1943562c9c97c49b Reviewed-on: https://chromium-review.googlesource.com/522874Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent 68dfe0c5
...@@ -84,6 +84,18 @@ void MemoryBuffer::fill(uint8_t datum) ...@@ -84,6 +84,18 @@ void MemoryBuffer::fill(uint8_t datum)
} }
} }
MemoryBuffer::MemoryBuffer(MemoryBuffer &&other) : MemoryBuffer()
{
*this = std::move(other);
}
MemoryBuffer &MemoryBuffer::operator=(MemoryBuffer &&other)
{
std::swap(mSize, other.mSize);
std::swap(mData, other.mData);
return *this;
}
// ScratchBuffer implementation. // ScratchBuffer implementation.
ScratchBuffer::ScratchBuffer(uint32_t lifetime) : mLifetime(lifetime), mResetCounter(lifetime) ScratchBuffer::ScratchBuffer(uint32_t lifetime) : mLifetime(lifetime), mResetCounter(lifetime)
......
...@@ -21,6 +21,9 @@ class MemoryBuffer final : NonCopyable ...@@ -21,6 +21,9 @@ class MemoryBuffer final : NonCopyable
MemoryBuffer(); MemoryBuffer();
~MemoryBuffer(); ~MemoryBuffer();
MemoryBuffer(MemoryBuffer &&other);
MemoryBuffer &operator=(MemoryBuffer &&other);
bool resize(size_t size); bool resize(size_t size);
size_t size() const; size_t size() const;
bool empty() const { return mSize == 0; } bool empty() const { return mSize == 0; }
......
...@@ -192,4 +192,9 @@ ShHandle Compiler::getCompilerHandle(GLenum type) ...@@ -192,4 +192,9 @@ ShHandle Compiler::getCompilerHandle(GLenum type)
return *compiler; return *compiler;
} }
const std::string &Compiler::getBuiltinResourcesString(GLenum type)
{
return sh::GetBuiltInResourcesString(getCompilerHandle(type));
}
} // namespace gl } // namespace gl
...@@ -31,6 +31,7 @@ class Compiler final : public RefCountObjectNoID ...@@ -31,6 +31,7 @@ class Compiler final : public RefCountObjectNoID
ShHandle getCompilerHandle(GLenum type); ShHandle getCompilerHandle(GLenum type);
ShShaderOutput getShaderOutputType() const { return mOutputType; } ShShaderOutput getShaderOutputType() const { return mOutputType; }
const std::string &getBuiltinResourcesString(GLenum type);
private: private:
~Compiler() override; ~Compiler() override;
......
...@@ -9,9 +9,19 @@ ...@@ -9,9 +9,19 @@
#ifndef LIBANGLE_CONSTANTS_H_ #ifndef LIBANGLE_CONSTANTS_H_
#define LIBANGLE_CONSTANTS_H_ #define LIBANGLE_CONSTANTS_H_
#include "common/platform.h"
namespace gl namespace gl
{ {
// The size to set for the program cache for default and low-end device cases.
#if !defined(ANGLE_PLATFORM_ANDROID)
const size_t kDefaultMaxProgramCacheMemoryBytes = 6 * 1024 * 1024;
#else
const size_t kDefaultMaxProgramCacheMemoryBytes = 2 * 1024 * 1024;
const size_t kLowEndMaxProgramCacheMemoryBytes = 512 * 1024;
#endif
enum enum
{ {
MAX_VERTEX_ATTRIBS = 16, MAX_VERTEX_ATTRIBS = 16,
......
...@@ -243,6 +243,7 @@ Context::Context(rx::EGLImplFactory *implFactory, ...@@ -243,6 +243,7 @@ Context::Context(rx::EGLImplFactory *implFactory,
const egl::Config *config, const egl::Config *config,
const Context *shareContext, const Context *shareContext,
TextureManager *shareTextures, TextureManager *shareTextures,
MemoryProgramCache *memoryProgramCache,
const egl::AttributeMap &attribs, const egl::AttributeMap &attribs,
const egl::DisplayExtensions &displayExtensions, const egl::DisplayExtensions &displayExtensions,
bool robustResourceInit) bool robustResourceInit)
...@@ -270,6 +271,7 @@ Context::Context(rx::EGLImplFactory *implFactory, ...@@ -270,6 +271,7 @@ Context::Context(rx::EGLImplFactory *implFactory,
mCurrentDisplay(static_cast<egl::Display *>(EGL_NO_DISPLAY)), mCurrentDisplay(static_cast<egl::Display *>(EGL_NO_DISPLAY)),
mSurfacelessFramebuffer(nullptr), mSurfacelessFramebuffer(nullptr),
mWebGLContext(GetWebGLContext(attribs)), mWebGLContext(GetWebGLContext(attribs)),
mMemoryProgramCache(memoryProgramCache),
mScratchBuffer(1000u) mScratchBuffer(1000u)
{ {
if (mRobustAccess) if (mRobustAccess)
...@@ -2739,6 +2741,12 @@ void Context::updateCaps() ...@@ -2739,6 +2741,12 @@ void Context::updateCaps()
mTextureCaps.insert(sizedInternalFormat, formatCaps); mTextureCaps.insert(sizedInternalFormat, formatCaps);
} }
// If program binary is disabled, blank out the memory cache pointer.
if (!mImplementation->getNativeExtensions().getProgramBinary)
{
mMemoryProgramCache = nullptr;
}
} }
void Context::initWorkarounds() void Context::initWorkarounds()
......
...@@ -43,20 +43,21 @@ class Thread; ...@@ -43,20 +43,21 @@ class Thread;
namespace gl namespace gl
{ {
class Buffer;
class Compiler; class Compiler;
class Shader;
class Program;
class Texture;
class Framebuffer;
class Renderbuffer;
class FenceNV; class FenceNV;
class FenceSync; class FenceSync;
class Framebuffer;
class MemoryProgramCache;
class Program;
class Query; class Query;
class Buffer; class Renderbuffer;
struct VertexAttribute;
class VertexArray;
class Sampler; class Sampler;
class Shader;
class Texture;
class TransformFeedback; class TransformFeedback;
class VertexArray;
struct VertexAttribute;
class Context final : public ValidationContext class Context final : public ValidationContext
{ {
...@@ -65,6 +66,7 @@ class Context final : public ValidationContext ...@@ -65,6 +66,7 @@ class Context final : public ValidationContext
const egl::Config *config, const egl::Config *config,
const Context *shareContext, const Context *shareContext,
TextureManager *shareTextures, TextureManager *shareTextures,
MemoryProgramCache *memoryProgramCache,
const egl::AttributeMap &attribs, const egl::AttributeMap &attribs,
const egl::DisplayExtensions &displayExtensions, const egl::DisplayExtensions &displayExtensions,
bool robustResourceInit); bool robustResourceInit);
...@@ -794,6 +796,8 @@ class Context final : public ValidationContext ...@@ -794,6 +796,8 @@ class Context final : public ValidationContext
void dispatchCompute(GLuint numGroupsX, GLuint numGroupsY, GLuint numGroupsZ); void dispatchCompute(GLuint numGroupsX, GLuint numGroupsY, GLuint numGroupsZ);
MemoryProgramCache *getMemoryProgramCache() const { return mMemoryProgramCache; }
template <EntryPoint EP, typename... ParamsT> template <EntryPoint EP, typename... ParamsT>
void gatherParams(ParamsT &&... params); void gatherParams(ParamsT &&... params);
...@@ -895,6 +899,7 @@ class Context final : public ValidationContext ...@@ -895,6 +899,7 @@ class Context final : public ValidationContext
egl::Display *mCurrentDisplay; egl::Display *mCurrentDisplay;
Framebuffer *mSurfacelessFramebuffer; Framebuffer *mSurfacelessFramebuffer;
bool mWebGLContext; bool mWebGLContext;
MemoryProgramCache *mMemoryProgramCache;
State::DirtyBits mTexImageDirtyBits; State::DirtyBits mTexImageDirtyBits;
State::DirtyObjects mTexImageDirtyObjects; State::DirtyObjects mTexImageDirtyObjects;
......
...@@ -372,6 +372,7 @@ Display::Display(EGLenum platform, EGLNativeDisplayType displayId, Device *eglDe ...@@ -372,6 +372,7 @@ Display::Display(EGLenum platform, EGLNativeDisplayType displayId, Device *eglDe
mDevice(eglDevice), mDevice(eglDevice),
mPlatform(platform), mPlatform(platform),
mTextureManager(nullptr), mTextureManager(nullptr),
mMemoryProgramCache(gl::kDefaultMaxProgramCacheMemoryBytes),
mGlobalTextureShareGroupUsers(0), mGlobalTextureShareGroupUsers(0),
mProxyContext(this) mProxyContext(this)
{ {
...@@ -491,7 +492,7 @@ Error Display::initialize() ...@@ -491,7 +492,7 @@ Error Display::initialize()
} }
mProxyContext.reset(nullptr); mProxyContext.reset(nullptr);
gl::Context *proxyContext = new gl::Context(mImplementation, nullptr, nullptr, nullptr, gl::Context *proxyContext = new gl::Context(mImplementation, nullptr, nullptr, nullptr, nullptr,
egl::AttributeMap(), mDisplayExtensions, false); egl::AttributeMap(), mDisplayExtensions, false);
mProxyContext.reset(proxyContext); mProxyContext.reset(proxyContext);
...@@ -504,6 +505,8 @@ Error Display::terminate() ...@@ -504,6 +505,8 @@ Error Display::terminate()
{ {
ANGLE_TRY(makeCurrent(nullptr, nullptr, nullptr)); ANGLE_TRY(makeCurrent(nullptr, nullptr, nullptr));
mMemoryProgramCache.clear();
mProxyContext.reset(nullptr); mProxyContext.reset(nullptr);
while (!mContextSet.empty()) while (!mContextSet.empty())
...@@ -738,9 +741,9 @@ Error Display::createContext(const Config *configuration, ...@@ -738,9 +741,9 @@ Error Display::createContext(const Config *configuration,
shareTextures = mTextureManager; shareTextures = mTextureManager;
} }
gl::Context *context = gl::Context *context = new gl::Context(mImplementation, configuration, shareContext,
new gl::Context(mImplementation, configuration, shareContext, shareTextures, attribs, shareTextures, &mMemoryProgramCache, attribs,
mDisplayExtensions, isRobustResourceInitEnabled()); mDisplayExtensions, isRobustResourceInitEnabled());
ASSERT(context != nullptr); ASSERT(context != nullptr);
mContextSet.insert(context); mContextSet.insert(context);
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "libANGLE/Config.h" #include "libANGLE/Config.h"
#include "libANGLE/Error.h" #include "libANGLE/Error.h"
#include "libANGLE/LoggingAnnotator.h" #include "libANGLE/LoggingAnnotator.h"
#include "libANGLE/MemoryProgramCache.h"
#include "libANGLE/Version.h" #include "libANGLE/Version.h"
namespace gl namespace gl
...@@ -188,6 +189,7 @@ class Display final : angle::NonCopyable ...@@ -188,6 +189,7 @@ class Display final : angle::NonCopyable
angle::LoggingAnnotator mAnnotator; angle::LoggingAnnotator mAnnotator;
gl::TextureManager *mTextureManager; gl::TextureManager *mTextureManager;
gl::MemoryProgramCache mMemoryProgramCache;
size_t mGlobalTextureShareGroupUsers; size_t mGlobalTextureShareGroupUsers;
// This gl::Context is a simple proxy to the Display for the GL back-end entry points // This gl::Context is a simple proxy to the Display for the GL back-end entry points
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "libANGLE/MemoryProgramCache.h" #include "libANGLE/MemoryProgramCache.h"
#include <GLSLANG/ShaderVars.h> #include <GLSLANG/ShaderVars.h>
#include <anglebase/sha1.h>
#include "common/version.h" #include "common/version.h"
#include "libANGLE/BinaryStream.h" #include "libANGLE/BinaryStream.h"
...@@ -22,6 +23,7 @@ namespace gl ...@@ -22,6 +23,7 @@ namespace gl
namespace namespace
{ {
constexpr unsigned int kWarningLimit = 3;
void WriteShaderVar(BinaryOutputStream *stream, const sh::ShaderVariable &var) void WriteShaderVar(BinaryOutputStream *stream, const sh::ShaderVariable &var)
{ {
...@@ -46,8 +48,62 @@ void LoadShaderVar(BinaryInputStream *stream, sh::ShaderVariable *var) ...@@ -46,8 +48,62 @@ void LoadShaderVar(BinaryInputStream *stream, sh::ShaderVariable *var)
var->structName = stream->readString(); var->structName = stream->readString();
} }
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 } // anonymous namespace
MemoryProgramCache::MemoryProgramCache(size_t maxCacheSizeBytes)
: mProgramBinaryCache(maxCacheSizeBytes), mIssuedWarnings(0)
{
}
MemoryProgramCache::~MemoryProgramCache()
{
}
// static // static
LinkResult MemoryProgramCache::Deserialize(const Context *context, LinkResult MemoryProgramCache::Deserialize(const Context *context,
const Program *program, const Program *program,
...@@ -387,4 +443,118 @@ void MemoryProgramCache::Serialize(const Context *context, ...@@ -387,4 +443,118 @@ void MemoryProgramCache::Serialize(const Context *context,
memcpy(binaryOut->data(), stream.data(), stream.length()); memcpy(binaryOut->data(), stream.data(), stream.length());
} }
// static
void MemoryProgramCache::ComputeHash(const Context *context,
const Program *program,
ProgramHash *hashOut)
{
auto vertexShader = program->getAttachedVertexShader();
auto fragmentShader = program->getAttachedFragmentShader();
auto 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);
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)
{
return mProgramBinaryCache.get(programHash, programOut);
}
void MemoryProgramCache::remove(const ProgramHash &programHash)
{
bool result = mProgramBinaryCache.eraseByKey(programHash);
ASSERT(result);
}
void MemoryProgramCache::put(const ProgramHash &program, angle::MemoryBuffer &&binaryProgram)
{
if (!mProgramBinaryCache.put(program, std::move(binaryProgram), binaryProgram.size()))
{
ERR() << "Failed to store binary program in memory cache, program is too large.";
}
}
void MemoryProgramCache::putProgram(const ProgramHash &programHash,
const Context *context,
const Program *program)
{
angle::MemoryBuffer binaryProgram;
Serialize(context, program, &binaryProgram);
put(programHash, std::move(binaryProgram));
}
void MemoryProgramCache::putBinary(const Context *context,
const Program *program,
const uint8_t *binary,
size_t length)
{
// Copy the binary.
angle::MemoryBuffer binaryProgram;
binaryProgram.resize(length);
memcpy(binaryProgram.data(), binary, length);
// Compute the hash.
ProgramHash programHash;
ComputeHash(context, program, &programHash);
// Store the binary.
put(programHash, std::move(binaryProgram));
}
void MemoryProgramCache::clear()
{
mProgramBinaryCache.clear();
mIssuedWarnings = 0;
}
} // namespace gl } // namespace gl
...@@ -10,8 +10,36 @@ ...@@ -10,8 +10,36 @@
#ifndef LIBANGLE_MEMORY_PROGRAM_CACHE_H_ #ifndef LIBANGLE_MEMORY_PROGRAM_CACHE_H_
#define LIBANGLE_MEMORY_PROGRAM_CACHE_H_ #define LIBANGLE_MEMORY_PROGRAM_CACHE_H_
#include <array>
#include "common/MemoryBuffer.h" #include "common/MemoryBuffer.h"
#include "libANGLE/Error.h" #include "libANGLE/Error.h"
#include "libANGLE/SizedMRUCache.h"
namespace gl
{
// 128-bit program hash key.
using ProgramHash = std::array<uint8_t, 20>;
} // namespace gl
namespace std
{
template <>
struct hash<gl::ProgramHash>
{
// Simple routine to hash four ints.
size_t operator()(const gl::ProgramHash &programHash) const
{
unsigned int hash = 0;
for (uint32_t num : programHash)
{
hash *= 37;
hash += num;
}
return hash;
}
};
} // namespace std
namespace gl namespace gl
{ {
...@@ -23,6 +51,9 @@ class ProgramState; ...@@ -23,6 +51,9 @@ class ProgramState;
class MemoryProgramCache final : angle::NonCopyable class MemoryProgramCache final : angle::NonCopyable
{ {
public: public:
MemoryProgramCache(size_t maxCacheSizeBytes);
~MemoryProgramCache();
// Writes a program's binary to the output memory buffer. // Writes a program's binary to the output memory buffer.
static void Serialize(const Context *context, static void Serialize(const Context *context,
const Program *program, const Program *program,
...@@ -35,6 +66,40 @@ class MemoryProgramCache final : angle::NonCopyable ...@@ -35,6 +66,40 @@ class MemoryProgramCache final : angle::NonCopyable
const uint8_t *binary, const uint8_t *binary,
size_t length, size_t length,
InfoLog &infoLog); InfoLog &infoLog);
static void ComputeHash(const Context *context, const Program *program, ProgramHash *hashOut);
// Check if the cache contains a binary matching the specified program.
bool get(const ProgramHash &programHash, const angle::MemoryBuffer **programOut);
// Evict a program from the binary cache.
void remove(const ProgramHash &programHash);
// Helper method that serializes a program.
void putProgram(const ProgramHash &programHash, const Context *context, const Program *program);
// Helper method that copies a user binary.
void putBinary(const Context *context,
const Program *program,
const uint8_t *binary,
size_t length);
// Check the cache, and deserialize and load the program if found. Evict existing hash if load
// fails.
LinkResult getProgram(const Context *context,
const Program *program,
ProgramState *state,
ProgramHash *hashOut);
// Empty the cache.
void clear();
private:
// Insert or update a binary program. Program contents are transferred.
void put(const ProgramHash &programHash, angle::MemoryBuffer &&binaryProgram);
angle::SizedMRUCache<ProgramHash, angle::MemoryBuffer> mProgramBinaryCache;
unsigned int mIssuedWarnings;
}; };
} // namespace gl } // namespace gl
......
...@@ -616,6 +616,20 @@ Error Program::link(const gl::Context *context) ...@@ -616,6 +616,20 @@ Error Program::link(const gl::Context *context)
unlink(); unlink();
ProgramHash programHash;
auto *cache = context->getMemoryProgramCache();
if (cache)
{
ANGLE_TRY_RESULT(cache->getProgram(context, this, &mState, &programHash), mLinked);
}
if (mLinked)
{
return NoError();
}
// Cache load failed, fall through to normal linking.
unlink();
mInfoLog.reset(); mInfoLog.reset();
const Caps &caps = data.getCaps(); const Caps &caps = data.getCaps();
...@@ -747,6 +761,13 @@ Error Program::link(const gl::Context *context) ...@@ -747,6 +761,13 @@ Error Program::link(const gl::Context *context)
gatherInterfaceBlockInfo(context); gatherInterfaceBlockInfo(context);
// Save to the program cache.
if (cache && (mState.mLinkedTransformFeedbackVaryings.empty() ||
!context->getWorkarounds().disableProgramCachingForTransformFeedback))
{
cache->putProgram(programHash, context, this);
}
return NoError(); return NoError();
} }
...@@ -797,6 +818,10 @@ Error Program::loadBinary(const Context *context, ...@@ -797,6 +818,10 @@ Error 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_TRY_RESULT( ANGLE_TRY_RESULT(
MemoryProgramCache::Deserialize(context, this, &mState, bytes, length, mInfoLog), mLinked); MemoryProgramCache::Deserialize(context, this, &mState, bytes, length, mInfoLog), mLinked);
// Currently we require the full shader text to compute the program hash.
// TODO(jmadill): Store the binary in the internal program cache.
return NoError(); return NoError();
#endif // #if ANGLE_PROGRAM_BINARY_LOAD == ANGLE_ENABLED #endif // #if ANGLE_PROGRAM_BINARY_LOAD == ANGLE_ENABLED
} }
......
...@@ -504,6 +504,10 @@ class Program final : angle::NonCopyable, public LabeledObject ...@@ -504,6 +504,10 @@ class Program final : angle::NonCopyable, public LabeledObject
std::unordered_map<std::string, GLuint> mBindings; std::unordered_map<std::string, GLuint> mBindings;
}; };
const Bindings &getAttributeBindings() const { return mAttributeBindings; }
const Bindings &getUniformLocationBindings() const { return mUniformLocationBindings; }
const Bindings &getFragmentInputBindings() const { return mFragmentInputBindings; }
private: private:
~Program(); ~Program();
...@@ -518,7 +522,6 @@ class Program final : angle::NonCopyable, public LabeledObject ...@@ -518,7 +522,6 @@ class Program final : angle::NonCopyable, public LabeledObject
using MergedVaryings = std::map<std::string, VaryingRef>; using MergedVaryings = std::map<std::string, VaryingRef>;
void unlink(); void unlink();
void resetUniformBlockBindings();
bool linkAttributes(const Context *context, InfoLog &infoLog); bool linkAttributes(const Context *context, InfoLog &infoLog);
bool validateUniformBlocksCount(GLuint maxUniformBlocks, bool validateUniformBlocksCount(GLuint maxUniformBlocks,
......
...@@ -469,4 +469,10 @@ const sh::WorkGroupSize &Shader::getWorkGroupSize(const Context *context) ...@@ -469,4 +469,10 @@ const sh::WorkGroupSize &Shader::getWorkGroupSize(const Context *context)
return mState.mLocalSize; return mState.mLocalSize;
} }
const std::string &Shader::getCompilerResourcesString() const
{
ASSERT(mBoundCompiler.get());
return mBoundCompiler->getBuiltinResourcesString(mState.mShaderType);
}
} // namespace gl } // namespace gl
...@@ -118,6 +118,7 @@ class Shader final : angle::NonCopyable, public LabeledObject ...@@ -118,6 +118,7 @@ class Shader final : angle::NonCopyable, public LabeledObject
int getInfoLogLength(const Context *context); int getInfoLogLength(const Context *context);
void getInfoLog(const Context *context, GLsizei bufSize, GLsizei *length, char *infoLog); void getInfoLog(const Context *context, GLsizei bufSize, GLsizei *length, char *infoLog);
int getSourceLength() const; int getSourceLength() const;
const std::string &getSourceString() const { return mState.getSource(); }
void getSource(GLsizei bufSize, GLsizei *length, char *buffer) const; void getSource(GLsizei bufSize, GLsizei *length, char *buffer) const;
int getTranslatedSourceLength(const Context *context); int getTranslatedSourceLength(const Context *context);
int getTranslatedSourceWithDebugInfoLength(const Context *context); int getTranslatedSourceWithDebugInfoLength(const Context *context);
...@@ -150,6 +151,8 @@ class Shader final : angle::NonCopyable, public LabeledObject ...@@ -150,6 +151,8 @@ class Shader final : angle::NonCopyable, public LabeledObject
const sh::WorkGroupSize &getWorkGroupSize(const Context *context); const sh::WorkGroupSize &getWorkGroupSize(const Context *context);
const std::string &getCompilerResourcesString() const;
private: private:
virtual ~Shader(); virtual ~Shader();
static void GetSourceImpl(const std::string &source, static void GetSourceImpl(const std::string &source,
......
...@@ -25,9 +25,12 @@ class SizedMRUCache final : angle::NonCopyable ...@@ -25,9 +25,12 @@ class SizedMRUCache final : angle::NonCopyable
{ {
} }
void put(const Key &key, Value &&value, size_t size) bool put(const Key &key, Value &&value, size_t size)
{ {
ASSERT(size <= mMaximumTotalSize); if (size > mMaximumTotalSize)
{
return false;
}
// Check for existing key. // Check for existing key.
eraseByKey(key); eraseByKey(key);
...@@ -42,6 +45,8 @@ class SizedMRUCache final : angle::NonCopyable ...@@ -42,6 +45,8 @@ class SizedMRUCache final : angle::NonCopyable
mCurrentSize -= iter->second.size; mCurrentSize -= iter->second.size;
mStore.Erase(iter); mStore.Erase(iter);
} }
return true;
} }
bool get(const Key &key, const Value **valueOut) bool get(const Key &key, const Value **valueOut)
......
...@@ -29,11 +29,11 @@ TEST(SizedMRUCacheTest, MaxSizedValue) ...@@ -29,11 +29,11 @@ TEST(SizedMRUCacheTest, MaxSizedValue)
constexpr size_t kSize = 32; constexpr size_t kSize = 32;
SizedMRUCache<std::string, Blob> sizedCache(kSize); SizedMRUCache<std::string, Blob> sizedCache(kSize);
sizedCache.put("test", MakeBlob(kSize), kSize); EXPECT_TRUE(sizedCache.put("test", MakeBlob(kSize), kSize));
EXPECT_EQ(32u, sizedCache.size()); EXPECT_EQ(32u, sizedCache.size());
EXPECT_FALSE(sizedCache.empty()); EXPECT_FALSE(sizedCache.empty());
sizedCache.put("test2", MakeBlob(kSize), kSize); EXPECT_TRUE(sizedCache.put("test2", MakeBlob(kSize), kSize));
EXPECT_EQ(32u, sizedCache.size()); EXPECT_EQ(32u, sizedCache.size());
EXPECT_FALSE(sizedCache.empty()); EXPECT_FALSE(sizedCache.empty());
...@@ -52,7 +52,7 @@ TEST(SizedMRUCacheTest, ManySmallValues) ...@@ -52,7 +52,7 @@ TEST(SizedMRUCacheTest, ManySmallValues)
for (size_t value = 0; value < kSize; ++value) for (size_t value = 0; value < kSize; ++value)
{ {
sizedCache.put(value, std::move(value), 1); EXPECT_TRUE(sizedCache.put(value, std::move(value), 1));
const size_t *qvalue = nullptr; const size_t *qvalue = nullptr;
EXPECT_TRUE(sizedCache.get(value, &qvalue)); EXPECT_TRUE(sizedCache.get(value, &qvalue));
...@@ -66,13 +66,13 @@ TEST(SizedMRUCacheTest, ManySmallValues) ...@@ -66,13 +66,13 @@ TEST(SizedMRUCacheTest, ManySmallValues)
EXPECT_FALSE(sizedCache.empty()); EXPECT_FALSE(sizedCache.empty());
// Putting one element evicts the first element. // Putting one element evicts the first element.
sizedCache.put(kSize, std::move(static_cast<int>(kSize)), 1); EXPECT_TRUE(sizedCache.put(kSize, std::move(static_cast<int>(kSize)), 1));
const size_t *qvalue = nullptr; const size_t *qvalue = nullptr;
EXPECT_FALSE(sizedCache.get(0, &qvalue)); EXPECT_FALSE(sizedCache.get(0, &qvalue));
// Putting one large element cleans out the whole stack. // Putting one large element cleans out the whole stack.
sizedCache.put(kSize + 1, kSize + 1, kSize); EXPECT_TRUE(sizedCache.put(kSize + 1, kSize + 1, kSize));
EXPECT_EQ(32u, sizedCache.size()); EXPECT_EQ(32u, sizedCache.size());
EXPECT_FALSE(sizedCache.empty()); EXPECT_FALSE(sizedCache.empty());
...@@ -89,10 +89,19 @@ TEST(SizedMRUCacheTest, ManySmallValues) ...@@ -89,10 +89,19 @@ TEST(SizedMRUCacheTest, ManySmallValues)
// Put a bunch of items in the cache sequentially. // Put a bunch of items in the cache sequentially.
for (size_t value = 0; value < kSize * 10; ++value) for (size_t value = 0; value < kSize * 10; ++value)
{ {
sizedCache.put(value, std::move(value), 1); EXPECT_TRUE(sizedCache.put(value, std::move(value), 1));
} }
EXPECT_EQ(32u, sizedCache.size()); EXPECT_EQ(32u, sizedCache.size());
} }
// Tests putting an oversize element.
TEST(SizedMRUCacheTest, OversizeValue)
{
constexpr size_t kSize = 32;
SizedMRUCache<size_t, size_t> sizedCache(kSize);
EXPECT_FALSE(sizedCache.put(5, 5, 100));
}
} // namespace angle } // namespace angle
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