diff options
Diffstat (limited to '')
-rw-r--r-- | gfx/angle/checkout/src/libANGLE/Shader.cpp | 1331 |
1 files changed, 1331 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/libANGLE/Shader.cpp b/gfx/angle/checkout/src/libANGLE/Shader.cpp new file mode 100644 index 0000000000..b1a718131a --- /dev/null +++ b/gfx/angle/checkout/src/libANGLE/Shader.cpp @@ -0,0 +1,1331 @@ +// +// Copyright 2002 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. +// + +// Shader.cpp: Implements the gl::Shader class and its derived classes +// VertexShader and FragmentShader. Implements GL shader objects and related +// functionality. [OpenGL ES 2.0.24] section 2.10 page 24 and section 3.8 page 84. + +#include "libANGLE/Shader.h" + +#include <functional> +#include <sstream> + +#include "GLSLANG/ShaderLang.h" +#include "common/utilities.h" +#include "libANGLE/Caps.h" +#include "libANGLE/Compiler.h" +#include "libANGLE/Constants.h" +#include "libANGLE/Context.h" +#include "libANGLE/Display.h" +#include "libANGLE/MemoryShaderCache.h" +#include "libANGLE/Program.h" +#include "libANGLE/ResourceManager.h" +#include "libANGLE/renderer/GLImplFactory.h" +#include "libANGLE/renderer/ShaderImpl.h" +#include "platform/FrontendFeatures_autogen.h" + +namespace gl +{ + +namespace +{ +constexpr uint32_t kShaderCacheIdentifier = 0x12345678; + +template <typename VarT> +std::vector<VarT> GetActiveShaderVariables(const std::vector<VarT> *variableList) +{ + ASSERT(variableList); + std::vector<VarT> result; + for (size_t varIndex = 0; varIndex < variableList->size(); varIndex++) + { + const VarT &var = variableList->at(varIndex); + if (var.active) + { + result.push_back(var); + } + } + return result; +} + +template <typename VarT> +const std::vector<VarT> &GetShaderVariables(const std::vector<VarT> *variableList) +{ + ASSERT(variableList); + return *variableList; +} + +void WriteInterfaceBlock(gl::BinaryOutputStream *stream, const sh::InterfaceBlock &block) +{ + stream->writeString(block.name); + stream->writeString(block.mappedName); + stream->writeString(block.instanceName); + stream->writeInt(block.arraySize); + stream->writeEnum(block.layout); + stream->writeBool(block.isRowMajorLayout); + stream->writeInt(block.binding); + stream->writeBool(block.staticUse); + stream->writeBool(block.active); + stream->writeEnum(block.blockType); + + stream->writeInt(block.fields.size()); + for (const sh::ShaderVariable &shaderVariable : block.fields) + { + WriteShaderVar(stream, shaderVariable); + } +} + +void LoadInterfaceBlock(gl::BinaryInputStream *stream, sh::InterfaceBlock &block) +{ + stream->readString(&block.name); + stream->readString(&block.mappedName); + stream->readString(&block.instanceName); + stream->readInt(&block.arraySize); + stream->readEnum(&block.layout); + stream->readBool(&block.isRowMajorLayout); + stream->readInt(&block.binding); + stream->readBool(&block.staticUse); + stream->readBool(&block.active); + stream->readEnum(&block.blockType); + + size_t size = stream->readInt<size_t>(); + block.fields.resize(size); + for (sh::ShaderVariable &shaderVariable : block.fields) + { + LoadShaderVar(stream, &shaderVariable); + } +} +} // anonymous namespace + +// true if varying x has a higher priority in packing than y +bool CompareShaderVar(const sh::ShaderVariable &x, const sh::ShaderVariable &y) +{ + if (x.type == y.type) + { + return x.getArraySizeProduct() > y.getArraySizeProduct(); + } + + // Special case for handling structs: we sort these to the end of the list + if (x.type == GL_NONE) + { + return false; + } + + if (y.type == GL_NONE) + { + return true; + } + + return gl::VariableSortOrder(x.type) < gl::VariableSortOrder(y.type); +} + +const char *GetShaderTypeString(ShaderType type) +{ + switch (type) + { + case ShaderType::Vertex: + return "VERTEX"; + + case ShaderType::Fragment: + return "FRAGMENT"; + + case ShaderType::Compute: + return "COMPUTE"; + + case ShaderType::Geometry: + return "GEOMETRY"; + + case ShaderType::TessControl: + return "TESS_CONTROL"; + + case ShaderType::TessEvaluation: + return "TESS_EVALUATION"; + + default: + UNREACHABLE(); + return ""; + } +} + +class [[nodiscard]] ScopedExit final : angle::NonCopyable +{ + public: + ScopedExit(std::function<void()> exit) : mExit(exit) {} + ~ScopedExit() { mExit(); } + + private: + std::function<void()> mExit; +}; + +struct Shader::CompilingState +{ + std::shared_ptr<rx::WaitableCompileEvent> compileEvent; + ShCompilerInstance shCompilerInstance; + egl::BlobCache::Key shaderHash; +}; + +ShaderState::ShaderState(ShaderType shaderType) + : mLabel(), + mShaderType(shaderType), + mShaderVersion(100), + mNumViews(-1), + mGeometryShaderInvocations(1), + mCompileStatus(CompileStatus::NOT_COMPILED) +{ + mLocalSize.fill(-1); +} + +ShaderState::~ShaderState() {} + +Shader::Shader(ShaderProgramManager *manager, + rx::GLImplFactory *implFactory, + const gl::Limitations &rendererLimitations, + ShaderType type, + ShaderProgramID handle) + : mState(type), + mImplementation(implFactory->createShader(mState)), + mRendererLimitations(rendererLimitations), + mHandle(handle), + mType(type), + mRefCount(0), + mDeleteStatus(false), + mResourceManager(manager), + mCurrentMaxComputeWorkGroupInvocations(0u) +{ + ASSERT(mImplementation); +} + +void Shader::onDestroy(const gl::Context *context) +{ + resolveCompile(context); + mImplementation->destroy(); + mBoundCompiler.set(context, nullptr); + mImplementation.reset(nullptr); + delete this; +} + +Shader::~Shader() +{ + ASSERT(!mImplementation); +} + +angle::Result Shader::setLabel(const Context *context, const std::string &label) +{ + mState.mLabel = label; + + if (mImplementation) + { + return mImplementation->onLabelUpdate(context); + } + return angle::Result::Continue; +} + +const std::string &Shader::getLabel() const +{ + return mState.mLabel; +} + +ShaderProgramID Shader::getHandle() const +{ + return mHandle; +} + +void Shader::setSource(GLsizei count, const char *const *string, const GLint *length) +{ + std::ostringstream stream; + + for (int i = 0; i < count; i++) + { + if (length == nullptr || length[i] < 0) + { + stream.write(string[i], strlen(string[i])); + } + else + { + stream.write(string[i], length[i]); + } + } + + mState.mSource = stream.str(); +} + +int Shader::getInfoLogLength(const Context *context) +{ + resolveCompile(context); + if (mInfoLog.empty()) + { + return 0; + } + + return (static_cast<int>(mInfoLog.length()) + 1); +} + +void Shader::getInfoLog(const Context *context, GLsizei bufSize, GLsizei *length, char *infoLog) +{ + resolveCompile(context); + + int index = 0; + + if (bufSize > 0) + { + index = std::min(bufSize - 1, static_cast<GLsizei>(mInfoLog.length())); + memcpy(infoLog, mInfoLog.c_str(), index); + + infoLog[index] = '\0'; + } + + if (length) + { + *length = index; + } +} + +int Shader::getSourceLength() const +{ + return mState.mSource.empty() ? 0 : (static_cast<int>(mState.mSource.length()) + 1); +} + +int Shader::getTranslatedSourceLength(const Context *context) +{ + resolveCompile(context); + + if (mState.mTranslatedSource.empty()) + { + return 0; + } + + return (static_cast<int>(mState.mTranslatedSource.length()) + 1); +} + +int Shader::getTranslatedSourceWithDebugInfoLength(const Context *context) +{ + resolveCompile(context); + + const std::string &debugInfo = mImplementation->getDebugInfo(); + if (debugInfo.empty()) + { + return 0; + } + + return (static_cast<int>(debugInfo.length()) + 1); +} + +// static +void Shader::GetSourceImpl(const std::string &source, + GLsizei bufSize, + GLsizei *length, + char *buffer) +{ + int index = 0; + + if (bufSize > 0) + { + index = std::min(bufSize - 1, static_cast<GLsizei>(source.length())); + memcpy(buffer, source.c_str(), index); + + buffer[index] = '\0'; + } + + if (length) + { + *length = index; + } +} + +void Shader::getSource(GLsizei bufSize, GLsizei *length, char *buffer) const +{ + GetSourceImpl(mState.mSource, bufSize, length, buffer); +} + +void Shader::getTranslatedSource(const Context *context, + GLsizei bufSize, + GLsizei *length, + char *buffer) +{ + GetSourceImpl(getTranslatedSource(context), bufSize, length, buffer); +} + +const std::string &Shader::getTranslatedSource(const Context *context) +{ + resolveCompile(context); + return mState.mTranslatedSource; +} + +const sh::BinaryBlob &Shader::getCompiledBinary(const Context *context) +{ + resolveCompile(context); + return mState.mCompiledBinary; +} + +void Shader::getTranslatedSourceWithDebugInfo(const Context *context, + GLsizei bufSize, + GLsizei *length, + char *buffer) +{ + resolveCompile(context); + const std::string &debugInfo = mImplementation->getDebugInfo(); + GetSourceImpl(debugInfo, bufSize, length, buffer); +} + +void Shader::compile(const Context *context) +{ + resolveCompile(context); + + mState.mTranslatedSource.clear(); + mState.mCompiledBinary.clear(); + mInfoLog.clear(); + mState.mShaderVersion = 100; + mState.mInputVaryings.clear(); + mState.mOutputVaryings.clear(); + mState.mUniforms.clear(); + mState.mUniformBlocks.clear(); + mState.mShaderStorageBlocks.clear(); + mState.mActiveAttributes.clear(); + mState.mActiveOutputVariables.clear(); + mState.mNumViews = -1; + mState.mGeometryShaderInputPrimitiveType.reset(); + mState.mGeometryShaderOutputPrimitiveType.reset(); + mState.mGeometryShaderMaxVertices.reset(); + mState.mGeometryShaderInvocations = 1; + mState.mTessControlShaderVertices = 0; + mState.mTessGenMode = 0; + mState.mTessGenSpacing = 0; + mState.mTessGenVertexOrder = 0; + mState.mTessGenPointMode = 0; + mState.mAdvancedBlendEquations.reset(); + mState.mHasDiscard = false; + mState.mEnablesPerSampleShading = false; + mState.mSpecConstUsageBits.reset(); + + mCurrentMaxComputeWorkGroupInvocations = + static_cast<GLuint>(context->getCaps().maxComputeWorkGroupInvocations); + mMaxComputeSharedMemory = context->getCaps().maxComputeSharedMemorySize; + + ShCompileOptions options = {}; + options.objectCode = true; + options.variables = true; + options.emulateGLDrawID = true; + + // Add default options to WebGL shaders to prevent unexpected behavior during + // compilation. + if (context->isWebGL()) + { + options.initGLPosition = true; + options.limitCallStackDepth = true; + options.limitExpressionComplexity = true; + options.enforcePackingRestrictions = true; + options.initSharedVariables = true; + } + else + { + // Per https://github.com/KhronosGroup/WebGL/pull/3278 gl_BaseVertex/gl_BaseInstance are + // removed from WebGL + options.emulateGLBaseVertexBaseInstance = true; + } + + // Some targets (e.g. D3D11 Feature Level 9_3 and below) do not support non-constant loop + // indexes in fragment shaders. Shader compilation will fail. To provide a better error + // message we can instruct the compiler to pre-validate. + if (mRendererLimitations.shadersRequireIndexedLoopValidation) + { + options.validateLoopIndexing = true; + } + + if (context->getFrontendFeatures().scalarizeVecAndMatConstructorArgs.enabled) + { + options.scalarizeVecAndMatConstructorArgs = true; + } + + if (context->getFrontendFeatures().forceInitShaderVariables.enabled) + { + options.initOutputVariables = true; + options.initializeUninitializedLocals = true; + } + + mBoundCompiler.set(context, context->getCompiler()); + + ASSERT(mBoundCompiler.get()); + ShCompilerInstance compilerInstance = mBoundCompiler->getInstance(mState.mShaderType); + ShHandle compilerHandle = compilerInstance.getHandle(); + ASSERT(compilerHandle); + mCompilerResourcesString = compilerInstance.getBuiltinResourcesString(); + + // Find a shader in Blob Cache + egl::BlobCache::Key shaderHash = {0}; + MemoryShaderCache *shaderCache = context->getMemoryShaderCache(); + if (shaderCache) + { + angle::Result cacheResult = + shaderCache->getShader(context, this, options, compilerInstance, &shaderHash); + + if (cacheResult == angle::Result::Continue) + { + compilerInstance.destroy(); + return; + } + } + + // Cache load failed, fall through normal compiling. + mState.mCompileStatus = CompileStatus::COMPILE_REQUESTED; + mCompilingState.reset(new CompilingState()); + mCompilingState->shCompilerInstance = std::move(compilerInstance); + mCompilingState->shaderHash = shaderHash; + mCompilingState->compileEvent = + mImplementation->compile(context, &(mCompilingState->shCompilerInstance), &options); +} + +void Shader::resolveCompile(const Context *context) +{ + if (!mState.compilePending()) + { + return; + } + + ASSERT(mCompilingState.get()); + + mCompilingState->compileEvent->wait(); + + mInfoLog += mCompilingState->compileEvent->getInfoLog(); + + ScopedExit exit([this]() { + mBoundCompiler->putInstance(std::move(mCompilingState->shCompilerInstance)); + mCompilingState->compileEvent.reset(); + mCompilingState.reset(); + }); + + ShHandle compilerHandle = mCompilingState->shCompilerInstance.getHandle(); + if (!mCompilingState->compileEvent->getResult()) + { + mInfoLog += sh::GetInfoLog(compilerHandle); + INFO() << std::endl << mInfoLog; + mState.mCompileStatus = CompileStatus::NOT_COMPILED; + return; + } + + const ShShaderOutput outputType = mCompilingState->shCompilerInstance.getShaderOutputType(); + const bool isBinaryOutput = + outputType == SH_SPIRV_VULKAN_OUTPUT || outputType == SH_SPIRV_METAL_OUTPUT; + + if (isBinaryOutput) + { + mState.mCompiledBinary = sh::GetObjectBinaryBlob(compilerHandle); + } + else + { + mState.mTranslatedSource = sh::GetObjectCode(compilerHandle); + +#if !defined(NDEBUG) + // Prefix translated shader with commented out un-translated shader. + // Useful in diagnostics tools which capture the shader source. + std::ostringstream shaderStream; + shaderStream << "// GLSL\n"; + shaderStream << "//\n"; + + std::istringstream inputSourceStream(mState.mSource); + std::string line; + while (std::getline(inputSourceStream, line)) + { + // Remove null characters from the source line + line.erase(std::remove(line.begin(), line.end(), '\0'), line.end()); + + shaderStream << "// " << line; + + // glslang complains if a comment ends with backslash + if (!line.empty() && line.back() == '\\') + { + shaderStream << "\\"; + } + + shaderStream << std::endl; + } + shaderStream << "\n\n"; + shaderStream << mState.mTranslatedSource; + mState.mTranslatedSource = shaderStream.str(); +#endif // !defined(NDEBUG) + } + + // Gather the shader information + mState.mShaderVersion = sh::GetShaderVersion(compilerHandle); + + mState.mUniforms = GetShaderVariables(sh::GetUniforms(compilerHandle)); + mState.mUniformBlocks = GetShaderVariables(sh::GetUniformBlocks(compilerHandle)); + mState.mShaderStorageBlocks = GetShaderVariables(sh::GetShaderStorageBlocks(compilerHandle)); + mState.mSpecConstUsageBits = + rx::SpecConstUsageBits(sh::GetShaderSpecConstUsageBits(compilerHandle)); + + switch (mState.mShaderType) + { + case ShaderType::Compute: + { + mState.mAllAttributes = GetShaderVariables(sh::GetAttributes(compilerHandle)); + mState.mActiveAttributes = GetActiveShaderVariables(&mState.mAllAttributes); + mState.mLocalSize = sh::GetComputeShaderLocalGroupSize(compilerHandle); + if (mState.mLocalSize.isDeclared()) + { + angle::CheckedNumeric<uint32_t> checked_local_size_product(mState.mLocalSize[0]); + checked_local_size_product *= mState.mLocalSize[1]; + checked_local_size_product *= mState.mLocalSize[2]; + + if (!checked_local_size_product.IsValid()) + { + WARN() << std::endl + << "Integer overflow when computing the product of local_size_x, " + << "local_size_y and local_size_z."; + mState.mCompileStatus = CompileStatus::NOT_COMPILED; + return; + } + if (checked_local_size_product.ValueOrDie() > + mCurrentMaxComputeWorkGroupInvocations) + { + WARN() << std::endl + << "The total number of invocations within a work group exceeds " + << "MAX_COMPUTE_WORK_GROUP_INVOCATIONS."; + mState.mCompileStatus = CompileStatus::NOT_COMPILED; + return; + } + } + + unsigned int sharedMemSize = sh::GetShaderSharedMemorySize(compilerHandle); + if (sharedMemSize > mMaxComputeSharedMemory) + { + WARN() << std::endl << "Exceeded maximum shared memory size"; + mState.mCompileStatus = CompileStatus::NOT_COMPILED; + return; + } + break; + } + case ShaderType::Vertex: + { + mState.mOutputVaryings = GetShaderVariables(sh::GetOutputVaryings(compilerHandle)); + mState.mAllAttributes = GetShaderVariables(sh::GetAttributes(compilerHandle)); + mState.mActiveAttributes = GetActiveShaderVariables(&mState.mAllAttributes); + mState.mNumViews = sh::GetVertexShaderNumViews(compilerHandle); + break; + } + case ShaderType::Fragment: + { + mState.mAllAttributes = GetShaderVariables(sh::GetAttributes(compilerHandle)); + mState.mActiveAttributes = GetActiveShaderVariables(&mState.mAllAttributes); + mState.mInputVaryings = GetShaderVariables(sh::GetInputVaryings(compilerHandle)); + // TODO(jmadill): Figure out why we only sort in the FS, and if we need to. + std::sort(mState.mInputVaryings.begin(), mState.mInputVaryings.end(), CompareShaderVar); + mState.mActiveOutputVariables = + GetActiveShaderVariables(sh::GetOutputVariables(compilerHandle)); + mState.mHasDiscard = sh::HasDiscardInFragmentShader(compilerHandle); + mState.mEnablesPerSampleShading = sh::EnablesPerSampleShading(compilerHandle); + mState.mAdvancedBlendEquations = + BlendEquationBitSet(sh::GetAdvancedBlendEquations(compilerHandle)); + break; + } + case ShaderType::Geometry: + { + mState.mInputVaryings = GetShaderVariables(sh::GetInputVaryings(compilerHandle)); + mState.mOutputVaryings = GetShaderVariables(sh::GetOutputVaryings(compilerHandle)); + + if (sh::HasValidGeometryShaderInputPrimitiveType(compilerHandle)) + { + mState.mGeometryShaderInputPrimitiveType = FromGLenum<PrimitiveMode>( + sh::GetGeometryShaderInputPrimitiveType(compilerHandle)); + } + if (sh::HasValidGeometryShaderOutputPrimitiveType(compilerHandle)) + { + mState.mGeometryShaderOutputPrimitiveType = FromGLenum<PrimitiveMode>( + sh::GetGeometryShaderOutputPrimitiveType(compilerHandle)); + } + if (sh::HasValidGeometryShaderMaxVertices(compilerHandle)) + { + mState.mGeometryShaderMaxVertices = + sh::GetGeometryShaderMaxVertices(compilerHandle); + } + mState.mGeometryShaderInvocations = sh::GetGeometryShaderInvocations(compilerHandle); + break; + } + case ShaderType::TessControl: + { + mState.mInputVaryings = GetShaderVariables(sh::GetInputVaryings(compilerHandle)); + mState.mOutputVaryings = GetShaderVariables(sh::GetOutputVaryings(compilerHandle)); + mState.mTessControlShaderVertices = sh::GetTessControlShaderVertices(compilerHandle); + break; + } + case ShaderType::TessEvaluation: + { + mState.mInputVaryings = GetShaderVariables(sh::GetInputVaryings(compilerHandle)); + mState.mOutputVaryings = GetShaderVariables(sh::GetOutputVaryings(compilerHandle)); + if (sh::HasValidTessGenMode(compilerHandle)) + { + mState.mTessGenMode = sh::GetTessGenMode(compilerHandle); + } + if (sh::HasValidTessGenSpacing(compilerHandle)) + { + mState.mTessGenSpacing = sh::GetTessGenSpacing(compilerHandle); + } + if (sh::HasValidTessGenVertexOrder(compilerHandle)) + { + mState.mTessGenVertexOrder = sh::GetTessGenVertexOrder(compilerHandle); + } + if (sh::HasValidTessGenPointMode(compilerHandle)) + { + mState.mTessGenPointMode = sh::GetTessGenPointMode(compilerHandle); + } + break; + } + + default: + UNREACHABLE(); + } + + ASSERT(!mState.mTranslatedSource.empty() || !mState.mCompiledBinary.empty()); + + bool success = mCompilingState->compileEvent->postTranslate(&mInfoLog); + mState.mCompileStatus = success ? CompileStatus::COMPILED : CompileStatus::NOT_COMPILED; + + MemoryShaderCache *shaderCache = context->getMemoryShaderCache(); + if (success && shaderCache) + { + // Save to the shader cache. + if (shaderCache->putShader(context, mCompilingState->shaderHash, this) != + angle::Result::Continue) + { + ANGLE_PERF_WARNING(context->getState().getDebug(), GL_DEBUG_SEVERITY_LOW, + "Failed to save compiled shader to memory shader cache."); + } + } +} + +void Shader::addRef() +{ + mRefCount++; +} + +void Shader::release(const Context *context) +{ + mRefCount--; + + if (mRefCount == 0 && mDeleteStatus) + { + mResourceManager->deleteShader(context, mHandle); + } +} + +unsigned int Shader::getRefCount() const +{ + return mRefCount; +} + +bool Shader::isFlaggedForDeletion() const +{ + return mDeleteStatus; +} + +void Shader::flagForDeletion() +{ + mDeleteStatus = true; +} + +bool Shader::isCompiled(const Context *context) +{ + resolveCompile(context); + return mState.mCompileStatus == CompileStatus::COMPILED; +} + +bool Shader::isCompleted() +{ + return (!mState.compilePending() || mCompilingState->compileEvent->isReady()); +} + +int Shader::getShaderVersion(const Context *context) +{ + resolveCompile(context); + return mState.mShaderVersion; +} + +const std::vector<sh::ShaderVariable> &Shader::getInputVaryings(const Context *context) +{ + resolveCompile(context); + return mState.getInputVaryings(); +} + +const std::vector<sh::ShaderVariable> &Shader::getOutputVaryings(const Context *context) +{ + resolveCompile(context); + return mState.getOutputVaryings(); +} + +const std::vector<sh::ShaderVariable> &Shader::getUniforms(const Context *context) +{ + resolveCompile(context); + return mState.getUniforms(); +} + +const std::vector<sh::InterfaceBlock> &Shader::getUniformBlocks(const Context *context) +{ + resolveCompile(context); + return mState.getUniformBlocks(); +} + +const std::vector<sh::InterfaceBlock> &Shader::getShaderStorageBlocks(const Context *context) +{ + resolveCompile(context); + return mState.getShaderStorageBlocks(); +} + +const std::vector<sh::ShaderVariable> &Shader::getActiveAttributes(const Context *context) +{ + resolveCompile(context); + return mState.getActiveAttributes(); +} + +const std::vector<sh::ShaderVariable> &Shader::getAllAttributes(const Context *context) +{ + resolveCompile(context); + return mState.getAllAttributes(); +} + +const std::vector<sh::ShaderVariable> &Shader::getActiveOutputVariables(const Context *context) +{ + resolveCompile(context); + return mState.getActiveOutputVariables(); +} + +std::string Shader::getTransformFeedbackVaryingMappedName(const Context *context, + const std::string &tfVaryingName) +{ + ASSERT(mState.getShaderType() != ShaderType::Fragment && + mState.getShaderType() != ShaderType::Compute); + const auto &varyings = getOutputVaryings(context); + auto bracketPos = tfVaryingName.find("["); + if (bracketPos != std::string::npos) + { + auto tfVaryingBaseName = tfVaryingName.substr(0, bracketPos); + for (const auto &varying : varyings) + { + if (varying.name == tfVaryingBaseName) + { + std::string mappedNameWithArrayIndex = + varying.mappedName + tfVaryingName.substr(bracketPos); + return mappedNameWithArrayIndex; + } + } + } + else + { + for (const auto &varying : varyings) + { + if (varying.name == tfVaryingName) + { + return varying.mappedName; + } + else if (varying.isStruct()) + { + GLuint fieldIndex = 0; + const auto *field = varying.findField(tfVaryingName, &fieldIndex); + if (field == nullptr) + { + continue; + } + ASSERT(field != nullptr && !field->isStruct() && + (!field->isArray() || varying.isShaderIOBlock)); + std::string mappedName; + // If it's an I/O block without an instance name, don't include the block name. + if (!varying.isShaderIOBlock || !varying.name.empty()) + { + mappedName = varying.isShaderIOBlock ? varying.mappedStructOrBlockName + : varying.mappedName; + mappedName += '.'; + } + return mappedName + field->mappedName; + } + } + } + UNREACHABLE(); + return std::string(); +} + +const sh::WorkGroupSize &Shader::getWorkGroupSize(const Context *context) +{ + resolveCompile(context); + return mState.mLocalSize; +} + +int Shader::getNumViews(const Context *context) +{ + resolveCompile(context); + return mState.mNumViews; +} + +Optional<PrimitiveMode> Shader::getGeometryShaderInputPrimitiveType(const Context *context) +{ + resolveCompile(context); + return mState.mGeometryShaderInputPrimitiveType; +} + +Optional<PrimitiveMode> Shader::getGeometryShaderOutputPrimitiveType(const Context *context) +{ + resolveCompile(context); + return mState.mGeometryShaderOutputPrimitiveType; +} + +int Shader::getGeometryShaderInvocations(const Context *context) +{ + resolveCompile(context); + return mState.mGeometryShaderInvocations; +} + +Optional<GLint> Shader::getGeometryShaderMaxVertices(const Context *context) +{ + resolveCompile(context); + return mState.mGeometryShaderMaxVertices; +} + +int Shader::getTessControlShaderVertices(const Context *context) +{ + resolveCompile(context); + return mState.mTessControlShaderVertices; +} + +GLenum Shader::getTessGenMode(const Context *context) +{ + resolveCompile(context); + return mState.mTessGenMode; +} + +GLenum Shader::getTessGenSpacing(const Context *context) +{ + resolveCompile(context); + return mState.mTessGenSpacing; +} + +GLenum Shader::getTessGenVertexOrder(const Context *context) +{ + resolveCompile(context); + return mState.mTessGenVertexOrder; +} + +GLenum Shader::getTessGenPointMode(const Context *context) +{ + resolveCompile(context); + return mState.mTessGenPointMode; +} + +const std::string &Shader::getCompilerResourcesString() const +{ + return mCompilerResourcesString; +} + +angle::Result Shader::serialize(const Context *context, angle::MemoryBuffer *binaryOut) const +{ + BinaryOutputStream stream; + + stream.writeInt(kShaderCacheIdentifier); + stream.writeString(mState.mLabel); + stream.writeInt(mState.mShaderVersion); + stream.writeString(mCompilerResourcesString); + + stream.writeInt(mState.mUniforms.size()); + for (const sh::ShaderVariable &shaderVariable : mState.mUniforms) + { + WriteShaderVar(&stream, shaderVariable); + } + + stream.writeInt(mState.mUniformBlocks.size()); + for (const sh::InterfaceBlock &interfaceBlock : mState.mUniformBlocks) + { + WriteInterfaceBlock(&stream, interfaceBlock); + } + + stream.writeInt(mState.mShaderStorageBlocks.size()); + for (const sh::InterfaceBlock &interfaceBlock : mState.mShaderStorageBlocks) + { + WriteInterfaceBlock(&stream, interfaceBlock); + } + + stream.writeInt(mState.mSpecConstUsageBits.bits()); + + switch (mType) + { + case ShaderType::Compute: + { + stream.writeInt(mState.mAllAttributes.size()); + for (const sh::ShaderVariable &shaderVariable : mState.mAllAttributes) + { + WriteShaderVar(&stream, shaderVariable); + } + stream.writeInt(mState.mActiveAttributes.size()); + for (const sh::ShaderVariable &shaderVariable : mState.mActiveAttributes) + { + WriteShaderVar(&stream, shaderVariable); + } + stream.writeInt(mState.mLocalSize[0]); + stream.writeInt(mState.mLocalSize[1]); + stream.writeInt(mState.mLocalSize[2]); + break; + } + + case ShaderType::Vertex: + { + stream.writeInt(mState.mOutputVaryings.size()); + for (const sh::ShaderVariable &shaderVariable : mState.mOutputVaryings) + { + WriteShaderVar(&stream, shaderVariable); + } + stream.writeInt(mState.mAllAttributes.size()); + for (const sh::ShaderVariable &shaderVariable : mState.mAllAttributes) + { + WriteShaderVar(&stream, shaderVariable); + } + stream.writeInt(mState.mActiveAttributes.size()); + for (const sh::ShaderVariable &shaderVariable : mState.mActiveAttributes) + { + WriteShaderVar(&stream, shaderVariable); + } + stream.writeInt(mState.mNumViews); + break; + } + case ShaderType::Fragment: + { + stream.writeInt(mState.mInputVaryings.size()); + for (const sh::ShaderVariable &shaderVariable : mState.mInputVaryings) + { + WriteShaderVar(&stream, shaderVariable); + } + stream.writeInt(mState.mActiveOutputVariables.size()); + for (const sh::ShaderVariable &shaderVariable : mState.mActiveOutputVariables) + { + WriteShaderVar(&stream, shaderVariable); + } + stream.writeBool(mState.mEnablesPerSampleShading); + stream.writeInt(mState.mAdvancedBlendEquations.bits()); + break; + } + case ShaderType::Geometry: + { + bool valid; + + stream.writeInt(mState.mInputVaryings.size()); + for (const sh::ShaderVariable &shaderVariable : mState.mInputVaryings) + { + WriteShaderVar(&stream, shaderVariable); + } + stream.writeInt(mState.mOutputVaryings.size()); + for (const sh::ShaderVariable &shaderVariable : mState.mOutputVaryings) + { + WriteShaderVar(&stream, shaderVariable); + } + + valid = (bool)mState.mGeometryShaderInputPrimitiveType.valid(); + stream.writeBool(valid); + if (valid) + { + unsigned char value = + (unsigned char)mState.mGeometryShaderInputPrimitiveType.value(); + stream.writeBytes(&value, 1); + } + valid = (bool)mState.mGeometryShaderOutputPrimitiveType.valid(); + stream.writeBool(valid); + if (valid) + { + unsigned char value = + (unsigned char)mState.mGeometryShaderOutputPrimitiveType.value(); + stream.writeBytes(&value, 1); + } + valid = mState.mGeometryShaderMaxVertices.valid(); + stream.writeBool(valid); + if (valid) + { + int value = (int)mState.mGeometryShaderMaxVertices.value(); + stream.writeInt(value); + } + + stream.writeInt(mState.mGeometryShaderInvocations); + break; + } + case ShaderType::TessControl: + { + stream.writeInt(mState.mInputVaryings.size()); + for (const sh::ShaderVariable &shaderVariable : mState.mInputVaryings) + { + WriteShaderVar(&stream, shaderVariable); + } + stream.writeInt(mState.mOutputVaryings.size()); + for (const sh::ShaderVariable &shaderVariable : mState.mOutputVaryings) + { + WriteShaderVar(&stream, shaderVariable); + } + stream.writeInt(mState.mTessControlShaderVertices); + break; + } + case ShaderType::TessEvaluation: + { + unsigned int value; + + stream.writeInt(mState.mInputVaryings.size()); + for (const sh::ShaderVariable &shaderVariable : mState.mInputVaryings) + { + WriteShaderVar(&stream, shaderVariable); + } + stream.writeInt(mState.mOutputVaryings.size()); + for (const sh::ShaderVariable &shaderVariable : mState.mOutputVaryings) + { + WriteShaderVar(&stream, shaderVariable); + } + + value = (unsigned int)(mState.mTessGenMode); + stream.writeInt(value); + + value = (unsigned int)mState.mTessGenSpacing; + stream.writeInt(value); + + value = (unsigned int)mState.mTessGenVertexOrder; + stream.writeInt(value); + + value = (unsigned int)mState.mTessGenPointMode; + stream.writeInt(value); + break; + } + default: + UNREACHABLE(); + } + + stream.writeIntVector(mState.mCompiledBinary); + stream.writeEnum(mState.mCompileStatus); + + ASSERT(binaryOut); + if (!binaryOut->resize(stream.length())) + { + std::stringstream sstream; + sstream << "Failed to allocate enough memory to serialize a shader. (" << stream.length() + << " bytes )"; + ANGLE_PERF_WARNING(context->getState().getDebug(), GL_DEBUG_SEVERITY_LOW, + sstream.str().c_str()); + return angle::Result::Incomplete; + } + + memcpy(binaryOut->data(), stream.data(), stream.length()); + + return angle::Result::Continue; +} + +angle::Result Shader::deserialize(const Context *context, BinaryInputStream &stream) +{ + size_t size; + + if (stream.readInt<uint32_t>() != kShaderCacheIdentifier) + { + return angle::Result::Stop; + } + + stream.readString(&mState.mLabel); + stream.readInt(&mState.mShaderVersion); + stream.readString(&mCompilerResourcesString); + + size = stream.readInt<size_t>(); + mState.mUniforms.resize(size); + for (sh::ShaderVariable &shaderVariable : mState.mUniforms) + { + LoadShaderVar(&stream, &shaderVariable); + } + + size = stream.readInt<size_t>(); + mState.mUniformBlocks.resize(size); + for (sh::InterfaceBlock &interfaceBlock : mState.mUniformBlocks) + { + LoadInterfaceBlock(&stream, interfaceBlock); + } + + size = stream.readInt<size_t>(); + mState.mShaderStorageBlocks.resize(size); + for (sh::InterfaceBlock &interfaceBlock : mState.mShaderStorageBlocks) + { + LoadInterfaceBlock(&stream, interfaceBlock); + } + + mState.mSpecConstUsageBits = rx::SpecConstUsageBits(stream.readInt<uint32_t>()); + + switch (mType) + { + case ShaderType::Compute: + { + size = stream.readInt<size_t>(); + mState.mAllAttributes.resize(size); + for (sh::ShaderVariable &shaderVariable : mState.mAllAttributes) + { + LoadShaderVar(&stream, &shaderVariable); + } + size = stream.readInt<size_t>(); + mState.mActiveAttributes.resize(size); + for (sh::ShaderVariable &shaderVariable : mState.mActiveAttributes) + { + LoadShaderVar(&stream, &shaderVariable); + } + stream.readInt(&mState.mLocalSize[0]); + stream.readInt(&mState.mLocalSize[1]); + stream.readInt(&mState.mLocalSize[2]); + break; + } + case ShaderType::Vertex: + { + size = stream.readInt<size_t>(); + mState.mOutputVaryings.resize(size); + for (sh::ShaderVariable &shaderVariable : mState.mOutputVaryings) + { + LoadShaderVar(&stream, &shaderVariable); + } + size = stream.readInt<size_t>(); + mState.mAllAttributes.resize(size); + for (sh::ShaderVariable &shaderVariable : mState.mAllAttributes) + { + LoadShaderVar(&stream, &shaderVariable); + } + size = stream.readInt<size_t>(); + mState.mActiveAttributes.resize(size); + for (sh::ShaderVariable &shaderVariable : mState.mActiveAttributes) + { + LoadShaderVar(&stream, &shaderVariable); + } + stream.readInt(&mState.mNumViews); + break; + } + case ShaderType::Fragment: + { + size = stream.readInt<size_t>(); + mState.mInputVaryings.resize(size); + for (sh::ShaderVariable &shaderVariable : mState.mInputVaryings) + { + LoadShaderVar(&stream, &shaderVariable); + } + size = stream.readInt<size_t>(); + mState.mActiveOutputVariables.resize(size); + for (sh::ShaderVariable &shaderVariable : mState.mActiveOutputVariables) + { + LoadShaderVar(&stream, &shaderVariable); + } + stream.readBool(&mState.mEnablesPerSampleShading); + int advancedBlendEquationBits; + stream.readInt(&advancedBlendEquationBits); + mState.mAdvancedBlendEquations = BlendEquationBitSet(advancedBlendEquationBits); + break; + } + case ShaderType::Geometry: + { + bool valid; + + size = stream.readInt<size_t>(); + mState.mInputVaryings.resize(size); + for (sh::ShaderVariable &shaderVariable : mState.mInputVaryings) + { + LoadShaderVar(&stream, &shaderVariable); + } + size = stream.readInt<size_t>(); + mState.mOutputVaryings.resize(size); + for (sh::ShaderVariable &shaderVariable : mState.mOutputVaryings) + { + LoadShaderVar(&stream, &shaderVariable); + } + + stream.readBool(&valid); + if (valid) + { + unsigned char value; + stream.readBytes(&value, 1); + mState.mGeometryShaderInputPrimitiveType = static_cast<PrimitiveMode>(value); + } + else + { + mState.mGeometryShaderInputPrimitiveType.reset(); + } + + stream.readBool(&valid); + if (valid) + { + unsigned char value; + stream.readBytes(&value, 1); + mState.mGeometryShaderOutputPrimitiveType = static_cast<PrimitiveMode>(value); + } + else + { + mState.mGeometryShaderOutputPrimitiveType.reset(); + } + + stream.readBool(&valid); + if (valid) + { + int value; + stream.readInt(&value); + mState.mGeometryShaderMaxVertices = static_cast<GLint>(value); + } + else + { + mState.mGeometryShaderMaxVertices.reset(); + } + + stream.readInt(&mState.mGeometryShaderInvocations); + break; + } + case ShaderType::TessControl: + { + size = stream.readInt<size_t>(); + mState.mInputVaryings.resize(size); + for (sh::ShaderVariable &shaderVariable : mState.mInputVaryings) + { + LoadShaderVar(&stream, &shaderVariable); + } + size = stream.readInt<size_t>(); + mState.mOutputVaryings.resize(size); + for (sh::ShaderVariable &shaderVariable : mState.mOutputVaryings) + { + LoadShaderVar(&stream, &shaderVariable); + } + stream.readInt(&mState.mTessControlShaderVertices); + break; + } + case ShaderType::TessEvaluation: + { + unsigned int value; + + size = stream.readInt<size_t>(); + mState.mInputVaryings.resize(size); + for (sh::ShaderVariable &shaderVariable : mState.mInputVaryings) + { + LoadShaderVar(&stream, &shaderVariable); + } + size = stream.readInt<size_t>(); + mState.mOutputVaryings.resize(size); + for (sh::ShaderVariable &shaderVariable : mState.mOutputVaryings) + { + LoadShaderVar(&stream, &shaderVariable); + } + + stream.readInt(&value); + mState.mTessGenMode = (GLenum)value; + + stream.readInt(&value); + mState.mTessGenSpacing = (GLenum)value; + + stream.readInt(&value); + mState.mTessGenVertexOrder = (GLenum)value; + + stream.readInt(&value); + mState.mTessGenPointMode = (GLenum)value; + break; + } + default: + UNREACHABLE(); + } + + stream.readIntVector<unsigned int>(&mState.mCompiledBinary); + mState.mCompileStatus = stream.readEnum<CompileStatus>(); + + return angle::Result::Continue; +} + +angle::Result Shader::loadBinary(const Context *context, const void *binary, GLsizei length) +{ + BinaryInputStream stream(binary, length); + ANGLE_TRY(deserialize(context, stream)); + + return angle::Result::Continue; +} + +} // namespace gl |