summaryrefslogtreecommitdiffstats
path: root/gfx/angle/checkout/src/libANGLE/Shader.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--gfx/angle/checkout/src/libANGLE/Shader.cpp1331
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