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->emulateSeamfulCubeMapSampling()) 74 { 75 options->emulateSeamfulCubeMapSampling = true; 76 } 77 78 if (!contextVk->getFeatures().enablePrecisionQualifiers.enabled) 79 { 80 options->ignorePrecisionQualifiers = true; 81 } 82 83 if (contextVk->getFeatures().forceFragmentShaderPrecisionHighpToMediump.enabled) 84 { 85 options->forceShaderPrecisionHighpToMediump = true; 86 } 87 88 // Let compiler use specialized constant for pre-rotation. 89 if (!contextVk->getFeatures().preferDriverUniformOverSpecConst.enabled) 90 { 91 options->useSpecializationConstant = true; 92 } 93 94 if (contextVk->getFeatures().clampFragDepth.enabled) 95 { 96 options->clampFragDepth = true; 97 } 98 99 if (!contextVk->getFeatures().supportsDepthClipControl.enabled) 100 { 101 options->addVulkanDepthCorrection = true; 102 } 103 104 if (contextVk->getFeatures().supportsTransformFeedbackExtension.enabled) 105 { 106 options->addVulkanXfbExtensionSupportCode = true; 107 } 108 else if (mState.getShaderType() == gl::ShaderType::Vertex && 109 contextVk->getFeatures().emulateTransformFeedback.enabled) 110 { 111 options->addVulkanXfbEmulationSupportCode = true; 112 } 113 114 if (contextVk->getFeatures().roundOutputAfterDithering.enabled) 115 { 116 options->roundOutputAfterDithering = true; 117 } 118 119 if (contextVk->getFeatures().appendAliasedMemoryDecorations.enabled) 120 { 121 options->aliasedUnlessRestrict = true; 122 } 123 124 if (contextVk->getFeatures().explicitlyCastMediumpFloatTo16Bit.enabled) 125 { 126 options->castMediumpFloatTo16Bit = true; 127 } 128 129 if (contextVk->getExtensions().shaderPixelLocalStorageANGLE) 130 { 131 options->pls = contextVk->getNativePixelLocalStorageOptions(); 132 } 133 134 if (contextVk->getFeatures().avoidOpSelectWithMismatchingRelaxedPrecision.enabled) 135 { 136 options->avoidOpSelectWithMismatchingRelaxedPrecision = true; 137 } 138 139 // The Vulkan backend needs no post-processing of the translated shader. 140 return std::shared_ptr<ShaderTranslateTask>(new ShaderTranslateTask); 141 } 142 getDebugInfo() const143std::string ShaderVk::getDebugInfo() const 144 { 145 const sh::BinaryBlob &spirv = mState.getCompiledState()->compiledBinary; 146 if (spirv.empty()) 147 { 148 return ""; 149 } 150 151 std::ostringstream blob; 152 if (!mState.getCompiledState()->inputVaryings.empty()) 153 { 154 blob << "Inputs:"; 155 for (const sh::ShaderVariable &var : mState.getCompiledState()->inputVaryings) 156 { 157 blob << " " << var.name; 158 } 159 blob << std::endl; 160 } 161 if (!mState.getCompiledState()->activeAttributes.empty()) 162 { 163 blob << "Inputs:"; 164 for (const sh::ShaderVariable &var : mState.getCompiledState()->activeAttributes) 165 { 166 blob << " " << var.name; 167 } 168 blob << std::endl; 169 } 170 if (!mState.getCompiledState()->outputVaryings.empty()) 171 { 172 blob << "Outputs:"; 173 for (const sh::ShaderVariable &var : mState.getCompiledState()->outputVaryings) 174 { 175 blob << " " << var.name; 176 } 177 blob << std::endl; 178 } 179 if (!mState.getCompiledState()->activeOutputVariables.empty()) 180 { 181 blob << "Outputs:"; 182 for (const sh::ShaderVariable &var : mState.getCompiledState()->activeOutputVariables) 183 { 184 blob << " " << var.name; 185 } 186 blob << std::endl; 187 } 188 if (!mState.getCompiledState()->uniforms.empty()) 189 { 190 blob << "Uniforms:"; 191 for (const sh::ShaderVariable &var : mState.getCompiledState()->uniforms) 192 { 193 blob << " " << var.name; 194 } 195 blob << std::endl; 196 } 197 if (!mState.getCompiledState()->uniformBlocks.empty()) 198 { 199 blob << "Uniform blocks:"; 200 for (const sh::InterfaceBlock &block : mState.getCompiledState()->uniformBlocks) 201 { 202 blob << " " << block.name; 203 } 204 blob << std::endl; 205 } 206 if (!mState.getCompiledState()->shaderStorageBlocks.empty()) 207 { 208 blob << "Storage blocks:"; 209 for (const sh::InterfaceBlock &block : mState.getCompiledState()->shaderStorageBlocks) 210 { 211 blob << " " << block.name; 212 } 213 blob << std::endl; 214 } 215 216 blob << R"( 217 Paste the following SPIR-V binary in https://www.khronos.org/spir/visualizer/ 218 219 Setting the environment variable ANGLE_FEATURE_OVERRIDES_ENABLED=retainSPIRVDebugInfo will retain debug info 220 221 )"; 222 223 constexpr size_t kIndicesPerRow = 10; 224 size_t rowOffset = 0; 225 for (size_t index = 0; index < spirv.size(); ++index, ++rowOffset) 226 { 227 if (rowOffset == kIndicesPerRow) 228 { 229 blob << std::endl; 230 rowOffset = 0; 231 } 232 blob << "0x" << std::uppercase << std::setfill('0') << std::setw(8) << std::hex 233 << spirv[index] << ","; 234 } 235 236 return blob.str(); 237 } 238 239 } // namespace rx 240