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