// // 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 &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 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(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); 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; } 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; 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 &getActiveImageShaderBits() const { return mActiveImageShaderBits; } const ActiveTextureMask &getActiveYUVSamplers() const { return mActiveSamplerYUV; } const ActiveTextureArray &getActiveSamplerTypes() const { return mActiveSamplerTypes; } 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 &getProgramInputs() const { return mProgramInputs; } const std::vector &getOutputVariables() const { return mOutputVariables; } const std::vector &getOutputLocations() const { return mOutputLocations; } const std::vector &getSecondaryOutputLocations() const { return mSecondaryOutputLocations; } const std::vector &getUniforms() const { return mUniforms; } const std::vector &getUniformNames() const { return mUniformNames; } const std::vector &getUniformMappedNames() const { return mUniformMappedNames; } const std::vector &getUniformBlocks() const { return mUniformBlocks; } const std::vector &getUniformLocations() const { return mUniformLocations; } const std::vector &getSamplerBindings() const { return mSamplerBindings; } const std::vector &getSamplerBoundTextureUnits() const { return mSamplerBoundTextureUnits; } const std::vector &getImageBindings() const { return mImageBindings; } const std::vector &getPixelLocalStorageFormats() const { return mPixelLocalStorageFormats; } std::vector *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 &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 &getTransformFeedbackStrides() const { return mTransformFeedbackStrides; } const std::vector &getAtomicCounterBuffers() const { return mAtomicCounterBuffers; } const std::vector &getShaderStorageBlocks() const { return mShaderStorageBlocks; } const std::vector &getBufferVariables() const { return mBufferVariables; } const LinkedUniform &getUniformByIndex(size_t index) const { ASSERT(index < static_cast(mUniforms.size())); return mUniforms[index]; } const std::string &getUniformNameByIndex(size_t index) const { ASSERT(index < static_cast(mUniforms.size())); return mUniformNames[index]; } GLuint getUniformIndexFromImageIndex(size_t imageIndex) const { ASSERT(imageIndex < mPod.imageUniformRange.length()); return static_cast(imageIndex) + mPod.imageUniformRange.low(); } GLuint getUniformIndexFromSamplerIndex(size_t samplerIndex) const { ASSERT(samplerIndex < mPod.samplerUniformRange.length()); return static_cast(samplerIndex) + mPod.samplerUniformRange.low(); } void saveLinkedStateInfo(const ProgramState &state); const std::vector &getLinkedOutputVaryings(ShaderType shaderType) const { return mLinkedOutputVaryings[shaderType]; } const std::vector &getLinkedInputVaryings(ShaderType shaderType) const { return mLinkedInputVaryings[shaderType]; } const std::vector &getLinkedUniforms(ShaderType shaderType) const { return mLinkedUniforms[shaderType]; } const std::vector &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 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> &shaderUniforms, const ProgramAliasedBindings &uniformLocationBindings, GLuint *combinedImageUniformsCount, std::vector *unusedUniforms); void copyInputsFromProgram(const ProgramExecutable &executable); void copyUniformBuffersFromProgram(const ProgramExecutable &executable, ShaderType shaderType, ProgramUniformBlockArray *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 &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 &getUniformBlockIndexToBufferBindingForCapture() const { return mUniformBlockIndexToBufferBinding; } const ShaderMap &getPPOProgramExecutables() const { return mPPOProgramExecutables; } bool IsPPO() const { return mIsPPO; } // Post-link task helpers const std::vector> &getPostLinkSubTasks() const { return mPostLinkSubTasks; } const std::vector> &getPostLinkSubTaskWaitableEvents() const { return mPostLinkSubTaskWaitableEvents; } void onPostLinkTasksComplete() const { mPostLinkSubTasks.clear(); mPostLinkSubTaskWaitableEvents.clear(); } void waitForPostLinkTasks(const Context *context); 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 GLsizei clampUniformCount(const VariableLocation &locationInfo, GLsizei count, int vectorSize, const T *v); template 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 void getUniformInternal(const Context *context, DestT *dataOut, UniformLocation location, GLenum nativeType, int components) const; template void setUniformGeneric(UniformLocation location, GLsizei count, const UniformT *v); template 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 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; // 4 bytes each. GL_OVR_multiview / GL_OVR_multiview2 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 linkedShaderVersions; } mPod; ANGLE_DISABLE_STRUCT_PADDING_WARNINGS // Cached mask of active samplers and sampler types. ActiveTextureMask mActiveSamplersMask; ActiveTextureArray mActiveSamplerRefCounts; ActiveTextureArray mActiveSamplerTypes; ActiveTextureMask mActiveSamplerYUV; ActiveTextureArray mActiveSamplerFormats; ActiveTextureArray mActiveSamplerShaderBits; // Cached mask of active images. ActiveTextureMask mActiveImagesMask; ActiveTextureArray mActiveImageShaderBits; // Names and mapped names of output variables that are arrays include [0] in the end, similarly // to uniforms. std::vector mOutputVariables; std::vector mOutputLocations; // EXT_blend_func_extended secondary outputs (ones with index 1) std::vector mSecondaryOutputLocations; // Vertex attributes, Fragment input varyings, etc. std::vector mProgramInputs; std::vector 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 mTransformFeedbackVaryingNames; // The size of the data written to each transform feedback buffer per vertex. std::vector 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 mUniforms; std::vector mUniformNames; // Only used by GL and D3D backend std::vector mUniformMappedNames; std::vector mUniformBlocks; std::vector mUniformLocations; std::vector mAtomicCounterBuffers; std::vector mShaderStorageBlocks; std::vector mBufferVariables; // An array of the samplers that are used by the program std::vector mSamplerBindings; // List of all textures bound to all samplers. Each SamplerBinding will point to a subset in // this vector. std::vector mSamplerBoundTextureUnits; // An array of the images that are used by the program std::vector mImageBindings; // ANGLE_shader_pixel_local_storage: A mapping from binding index to the PLS uniform format at // that index. std::vector mPixelLocalStorageFormats; ShaderMap> mLinkedOutputVaryings; ShaderMap> mLinkedInputVaryings; ShaderMap> mLinkedUniforms; ShaderMap> 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 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 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 mPPOProgramExecutables; // Flag for an easy check for PPO without inspecting mPPOProgramExecutables bool mIsPPO; // Cache for sampler validation mutable Optional 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> mPostLinkSubTasks; mutable std::vector> mPostLinkSubTaskWaitableEvents; }; void InstallExecutable(const Context *context, const SharedProgramExecutable &toInstall, SharedProgramExecutable *executable); void UninstallExecutable(const Context *context, SharedProgramExecutable *executable); } // namespace gl #endif // LIBANGLE_PROGRAMEXECUTABLE_H_