Edit

kc3-lang/angle/src/libANGLE/MemoryProgramCache.cpp

Branch :

  • Show log

    Commit

  • Author : Lee Salzman
    Date : 2019-04-30 23:42:31
    Hash : 8ba78da0
    Message : add support for EXT_blend_func_extended to D3D11 Change-Id: Id66868851a490d0a68a7e76280720825c4844a45 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1591192 Commit-Queue: Geoff Lang <geofflang@chromium.org> Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>

  • src/libANGLE/MemoryProgramCache.cpp
  • //
    // 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
    {
    constexpr unsigned int kWarningLimit = 3;
    
    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 ProgramBindings &bindings)
    {
        for (const auto &binding : bindings)
        {
            stream << binding.first << binding.second.location;
        }
        return stream;
    }
    
    HashStream &operator<<(HashStream &stream, const std::vector<std::string> &strings)
    {
        for (const auto &str : strings)
        {
            stream << str;
        }
        return stream;
    }
    
    HashStream &operator<<(HashStream &stream, const std::vector<gl::VariableLocation> &locations)
    {
        for (const auto &loc : locations)
        {
            stream << loc.index << loc.arrayIndex << loc.ignored;
        }
        return stream;
    }
    
    }  // anonymous namespace
    
    MemoryProgramCache::MemoryProgramCache(egl::BlobCache &blobCache)
        : mBlobCache(blobCache), mIssuedWarnings(0)
    {}
    
    MemoryProgramCache::~MemoryProgramCache() {}
    
    void MemoryProgramCache::ComputeHash(const Context *context,
                                         const Program *program,
                                         egl::BlobCache::Key *hashOut)
    {
        // Compute the program hash. Start with the shader hashes and resource strings.
        HashStream hashStream;
        for (ShaderType shaderType : AllShaderTypes())
        {
            hashStream << program->getAttachedShader(shaderType);
        }
    
        // 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()
                   << program->getState().getOutputLocations()
                   << program->getState().getSecondaryOutputLocations();
    
        // 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());
    }
    
    angle::Result MemoryProgramCache::getProgram(const Context *context,
                                                 Program *program,
                                                 egl::BlobCache::Key *hashOut)
    {
        // If caching is effectively disabled, don't bother calculating the hash.
        if (!mBlobCache.isCachingEnabled())
        {
            return angle::Result::Incomplete;
        }
    
        ComputeHash(context, program, hashOut);
        egl::BlobCache::Value binaryProgram;
        if (get(context, *hashOut, &binaryProgram))
        {
            angle::Result result = program->loadBinary(context, GL_PROGRAM_BINARY_ANGLE,
                                                       binaryProgram.data(), binaryProgram.size());
            ANGLE_HISTOGRAM_BOOLEAN("GPU.ANGLE.ProgramCache.LoadBinarySuccess",
                                    result == angle::Result::Continue);
            ANGLE_TRY(result);
    
            if (result == angle::Result::Continue)
                return angle::Result::Continue;
    
            // Cache load failed, evict.
            if (mIssuedWarnings++ < kWarningLimit)
            {
                WARN() << "Failed to load binary from cache.";
    
                if (mIssuedWarnings == kWarningLimit)
                {
                    WARN() << "Reaching warning limit for cache load failures, silencing "
                              "subsequent warnings.";
                }
            }
            remove(*hashOut);
        }
        return angle::Result::Incomplete;
    }
    
    bool MemoryProgramCache::get(const Context *context,
                                 const egl::BlobCache::Key &programHash,
                                 egl::BlobCache::Value *programOut)
    {
        return mBlobCache.get(context->getScratchBuffer(), programHash, programOut);
    }
    
    bool MemoryProgramCache::getAt(size_t index,
                                   const egl::BlobCache::Key **hashOut,
                                   egl::BlobCache::Value *programOut)
    {
        return mBlobCache.getAt(index, hashOut, programOut);
    }
    
    void MemoryProgramCache::remove(const egl::BlobCache::Key &programHash)
    {
        mBlobCache.remove(programHash);
    }
    
    void MemoryProgramCache::putProgram(const egl::BlobCache::Key &programHash,
                                        const Context *context,
                                        const Program *program)
    {
        // If caching is effectively disabled, don't bother serializing the program.
        if (!mBlobCache.isCachingEnabled())
        {
            return;
        }
    
        angle::MemoryBuffer serializedProgram;
        program->serialize(context, &serializedProgram);
    
        ANGLE_HISTOGRAM_COUNTS("GPU.ANGLE.ProgramCache.ProgramBinarySizeBytes",
                               static_cast<int>(serializedProgram.size()));
    
        // TODO(syoussefi): to be removed.  Compatibility for Chrome until it supports
        // EGL_ANDROID_blob_cache. http://anglebug.com/2516
        auto *platform = ANGLEPlatformCurrent();
        platform->cacheProgram(platform, programHash, serializedProgram.size(),
                               serializedProgram.data());
    
        mBlobCache.put(programHash, std::move(serializedProgram));
    }
    
    void MemoryProgramCache::updateProgram(const Context *context, const Program *program)
    {
        egl::BlobCache::Key programHash;
        ComputeHash(context, program, &programHash);
        putProgram(programHash, context, program);
    }
    
    void MemoryProgramCache::putBinary(const egl::BlobCache::Key &programHash,
                                       const uint8_t *binary,
                                       size_t length)
    {
        // Copy the binary.
        angle::MemoryBuffer newEntry;
        newEntry.resize(length);
        memcpy(newEntry.data(), binary, length);
    
        // Store the binary.
        mBlobCache.populate(programHash, std::move(newEntry));
    }
    
    void MemoryProgramCache::clear()
    {
        mBlobCache.clear();
        mIssuedWarnings = 0;
    }
    
    void MemoryProgramCache::resize(size_t maxCacheSizeBytes)
    {
        mBlobCache.resize(maxCacheSizeBytes);
    }
    
    size_t MemoryProgramCache::entryCount() const
    {
        return mBlobCache.entryCount();
    }
    
    size_t MemoryProgramCache::trim(size_t limit)
    {
        return mBlobCache.trim(limit);
    }
    
    size_t MemoryProgramCache::size() const
    {
        return mBlobCache.size();
    }
    
    size_t MemoryProgramCache::maxSize() const
    {
        return mBlobCache.maxSize();
    }
    
    }  // namespace gl