1 // 2 // Copyright 2020 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 // ProgramExecutable.h: Collects the information and interfaces common to both Programs and 7 // ProgramPipelines in order to execute/draw with either. 8 9 #ifndef LIBANGLE_PROGRAMEXECUTABLE_H_ 10 #define LIBANGLE_PROGRAMEXECUTABLE_H_ 11 12 #include "common/BinaryStream.h" 13 #include "libANGLE/Caps.h" 14 #include "libANGLE/InfoLog.h" 15 #include "libANGLE/ProgramLinkedResources.h" 16 #include "libANGLE/Shader.h" 17 #include "libANGLE/Uniform.h" 18 #include "libANGLE/VaryingPacking.h" 19 #include "libANGLE/angletypes.h" 20 21 namespace gl 22 { 23 24 // This small structure encapsulates binding sampler uniforms to active GL textures. 25 struct SamplerBinding 26 { 27 SamplerBinding(); 28 SamplerBinding(TextureType textureTypeIn, 29 GLenum samplerTypeIn, 30 SamplerFormat formatIn, 31 size_t elementCount); 32 SamplerBinding(const SamplerBinding &other); 33 ~SamplerBinding(); 34 35 // Necessary for retrieving active textures from the GL state. 36 TextureType textureType; 37 38 GLenum samplerType; 39 40 SamplerFormat format; 41 42 // List of all textures bound to this sampler, of type textureType. 43 // Cropped by the amount of unused elements reported by the driver. 44 std::vector<GLuint> boundTextureUnits; 45 }; 46 47 struct ImageBinding 48 { 49 ImageBinding(); 50 ImageBinding(size_t count, TextureType textureTypeIn); 51 ImageBinding(GLuint imageUnit, size_t count, TextureType textureTypeIn); 52 ImageBinding(const ImageBinding &other); 53 ~ImageBinding(); 54 55 // Necessary for distinguishing between textures with images and texture buffers. 56 TextureType textureType; 57 58 // List of all textures bound. 59 // Cropped by the amount of unused elements reported by the driver. 60 std::vector<GLuint> boundImageUnits; 61 }; 62 63 // A varying with transform feedback enabled. If it's an array, either the whole array or one of its 64 // elements specified by 'arrayIndex' can set to be enabled. 65 struct TransformFeedbackVarying : public sh::ShaderVariable 66 { 67 TransformFeedbackVarying() = default; 68 TransformFeedbackVaryingTransformFeedbackVarying69 TransformFeedbackVarying(const sh::ShaderVariable &varyingIn, GLuint arrayIndexIn) 70 : sh::ShaderVariable(varyingIn), arrayIndex(arrayIndexIn) 71 { 72 ASSERT(!isArrayOfArrays()); 73 } 74 TransformFeedbackVaryingTransformFeedbackVarying75 TransformFeedbackVarying(const sh::ShaderVariable &field, const sh::ShaderVariable &parent) 76 : arrayIndex(GL_INVALID_INDEX) 77 { 78 sh::ShaderVariable *thisVar = this; 79 *thisVar = field; 80 interpolation = parent.interpolation; 81 isInvariant = parent.isInvariant; 82 ASSERT(parent.isShaderIOBlock || !parent.name.empty()); 83 if (!parent.name.empty()) 84 { 85 name = parent.name + "." + name; 86 mappedName = parent.mappedName + "." + mappedName; 87 } 88 structOrBlockName = parent.structOrBlockName; 89 mappedStructOrBlockName = parent.mappedStructOrBlockName; 90 } 91 nameWithArrayIndexTransformFeedbackVarying92 std::string nameWithArrayIndex() const 93 { 94 std::stringstream fullNameStr; 95 fullNameStr << name; 96 if (arrayIndex != GL_INVALID_INDEX) 97 { 98 fullNameStr << "[" << arrayIndex << "]"; 99 } 100 return fullNameStr.str(); 101 } sizeTransformFeedbackVarying102 GLsizei size() const 103 { 104 return (isArray() && arrayIndex == GL_INVALID_INDEX ? getOutermostArraySize() : 1); 105 } 106 107 GLuint arrayIndex; 108 }; 109 110 class ProgramState; 111 class ProgramPipelineState; 112 113 class ProgramExecutable final : public angle::Subject 114 { 115 public: 116 ProgramExecutable(); 117 ProgramExecutable(const ProgramExecutable &other); 118 ~ProgramExecutable() override; 119 120 void reset(bool clearInfoLog); 121 122 void save(bool isSeparable, gl::BinaryOutputStream *stream) const; 123 void load(bool isSeparable, gl::BinaryInputStream *stream); 124 125 int getInfoLogLength() const; getInfoLog()126 InfoLog &getInfoLog() { return mInfoLog; } 127 void getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const; 128 std::string getInfoLogString() const; resetInfoLog()129 void resetInfoLog() { mInfoLog.reset(); } 130 resetLinkedShaderStages()131 void resetLinkedShaderStages() { mLinkedShaderStages.reset(); } getLinkedShaderStages()132 const ShaderBitSet getLinkedShaderStages() const { return mLinkedShaderStages; } setLinkedShaderStages(ShaderType shaderType)133 void setLinkedShaderStages(ShaderType shaderType) 134 { 135 mLinkedShaderStages.set(shaderType); 136 updateCanDrawWith(); 137 } hasLinkedShaderStage(ShaderType shaderType)138 bool hasLinkedShaderStage(ShaderType shaderType) const 139 { 140 ASSERT(shaderType != ShaderType::InvalidEnum); 141 return mLinkedShaderStages[shaderType]; 142 } getLinkedShaderStageCount()143 size_t getLinkedShaderStageCount() const { return mLinkedShaderStages.count(); } hasLinkedGraphicsShader()144 bool hasLinkedGraphicsShader() const 145 { 146 return mLinkedShaderStages.any() && 147 mLinkedShaderStages != gl::ShaderBitSet{gl::ShaderType::Compute}; 148 } hasLinkedTessellationShader()149 bool hasLinkedTessellationShader() const 150 { 151 return mLinkedShaderStages[ShaderType::TessEvaluation]; 152 } 153 154 ShaderType getLinkedTransformFeedbackStage() const; 155 getActiveAttribLocationsMask()156 const AttributesMask &getActiveAttribLocationsMask() const 157 { 158 return mActiveAttribLocationsMask; 159 } 160 bool isAttribLocationActive(size_t attribLocation) const; getNonBuiltinAttribLocationsMask()161 AttributesMask getNonBuiltinAttribLocationsMask() const { return mAttributesMask; } getMaxActiveAttribLocation()162 unsigned int getMaxActiveAttribLocation() const { return mMaxActiveAttribLocation; } getAttributesTypeMask()163 ComponentTypeMask getAttributesTypeMask() const { return mAttributesTypeMask; } 164 AttributesMask getAttributesMask() const; 165 getActiveSamplersMask()166 const ActiveTextureMask &getActiveSamplersMask() const { return mActiveSamplersMask; } setActiveTextureMask(ActiveTextureMask mask)167 void setActiveTextureMask(ActiveTextureMask mask) { mActiveSamplersMask = mask; } getSamplerFormatForTextureUnitIndex(size_t textureUnitIndex)168 SamplerFormat getSamplerFormatForTextureUnitIndex(size_t textureUnitIndex) const 169 { 170 return mActiveSamplerFormats[textureUnitIndex]; 171 } getSamplerShaderBitsForTextureUnitIndex(size_t textureUnitIndex)172 const ShaderBitSet getSamplerShaderBitsForTextureUnitIndex(size_t textureUnitIndex) const 173 { 174 return mActiveSamplerShaderBits[textureUnitIndex]; 175 } getActiveImagesMask()176 const ActiveTextureMask &getActiveImagesMask() const { return mActiveImagesMask; } setActiveImagesMask(ActiveTextureMask mask)177 void setActiveImagesMask(ActiveTextureMask mask) { mActiveImagesMask = mask; } getActiveImageShaderBits()178 const ActiveTextureArray<ShaderBitSet> &getActiveImageShaderBits() const 179 { 180 return mActiveImageShaderBits; 181 } 182 getActiveYUVSamplers()183 const ActiveTextureMask &getActiveYUVSamplers() const { return mActiveSamplerYUV; } 184 getActiveSamplerTypes()185 const ActiveTextureArray<TextureType> &getActiveSamplerTypes() const 186 { 187 return mActiveSamplerTypes; 188 } 189 190 void setActive(size_t textureUnit, 191 const SamplerBinding &samplerBinding, 192 const gl::LinkedUniform &samplerUniform); 193 void setInactive(size_t textureUnit); 194 void hasSamplerTypeConflict(size_t textureUnit); 195 void hasSamplerFormatConflict(size_t textureUnit); 196 197 void updateActiveSamplers(const ProgramState &programState); 198 199 bool hasDefaultUniforms() const; 200 bool hasTextures() const; 201 bool hasUniformBuffers() const; 202 bool hasStorageBuffers() const; 203 bool hasAtomicCounterBuffers() const; 204 bool hasImages() const; hasTransformFeedbackOutput()205 bool hasTransformFeedbackOutput() const 206 { 207 return !getLinkedTransformFeedbackVaryings().empty(); 208 } 209 bool usesFramebufferFetch() const; 210 211 // Count the number of uniform and storage buffer declarations, counting arrays as one. getTransformFeedbackBufferCount()212 size_t getTransformFeedbackBufferCount() const { return mTransformFeedbackStrides.size(); } 213 214 void updateCanDrawWith(); hasVertexShader()215 bool hasVertexShader() const { return mCanDrawWith; } 216 getProgramInputs()217 const std::vector<sh::ShaderVariable> &getProgramInputs() const { return mProgramInputs; } getOutputVariables()218 const std::vector<sh::ShaderVariable> &getOutputVariables() const { return mOutputVariables; } getOutputLocations()219 const std::vector<VariableLocation> &getOutputLocations() const { return mOutputLocations; } getSecondaryOutputLocations()220 const std::vector<VariableLocation> &getSecondaryOutputLocations() const 221 { 222 return mSecondaryOutputLocations; 223 } getUniforms()224 const std::vector<LinkedUniform> &getUniforms() const { return mUniforms; } getUniformBlocks()225 const std::vector<InterfaceBlock> &getUniformBlocks() const { return mUniformBlocks; } getActiveUniformBlockBindings()226 const UniformBlockBindingMask &getActiveUniformBlockBindings() const 227 { 228 return mActiveUniformBlockBindings; 229 } getSamplerBindings()230 const std::vector<SamplerBinding> &getSamplerBindings() const { return mSamplerBindings; } getImageBindings()231 const std::vector<ImageBinding> &getImageBindings() const { return mImageBindings; } getImageBindings()232 std::vector<ImageBinding> *getImageBindings() { return &mImageBindings; } getDefaultUniformRange()233 const RangeUI &getDefaultUniformRange() const { return mDefaultUniformRange; } getSamplerUniformRange()234 const RangeUI &getSamplerUniformRange() const { return mSamplerUniformRange; } getImageUniformRange()235 const RangeUI &getImageUniformRange() const { return mImageUniformRange; } getAtomicCounterUniformRange()236 const RangeUI &getAtomicCounterUniformRange() const { return mAtomicCounterUniformRange; } getFragmentInoutRange()237 const RangeUI &getFragmentInoutRange() const { return mFragmentInoutRange; } hasClipDistance()238 bool hasClipDistance() const { return mHasClipDistance; } hasDiscard()239 bool hasDiscard() const { return mHasDiscard; } enablesPerSampleShading()240 bool enablesPerSampleShading() const { return mEnablesPerSampleShading; } getAdvancedBlendEquations()241 BlendEquationBitSet getAdvancedBlendEquations() const { return mAdvancedBlendEquations; } getLinkedTransformFeedbackVaryings()242 const std::vector<TransformFeedbackVarying> &getLinkedTransformFeedbackVaryings() const 243 { 244 return mLinkedTransformFeedbackVaryings; 245 } getTransformFeedbackBufferMode()246 GLint getTransformFeedbackBufferMode() const { return mTransformFeedbackBufferMode; } getUniformBlockBinding(GLuint uniformBlockIndex)247 GLuint getUniformBlockBinding(GLuint uniformBlockIndex) const 248 { 249 ASSERT(uniformBlockIndex < mUniformBlocks.size()); 250 return mUniformBlocks[uniformBlockIndex].binding; 251 } getShaderStorageBlockBinding(GLuint blockIndex)252 GLuint getShaderStorageBlockBinding(GLuint blockIndex) const 253 { 254 ASSERT(blockIndex < mShaderStorageBlocks.size()); 255 return mShaderStorageBlocks[blockIndex].binding; 256 } getTransformFeedbackStrides()257 const std::vector<GLsizei> &getTransformFeedbackStrides() const 258 { 259 return mTransformFeedbackStrides; 260 } getAtomicCounterBuffers()261 const std::vector<AtomicCounterBuffer> &getAtomicCounterBuffers() const 262 { 263 return mAtomicCounterBuffers; 264 } getShaderStorageBlocks()265 const std::vector<InterfaceBlock> &getShaderStorageBlocks() const 266 { 267 return mShaderStorageBlocks; 268 } getUniformByIndex(GLuint index)269 const LinkedUniform &getUniformByIndex(GLuint index) const 270 { 271 ASSERT(index < static_cast<size_t>(mUniforms.size())); 272 return mUniforms[index]; 273 } 274 getActiveUniformBlockCount()275 ANGLE_INLINE GLuint getActiveUniformBlockCount() const 276 { 277 return static_cast<GLuint>(mUniformBlocks.size()); 278 } 279 getActiveAtomicCounterBufferCount()280 ANGLE_INLINE GLuint getActiveAtomicCounterBufferCount() const 281 { 282 return static_cast<GLuint>(mAtomicCounterBuffers.size()); 283 } 284 getActiveShaderStorageBlockCount()285 ANGLE_INLINE GLuint getActiveShaderStorageBlockCount() const 286 { 287 size_t shaderStorageBlocksSize = mShaderStorageBlocks.size(); 288 return static_cast<GLuint>(shaderStorageBlocksSize); 289 } 290 291 GLuint getUniformIndexFromImageIndex(GLuint imageIndex) const; 292 293 GLuint getUniformIndexFromSamplerIndex(GLuint samplerIndex) const; 294 295 void saveLinkedStateInfo(const Context *context, const ProgramState &state); getLinkedOutputVaryings(ShaderType shaderType)296 const std::vector<sh::ShaderVariable> &getLinkedOutputVaryings(ShaderType shaderType) const 297 { 298 return mLinkedOutputVaryings[shaderType]; 299 } getLinkedInputVaryings(ShaderType shaderType)300 const std::vector<sh::ShaderVariable> &getLinkedInputVaryings(ShaderType shaderType) const 301 { 302 return mLinkedInputVaryings[shaderType]; 303 } 304 getLinkedUniforms(ShaderType shaderType)305 const std::vector<sh::ShaderVariable> &getLinkedUniforms(ShaderType shaderType) const 306 { 307 return mLinkedUniforms[shaderType]; 308 } 309 getLinkedUniformBlocks(ShaderType shaderType)310 const std::vector<sh::InterfaceBlock> &getLinkedUniformBlocks(ShaderType shaderType) const 311 { 312 return mLinkedUniformBlocks[shaderType]; 313 } 314 getLinkedShaderVersion(ShaderType shaderType)315 int getLinkedShaderVersion(ShaderType shaderType) const 316 { 317 return mLinkedShaderVersions[shaderType]; 318 } 319 320 bool isYUVOutput() const; 321 getGeometryShaderInputPrimitiveType()322 PrimitiveMode getGeometryShaderInputPrimitiveType() const 323 { 324 return mGeometryShaderInputPrimitiveType; 325 } 326 getGeometryShaderOutputPrimitiveType()327 PrimitiveMode getGeometryShaderOutputPrimitiveType() const 328 { 329 return mGeometryShaderOutputPrimitiveType; 330 } 331 getGeometryShaderInvocations()332 int getGeometryShaderInvocations() const { return mGeometryShaderInvocations; } 333 getGeometryShaderMaxVertices()334 int getGeometryShaderMaxVertices() const { return mGeometryShaderMaxVertices; } 335 getTessGenMode()336 GLenum getTessGenMode() const { return mTessGenMode; } 337 resetCachedValidateSamplersResult()338 void resetCachedValidateSamplersResult() { mCachedValidateSamplersResult.reset(); } validateSamplers(InfoLog * infoLog,const Caps & caps)339 bool validateSamplers(InfoLog *infoLog, const Caps &caps) const 340 { 341 // Use the cache if: 342 // - we aren't using an info log (which gives the full error). 343 // - The sample mapping hasn't changed and we've already validated. 344 if (infoLog == nullptr && mCachedValidateSamplersResult.valid()) 345 { 346 return mCachedValidateSamplersResult.value(); 347 } 348 349 return validateSamplersImpl(infoLog, caps); 350 } 351 getFragmentOutputsTypeMask()352 ComponentTypeMask getFragmentOutputsTypeMask() const { return mDrawBufferTypeMask; } getActiveOutputVariablesMask()353 DrawBufferMask getActiveOutputVariablesMask() const { return mActiveOutputVariablesMask; } 354 355 bool linkUniforms(const Context *context, 356 const ShaderMap<std::vector<sh::ShaderVariable>> &shaderUniforms, 357 InfoLog &infoLog, 358 const ProgramAliasedBindings &uniformLocationBindings, 359 GLuint *combinedImageUniformsCount, 360 std::vector<UnusedUniform> *unusedUniforms, 361 std::vector<VariableLocation> *uniformLocationsOutOrNull); 362 363 void copyInputsFromProgram(const ProgramState &programState); 364 void copyShaderBuffersFromProgram(const ProgramState &programState, ShaderType shaderType); 365 void clearSamplerBindings(); 366 void copySamplerBindingsFromProgram(const ProgramState &programState); 367 void copyImageBindingsFromProgram(const ProgramState &programState); 368 void copyOutputsFromProgram(const ProgramState &programState); 369 void copyUniformsFromProgramMap(const ShaderMap<Program *> &programs); 370 371 private: 372 friend class Program; 373 friend class ProgramPipeline; 374 friend class ProgramState; 375 376 void updateActiveImages(const ProgramExecutable &executable); 377 378 // Scans the sampler bindings for type conflicts with sampler 'textureUnitIndex'. 379 void setSamplerUniformTextureTypeAndFormat(size_t textureUnitIndex, 380 std::vector<SamplerBinding> &samplerBindings); 381 382 bool linkMergedVaryings(const Context *context, 383 const ProgramMergedVaryings &mergedVaryings, 384 const std::vector<std::string> &transformFeedbackVaryingNames, 385 const LinkingVariables &linkingVariables, 386 bool isSeparable, 387 ProgramVaryingPacking *varyingPacking); 388 389 bool linkValidateTransformFeedback( 390 const Context *context, 391 const ProgramMergedVaryings &varyings, 392 ShaderType stage, 393 const std::vector<std::string> &transformFeedbackVaryingNames); 394 395 void gatherTransformFeedbackVaryings( 396 const ProgramMergedVaryings &varyings, 397 ShaderType stage, 398 const std::vector<std::string> &transformFeedbackVaryingNames); 399 400 void updateTransformFeedbackStrides(); 401 402 bool validateSamplersImpl(InfoLog *infoLog, const Caps &caps) const; 403 404 bool linkValidateOutputVariables(const Caps &caps, 405 const Extensions &extensions, 406 const Version &version, 407 GLuint combinedImageUniformsCount, 408 GLuint combinedShaderStorageBlocksCount, 409 const std::vector<sh::ShaderVariable> &outputVariables, 410 int fragmentShaderVersion, 411 const ProgramAliasedBindings &fragmentOutputLocations, 412 const ProgramAliasedBindings &fragmentOutputIndices); 413 414 void linkSamplerAndImageBindings(GLuint *combinedImageUniformsCount); 415 bool linkAtomicCounterBuffers(const Context *context, InfoLog &infoLog); 416 417 InfoLog mInfoLog; 418 419 ShaderBitSet mLinkedShaderStages; 420 421 angle::BitSet<MAX_VERTEX_ATTRIBS> mActiveAttribLocationsMask; 422 unsigned int mMaxActiveAttribLocation; 423 ComponentTypeMask mAttributesTypeMask; 424 // mAttributesMask is identical to mActiveAttribLocationsMask with built-in attributes removed. 425 AttributesMask mAttributesMask; 426 427 // Cached mask of active samplers and sampler types. 428 ActiveTextureMask mActiveSamplersMask; 429 ActiveTextureArray<uint32_t> mActiveSamplerRefCounts; 430 ActiveTextureArray<TextureType> mActiveSamplerTypes; 431 ActiveTextureMask mActiveSamplerYUV; 432 ActiveTextureArray<SamplerFormat> mActiveSamplerFormats; 433 ActiveTextureArray<ShaderBitSet> mActiveSamplerShaderBits; 434 435 // Cached mask of active images. 436 ActiveTextureMask mActiveImagesMask; 437 ActiveTextureArray<ShaderBitSet> mActiveImageShaderBits; 438 439 bool mCanDrawWith; 440 441 // Names and mapped names of output variables that are arrays include [0] in the end, similarly 442 // to uniforms. 443 std::vector<sh::ShaderVariable> mOutputVariables; 444 std::vector<VariableLocation> mOutputLocations; 445 DrawBufferMask mActiveOutputVariablesMask; 446 // EXT_blend_func_extended secondary outputs (ones with index 1) 447 std::vector<VariableLocation> mSecondaryOutputLocations; 448 bool mYUVOutput; 449 // Vertex attributes, Fragment input varyings, etc. 450 std::vector<sh::ShaderVariable> mProgramInputs; 451 std::vector<TransformFeedbackVarying> mLinkedTransformFeedbackVaryings; 452 // The size of the data written to each transform feedback buffer per vertex. 453 std::vector<GLsizei> mTransformFeedbackStrides; 454 GLenum mTransformFeedbackBufferMode; 455 // Uniforms are sorted in order: 456 // 1. Non-opaque uniforms 457 // 2. Sampler uniforms 458 // 3. Image uniforms 459 // 4. Atomic counter uniforms 460 // 5. Subpass Input uniforms (Only for Vulkan) 461 // 6. Uniform block uniforms 462 // This makes opaque uniform validation easier, since we don't need a separate list. 463 // For generating the entries and naming them we follow the spec: GLES 3.1 November 2016 section 464 // 7.3.1.1 Naming Active Resources. There's a separate entry for each struct member and each 465 // inner array of an array of arrays. Names and mapped names of uniforms that are arrays include 466 // [0] in the end. This makes implementation of queries simpler. 467 std::vector<LinkedUniform> mUniforms; 468 RangeUI mDefaultUniformRange; 469 RangeUI mSamplerUniformRange; 470 RangeUI mImageUniformRange; 471 RangeUI mAtomicCounterUniformRange; 472 std::vector<InterfaceBlock> mUniformBlocks; 473 474 // For faster iteration on the blocks currently being bound. 475 UniformBlockBindingMask mActiveUniformBlockBindings; 476 477 std::vector<AtomicCounterBuffer> mAtomicCounterBuffers; 478 std::vector<InterfaceBlock> mShaderStorageBlocks; 479 480 RangeUI mFragmentInoutRange; 481 bool mHasClipDistance; 482 bool mHasDiscard; 483 bool mEnablesPerSampleShading; 484 485 // KHR_blend_equation_advanced supported equation list 486 BlendEquationBitSet mAdvancedBlendEquations; 487 488 // An array of the samplers that are used by the program 489 std::vector<SamplerBinding> mSamplerBindings; 490 491 // An array of the images that are used by the program 492 std::vector<ImageBinding> mImageBindings; 493 494 ShaderMap<std::vector<sh::ShaderVariable>> mLinkedOutputVaryings; 495 ShaderMap<std::vector<sh::ShaderVariable>> mLinkedInputVaryings; 496 ShaderMap<std::vector<sh::ShaderVariable>> mLinkedUniforms; 497 ShaderMap<std::vector<sh::InterfaceBlock>> mLinkedUniformBlocks; 498 499 ShaderMap<int> mLinkedShaderVersions; 500 501 // GL_EXT_geometry_shader. 502 PrimitiveMode mGeometryShaderInputPrimitiveType; 503 PrimitiveMode mGeometryShaderOutputPrimitiveType; 504 int mGeometryShaderInvocations; 505 int mGeometryShaderMaxVertices; 506 507 // GL_EXT_tessellation_shader 508 int mTessControlShaderVertices; 509 GLenum mTessGenMode; 510 GLenum mTessGenSpacing; 511 GLenum mTessGenVertexOrder; 512 GLenum mTessGenPointMode; 513 514 // Fragment output variable base types: FLOAT, INT, or UINT. Ordered by location. 515 std::vector<GLenum> mOutputVariableTypes; 516 ComponentTypeMask mDrawBufferTypeMask; 517 518 // Cache for sampler validation 519 mutable Optional<bool> mCachedValidateSamplersResult; 520 }; 521 } // namespace gl 522 523 #endif // LIBANGLE_PROGRAMEXECUTABLE_H_ 524