| // |
| // Copyright 2015 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. |
| // |
| |
| // ShaderGL.cpp: Implements the class methods for ShaderGL. |
| |
| #include "libANGLE/renderer/gl/ShaderGL.h" |
| |
| #include "common/debug.h" |
| #include "libANGLE/Compiler.h" |
| #include "libANGLE/Context.h" |
| #include "libANGLE/renderer/gl/FunctionsGL.h" |
| #include "libANGLE/renderer/gl/RendererGL.h" |
| #include "platform/FeaturesGL.h" |
| |
| #include <iostream> |
| |
| namespace rx |
| { |
| |
| using CompileAndCheckShaderInWorkerFunctor = std::function<bool(const char *source)>; |
| class TranslateTaskGL : public angle::Closure |
| { |
| public: |
| TranslateTaskGL(ShHandle handle, |
| ShCompileOptions options, |
| const std::string &source, |
| CompileAndCheckShaderInWorkerFunctor &&compileAndCheckShaderInWorkerFunctor) |
| : mHandle(handle), |
| mOptions(options), |
| mSource(source), |
| mCompileAndCheckShaderInWorkerFunctor(std::move(compileAndCheckShaderInWorkerFunctor)), |
| mResult(false), |
| mWorkerAvailable(true) |
| {} |
| |
| void operator()() override |
| { |
| const char *source = mSource.c_str(); |
| mResult = sh::Compile(mHandle, &source, 1, mOptions); |
| if (mResult) |
| { |
| mWorkerAvailable = |
| mCompileAndCheckShaderInWorkerFunctor(sh::GetObjectCode(mHandle).c_str()); |
| } |
| } |
| |
| bool getResult() { return mResult; } |
| |
| bool workerAvailable() { return mWorkerAvailable; } |
| |
| ShHandle getHandle() { return mHandle; } |
| |
| private: |
| ShHandle mHandle; |
| ShCompileOptions mOptions; |
| std::string mSource; |
| CompileAndCheckShaderInWorkerFunctor mCompileAndCheckShaderInWorkerFunctor; |
| bool mResult; |
| bool mWorkerAvailable; |
| }; |
| |
| using PostTranslateFunctor = std::function<bool(std::string *infoLog)>; |
| using CompileAndCheckShaderFunctor = std::function<void(const char *source)>; |
| class WaitableCompileEventWorkerContext final : public WaitableCompileEvent |
| { |
| public: |
| WaitableCompileEventWorkerContext(std::shared_ptr<angle::WaitableEvent> waitableEvent, |
| CompileAndCheckShaderFunctor &&compileAndCheckShaderFunctor, |
| PostTranslateFunctor &&postTranslateFunctor, |
| std::shared_ptr<TranslateTaskGL> translateTask) |
| : WaitableCompileEvent(waitableEvent), |
| mCompileAndCheckShaderFunctor(std::move(compileAndCheckShaderFunctor)), |
| mPostTranslateFunctor(std::move(postTranslateFunctor)), |
| mTranslateTask(translateTask) |
| {} |
| |
| bool getResult() override { return mTranslateTask->getResult(); } |
| |
| bool postTranslate(std::string *infoLog) override |
| { |
| if (!mTranslateTask->workerAvailable()) |
| { |
| ShHandle handle = mTranslateTask->getHandle(); |
| mCompileAndCheckShaderFunctor(sh::GetObjectCode(handle).c_str()); |
| } |
| return mPostTranslateFunctor(infoLog); |
| } |
| |
| private: |
| CompileAndCheckShaderFunctor mCompileAndCheckShaderFunctor; |
| PostTranslateFunctor mPostTranslateFunctor; |
| std::shared_ptr<TranslateTaskGL> mTranslateTask; |
| }; |
| |
| using PeekCompletionFunctor = std::function<bool()>; |
| using CheckShaderFunctor = std::function<void()>; |
| |
| class WaitableCompileEventNativeParallel final : public WaitableCompileEvent |
| { |
| public: |
| WaitableCompileEventNativeParallel(PostTranslateFunctor &&postTranslateFunctor, |
| bool result, |
| CheckShaderFunctor &&checkShaderFunctor, |
| PeekCompletionFunctor &&peekCompletionFunctor) |
| : WaitableCompileEvent(std::shared_ptr<angle::WaitableEventDone>()), |
| mPostTranslateFunctor(std::move(postTranslateFunctor)), |
| mResult(result), |
| mCheckShaderFunctor(std::move(checkShaderFunctor)), |
| mPeekCompletionFunctor(std::move(peekCompletionFunctor)) |
| {} |
| |
| void wait() override { mCheckShaderFunctor(); } |
| |
| bool isReady() override { return mPeekCompletionFunctor(); } |
| |
| bool getResult() override { return mResult; } |
| |
| bool postTranslate(std::string *infoLog) override { return mPostTranslateFunctor(infoLog); } |
| |
| private: |
| PostTranslateFunctor mPostTranslateFunctor; |
| bool mResult; |
| CheckShaderFunctor mCheckShaderFunctor; |
| PeekCompletionFunctor mPeekCompletionFunctor; |
| }; |
| |
| class WaitableCompileEventDone final : public WaitableCompileEvent |
| { |
| public: |
| WaitableCompileEventDone(PostTranslateFunctor &&postTranslateFunctor, bool result) |
| : WaitableCompileEvent(std::make_shared<angle::WaitableEventDone>()), |
| mPostTranslateFunctor(std::move(postTranslateFunctor)), |
| mResult(result) |
| {} |
| |
| bool getResult() override { return mResult; } |
| |
| bool postTranslate(std::string *infoLog) override { return mPostTranslateFunctor(infoLog); } |
| |
| private: |
| PostTranslateFunctor mPostTranslateFunctor; |
| bool mResult; |
| }; |
| |
| ShaderGL::ShaderGL(const gl::ShaderState &data, |
| GLuint shaderID, |
| MultiviewImplementationTypeGL multiviewImplementationType, |
| const std::shared_ptr<RendererGL> &renderer) |
| : ShaderImpl(data), |
| mShaderID(shaderID), |
| mMultiviewImplementationType(multiviewImplementationType), |
| mRenderer(renderer), |
| mCompileStatus(GL_FALSE) |
| {} |
| |
| ShaderGL::~ShaderGL() |
| { |
| ASSERT(mShaderID == 0); |
| } |
| |
| void ShaderGL::destroy() |
| { |
| mRenderer->getFunctions()->deleteShader(mShaderID); |
| mShaderID = 0; |
| } |
| |
| void ShaderGL::compileAndCheckShader(const char *source) |
| { |
| compileShader(source); |
| checkShader(); |
| } |
| |
| void ShaderGL::compileShader(const char *source) |
| { |
| const FunctionsGL *functions = mRenderer->getFunctions(); |
| functions->shaderSource(mShaderID, 1, &source, nullptr); |
| functions->compileShader(mShaderID); |
| } |
| |
| void ShaderGL::checkShader() |
| { |
| const FunctionsGL *functions = mRenderer->getFunctions(); |
| |
| // Check for compile errors from the native driver |
| mCompileStatus = GL_FALSE; |
| functions->getShaderiv(mShaderID, GL_COMPILE_STATUS, &mCompileStatus); |
| if (mCompileStatus == GL_FALSE) |
| { |
| // Compilation failed, put the error into the info log |
| GLint infoLogLength = 0; |
| functions->getShaderiv(mShaderID, GL_INFO_LOG_LENGTH, &infoLogLength); |
| |
| // Info log length includes the null terminator, so 1 means that the info log is an empty |
| // string. |
| if (infoLogLength > 1) |
| { |
| std::vector<char> buf(infoLogLength); |
| functions->getShaderInfoLog(mShaderID, infoLogLength, nullptr, &buf[0]); |
| |
| mInfoLog += &buf[0]; |
| WARN() << std::endl << mInfoLog; |
| } |
| else |
| { |
| WARN() << std::endl << "Shader compilation failed with no info log."; |
| } |
| } |
| } |
| |
| bool ShaderGL::peekCompletion() |
| { |
| const FunctionsGL *functions = mRenderer->getFunctions(); |
| GLint status = GL_FALSE; |
| functions->getShaderiv(mShaderID, GL_COMPLETION_STATUS, &status); |
| return status == GL_TRUE; |
| } |
| |
| bool ShaderGL::compileAndCheckShaderInWorker(const char *source) |
| { |
| std::string workerInfoLog; |
| ScopedWorkerContextGL worker(mRenderer.get(), &workerInfoLog); |
| if (worker()) |
| { |
| compileAndCheckShader(source); |
| return true; |
| } |
| else |
| { |
| #if !defined(NDEBUG) |
| mInfoLog += "bindWorkerContext failed.\n" + workerInfoLog; |
| #endif |
| return false; |
| } |
| } |
| |
| std::shared_ptr<WaitableCompileEvent> ShaderGL::compile(const gl::Context *context, |
| gl::ShCompilerInstance *compilerInstance, |
| ShCompileOptions options) |
| { |
| mInfoLog.clear(); |
| |
| ShCompileOptions additionalOptions = SH_INIT_GL_POSITION; |
| |
| bool isWebGL = context->getExtensions().webglCompatibility; |
| if (isWebGL && (mData.getShaderType() != gl::ShaderType::Compute)) |
| { |
| additionalOptions |= SH_INIT_OUTPUT_VARIABLES; |
| } |
| |
| const angle::FeaturesGL &features = GetFeaturesGL(context); |
| |
| if (features.doWhileGLSLCausesGPUHang.enabled) |
| { |
| additionalOptions |= SH_REWRITE_DO_WHILE_LOOPS; |
| } |
| |
| if (features.emulateAbsIntFunction.enabled) |
| { |
| additionalOptions |= SH_EMULATE_ABS_INT_FUNCTION; |
| } |
| |
| if (features.addAndTrueToLoopCondition.enabled) |
| { |
| additionalOptions |= SH_ADD_AND_TRUE_TO_LOOP_CONDITION; |
| } |
| |
| if (features.emulateIsnanFloat.enabled) |
| { |
| additionalOptions |= SH_EMULATE_ISNAN_FLOAT_FUNCTION; |
| } |
| |
| if (features.emulateAtan2Float.enabled) |
| { |
| additionalOptions |= SH_EMULATE_ATAN2_FLOAT_FUNCTION; |
| } |
| |
| if (features.useUnusedBlocksWithStandardOrSharedLayout.enabled) |
| { |
| additionalOptions |= SH_USE_UNUSED_STANDARD_SHARED_BLOCKS; |
| } |
| |
| if (features.removeInvariantAndCentroidForESSL3.enabled) |
| { |
| additionalOptions |= SH_REMOVE_INVARIANT_AND_CENTROID_FOR_ESSL3; |
| } |
| |
| if (features.rewriteFloatUnaryMinusOperator.enabled) |
| { |
| additionalOptions |= SH_REWRITE_FLOAT_UNARY_MINUS_OPERATOR; |
| } |
| |
| if (!features.dontInitializeUninitializedLocals.enabled) |
| { |
| additionalOptions |= SH_INITIALIZE_UNINITIALIZED_LOCALS; |
| } |
| |
| if (features.clampPointSize.enabled) |
| { |
| additionalOptions |= SH_CLAMP_POINT_SIZE; |
| } |
| |
| if (features.rewriteVectorScalarArithmetic.enabled) |
| { |
| additionalOptions |= SH_REWRITE_VECTOR_SCALAR_ARITHMETIC; |
| } |
| |
| if (features.dontUseLoopsToInitializeVariables.enabled) |
| { |
| additionalOptions |= SH_DONT_USE_LOOPS_TO_INITIALIZE_VARIABLES; |
| } |
| |
| if (features.clampFragDepth.enabled) |
| { |
| additionalOptions |= SH_CLAMP_FRAG_DEPTH; |
| } |
| |
| if (features.rewriteRepeatedAssignToSwizzled.enabled) |
| { |
| additionalOptions |= SH_REWRITE_REPEATED_ASSIGN_TO_SWIZZLED; |
| } |
| |
| if (mMultiviewImplementationType == MultiviewImplementationTypeGL::NV_VIEWPORT_ARRAY2) |
| { |
| additionalOptions |= SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW; |
| additionalOptions |= SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER; |
| } |
| |
| if (features.clampArrayAccess.enabled) |
| { |
| additionalOptions |= SH_CLAMP_INDIRECT_ARRAY_BOUNDS; |
| } |
| |
| if (features.addBaseVertexToVertexID.enabled) |
| { |
| additionalOptions |= SH_ADD_BASE_VERTEX_TO_VERTEX_ID; |
| } |
| |
| if (features.unfoldShortCircuits.enabled) |
| { |
| additionalOptions |= SH_UNFOLD_SHORT_CIRCUIT; |
| } |
| |
| if (features.removeDynamicIndexingOfSwizzledVector.enabled) |
| { |
| additionalOptions |= SH_REMOVE_DYNAMIC_INDEXING_OF_SWIZZLED_VECTOR; |
| } |
| |
| if (features.preAddTexelFetchOffsets.enabled) |
| { |
| additionalOptions |= SH_REWRITE_TEXELFETCHOFFSET_TO_TEXELFETCH; |
| } |
| |
| if (features.regenerateStructNames.enabled) |
| { |
| additionalOptions |= SH_REGENERATE_STRUCT_NAMES; |
| } |
| |
| options |= additionalOptions; |
| |
| auto workerThreadPool = context->getWorkerThreadPool(); |
| |
| const std::string &source = mData.getSource(); |
| |
| auto postTranslateFunctor = [this](std::string *infoLog) { |
| if (mCompileStatus == GL_FALSE) |
| { |
| *infoLog = mInfoLog; |
| return false; |
| } |
| return true; |
| }; |
| |
| if (mRenderer->hasNativeParallelCompile()) |
| { |
| ShHandle handle = compilerInstance->getHandle(); |
| const char *str = source.c_str(); |
| bool result = sh::Compile(handle, &str, 1, options); |
| if (result) |
| { |
| compileShader(sh::GetObjectCode(handle).c_str()); |
| auto checkShaderFunctor = [this]() { checkShader(); }; |
| auto peekCompletionFunctor = [this]() { return peekCompletion(); }; |
| return std::make_shared<WaitableCompileEventNativeParallel>( |
| std::move(postTranslateFunctor), result, std::move(checkShaderFunctor), |
| std::move(peekCompletionFunctor)); |
| } |
| else |
| { |
| return std::make_shared<WaitableCompileEventDone>([](std::string *) { return true; }, |
| result); |
| } |
| } |
| else if (workerThreadPool->isAsync()) |
| { |
| auto compileAndCheckShaderInWorkerFunctor = [this](const char *source) { |
| return compileAndCheckShaderInWorker(source); |
| }; |
| auto translateTask = |
| std::make_shared<TranslateTaskGL>(compilerInstance->getHandle(), options, source, |
| std::move(compileAndCheckShaderInWorkerFunctor)); |
| |
| auto compileAndCheckShaderFunctor = [this](const char *source) { |
| compileAndCheckShader(source); |
| }; |
| return std::make_shared<WaitableCompileEventWorkerContext>( |
| angle::WorkerThreadPool::PostWorkerTask(workerThreadPool, translateTask), |
| std::move(compileAndCheckShaderFunctor), std::move(postTranslateFunctor), |
| translateTask); |
| } |
| else |
| { |
| ShHandle handle = compilerInstance->getHandle(); |
| const char *str = source.c_str(); |
| bool result = sh::Compile(handle, &str, 1, options); |
| if (result) |
| { |
| compileAndCheckShader(sh::GetObjectCode(handle).c_str()); |
| } |
| return std::make_shared<WaitableCompileEventDone>(std::move(postTranslateFunctor), result); |
| } |
| } |
| |
| std::string ShaderGL::getDebugInfo() const |
| { |
| return mData.getTranslatedSource(); |
| } |
| |
| GLuint ShaderGL::getShaderID() const |
| { |
| return mShaderID; |
| } |
| |
| } // namespace rx |