| // | |
| // Copyright 2020 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. | |
| // | |
| // ProgramExecutable.h: Collects the information and interfaces common to both Programs and | |
| // ProgramPipelines in order to execute/draw with either. | |
| #ifndef LIBANGLE_PROGRAMEXECUTABLE_H_ | |
| #define LIBANGLE_PROGRAMEXECUTABLE_H_ | |
| #include "common/BinaryStream.h" | |
| #include "libANGLE/Caps.h" | |
| #include "libANGLE/InfoLog.h" | |
| #include "libANGLE/ProgramLinkedResources.h" | |
| #include "libANGLE/Shader.h" | |
| #include "libANGLE/Uniform.h" | |
| #include "libANGLE/VaryingPacking.h" | |
| #include "libANGLE/angletypes.h" | |
| namespace rx | |
| { | |
| class GLImplFactory; | |
| class LinkSubTask; | |
| class ProgramExecutableImpl; | |
| } // namespace rx | |
| namespace gl | |
| { | |
| // This small structure encapsulates binding sampler uniforms to active GL textures. | |
| ANGLE_ENABLE_STRUCT_PADDING_WARNINGS | |
| struct SamplerBinding | |
| { | |
| SamplerBinding() = default; | |
| SamplerBinding(TextureType textureTypeIn, | |
| GLenum samplerTypeIn, | |
| SamplerFormat formatIn, | |
| uint16_t startIndex, | |
| uint16_t elementCount) | |
| : textureType(textureTypeIn), | |
| format(formatIn), | |
| textureUnitsStartIndex(startIndex), | |
| textureUnitsCount(elementCount) | |
| { | |
| SetBitField(samplerType, samplerTypeIn); | |
| } | |
| GLuint getTextureUnit(const std::vector<GLuint> &boundTextureUnits, | |
| unsigned int arrayIndex) const | |
| { | |
| return boundTextureUnits[textureUnitsStartIndex + arrayIndex]; | |
| } | |
| // Necessary for retrieving active textures from the GL state. | |
| TextureType textureType; | |
| SamplerFormat format; | |
| uint16_t samplerType; | |
| // [textureUnitsStartIndex, textureUnitsStartIndex+textureUnitsCount) Points to the subset in | |
| // mSamplerBoundTextureUnits that stores the texture unit bound to this sampler. Cropped by the | |
| // amount of unused elements reported by the driver. | |
| uint16_t textureUnitsStartIndex; | |
| uint16_t textureUnitsCount; | |
| }; | |
| ANGLE_DISABLE_STRUCT_PADDING_WARNINGS | |
| struct ImageBinding | |
| { | |
| ImageBinding() = default; | |
| ImageBinding(size_t count, TextureType textureTypeIn) | |
| : textureType(textureTypeIn), boundImageUnits(count, 0) | |
| {} | |
| ImageBinding(GLuint imageUnit, size_t count, TextureType textureTypeIn); | |
| // Necessary for distinguishing between textures with images and texture buffers. | |
| TextureType textureType; | |
| // List of all textures bound. | |
| // Cropped by the amount of unused elements reported by the driver. | |
| std::vector<GLuint> boundImageUnits; | |
| }; | |
| ANGLE_ENABLE_STRUCT_PADDING_WARNINGS | |
| struct ProgramInput | |
| { | |
| ProgramInput() = default; | |
| ProgramInput(const sh::ShaderVariable &var); | |
| GLenum getType() const { return pod.type; } | |
| bool isBuiltIn() const { return pod.flagBits.isBuiltIn; } | |
| bool isArray() const { return pod.flagBits.isArray; } | |
| bool isActive() const { return pod.flagBits.active; } | |
| bool isPatch() const { return pod.flagBits.isPatch; } | |
| int getLocation() const { return pod.location; } | |
| unsigned int getBasicTypeElementCount() const { return pod.basicTypeElementCount; } | |
| unsigned int getArraySizeProduct() const { return pod.arraySizeProduct; } | |
| uint32_t getId() const { return pod.id; } | |
| sh::InterpolationType getInterpolation() const | |
| { | |
| return static_cast<sh::InterpolationType>(pod.interpolation); | |
| } | |
| void setLocation(int location) { pod.location = location; } | |
| void resetEffectiveLocation() | |
| { | |
| if (pod.flagBits.hasImplicitLocation) | |
| { | |
| pod.location = -1; | |
| } | |
| } | |
| std::string name; | |
| std::string mappedName; | |
| // The struct bellow must only contain data of basic type so that entire struct can memcpy-able. | |
| struct PODStruct | |
| { | |
| uint16_t type; // GLenum | |
| uint16_t arraySizeProduct; | |
| int location; | |
| uint8_t interpolation; // sh::InterpolationType | |
| union | |
| { | |
| struct | |
| { | |
| uint8_t active : 1; | |
| uint8_t isPatch : 1; | |
| uint8_t hasImplicitLocation : 1; | |
| uint8_t isArray : 1; | |
| uint8_t isBuiltIn : 1; | |
| uint8_t padding : 3; | |
| } flagBits; | |
| uint8_t flagBitsAsUByte; | |
| }; | |
| int16_t basicTypeElementCount; | |
| uint32_t id; | |
| } pod; | |
| }; | |
| ANGLE_DISABLE_STRUCT_PADDING_WARNINGS | |
| ANGLE_ENABLE_STRUCT_PADDING_WARNINGS | |
| struct ProgramOutput | |
| { | |
| ProgramOutput() = default; | |
| ProgramOutput(const sh::ShaderVariable &var); | |
| GLenum getType() const { return pod.type; } | |
| bool isBuiltIn() const { return pod.isBuiltIn; } | |
| bool isArray() const { return pod.isArray; } | |
| int getLocation() const { return pod.location; } | |
| unsigned int getOutermostArraySize() const { return pod.outermostArraySize; } | |
| unsigned int getBasicTypeElementCount() const { return pod.basicTypeElementCount; } | |
| void resetEffectiveLocation() | |
| { | |
| if (pod.hasImplicitLocation) | |
| { | |
| pod.location = -1; | |
| } | |
| } | |
| std::string name; | |
| std::string mappedName; | |
| struct PODStruct | |
| { | |
| GLenum type; | |
| int location; | |
| int index; | |
| uint32_t id; | |
| uint16_t outermostArraySize; | |
| uint16_t basicTypeElementCount; | |
| uint32_t isPatch : 1; | |
| uint32_t yuv : 1; | |
| uint32_t isBuiltIn : 1; | |
| uint32_t isArray : 1; | |
| uint32_t hasImplicitLocation : 1; | |
| uint32_t hasShaderAssignedLocation : 1; | |
| uint32_t hasApiAssignedLocation : 1; | |
| uint32_t pad : 25; | |
| } pod; | |
| }; | |
| ANGLE_DISABLE_STRUCT_PADDING_WARNINGS | |
| // A varying with transform feedback enabled. If it's an array, either the whole array or one of its | |
| // elements specified by 'arrayIndex' can set to be enabled. | |
| struct TransformFeedbackVarying : public sh::ShaderVariable | |
| { | |
| TransformFeedbackVarying() = default; | |
| TransformFeedbackVarying(const sh::ShaderVariable &varyingIn, GLuint arrayIndexIn) | |
| : sh::ShaderVariable(varyingIn), arrayIndex(arrayIndexIn) | |
| { | |
| ASSERT(!isArrayOfArrays()); | |
| } | |
| TransformFeedbackVarying(const sh::ShaderVariable &field, const sh::ShaderVariable &parent) | |
| : arrayIndex(GL_INVALID_INDEX) | |
| { | |
| sh::ShaderVariable *thisVar = this; | |
| *thisVar = field; | |
| interpolation = parent.interpolation; | |
| isInvariant = parent.isInvariant; | |
| ASSERT(parent.isShaderIOBlock || !parent.name.empty()); | |
| if (!parent.name.empty()) | |
| { | |
| name = parent.name + "." + name; | |
| mappedName = parent.mappedName + "." + mappedName; | |
| } | |
| structOrBlockName = parent.structOrBlockName; | |
| mappedStructOrBlockName = parent.mappedStructOrBlockName; | |
| } | |
| std::string nameWithArrayIndex() const | |
| { | |
| std::stringstream fullNameStr; | |
| fullNameStr << name; | |
| if (arrayIndex != GL_INVALID_INDEX) | |
| { | |
| fullNameStr << "[" << arrayIndex << "]"; | |
| } | |
| return fullNameStr.str(); | |
| } | |
| GLsizei size() const | |
| { | |
| return (isArray() && arrayIndex == GL_INVALID_INDEX ? getOutermostArraySize() : 1); | |
| } | |
| GLuint arrayIndex; | |
| }; | |
| class ProgramState; | |
| class ProgramPipelineState; | |
| class ProgramExecutable; | |
| using SharedProgramExecutable = std::shared_ptr<ProgramExecutable>; | |
| class ProgramExecutable final : public angle::Subject | |
| { | |
| public: | |
| ProgramExecutable(rx::GLImplFactory *factory, InfoLog *infoLog); | |
| ~ProgramExecutable() override; | |
| void destroy(const Context *context); | |
| ANGLE_INLINE rx::ProgramExecutableImpl *getImplementation() const { return mImplementation; } | |
| void save(gl::BinaryOutputStream *stream) const; | |
| void load(gl::BinaryInputStream *stream); | |
| InfoLog &getInfoLog() const { return *mInfoLog; } | |
| std::string getInfoLogString() const; | |
| void resetInfoLog() const { mInfoLog->reset(); } | |
| void resetLinkedShaderStages() { mPod.linkedShaderStages.reset(); } | |
| const ShaderBitSet getLinkedShaderStages() const { return mPod.linkedShaderStages; } | |
| void setLinkedShaderStages(ShaderType shaderType) | |
| { | |
| mPod.linkedShaderStages.set(shaderType); | |
| updateCanDrawWith(); | |
| } | |
| bool hasLinkedShaderStage(ShaderType shaderType) const | |
| { | |
| ASSERT(shaderType != ShaderType::InvalidEnum); | |
| return mPod.linkedShaderStages[shaderType]; | |
| } | |
| size_t getLinkedShaderStageCount() const { return mPod.linkedShaderStages.count(); } | |
| bool hasLinkedGraphicsShader() const | |
| { | |
| return mPod.linkedShaderStages.any() && | |
| mPod.linkedShaderStages != gl::ShaderBitSet{gl::ShaderType::Compute}; | |
| } | |
| bool hasLinkedTessellationShader() const | |
| { | |
| return mPod.linkedShaderStages[ShaderType::TessEvaluation]; | |
| } | |
| ShaderType getFirstLinkedShaderStageType() const; | |
| ShaderType getLastLinkedShaderStageType() const; | |
| ShaderType getLinkedTransformFeedbackStage() const | |
| { | |
| return GetLastPreFragmentStage(mPod.linkedShaderStages); | |
| } | |
| const AttributesMask &getActiveAttribLocationsMask() const | |
| { | |
| return mPod.activeAttribLocationsMask; | |
| } | |
| bool isAttribLocationActive(size_t attribLocation) const | |
| { | |
| ASSERT(attribLocation < mPod.activeAttribLocationsMask.size()); | |
| return mPod.activeAttribLocationsMask[attribLocation]; | |
| } | |
| AttributesMask getNonBuiltinAttribLocationsMask() const { return mPod.attributesMask; } | |
| unsigned int getMaxActiveAttribLocation() const { return mPod.maxActiveAttribLocation; } | |
| ComponentTypeMask getAttributesTypeMask() const { return mPod.attributesTypeMask; } | |
| AttributesMask getAttributesMask() const { return mPod.attributesMask; } | |
| const ActiveTextureMask &getActiveSamplersMask() const { return mActiveSamplersMask; } | |
| void setActiveTextureMask(ActiveTextureMask mask) { mActiveSamplersMask = mask; } | |
| SamplerFormat getSamplerFormatForTextureUnitIndex(size_t textureUnitIndex) const | |
| { | |
| return mActiveSamplerFormats[textureUnitIndex]; | |
| } | |
| const ShaderBitSet getSamplerShaderBitsForTextureUnitIndex(size_t textureUnitIndex) const | |
| { | |
| return mActiveSamplerShaderBits[textureUnitIndex]; | |
| } | |
| const ActiveTextureMask &getActiveImagesMask() const { return mActiveImagesMask; } | |
| void setActiveImagesMask(ActiveTextureMask mask) { mActiveImagesMask = mask; } | |
| const ActiveTextureArray<ShaderBitSet> &getActiveImageShaderBits() const | |
| { | |
| return mActiveImageShaderBits; | |
| } | |
| const ActiveTextureMask &getActiveYUVSamplers() const { return mActiveSamplerYUV; } | |
| const ActiveTextureArray<TextureType> &getActiveSamplerTypes() const | |
| { | |
| return mActiveSamplerTypes; | |
| } | |
| const ProgramUniformBlockMask &getActiveUniformBufferBlocks() const | |
| { | |
| return mActiveUniformBufferBlocks; | |
| } | |
| const ProgramStorageBlockMask &getActiveStorageBufferBlocks() const | |
| { | |
| return mActiveStorageBufferBlocks; | |
| } | |
| void setActive(size_t textureUnit, | |
| const SamplerBinding &samplerBinding, | |
| const gl::LinkedUniform &samplerUniform); | |
| void setInactive(size_t textureUnit); | |
| void hasSamplerTypeConflict(size_t textureUnit); | |
| void hasSamplerFormatConflict(size_t textureUnit); | |
| void updateActiveSamplers(const ProgramExecutable &executable); | |
| bool hasDefaultUniforms() const { return !getDefaultUniformRange().empty(); } | |
| bool hasTextures() const { return !getSamplerBindings().empty(); } | |
| bool hasUniformBuffers() const { return !mUniformBlocks.empty(); } | |
| bool hasStorageBuffers() const { return !mShaderStorageBlocks.empty(); } | |
| bool hasAtomicCounterBuffers() const { return !mAtomicCounterBuffers.empty(); } | |
| bool hasImages() const { return !mImageBindings.empty(); } | |
| bool hasTransformFeedbackOutput() const | |
| { | |
| return !getLinkedTransformFeedbackVaryings().empty(); | |
| } | |
| bool usesColorFramebufferFetch() const { return mPod.fragmentInoutIndices.any(); } | |
| bool usesDepthFramebufferFetch() const { return mPod.hasDepthInputAttachment; } | |
| bool usesStencilFramebufferFetch() const { return mPod.hasStencilInputAttachment; } | |
| // Count the number of uniform and storage buffer declarations, counting arrays as one. | |
| size_t getTransformFeedbackBufferCount() const { return mTransformFeedbackStrides.size(); } | |
| void updateCanDrawWith() { mPod.canDrawWith = hasLinkedShaderStage(ShaderType::Vertex); } | |
| bool hasVertexShader() const { return mPod.canDrawWith; } | |
| const std::vector<ProgramInput> &getProgramInputs() const { return mProgramInputs; } | |
| const std::vector<ProgramOutput> &getOutputVariables() const { return mOutputVariables; } | |
| const std::vector<VariableLocation> &getOutputLocations() const { return mOutputLocations; } | |
| const std::vector<VariableLocation> &getSecondaryOutputLocations() const | |
| { | |
| return mSecondaryOutputLocations; | |
| } | |
| const std::vector<LinkedUniform> &getUniforms() const { return mUniforms; } | |
| const std::vector<std::string> &getUniformNames() const { return mUniformNames; } | |
| const std::vector<std::string> &getUniformMappedNames() const { return mUniformMappedNames; } | |
| const std::vector<InterfaceBlock> &getUniformBlocks() const { return mUniformBlocks; } | |
| const std::vector<VariableLocation> &getUniformLocations() const { return mUniformLocations; } | |
| const std::vector<SamplerBinding> &getSamplerBindings() const { return mSamplerBindings; } | |
| const std::vector<GLuint> &getSamplerBoundTextureUnits() const | |
| { | |
| return mSamplerBoundTextureUnits; | |
| } | |
| const std::vector<ImageBinding> &getImageBindings() const { return mImageBindings; } | |
| const std::vector<ShPixelLocalStorageFormat> &getPixelLocalStorageFormats() const | |
| { | |
| return mPixelLocalStorageFormats; | |
| } | |
| std::vector<ImageBinding> *getImageBindings() { return &mImageBindings; } | |
| const RangeUI &getDefaultUniformRange() const { return mPod.defaultUniformRange; } | |
| const RangeUI &getSamplerUniformRange() const { return mPod.samplerUniformRange; } | |
| const RangeUI &getImageUniformRange() const { return mPod.imageUniformRange; } | |
| const RangeUI &getAtomicCounterUniformRange() const { return mPod.atomicCounterUniformRange; } | |
| DrawBufferMask getFragmentInoutIndices() const { return mPod.fragmentInoutIndices; } | |
| bool hasClipDistance() const { return mPod.hasClipDistance; } | |
| bool hasDiscard() const { return mPod.hasDiscard; } | |
| bool hasDepthInputAttachment() const { return mPod.hasDepthInputAttachment; } | |
| bool hasStencilInputAttachment() const { return mPod.hasStencilInputAttachment; } | |
| bool enablesPerSampleShading() const { return mPod.enablesPerSampleShading; } | |
| BlendEquationBitSet getAdvancedBlendEquations() const { return mPod.advancedBlendEquations; } | |
| const std::vector<TransformFeedbackVarying> &getLinkedTransformFeedbackVaryings() const | |
| { | |
| return mLinkedTransformFeedbackVaryings; | |
| } | |
| GLint getTransformFeedbackBufferMode() const { return mPod.transformFeedbackBufferMode; } | |
| const sh::WorkGroupSize &getComputeShaderLocalSize() const | |
| { | |
| return mPod.computeShaderLocalSize; | |
| } | |
| void remapUniformBlockBinding(UniformBlockIndex uniformBlockIndex, GLuint uniformBlockBinding); | |
| GLuint getUniformBlockBinding(size_t uniformBlockIndex) const | |
| { | |
| ASSERT(uniformBlockIndex < mUniformBlocks.size()); | |
| // Unlike SSBOs and atomic counter buffers, GLES allows UBOs bindings to be remapped. Note | |
| // that desktop GL allows SSBO bindings to also be remapped, but that's not allowed in GLES. | |
| // | |
| // It's therefore important to never directly reference block.pod.inShaderBinding unless the | |
| // specific shader-specified binding is required. | |
| return mUniformBlockIndexToBufferBinding[uniformBlockIndex]; | |
| } | |
| GLuint getShaderStorageBlockBinding(size_t blockIndex) const | |
| { | |
| ASSERT(blockIndex < mShaderStorageBlocks.size()); | |
| // The buffer binding for SSBOs is the one specified in the shader | |
| return mShaderStorageBlocks[blockIndex].pod.inShaderBinding; | |
| } | |
| GLuint getAtomicCounterBufferBinding(size_t blockIndex) const | |
| { | |
| ASSERT(blockIndex < mAtomicCounterBuffers.size()); | |
| // The buffer binding for atomic counter buffers is the one specified in the shader | |
| return mAtomicCounterBuffers[blockIndex].pod.inShaderBinding; | |
| } | |
| const InterfaceBlock &getUniformBlockByIndex(size_t index) const | |
| { | |
| ASSERT(index < mUniformBlocks.size()); | |
| return mUniformBlocks[index]; | |
| } | |
| const InterfaceBlock &getShaderStorageBlockByIndex(size_t index) const | |
| { | |
| ASSERT(index < mShaderStorageBlocks.size()); | |
| return mShaderStorageBlocks[index]; | |
| } | |
| const BufferVariable &getBufferVariableByIndex(size_t index) const | |
| { | |
| ASSERT(index < mBufferVariables.size()); | |
| return mBufferVariables[index]; | |
| } | |
| const std::vector<GLsizei> &getTransformFeedbackStrides() const | |
| { | |
| return mTransformFeedbackStrides; | |
| } | |
| const std::vector<AtomicCounterBuffer> &getAtomicCounterBuffers() const | |
| { | |
| return mAtomicCounterBuffers; | |
| } | |
| const std::vector<InterfaceBlock> &getShaderStorageBlocks() const | |
| { | |
| return mShaderStorageBlocks; | |
| } | |
| const std::vector<BufferVariable> &getBufferVariables() const { return mBufferVariables; } | |
| const LinkedUniform &getUniformByIndex(size_t index) const | |
| { | |
| ASSERT(index < static_cast<size_t>(mUniforms.size())); | |
| return mUniforms[index]; | |
| } | |
| const std::string &getUniformNameByIndex(size_t index) const | |
| { | |
| ASSERT(index < static_cast<size_t>(mUniforms.size())); | |
| return mUniformNames[index]; | |
| } | |
| GLuint getUniformIndexFromImageIndex(size_t imageIndex) const | |
| { | |
| ASSERT(imageIndex < mPod.imageUniformRange.length()); | |
| return static_cast<GLuint>(imageIndex) + mPod.imageUniformRange.low(); | |
| } | |
| GLuint getUniformIndexFromSamplerIndex(size_t samplerIndex) const | |
| { | |
| ASSERT(samplerIndex < mPod.samplerUniformRange.length()); | |
| return static_cast<GLuint>(samplerIndex) + mPod.samplerUniformRange.low(); | |
| } | |
| void saveLinkedStateInfo(const ProgramState &state); | |
| const std::vector<sh::ShaderVariable> &getLinkedOutputVaryings(ShaderType shaderType) const | |
| { | |
| return mLinkedOutputVaryings[shaderType]; | |
| } | |
| const std::vector<sh::ShaderVariable> &getLinkedInputVaryings(ShaderType shaderType) const | |
| { | |
| return mLinkedInputVaryings[shaderType]; | |
| } | |
| const std::vector<sh::ShaderVariable> &getLinkedUniforms(ShaderType shaderType) const | |
| { | |
| return mLinkedUniforms[shaderType]; | |
| } | |
| const std::vector<sh::InterfaceBlock> &getLinkedUniformBlocks(ShaderType shaderType) const | |
| { | |
| return mLinkedUniformBlocks[shaderType]; | |
| } | |
| int getLinkedShaderVersion(ShaderType shaderType) const | |
| { | |
| return mPod.linkedShaderVersions[shaderType]; | |
| } | |
| bool isYUVOutput() const { return mPod.hasYUVOutput; } | |
| PrimitiveMode getGeometryShaderInputPrimitiveType() const | |
| { | |
| return mPod.geometryShaderInputPrimitiveType; | |
| } | |
| PrimitiveMode getGeometryShaderOutputPrimitiveType() const | |
| { | |
| return mPod.geometryShaderOutputPrimitiveType; | |
| } | |
| int getGeometryShaderInvocations() const { return mPod.geometryShaderInvocations; } | |
| int getGeometryShaderMaxVertices() const { return mPod.geometryShaderMaxVertices; } | |
| GLint getTessControlShaderVertices() const { return mPod.tessControlShaderVertices; } | |
| GLenum getTessGenMode() const { return mPod.tessGenMode; } | |
| GLenum getTessGenPointMode() const { return mPod.tessGenPointMode; } | |
| GLenum getTessGenSpacing() const { return mPod.tessGenSpacing; } | |
| GLenum getTessGenVertexOrder() const { return mPod.tessGenVertexOrder; } | |
| int getNumViews() const { return mPod.numViews; } | |
| bool usesMultiview() const { return mPod.numViews != -1; } | |
| rx::SpecConstUsageBits getSpecConstUsageBits() const { return mPod.specConstUsageBits; } | |
| int getDrawIDLocation() const { return mPod.drawIDLocation; } | |
| int getBaseVertexLocation() const { return mPod.baseVertexLocation; } | |
| int getBaseInstanceLocation() const { return mPod.baseInstanceLocation; } | |
| bool hasDrawIDUniform() const { return getDrawIDLocation() >= 0; } | |
| bool hasBaseVertexUniform() const { return getBaseVertexLocation() >= 0; } | |
| bool hasBaseInstanceUniform() const { return getBaseInstanceLocation() >= 0; } | |
| void resetCachedValidateSamplersResult() { mCachedValidateSamplersResult.reset(); } | |
| bool validateSamplers(const Caps &caps) const | |
| { | |
| // Use the cache if: | |
| // - we aren't using an info log (which gives the full error). | |
| // - The sample mapping hasn't changed and we've already validated. | |
| if (mCachedValidateSamplersResult.valid()) | |
| { | |
| return mCachedValidateSamplersResult.value(); | |
| } | |
| return validateSamplersImpl(caps); | |
| } | |
| ComponentTypeMask getFragmentOutputsTypeMask() const { return mPod.drawBufferTypeMask; } | |
| DrawBufferMask getActiveOutputVariablesMask() const { return mPod.activeOutputVariablesMask; } | |
| DrawBufferMask getActiveSecondaryOutputVariablesMask() const | |
| { | |
| return mPod.activeSecondaryOutputVariablesMask; | |
| } | |
| GLuint getInputResourceIndex(const GLchar *name) const; | |
| GLuint getOutputResourceIndex(const GLchar *name) const; | |
| void getInputResourceName(GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name) const; | |
| void getOutputResourceName(GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name) const; | |
| void getUniformResourceName(GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name) const; | |
| void getBufferVariableResourceName(GLuint index, | |
| GLsizei bufSize, | |
| GLsizei *length, | |
| GLchar *name) const; | |
| const ProgramInput &getInputResource(size_t index) const | |
| { | |
| ASSERT(index < mProgramInputs.size()); | |
| return mProgramInputs[index]; | |
| } | |
| GLuint getInputResourceMaxNameSize() const; | |
| GLuint getOutputResourceMaxNameSize() const; | |
| GLuint getInputResourceLocation(const GLchar *name) const; | |
| GLuint getOutputResourceLocation(const GLchar *name) const; | |
| const std::string getInputResourceName(GLuint index) const; | |
| const std::string getOutputResourceName(GLuint index) const; | |
| const gl::ProgramOutput &getOutputResource(size_t index) const | |
| { | |
| ASSERT(index < mOutputVariables.size()); | |
| return mOutputVariables[index]; | |
| } | |
| GLint getFragDataLocation(const std::string &name) const; | |
| // EXT_blend_func_extended | |
| GLint getFragDataIndex(const std::string &name) const; | |
| GLsizei getTransformFeedbackVaryingMaxLength() const; | |
| GLuint getTransformFeedbackVaryingResourceIndex(const GLchar *name) const; | |
| const TransformFeedbackVarying &getTransformFeedbackVaryingResource(GLuint index) const; | |
| void getTransformFeedbackVarying(GLuint index, | |
| GLsizei bufSize, | |
| GLsizei *length, | |
| GLsizei *size, | |
| GLenum *type, | |
| GLchar *name) const; | |
| void getActiveAttribute(GLuint index, | |
| GLsizei bufsize, | |
| GLsizei *length, | |
| GLint *size, | |
| GLenum *type, | |
| GLchar *name) const; | |
| GLint getActiveAttributeMaxLength() const; | |
| GLuint getAttributeLocation(const std::string &name) const; | |
| void getActiveUniform(GLuint index, | |
| GLsizei bufsize, | |
| GLsizei *length, | |
| GLint *size, | |
| GLenum *type, | |
| GLchar *name) const; | |
| GLint getActiveUniformMaxLength() const; | |
| bool isValidUniformLocation(UniformLocation location) const; | |
| const LinkedUniform &getUniformByLocation(UniformLocation location) const; | |
| const VariableLocation &getUniformLocation(UniformLocation location) const; | |
| UniformLocation getUniformLocation(const std::string &name) const; | |
| GLuint getUniformIndex(const std::string &name) const; | |
| void getActiveUniformBlockName(const Context *context, | |
| const UniformBlockIndex blockIndex, | |
| GLsizei bufSize, | |
| GLsizei *length, | |
| GLchar *blockName) const; | |
| void getActiveShaderStorageBlockName(const GLuint blockIndex, | |
| GLsizei bufSize, | |
| GLsizei *length, | |
| GLchar *blockName) const; | |
| GLint getActiveUniformBlockMaxNameLength() const; | |
| GLint getActiveShaderStorageBlockMaxNameLength() const; | |
| GLuint getUniformBlockIndex(const std::string &name) const; | |
| GLuint getShaderStorageBlockIndex(const std::string &name) const; | |
| GLuint getUniformIndexFromName(const std::string &name) const; | |
| GLuint getUniformIndexFromLocation(UniformLocation location) const; | |
| Optional<GLuint> getSamplerIndex(UniformLocation location) const; | |
| bool isSamplerUniformIndex(GLuint index) const; | |
| GLuint getSamplerIndexFromUniformIndex(GLuint uniformIndex) const; | |
| bool isImageUniformIndex(GLuint index) const; | |
| GLuint getImageIndexFromUniformIndex(GLuint uniformIndex) const; | |
| GLuint getBufferVariableIndexFromName(const std::string &name) const; | |
| bool linkUniforms(const Caps &caps, | |
| const ShaderMap<std::vector<sh::ShaderVariable>> &shaderUniforms, | |
| const ProgramAliasedBindings &uniformLocationBindings, | |
| GLuint *combinedImageUniformsCount, | |
| std::vector<UnusedUniform> *unusedUniforms); | |
| void copyInputsFromProgram(const ProgramExecutable &executable); | |
| void copyUniformBuffersFromProgram(const ProgramExecutable &executable, | |
| ShaderType shaderType, | |
| ProgramUniformBlockArray<GLuint> *ppoUniformBlockMap); | |
| void copyStorageBuffersFromProgram(const ProgramExecutable &executable, ShaderType shaderType); | |
| void clearSamplerBindings(); | |
| void copySamplerBindingsFromProgram(const ProgramExecutable &executable); | |
| void copyImageBindingsFromProgram(const ProgramExecutable &executable); | |
| void copyOutputsFromProgram(const ProgramExecutable &executable); | |
| void copyUniformsFromProgramMap(const ShaderMap<SharedProgramExecutable> &executables); | |
| void setUniform1fv(UniformLocation location, GLsizei count, const GLfloat *v); | |
| void setUniform2fv(UniformLocation location, GLsizei count, const GLfloat *v); | |
| void setUniform3fv(UniformLocation location, GLsizei count, const GLfloat *v); | |
| void setUniform4fv(UniformLocation location, GLsizei count, const GLfloat *v); | |
| void setUniform1iv(Context *context, UniformLocation location, GLsizei count, const GLint *v); | |
| void setUniform2iv(UniformLocation location, GLsizei count, const GLint *v); | |
| void setUniform3iv(UniformLocation location, GLsizei count, const GLint *v); | |
| void setUniform4iv(UniformLocation location, GLsizei count, const GLint *v); | |
| void setUniform1uiv(UniformLocation location, GLsizei count, const GLuint *v); | |
| void setUniform2uiv(UniformLocation location, GLsizei count, const GLuint *v); | |
| void setUniform3uiv(UniformLocation location, GLsizei count, const GLuint *v); | |
| void setUniform4uiv(UniformLocation location, GLsizei count, const GLuint *v); | |
| void setUniformMatrix2fv(UniformLocation location, | |
| GLsizei count, | |
| GLboolean transpose, | |
| const GLfloat *value); | |
| void setUniformMatrix3fv(UniformLocation location, | |
| GLsizei count, | |
| GLboolean transpose, | |
| const GLfloat *value); | |
| void setUniformMatrix4fv(UniformLocation location, | |
| GLsizei count, | |
| GLboolean transpose, | |
| const GLfloat *value); | |
| void setUniformMatrix2x3fv(UniformLocation location, | |
| GLsizei count, | |
| GLboolean transpose, | |
| const GLfloat *value); | |
| void setUniformMatrix3x2fv(UniformLocation location, | |
| GLsizei count, | |
| GLboolean transpose, | |
| const GLfloat *value); | |
| void setUniformMatrix2x4fv(UniformLocation location, | |
| GLsizei count, | |
| GLboolean transpose, | |
| const GLfloat *value); | |
| void setUniformMatrix4x2fv(UniformLocation location, | |
| GLsizei count, | |
| GLboolean transpose, | |
| const GLfloat *value); | |
| void setUniformMatrix3x4fv(UniformLocation location, | |
| GLsizei count, | |
| GLboolean transpose, | |
| const GLfloat *value); | |
| void setUniformMatrix4x3fv(UniformLocation location, | |
| GLsizei count, | |
| GLboolean transpose, | |
| const GLfloat *value); | |
| void getUniformfv(const Context *context, UniformLocation location, GLfloat *params) const; | |
| void getUniformiv(const Context *context, UniformLocation location, GLint *params) const; | |
| void getUniformuiv(const Context *context, UniformLocation location, GLuint *params) const; | |
| void setDrawIDUniform(GLint drawid); | |
| void setBaseVertexUniform(GLint baseVertex); | |
| void setBaseInstanceUniform(GLuint baseInstance); | |
| ProgramUniformBlockMask getUniformBufferBlocksMappedToBinding(size_t uniformBufferIndex) | |
| { | |
| return mUniformBufferBindingToUniformBlocks[uniformBufferIndex]; | |
| } | |
| const ProgramUniformBlockArray<GLuint> &getUniformBlockIndexToBufferBindingForCapture() const | |
| { | |
| return mUniformBlockIndexToBufferBinding; | |
| } | |
| const ShaderMap<SharedProgramExecutable> &getPPOProgramExecutables() const | |
| { | |
| return mPPOProgramExecutables; | |
| } | |
| bool IsPPO() const { return mIsPPO; } | |
| // Post-link task helpers | |
| const std::vector<std::shared_ptr<rx::LinkSubTask>> &getPostLinkSubTasks() const | |
| { | |
| return mPostLinkSubTasks; | |
| } | |
| const std::vector<std::shared_ptr<angle::WaitableEvent>> &getPostLinkSubTaskWaitableEvents() | |
| const | |
| { | |
| return mPostLinkSubTaskWaitableEvents; | |
| } | |
| void onPostLinkTasksComplete() const | |
| { | |
| mPostLinkSubTasks.clear(); | |
| mPostLinkSubTaskWaitableEvents.clear(); | |
| } | |
| void waitForPostLinkTasks(const Context *context); | |
| void updateActiveUniformBufferBlocks(); | |
| void updateActiveStorageBufferBlocks(); | |
| private: | |
| friend class Program; | |
| friend class ProgramPipeline; | |
| friend class ProgramState; | |
| friend class ProgramPipelineState; | |
| void reset(); | |
| void updateActiveImages(const ProgramExecutable &executable); | |
| bool linkMergedVaryings(const Caps &caps, | |
| const Limitations &limitations, | |
| const Version &clientVersion, | |
| bool webglCompatibility, | |
| const ProgramMergedVaryings &mergedVaryings, | |
| const LinkingVariables &linkingVariables, | |
| ProgramVaryingPacking *varyingPacking); | |
| bool linkValidateTransformFeedback(const Caps &caps, | |
| const Version &clientVersion, | |
| const ProgramMergedVaryings &varyings, | |
| ShaderType stage); | |
| void gatherTransformFeedbackVaryings(const ProgramMergedVaryings &varyings, ShaderType stage); | |
| void updateTransformFeedbackStrides(); | |
| bool validateSamplersImpl(const Caps &caps) const; | |
| bool linkValidateOutputVariables(const Caps &caps, | |
| const Version &version, | |
| GLuint combinedImageUniformsCount, | |
| GLuint combinedShaderStorageBlocksCount, | |
| int fragmentShaderVersion, | |
| const ProgramAliasedBindings &fragmentOutputLocations, | |
| const ProgramAliasedBindings &fragmentOutputIndices); | |
| bool gatherOutputTypes(); | |
| void linkSamplerAndImageBindings(GLuint *combinedImageUniformsCount); | |
| bool linkAtomicCounterBuffers(const Caps &caps); | |
| void getResourceName(const std::string name, | |
| GLsizei bufSize, | |
| GLsizei *length, | |
| GLchar *dest) const; | |
| bool shouldIgnoreUniform(UniformLocation location) const; | |
| GLuint getSamplerUniformBinding(const VariableLocation &uniformLocation) const; | |
| GLuint getImageUniformBinding(const VariableLocation &uniformLocation) const; | |
| void initInterfaceBlockBindings(); | |
| void setUniformValuesFromBindingQualifiers(); | |
| // Both these function update the cached uniform values and return a modified "count" | |
| // so that the uniform update doesn't overflow the uniform. | |
| template <typename T> | |
| GLsizei clampUniformCount(const VariableLocation &locationInfo, | |
| GLsizei count, | |
| int vectorSize, | |
| const T *v); | |
| template <size_t cols, size_t rows, typename T> | |
| GLsizei clampMatrixUniformCount(UniformLocation location, | |
| GLsizei count, | |
| GLboolean transpose, | |
| const T *v); | |
| void updateSamplerUniform(Context *context, | |
| const VariableLocation &locationInfo, | |
| GLsizei clampedCount, | |
| const GLint *v); | |
| // Scans the sampler bindings for type conflicts with sampler 'textureUnitIndex'. | |
| void setSamplerUniformTextureTypeAndFormat(size_t textureUnitIndex); | |
| template <typename DestT> | |
| void getUniformInternal(const Context *context, | |
| DestT *dataOut, | |
| UniformLocation location, | |
| GLenum nativeType, | |
| int components) const; | |
| template <typename UniformT, | |
| GLint UniformSize, | |
| void (rx::ProgramExecutableImpl::*SetUniformFunc)(GLint, GLsizei, const UniformT *)> | |
| void setUniformGeneric(UniformLocation location, GLsizei count, const UniformT *v); | |
| template <typename UniformT, | |
| GLint MatrixC, | |
| GLint MatrixR, | |
| void (rx::ProgramExecutableImpl::* | |
| SetUniformMatrixFunc)(GLint, GLsizei, GLboolean, const UniformT *)> | |
| void setUniformMatrixGeneric(UniformLocation location, | |
| GLsizei count, | |
| GLboolean transpose, | |
| const UniformT *v); | |
| rx::ProgramExecutableImpl *mImplementation; | |
| // A reference to the owning object's (Program or ProgramPipeline) info log. It's kept here for | |
| // convenience as numerous functions reference it. | |
| InfoLog *mInfoLog; | |
| ANGLE_ENABLE_STRUCT_PADDING_WARNINGS | |
| struct PODStruct | |
| { | |
| // 8 bytes each | |
| angle::BitSet<MAX_VERTEX_ATTRIBS> activeAttribLocationsMask; | |
| ComponentTypeMask attributesTypeMask; | |
| // attributesMask is identical to mActiveAttribLocationsMask with built-in attributes | |
| // removed. | |
| AttributesMask attributesMask; | |
| ComponentTypeMask drawBufferTypeMask; | |
| // 4 bytes each | |
| uint32_t maxActiveAttribLocation; | |
| // KHR_blend_equation_advanced supported equation list | |
| BlendEquationBitSet advancedBlendEquations; | |
| // 1 byte each | |
| ShaderBitSet linkedShaderStages; | |
| DrawBufferMask activeOutputVariablesMask; | |
| DrawBufferMask activeSecondaryOutputVariablesMask; | |
| uint8_t hasClipDistance : 1; | |
| uint8_t hasDiscard : 1; | |
| uint8_t hasYUVOutput : 1; | |
| uint8_t hasDepthInputAttachment : 1; | |
| uint8_t hasStencilInputAttachment : 1; | |
| uint8_t enablesPerSampleShading : 1; | |
| uint8_t canDrawWith : 1; | |
| uint8_t isSeparable : 1; | |
| // 12 bytes | |
| sh::WorkGroupSize computeShaderLocalSize; | |
| // 8 bytes each | |
| RangeUI defaultUniformRange; | |
| RangeUI samplerUniformRange; | |
| RangeUI imageUniformRange; | |
| RangeUI atomicCounterUniformRange; | |
| // 1 byte. Bitset of which input attachments have been declared | |
| DrawBufferMask fragmentInoutIndices; | |
| // GL_EXT_geometry_shader. | |
| uint8_t pad0; | |
| PrimitiveMode geometryShaderInputPrimitiveType; | |
| PrimitiveMode geometryShaderOutputPrimitiveType; | |
| int32_t geometryShaderInvocations; | |
| int32_t geometryShaderMaxVertices; | |
| GLenum transformFeedbackBufferMode; | |
| // GL_OVR_multiview | |
| int32_t numViews; | |
| // GL_ANGLE_multi_draw | |
| int32_t drawIDLocation; | |
| // GL_ANGLE_base_vertex_base_instance_shader_builtin | |
| int32_t baseVertexLocation; | |
| int32_t baseInstanceLocation; | |
| // GL_EXT_tessellation_shader | |
| int32_t tessControlShaderVertices; | |
| GLenum tessGenMode; | |
| GLenum tessGenSpacing; | |
| GLenum tessGenVertexOrder; | |
| GLenum tessGenPointMode; | |
| // 4 bytes | |
| rx::SpecConstUsageBits specConstUsageBits; | |
| // 24 bytes | |
| ShaderMap<int> linkedShaderVersions; | |
| } mPod; | |
| ANGLE_DISABLE_STRUCT_PADDING_WARNINGS | |
| // Cached mask of active samplers and sampler types. | |
| ActiveTextureMask mActiveSamplersMask; | |
| ActiveTextureArray<uint32_t> mActiveSamplerRefCounts; | |
| ActiveTextureArray<TextureType> mActiveSamplerTypes; | |
| ActiveTextureMask mActiveSamplerYUV; | |
| ActiveTextureArray<SamplerFormat> mActiveSamplerFormats; | |
| ActiveTextureArray<ShaderBitSet> mActiveSamplerShaderBits; | |
| // Cached mask of active images. | |
| ActiveTextureMask mActiveImagesMask; | |
| ActiveTextureArray<ShaderBitSet> mActiveImageShaderBits; | |
| // Cached mask of active uniform and storage buffer blocks | |
| ProgramUniformBlockMask mActiveUniformBufferBlocks; | |
| ProgramStorageBlockMask mActiveStorageBufferBlocks; | |
| // Names and mapped names of output variables that are arrays include [0] in the end, similarly | |
| // to uniforms. | |
| std::vector<ProgramOutput> mOutputVariables; | |
| std::vector<VariableLocation> mOutputLocations; | |
| // EXT_blend_func_extended secondary outputs (ones with index 1) | |
| std::vector<VariableLocation> mSecondaryOutputLocations; | |
| // Vertex attributes, Fragment input varyings, etc. | |
| std::vector<ProgramInput> mProgramInputs; | |
| std::vector<TransformFeedbackVarying> mLinkedTransformFeedbackVaryings; | |
| // Duplicate of ProgramState::mTransformFeedbackVaryingNames. This is cached here because the | |
| // xfb names may change, relink may fail, yet program pipeline link should be able to function | |
| // with the last installed executable. In truth, program pipeline link should have been able to | |
| // hoist transform feedback varyings directly from the executable, among most other things, but | |
| // that is currently not done. | |
| // | |
| // This array is not serialized, it's already done by the program, and will be duplicated during | |
| // deserialization. | |
| std::vector<std::string> mTransformFeedbackVaryingNames; | |
| // The size of the data written to each transform feedback buffer per vertex. | |
| std::vector<GLsizei> mTransformFeedbackStrides; | |
| // Uniforms are sorted in order: | |
| // 1. Non-opaque uniforms | |
| // 2. Sampler uniforms | |
| // 3. Image uniforms | |
| // 4. Atomic counter uniforms | |
| // 5. Uniform block uniforms | |
| // This makes opaque uniform validation easier, since we don't need a separate list. | |
| // For generating the entries and naming them we follow the spec: GLES 3.1 November 2016 section | |
| // 7.3.1.1 Naming Active Resources. There's a separate entry for each struct member and each | |
| // inner array of an array of arrays. Names and mapped names of uniforms that are arrays include | |
| // [0] in the end. This makes implementation of queries simpler. | |
| std::vector<LinkedUniform> mUniforms; | |
| std::vector<std::string> mUniformNames; | |
| // Only used by GL and D3D backend | |
| std::vector<std::string> mUniformMappedNames; | |
| std::vector<InterfaceBlock> mUniformBlocks; | |
| std::vector<VariableLocation> mUniformLocations; | |
| std::vector<AtomicCounterBuffer> mAtomicCounterBuffers; | |
| std::vector<InterfaceBlock> mShaderStorageBlocks; | |
| std::vector<BufferVariable> mBufferVariables; | |
| // An array of the samplers that are used by the program | |
| std::vector<SamplerBinding> mSamplerBindings; | |
| // List of all textures bound to all samplers. Each SamplerBinding will point to a subset in | |
| // this vector. | |
| std::vector<GLuint> mSamplerBoundTextureUnits; | |
| // An array of the images that are used by the program | |
| std::vector<ImageBinding> mImageBindings; | |
| // ANGLE_shader_pixel_local_storage: A mapping from binding index to the PLS uniform format at | |
| // that index. | |
| std::vector<ShPixelLocalStorageFormat> mPixelLocalStorageFormats; | |
| ShaderMap<std::vector<sh::ShaderVariable>> mLinkedOutputVaryings; | |
| ShaderMap<std::vector<sh::ShaderVariable>> mLinkedInputVaryings; | |
| ShaderMap<std::vector<sh::ShaderVariable>> mLinkedUniforms; | |
| ShaderMap<std::vector<sh::InterfaceBlock>> mLinkedUniformBlocks; | |
| // Cached value of base vertex and base instance | |
| // need to reset them to zero if using non base vertex or base instance draw calls. | |
| GLint mCachedBaseVertex; | |
| GLuint mCachedBaseInstance; | |
| // GLES allows uniform block indices in the program to be remapped to arbitrary buffer bindings | |
| // through calls to glUniformBlockBinding. (Desktop GL also includes | |
| // glShaderStorageBlockBinding, which does not exist in GLES). | |
| // This is not a part of the link results, and must be reset on glProgramBinary, so it's not | |
| // serialized. | |
| // A map from the program uniform block index to the buffer binding it is mapped to. | |
| ProgramUniformBlockArray<GLuint> mUniformBlockIndexToBufferBinding; | |
| // The reverse of the above map, i.e. from buffer bindings to the uniform blocks that are mapped | |
| // to it. For example, if the program's uniform blocks 1, 3 and 4 are mapped to buffer binding | |
| // 2, then mUniformBufferBindingToUniformBlocks[2] will be {1, 3, 4}. | |
| // | |
| // This is used to efficiently mark uniform blocks dirty when a buffer bound to a binding has | |
| // been modified. | |
| UniformBufferBindingArray<ProgramUniformBlockMask> mUniformBufferBindingToUniformBlocks; | |
| // PPO only: installed executables from the programs. Note that these may be different from the | |
| // programs' current executables, because they may have been unsuccessfully relinked. | |
| ShaderMap<SharedProgramExecutable> mPPOProgramExecutables; | |
| // Flag for an easy check for PPO without inspecting mPPOProgramExecutables | |
| bool mIsPPO; | |
| bool mBinaryRetrieveableHint; | |
| // Cache for sampler validation | |
| mutable Optional<bool> mCachedValidateSamplersResult; | |
| // Post-link subtask and wait events | |
| // These tasks are not waited on in |resolveLink|, but instead they are free to | |
| // run until first usage of the program (or relink). This is used by the backends (currently | |
| // only Vulkan) to run post-link optimization tasks which don't affect the link results. | |
| mutable std::vector<std::shared_ptr<rx::LinkSubTask>> mPostLinkSubTasks; | |
| mutable std::vector<std::shared_ptr<angle::WaitableEvent>> mPostLinkSubTaskWaitableEvents; | |
| }; | |
| void InstallExecutable(const Context *context, | |
| const SharedProgramExecutable &toInstall, | |
| SharedProgramExecutable *executable); | |
| void UninstallExecutable(const Context *context, SharedProgramExecutable *executable); | |
| } // namespace gl | |
| #endif // LIBANGLE_PROGRAMEXECUTABLE_H_ |