1 // 2 // Copyright 2022 The ANGLE Project Authors. All rights reserved. 3 // Use of this source code is governed by a BSD-style license that can be 4 // found in the LICENSE file. 5 // 6 7 // PixelLocalStorage.h: Defines the renderer-agnostic container classes 8 // gl::PixelLocalStorage and gl::PixelLocalStoragePlane for 9 // ANGLE_shader_pixel_local_storage. 10 11 #ifndef LIBANGLE_PIXEL_LOCAL_STORAGE_H_ 12 #define LIBANGLE_PIXEL_LOCAL_STORAGE_H_ 13 14 #include "GLSLANG/ShaderLang.h" 15 #include "libANGLE/Caps.h" 16 #include "libANGLE/ImageIndex.h" 17 #include "libANGLE/angletypes.h" 18 19 namespace gl 20 { 21 22 class Context; 23 class Texture; 24 25 // Holds the configuration of an ANGLE_shader_pixel_local_storage plane. 26 // 27 // Unlike normal framebuffer attachments, pixel local storage planes don't take effect until the 28 // application calls glBeginPixelLocalStorageANGLE, and the manner in which they take effect is 29 // highly dependent on the backend implementation. A PixelLocalStoragePlane is just a plain data 30 // description what to set up later once PLS is enabled. 31 class PixelLocalStoragePlane : angle::NonCopyable, public angle::ObserverInterface 32 { 33 public: 34 PixelLocalStoragePlane(); 35 ~PixelLocalStoragePlane() override; 36 37 // Called when the context is lost or destroyed. Causes this class to clear its GL object 38 // handles. 39 void onContextObjectsLost(); 40 41 void deinitialize(Context *); 42 void setMemoryless(Context *, GLenum internalformat); 43 void setTextureBacked(Context *, Texture *, int level, int layer); 44 void onSubjectStateChange(angle::SubjectIndex, angle::SubjectMessage) override; 45 46 // Returns true if the plane is deinitialized, either explicitly or implicitly via deleting the 47 // texture that was attached to it. 48 bool isDeinitialized() const; 49 getInternalformat()50 GLenum getInternalformat() const { return mInternalformat; } isMemoryless()51 bool isMemoryless() const { return mMemoryless; } getTextureID()52 TextureID getTextureID() const { return mTextureID; } 53 54 // Implements glGetIntegeri_v() for GL_PIXEL_LOCAL_FORMAT_ANGLE, 55 // GL_PIXEL_LOCAL_TEXTURE_NAME_ANGLE, GL_PIXEL_LOCAL_TEXTURE_LEVEL_ANGLE, and 56 // GL_PIXEL_LOCAL_TEXTURE_LAYER_ANGLE 57 GLint getIntegeri(GLenum target) const; 58 59 // If this plane is texture backed, stores the bound texture image's {width, height, 0} to 60 // Extents and returns true. Otherwise returns false, meaning the plane is either deinitialized 61 // or memoryless. 62 bool getTextureImageExtents(const Context *, Extents *extents) const; 63 64 // Ensures we have an internal backing texture for memoryless planes. In some implementations we 65 // need a backing texture even if the plane is memoryless. 66 void ensureBackingTextureIfMemoryless(Context *, Extents plsSize); 67 68 // Attaches this plane to the specified color attachment point on the current draw framebuffer. 69 void attachToDrawFramebuffer(Context *, GLenum colorAttachment) const; 70 71 // Interface for clearing typed pixel local storage planes. 72 class ClearCommands 73 { 74 public: ~ClearCommands()75 virtual ~ClearCommands() {} 76 virtual void clearfv(int target, const GLfloat[]) const = 0; 77 virtual void cleariv(int target, const GLint[]) const = 0; 78 virtual void clearuiv(int target, const GLuint[]) const = 0; 79 }; 80 81 // Issues the approprite command from ClearCommands for this plane's internalformat. Uses the 82 // clear state value that corresponds to mInternalFormat, and potentially clamps it to ensure it 83 // is representable. 84 void issueClearCommand(ClearCommands *, int target, GLenum loadop) const; 85 86 // Binds this PLS plane to a texture image unit for image load/store shader operations. 87 void bindToImage(Context *, GLuint unit, bool needsR32Packing) const; 88 89 // Low-level access to the backing texture. The plane must not be memoryless or deinitialized. getTextureImageIndex()90 const ImageIndex &getTextureImageIndex() const { return mTextureImageIndex; } 91 const Texture *getBackingTexture(const Context *context) const; 92 setClearValuef(const GLfloat value[4])93 void setClearValuef(const GLfloat value[4]) { memcpy(mClearValuef.data(), value, 4 * 4); } setClearValuei(const GLint value[4])94 void setClearValuei(const GLint value[4]) { memcpy(mClearValuei.data(), value, 4 * 4); } setClearValueui(const GLuint value[4])95 void setClearValueui(const GLuint value[4]) { memcpy(mClearValueui.data(), value, 4 * 4); } 96 getClearValuef(GLfloat value[4])97 void getClearValuef(GLfloat value[4]) const { memcpy(value, mClearValuef.data(), 4 * 4); } getClearValuei(GLint value[4])98 void getClearValuei(GLint value[4]) const { memcpy(value, mClearValuei.data(), 4 * 4); } getClearValueui(GLuint value[4])99 void getClearValueui(GLuint value[4]) const { memcpy(value, mClearValueui.data(), 4 * 4); } 100 101 // True if PLS is currently active and this plane is enabled. isActive()102 bool isActive() const { return mActive; } markActive(bool active)103 void markActive(bool active) { mActive = active; } 104 105 private: 106 GLenum mInternalformat = GL_NONE; // GL_NONE if this plane is in a deinitialized state. 107 bool mMemoryless = false; 108 TextureID mTextureID = TextureID(); 109 ImageIndex mTextureImageIndex; 110 111 // Clear value state. 112 std::array<GLfloat, 4> mClearValuef{}; 113 std::array<GLint, 4> mClearValuei{}; 114 std::array<GLuint, 4> mClearValueui{}; 115 116 // True if PLS is currently active and this plane is enabled. 117 bool mActive = false; 118 119 angle::ObserverBinding mTextureObserver; 120 }; 121 122 // Manages a collection of PixelLocalStoragePlanes and applies them to ANGLE's GL state. 123 // 124 // The main magic of ANGLE_shader_pixel_local_storage happens inside shaders, so we just emulate the 125 // client API on top of ANGLE's OpenGL ES API for simplicity. 126 class PixelLocalStorage 127 { 128 public: 129 static std::unique_ptr<PixelLocalStorage> Make(const Context *); 130 131 virtual ~PixelLocalStorage(); 132 133 // Called when the owning framebuffer is being destroyed. 134 void onFramebufferDestroyed(const Context *); 135 136 // Deletes any GL objects that have been allocated for pixel local storage. These can't be 137 // cleaned up in the destructor because they require a non-const Context object. 138 void deleteContextObjects(Context *); 139 getPlane(GLint plane)140 const PixelLocalStoragePlane &getPlane(GLint plane) const 141 { 142 ASSERT(0 <= plane && plane < IMPLEMENTATION_MAX_PIXEL_LOCAL_STORAGE_PLANES); 143 return mPlanes[plane]; 144 } 145 getPlanes()146 const PixelLocalStoragePlane *getPlanes() { return mPlanes.data(); } 147 interruptCount()148 size_t interruptCount() const { return mInterruptCount; } 149 150 // ANGLE_shader_pixel_local_storage API. deinitialize(Context * context,GLint plane)151 void deinitialize(Context *context, GLint plane) { mPlanes[plane].deinitialize(context); } setMemoryless(Context * context,GLint plane,GLenum internalformat)152 void setMemoryless(Context *context, GLint plane, GLenum internalformat) 153 { 154 mPlanes[plane].setMemoryless(context, internalformat); 155 } setTextureBacked(Context * context,GLint plane,Texture * tex,int level,int layer)156 void setTextureBacked(Context *context, GLint plane, Texture *tex, int level, int layer) 157 { 158 mPlanes[plane].setTextureBacked(context, tex, level, layer); 159 } setClearValuef(GLint plane,const GLfloat val[4])160 void setClearValuef(GLint plane, const GLfloat val[4]) { mPlanes[plane].setClearValuef(val); } setClearValuei(GLint plane,const GLint val[4])161 void setClearValuei(GLint plane, const GLint val[4]) { mPlanes[plane].setClearValuei(val); } setClearValueui(GLint plane,const GLuint val[4])162 void setClearValueui(GLint plane, const GLuint val[4]) { mPlanes[plane].setClearValueui(val); } 163 void begin(Context *, GLsizei n, const GLenum loadops[]); 164 void end(Context *, GLsizei n, const GLenum storeops[]); 165 void barrier(Context *); 166 void interrupt(Context *); 167 void restore(Context *); 168 169 // While pixel local storage is active, the draw buffers on and after 170 // 'FirstOverriddenDrawBuffer' are blocked from the client and reserved for internal use by PLS. FirstOverriddenDrawBuffer(const Caps & caps,GLuint numActivePlanes)171 static GLint FirstOverriddenDrawBuffer(const Caps &caps, GLuint numActivePlanes) 172 { 173 ASSERT(numActivePlanes > 0); 174 return std::min(caps.maxColorAttachmentsWithActivePixelLocalStorage, 175 caps.maxCombinedDrawBuffersAndPixelLocalStoragePlanes - numActivePlanes); 176 } 177 178 protected: 179 PixelLocalStorage(const ShPixelLocalStorageOptions &, const Caps &); 180 181 // Called when the context is lost or destroyed. Causes the subclass to clear its GL object 182 // handles. 183 virtual void onContextObjectsLost() = 0; 184 185 // Called when the framebuffer is being destroyed. Causes the subclass to delete its frontend GL 186 // object handles. 187 virtual void onDeleteContextObjects(Context *) = 0; 188 189 // ANGLE_shader_pixel_local_storage API. 190 virtual void onBegin(Context *, GLsizei n, const GLenum loadops[], Extents plsSize) = 0; 191 virtual void onEnd(Context *, GLsizei n, const GLenum storeops[]) = 0; 192 virtual void onBarrier(Context *) = 0; 193 194 const ShPixelLocalStorageOptions mPLSOptions; 195 196 private: 197 angle::FixedVector<PixelLocalStoragePlane, IMPLEMENTATION_MAX_PIXEL_LOCAL_STORAGE_PLANES> 198 mPlanes; 199 size_t mInterruptCount = 0; 200 GLsizei mActivePlanesAtInterrupt = 0; 201 }; 202 203 } // namespace gl 204 205 #endif // LIBANGLE_PIXEL_LOCAL_STORAGE_H_ 206