// // Copyright 2022 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. // // PLSProgramCache.h: Implements a cache of native programs used to render load/store operations for // EXT_shader_pixel_local_storage. #ifndef LIBANGLE_RENDERER_GL_PLS_PROGRAM_CACHE_H_ #define LIBANGLE_RENDERER_GL_PLS_PROGRAM_CACHE_H_ #include "libANGLE/SizedMRUCache.h" #include "libANGLE/renderer/gl/StateManagerGL.h" namespace gl { class PixelLocalStoragePlane; struct Caps; } // namespace gl namespace rx { class FunctionsGL; class PLSProgram; class PLSProgramKey; // Implements a cache of native PLSPrograms used to render load/store operations for // EXT_shader_pixel_local_storage. // // These programs require no vertex arrays, and draw fullscreen quads from 4-point // GL_TRIANGLE_STRIPs: // // glDrawArrays(GL_TRIANGLE_STRIP, 0, 4) // class PLSProgramCache : angle::NonCopyable { public: size_t MaximumTotalPrograms = 64 * 2; // Enough programs for 64 unique PLS configurations. PLSProgramCache(const FunctionsGL *, const gl::Caps &nativeCaps); ~PLSProgramCache(); const PLSProgram *getProgram(PLSProgramKey); // An empty vertex array object to bind when rendering with a program from this cache. GLuint getEmptyVAO() { return mEmptyVAO; } VertexArrayStateGL *getEmptyVAOState() { return &mEmptyVAOState; } private: const FunctionsGL *const mGL; const GLuint mVertexShaderID; const GLuint mEmptyVAO; VertexArrayStateGL mEmptyVAOState; angle::SizedMRUCache> mCache; }; enum class PLSProgramType : uint64_t { Load = 0, // Initializes PLS data with either a uniform color or an image load. Store = 1 // Stores texture-backed PLS data out to images. }; // Re-enumerates PLS formats with a 0-based index, for tighter packing in a PLSProgramKey. enum class PLSFormatKey : uint64_t { INACTIVE = 0, RGBA8 = 1, RGBA8I = 2, RGBA8UI = 3, R32F = 4, R32UI = 5 }; // Compact descriptor of an entire PLS load/store program. The LSB says whether the program is load // or store, and each following run of 5 bits state the format of a specific plane and whether it is // preserved. class PLSProgramKey { public: constexpr static int BitsPerPlane = 5; constexpr static int SinglePlaneMask = (1 << BitsPerPlane) - 1; PLSProgramKey() = default; PLSProgramKey(const PLSProgramKey &key) : PLSProgramKey(key.rawKey()) {} explicit PLSProgramKey(uint64_t rawKey) : mRawKey(rawKey) {} PLSProgramKey &operator=(const PLSProgramKey &key) { mRawKey = key.mRawKey; return *this; } uint64_t rawKey() const { return mRawKey; } PLSProgramType type() const; bool areAnyPreserved() const; // Iterates each active plane in the descriptor, in order. class Iter { public: Iter() = default; Iter(const PLSProgramKey &); int binding() const { return mBinding; } PLSFormatKey formatKey() const; bool preserved() const; std::tuple operator*() const { return {binding(), formatKey(), preserved()}; } bool operator!=(const Iter &iter) const; void operator++(); private: // Skips over any planes that are not active. The only effect inactive planes have on // shaders is to offset the next binding index. void skipInactivePlanes(); int mBinding = 0; uint64_t mPlaneKeys = 0; }; Iter begin() const { return Iter(*this); } Iter end() const { return Iter(); } private: uint64_t mRawKey = 0; }; class PLSProgramKeyBuilder { public: // Prepends a plane's format and whether it is preserved to the descriptor. void prependPlane(GLenum internalformat, bool preserved); PLSProgramKey finish(PLSProgramType); private: uint64_t mRawKey = 0; }; class PLSProgram : angle::NonCopyable { public: PLSProgram(const FunctionsGL *, GLuint vertexShaderID, PLSProgramKey); ~PLSProgram(); GLuint getProgramID() const { return mProgramID; } void setClearValues(const gl::PixelLocalStoragePlane[], const GLenum loadops[]) const; private: const FunctionsGL *const mGL; const PLSProgramKey mKey; const GLuint mProgramID; gl::DrawBuffersArray mClearValueUniformLocations; }; } // namespace rx #endif // LIBANGLE_RENDERER_GL_PLS_PROGRAM_CACHE_H_