1*8975f5c5SAndroid Build Coastguard Worker // 2*8975f5c5SAndroid Build Coastguard Worker // Copyright 2016 The ANGLE Project Authors. All rights reserved. 3*8975f5c5SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be 4*8975f5c5SAndroid Build Coastguard Worker // found in the LICENSE file. 5*8975f5c5SAndroid Build Coastguard Worker // 6*8975f5c5SAndroid Build Coastguard Worker // ShaderVk.cpp: 7*8975f5c5SAndroid Build Coastguard Worker // Implements the class methods for ShaderVk. 8*8975f5c5SAndroid Build Coastguard Worker // 9*8975f5c5SAndroid Build Coastguard Worker 10*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/renderer/vulkan/ShaderVk.h" 11*8975f5c5SAndroid Build Coastguard Worker 12*8975f5c5SAndroid Build Coastguard Worker #include "common/debug.h" 13*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/Context.h" 14*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/Display.h" 15*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/renderer/vulkan/ContextVk.h" 16*8975f5c5SAndroid Build Coastguard Worker 17*8975f5c5SAndroid Build Coastguard Worker namespace rx 18*8975f5c5SAndroid Build Coastguard Worker { ShaderVk(const gl::ShaderState & state)19*8975f5c5SAndroid Build Coastguard WorkerShaderVk::ShaderVk(const gl::ShaderState &state) : ShaderImpl(state) {} 20*8975f5c5SAndroid Build Coastguard Worker ~ShaderVk()21*8975f5c5SAndroid Build Coastguard WorkerShaderVk::~ShaderVk() {} 22*8975f5c5SAndroid Build Coastguard Worker compile(const gl::Context * context,ShCompileOptions * options)23*8975f5c5SAndroid Build Coastguard Workerstd::shared_ptr<ShaderTranslateTask> ShaderVk::compile(const gl::Context *context, 24*8975f5c5SAndroid Build Coastguard Worker ShCompileOptions *options) 25*8975f5c5SAndroid Build Coastguard Worker { 26*8975f5c5SAndroid Build Coastguard Worker ContextVk *contextVk = vk::GetImpl(context); 27*8975f5c5SAndroid Build Coastguard Worker 28*8975f5c5SAndroid Build Coastguard Worker if (context->isWebGL()) 29*8975f5c5SAndroid Build Coastguard Worker { 30*8975f5c5SAndroid Build Coastguard Worker // Only WebGL requires initialization of local variables, others don't. 31*8975f5c5SAndroid Build Coastguard Worker // Extra initialization in spirv shader may affect performance. 32*8975f5c5SAndroid Build Coastguard Worker options->initializeUninitializedLocals = true; 33*8975f5c5SAndroid Build Coastguard Worker 34*8975f5c5SAndroid Build Coastguard Worker // WebGL shaders may contain OOB array accesses which in turn cause undefined behavior, 35*8975f5c5SAndroid Build Coastguard Worker // which may result in security issues. See https://crbug.com/1189110. 36*8975f5c5SAndroid Build Coastguard Worker options->clampIndirectArrayBounds = true; 37*8975f5c5SAndroid Build Coastguard Worker 38*8975f5c5SAndroid Build Coastguard Worker if (mState.getShaderType() != gl::ShaderType::Compute) 39*8975f5c5SAndroid Build Coastguard Worker { 40*8975f5c5SAndroid Build Coastguard Worker options->initOutputVariables = true; 41*8975f5c5SAndroid Build Coastguard Worker } 42*8975f5c5SAndroid Build Coastguard Worker } 43*8975f5c5SAndroid Build Coastguard Worker 44*8975f5c5SAndroid Build Coastguard Worker if (contextVk->getFeatures().supportsSPIRV14.enabled) 45*8975f5c5SAndroid Build Coastguard Worker { 46*8975f5c5SAndroid Build Coastguard Worker options->emitSPIRV14 = true; 47*8975f5c5SAndroid Build Coastguard Worker } 48*8975f5c5SAndroid Build Coastguard Worker 49*8975f5c5SAndroid Build Coastguard Worker if (contextVk->getFeatures().retainSPIRVDebugInfo.enabled) 50*8975f5c5SAndroid Build Coastguard Worker { 51*8975f5c5SAndroid Build Coastguard Worker options->outputDebugInfo = true; 52*8975f5c5SAndroid Build Coastguard Worker } 53*8975f5c5SAndroid Build Coastguard Worker 54*8975f5c5SAndroid Build Coastguard Worker // robustBufferAccess on Vulkan doesn't support bound check on shader local variables 55*8975f5c5SAndroid Build Coastguard Worker // but the GL_EXT_robustness does support. 56*8975f5c5SAndroid Build Coastguard Worker // Enable the flag clampIndirectArrayBounds to ensure out of bounds local variable writes in 57*8975f5c5SAndroid Build Coastguard Worker // shaders are protected when the context has GL_EXT_robustness enabled 58*8975f5c5SAndroid Build Coastguard Worker if (contextVk->getShareGroup()->hasAnyContextWithRobustness()) 59*8975f5c5SAndroid Build Coastguard Worker { 60*8975f5c5SAndroid Build Coastguard Worker options->clampIndirectArrayBounds = true; 61*8975f5c5SAndroid Build Coastguard Worker } 62*8975f5c5SAndroid Build Coastguard Worker 63*8975f5c5SAndroid Build Coastguard Worker if (contextVk->getFeatures().clampPointSize.enabled) 64*8975f5c5SAndroid Build Coastguard Worker { 65*8975f5c5SAndroid Build Coastguard Worker options->clampPointSize = true; 66*8975f5c5SAndroid Build Coastguard Worker } 67*8975f5c5SAndroid Build Coastguard Worker 68*8975f5c5SAndroid Build Coastguard Worker if (contextVk->getFeatures().emulateAdvancedBlendEquations.enabled) 69*8975f5c5SAndroid Build Coastguard Worker { 70*8975f5c5SAndroid Build Coastguard Worker options->addAdvancedBlendEquationsEmulation = true; 71*8975f5c5SAndroid Build Coastguard Worker } 72*8975f5c5SAndroid Build Coastguard Worker 73*8975f5c5SAndroid Build Coastguard Worker if (!contextVk->getFeatures().enablePrecisionQualifiers.enabled) 74*8975f5c5SAndroid Build Coastguard Worker { 75*8975f5c5SAndroid Build Coastguard Worker options->ignorePrecisionQualifiers = true; 76*8975f5c5SAndroid Build Coastguard Worker } 77*8975f5c5SAndroid Build Coastguard Worker 78*8975f5c5SAndroid Build Coastguard Worker if (contextVk->getFeatures().forceFragmentShaderPrecisionHighpToMediump.enabled) 79*8975f5c5SAndroid Build Coastguard Worker { 80*8975f5c5SAndroid Build Coastguard Worker options->forceShaderPrecisionHighpToMediump = true; 81*8975f5c5SAndroid Build Coastguard Worker } 82*8975f5c5SAndroid Build Coastguard Worker 83*8975f5c5SAndroid Build Coastguard Worker // Let compiler use specialized constant for pre-rotation. 84*8975f5c5SAndroid Build Coastguard Worker if (!contextVk->getFeatures().preferDriverUniformOverSpecConst.enabled) 85*8975f5c5SAndroid Build Coastguard Worker { 86*8975f5c5SAndroid Build Coastguard Worker options->useSpecializationConstant = true; 87*8975f5c5SAndroid Build Coastguard Worker } 88*8975f5c5SAndroid Build Coastguard Worker 89*8975f5c5SAndroid Build Coastguard Worker if (contextVk->getFeatures().clampFragDepth.enabled) 90*8975f5c5SAndroid Build Coastguard Worker { 91*8975f5c5SAndroid Build Coastguard Worker options->clampFragDepth = true; 92*8975f5c5SAndroid Build Coastguard Worker } 93*8975f5c5SAndroid Build Coastguard Worker 94*8975f5c5SAndroid Build Coastguard Worker if (!contextVk->getFeatures().supportsDepthClipControl.enabled) 95*8975f5c5SAndroid Build Coastguard Worker { 96*8975f5c5SAndroid Build Coastguard Worker options->addVulkanDepthCorrection = true; 97*8975f5c5SAndroid Build Coastguard Worker } 98*8975f5c5SAndroid Build Coastguard Worker 99*8975f5c5SAndroid Build Coastguard Worker if (contextVk->getFeatures().supportsTransformFeedbackExtension.enabled) 100*8975f5c5SAndroid Build Coastguard Worker { 101*8975f5c5SAndroid Build Coastguard Worker options->addVulkanXfbExtensionSupportCode = true; 102*8975f5c5SAndroid Build Coastguard Worker } 103*8975f5c5SAndroid Build Coastguard Worker else if (mState.getShaderType() == gl::ShaderType::Vertex && 104*8975f5c5SAndroid Build Coastguard Worker contextVk->getFeatures().emulateTransformFeedback.enabled) 105*8975f5c5SAndroid Build Coastguard Worker { 106*8975f5c5SAndroid Build Coastguard Worker options->addVulkanXfbEmulationSupportCode = true; 107*8975f5c5SAndroid Build Coastguard Worker } 108*8975f5c5SAndroid Build Coastguard Worker 109*8975f5c5SAndroid Build Coastguard Worker if (contextVk->getFeatures().roundOutputAfterDithering.enabled) 110*8975f5c5SAndroid Build Coastguard Worker { 111*8975f5c5SAndroid Build Coastguard Worker options->roundOutputAfterDithering = true; 112*8975f5c5SAndroid Build Coastguard Worker } 113*8975f5c5SAndroid Build Coastguard Worker 114*8975f5c5SAndroid Build Coastguard Worker if (contextVk->getFeatures().appendAliasedMemoryDecorations.enabled) 115*8975f5c5SAndroid Build Coastguard Worker { 116*8975f5c5SAndroid Build Coastguard Worker options->aliasedUnlessRestrict = true; 117*8975f5c5SAndroid Build Coastguard Worker } 118*8975f5c5SAndroid Build Coastguard Worker 119*8975f5c5SAndroid Build Coastguard Worker if (contextVk->getFeatures().explicitlyCastMediumpFloatTo16Bit.enabled) 120*8975f5c5SAndroid Build Coastguard Worker { 121*8975f5c5SAndroid Build Coastguard Worker options->castMediumpFloatTo16Bit = true; 122*8975f5c5SAndroid Build Coastguard Worker } 123*8975f5c5SAndroid Build Coastguard Worker 124*8975f5c5SAndroid Build Coastguard Worker if (contextVk->getExtensions().shaderPixelLocalStorageANGLE) 125*8975f5c5SAndroid Build Coastguard Worker { 126*8975f5c5SAndroid Build Coastguard Worker options->pls = contextVk->getNativePixelLocalStorageOptions(); 127*8975f5c5SAndroid Build Coastguard Worker } 128*8975f5c5SAndroid Build Coastguard Worker 129*8975f5c5SAndroid Build Coastguard Worker if (contextVk->getFeatures().avoidOpSelectWithMismatchingRelaxedPrecision.enabled) 130*8975f5c5SAndroid Build Coastguard Worker { 131*8975f5c5SAndroid Build Coastguard Worker options->avoidOpSelectWithMismatchingRelaxedPrecision = true; 132*8975f5c5SAndroid Build Coastguard Worker } 133*8975f5c5SAndroid Build Coastguard Worker 134*8975f5c5SAndroid Build Coastguard Worker if (contextVk->getFeatures().wrapSwitchInIfTrue.enabled) 135*8975f5c5SAndroid Build Coastguard Worker { 136*8975f5c5SAndroid Build Coastguard Worker options->wrapSwitchInIfTrue = true; 137*8975f5c5SAndroid Build Coastguard Worker } 138*8975f5c5SAndroid Build Coastguard Worker 139*8975f5c5SAndroid Build Coastguard Worker if (contextVk->getFeatures().emulateR32fImageAtomicExchange.enabled) 140*8975f5c5SAndroid Build Coastguard Worker { 141*8975f5c5SAndroid Build Coastguard Worker options->emulateR32fImageAtomicExchange = true; 142*8975f5c5SAndroid Build Coastguard Worker } 143*8975f5c5SAndroid Build Coastguard Worker 144*8975f5c5SAndroid Build Coastguard Worker // The Vulkan backend needs no post-processing of the translated shader. 145*8975f5c5SAndroid Build Coastguard Worker return std::shared_ptr<ShaderTranslateTask>(new ShaderTranslateTask); 146*8975f5c5SAndroid Build Coastguard Worker } 147*8975f5c5SAndroid Build Coastguard Worker load(const gl::Context * context,gl::BinaryInputStream * stream)148*8975f5c5SAndroid Build Coastguard Workerstd::shared_ptr<ShaderTranslateTask> ShaderVk::load(const gl::Context *context, 149*8975f5c5SAndroid Build Coastguard Worker gl::BinaryInputStream *stream) 150*8975f5c5SAndroid Build Coastguard Worker { 151*8975f5c5SAndroid Build Coastguard Worker return std::shared_ptr<ShaderTranslateTask>(new ShaderTranslateTask); 152*8975f5c5SAndroid Build Coastguard Worker } 153*8975f5c5SAndroid Build Coastguard Worker getDebugInfo() const154*8975f5c5SAndroid Build Coastguard Workerstd::string ShaderVk::getDebugInfo() const 155*8975f5c5SAndroid Build Coastguard Worker { 156*8975f5c5SAndroid Build Coastguard Worker const sh::BinaryBlob &spirv = mState.getCompiledState()->compiledBinary; 157*8975f5c5SAndroid Build Coastguard Worker if (spirv.empty()) 158*8975f5c5SAndroid Build Coastguard Worker { 159*8975f5c5SAndroid Build Coastguard Worker return ""; 160*8975f5c5SAndroid Build Coastguard Worker } 161*8975f5c5SAndroid Build Coastguard Worker 162*8975f5c5SAndroid Build Coastguard Worker std::ostringstream blob; 163*8975f5c5SAndroid Build Coastguard Worker if (!mState.getCompiledState()->inputVaryings.empty()) 164*8975f5c5SAndroid Build Coastguard Worker { 165*8975f5c5SAndroid Build Coastguard Worker blob << "Inputs:"; 166*8975f5c5SAndroid Build Coastguard Worker for (const sh::ShaderVariable &var : mState.getCompiledState()->inputVaryings) 167*8975f5c5SAndroid Build Coastguard Worker { 168*8975f5c5SAndroid Build Coastguard Worker blob << " " << var.name; 169*8975f5c5SAndroid Build Coastguard Worker } 170*8975f5c5SAndroid Build Coastguard Worker blob << std::endl; 171*8975f5c5SAndroid Build Coastguard Worker } 172*8975f5c5SAndroid Build Coastguard Worker if (!mState.getCompiledState()->activeAttributes.empty()) 173*8975f5c5SAndroid Build Coastguard Worker { 174*8975f5c5SAndroid Build Coastguard Worker blob << "Inputs:"; 175*8975f5c5SAndroid Build Coastguard Worker for (const sh::ShaderVariable &var : mState.getCompiledState()->activeAttributes) 176*8975f5c5SAndroid Build Coastguard Worker { 177*8975f5c5SAndroid Build Coastguard Worker blob << " " << var.name; 178*8975f5c5SAndroid Build Coastguard Worker } 179*8975f5c5SAndroid Build Coastguard Worker blob << std::endl; 180*8975f5c5SAndroid Build Coastguard Worker } 181*8975f5c5SAndroid Build Coastguard Worker if (!mState.getCompiledState()->outputVaryings.empty()) 182*8975f5c5SAndroid Build Coastguard Worker { 183*8975f5c5SAndroid Build Coastguard Worker blob << "Outputs:"; 184*8975f5c5SAndroid Build Coastguard Worker for (const sh::ShaderVariable &var : mState.getCompiledState()->outputVaryings) 185*8975f5c5SAndroid Build Coastguard Worker { 186*8975f5c5SAndroid Build Coastguard Worker blob << " " << var.name; 187*8975f5c5SAndroid Build Coastguard Worker } 188*8975f5c5SAndroid Build Coastguard Worker blob << std::endl; 189*8975f5c5SAndroid Build Coastguard Worker } 190*8975f5c5SAndroid Build Coastguard Worker if (!mState.getCompiledState()->activeOutputVariables.empty()) 191*8975f5c5SAndroid Build Coastguard Worker { 192*8975f5c5SAndroid Build Coastguard Worker blob << "Outputs:"; 193*8975f5c5SAndroid Build Coastguard Worker for (const sh::ShaderVariable &var : mState.getCompiledState()->activeOutputVariables) 194*8975f5c5SAndroid Build Coastguard Worker { 195*8975f5c5SAndroid Build Coastguard Worker blob << " " << var.name; 196*8975f5c5SAndroid Build Coastguard Worker } 197*8975f5c5SAndroid Build Coastguard Worker blob << std::endl; 198*8975f5c5SAndroid Build Coastguard Worker } 199*8975f5c5SAndroid Build Coastguard Worker if (!mState.getCompiledState()->uniforms.empty()) 200*8975f5c5SAndroid Build Coastguard Worker { 201*8975f5c5SAndroid Build Coastguard Worker blob << "Uniforms:"; 202*8975f5c5SAndroid Build Coastguard Worker for (const sh::ShaderVariable &var : mState.getCompiledState()->uniforms) 203*8975f5c5SAndroid Build Coastguard Worker { 204*8975f5c5SAndroid Build Coastguard Worker blob << " " << var.name; 205*8975f5c5SAndroid Build Coastguard Worker } 206*8975f5c5SAndroid Build Coastguard Worker blob << std::endl; 207*8975f5c5SAndroid Build Coastguard Worker } 208*8975f5c5SAndroid Build Coastguard Worker if (!mState.getCompiledState()->uniformBlocks.empty()) 209*8975f5c5SAndroid Build Coastguard Worker { 210*8975f5c5SAndroid Build Coastguard Worker blob << "Uniform blocks:"; 211*8975f5c5SAndroid Build Coastguard Worker for (const sh::InterfaceBlock &block : mState.getCompiledState()->uniformBlocks) 212*8975f5c5SAndroid Build Coastguard Worker { 213*8975f5c5SAndroid Build Coastguard Worker blob << " " << block.name; 214*8975f5c5SAndroid Build Coastguard Worker } 215*8975f5c5SAndroid Build Coastguard Worker blob << std::endl; 216*8975f5c5SAndroid Build Coastguard Worker } 217*8975f5c5SAndroid Build Coastguard Worker if (!mState.getCompiledState()->shaderStorageBlocks.empty()) 218*8975f5c5SAndroid Build Coastguard Worker { 219*8975f5c5SAndroid Build Coastguard Worker blob << "Storage blocks:"; 220*8975f5c5SAndroid Build Coastguard Worker for (const sh::InterfaceBlock &block : mState.getCompiledState()->shaderStorageBlocks) 221*8975f5c5SAndroid Build Coastguard Worker { 222*8975f5c5SAndroid Build Coastguard Worker blob << " " << block.name; 223*8975f5c5SAndroid Build Coastguard Worker } 224*8975f5c5SAndroid Build Coastguard Worker blob << std::endl; 225*8975f5c5SAndroid Build Coastguard Worker } 226*8975f5c5SAndroid Build Coastguard Worker 227*8975f5c5SAndroid Build Coastguard Worker blob << R"( 228*8975f5c5SAndroid Build Coastguard Worker Paste the following SPIR-V binary in https://www.khronos.org/spir/visualizer/ or pass to a recent build of `spirv-dis` (optionally with `--comment --nested-indent`) 229*8975f5c5SAndroid Build Coastguard Worker 230*8975f5c5SAndroid Build Coastguard Worker Setting the environment variable ANGLE_FEATURE_OVERRIDES_ENABLED=retainSPIRVDebugInfo will retain debug info 231*8975f5c5SAndroid Build Coastguard Worker 232*8975f5c5SAndroid Build Coastguard Worker )"; 233*8975f5c5SAndroid Build Coastguard Worker 234*8975f5c5SAndroid Build Coastguard Worker constexpr size_t kIndicesPerRow = 10; 235*8975f5c5SAndroid Build Coastguard Worker size_t rowOffset = 0; 236*8975f5c5SAndroid Build Coastguard Worker for (size_t index = 0; index < spirv.size(); ++index, ++rowOffset) 237*8975f5c5SAndroid Build Coastguard Worker { 238*8975f5c5SAndroid Build Coastguard Worker if (rowOffset == kIndicesPerRow) 239*8975f5c5SAndroid Build Coastguard Worker { 240*8975f5c5SAndroid Build Coastguard Worker blob << std::endl; 241*8975f5c5SAndroid Build Coastguard Worker rowOffset = 0; 242*8975f5c5SAndroid Build Coastguard Worker } 243*8975f5c5SAndroid Build Coastguard Worker blob << "0x" << std::uppercase << std::setfill('0') << std::setw(8) << std::hex 244*8975f5c5SAndroid Build Coastguard Worker << spirv[index] << ","; 245*8975f5c5SAndroid Build Coastguard Worker } 246*8975f5c5SAndroid Build Coastguard Worker 247*8975f5c5SAndroid Build Coastguard Worker return blob.str(); 248*8975f5c5SAndroid Build Coastguard Worker } 249*8975f5c5SAndroid Build Coastguard Worker 250*8975f5c5SAndroid Build Coastguard Worker } // namespace rx 251