1 // Copyright 2017 The Dawn Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include "dawn_native/opengl/ShaderModuleGL.h" 16 17 #include "common/Assert.h" 18 #include "common/Platform.h" 19 #include "dawn_native/opengl/DeviceGL.h" 20 21 #include <spirv_glsl.hpp> 22 23 #include <sstream> 24 25 namespace dawn_native { namespace opengl { 26 GetBindingName(uint32_t group,uint32_t binding)27 std::string GetBindingName(uint32_t group, uint32_t binding) { 28 std::ostringstream o; 29 o << "dawn_binding_" << group << "_" << binding; 30 return o.str(); 31 } 32 operator <(const BindingLocation & a,const BindingLocation & b)33 bool operator<(const BindingLocation& a, const BindingLocation& b) { 34 return std::tie(a.group, a.binding) < std::tie(b.group, b.binding); 35 } 36 operator <(const CombinedSampler & a,const CombinedSampler & b)37 bool operator<(const CombinedSampler& a, const CombinedSampler& b) { 38 return std::tie(a.samplerLocation, a.textureLocation) < 39 std::tie(b.samplerLocation, b.textureLocation); 40 } 41 GetName() const42 std::string CombinedSampler::GetName() const { 43 std::ostringstream o; 44 o << "dawn_combined"; 45 o << "_" << samplerLocation.group << "_" << samplerLocation.binding; 46 o << "_with_" << textureLocation.group << "_" << textureLocation.binding; 47 return o.str(); 48 } 49 50 // static Create(Device * device,const ShaderModuleDescriptor * descriptor)51 ResultOrError<ShaderModule*> ShaderModule::Create(Device* device, 52 const ShaderModuleDescriptor* descriptor) { 53 std::unique_ptr<ShaderModule> module(new ShaderModule(device, descriptor)); 54 if (!module) 55 return DAWN_VALIDATION_ERROR("Unable to create ShaderModule"); 56 DAWN_TRY(module->Initialize(descriptor)); 57 return module.release(); 58 } 59 GetSource() const60 const char* ShaderModule::GetSource() const { 61 return mGlslSource.c_str(); 62 } 63 GetCombinedSamplerInfo() const64 const ShaderModule::CombinedSamplerInfo& ShaderModule::GetCombinedSamplerInfo() const { 65 return mCombinedInfo; 66 } 67 ShaderModule(Device * device,const ShaderModuleDescriptor * descriptor)68 ShaderModule::ShaderModule(Device* device, const ShaderModuleDescriptor* descriptor) 69 : ShaderModuleBase(device, descriptor) { 70 } 71 Initialize(const ShaderModuleDescriptor * descriptor)72 MaybeError ShaderModule::Initialize(const ShaderModuleDescriptor* descriptor) { 73 std::unique_ptr<spirv_cross::CompilerGLSL> compiler_impl; 74 spirv_cross::CompilerGLSL* compiler; 75 76 if (GetDevice()->IsToggleEnabled(Toggle::UseSpvc)) { 77 // If these options are changed, the values in DawnSPIRVCrossGLSLFastFuzzer.cpp need to 78 // be updated. 79 shaderc_spvc::CompileOptions options = GetCompileOptions(); 80 81 // The range of Z-coordinate in the clipping volume of OpenGL is [-w, w], while it is 82 // [0, w] in D3D12, Metal and Vulkan, so we should normalize it in shaders in all 83 // backends. See the documentation of 84 // spirv_cross::CompilerGLSL::Options::vertex::fixup_clipspace for more details. 85 options.SetFlipVertY(true); 86 options.SetFixupClipspace(true); 87 88 // TODO(cwallez@chromium.org): discover the backing context version and use that. 89 #if defined(DAWN_PLATFORM_APPLE) 90 options.SetGLSLLanguageVersion(410); 91 #else 92 options.SetGLSLLanguageVersion(440); 93 #endif 94 DAWN_TRY(CheckSpvcSuccess( 95 mSpvcContext.InitializeForGlsl(descriptor->code, descriptor->codeSize, options), 96 "Unable to initialize instance of spvc")); 97 DAWN_TRY(CheckSpvcSuccess(mSpvcContext.GetCompiler(reinterpret_cast<void**>(&compiler)), 98 "Unable to get cross compiler")); 99 } else { 100 // If these options are changed, the values in DawnSPIRVCrossGLSLFastFuzzer.cpp need to 101 // be updated. 102 spirv_cross::CompilerGLSL::Options options; 103 104 // The range of Z-coordinate in the clipping volume of OpenGL is [-w, w], while it is 105 // [0, w] in D3D12, Metal and Vulkan, so we should normalize it in shaders in all 106 // backends. See the documentation of 107 // spirv_cross::CompilerGLSL::Options::vertex::fixup_clipspace for more details. 108 options.vertex.flip_vert_y = true; 109 options.vertex.fixup_clipspace = true; 110 111 // TODO(cwallez@chromium.org): discover the backing context version and use that. 112 #if defined(DAWN_PLATFORM_APPLE) 113 options.version = 410; 114 #else 115 options.version = 440; 116 #endif 117 118 compiler_impl = 119 std::make_unique<spirv_cross::CompilerGLSL>(descriptor->code, descriptor->codeSize); 120 compiler = compiler_impl.get(); 121 compiler->set_common_options(options); 122 } 123 124 DAWN_TRY(ExtractSpirvInfo(*compiler)); 125 126 const ShaderModuleBase::ModuleBindingInfo& bindingInfo = GetBindingInfo(); 127 128 // Extract bindings names so that it can be used to get its location in program. 129 // Now translate the separate sampler / textures into combined ones and store their info. 130 // We need to do this before removing the set and binding decorations. 131 if (GetDevice()->IsToggleEnabled(Toggle::UseSpvc)) { 132 mSpvcContext.BuildCombinedImageSamplers(); 133 } else { 134 compiler->build_combined_image_samplers(); 135 } 136 137 if (GetDevice()->IsToggleEnabled(Toggle::UseSpvc)) { 138 std::vector<shaderc_spvc_combined_image_sampler> samplers; 139 mSpvcContext.GetCombinedImageSamplers(&samplers); 140 for (auto sampler : samplers) { 141 mCombinedInfo.emplace_back(); 142 auto& info = mCombinedInfo.back(); 143 144 mSpvcContext.GetDecoration(sampler.sampler_id, 145 shaderc_spvc_decoration_descriptorset, 146 &info.samplerLocation.group); 147 mSpvcContext.GetDecoration(sampler.sampler_id, shaderc_spvc_decoration_binding, 148 &info.samplerLocation.binding); 149 mSpvcContext.GetDecoration(sampler.image_id, shaderc_spvc_decoration_descriptorset, 150 &info.textureLocation.group); 151 mSpvcContext.GetDecoration(sampler.image_id, shaderc_spvc_decoration_binding, 152 &info.textureLocation.binding); 153 mSpvcContext.SetName(sampler.combined_id, info.GetName()); 154 } 155 } else { 156 for (const auto& combined : compiler->get_combined_image_samplers()) { 157 mCombinedInfo.emplace_back(); 158 159 auto& info = mCombinedInfo.back(); 160 info.samplerLocation.group = 161 compiler->get_decoration(combined.sampler_id, spv::DecorationDescriptorSet); 162 info.samplerLocation.binding = 163 compiler->get_decoration(combined.sampler_id, spv::DecorationBinding); 164 info.textureLocation.group = 165 compiler->get_decoration(combined.image_id, spv::DecorationDescriptorSet); 166 info.textureLocation.binding = 167 compiler->get_decoration(combined.image_id, spv::DecorationBinding); 168 compiler->set_name(combined.combined_id, info.GetName()); 169 } 170 } 171 172 // Change binding names to be "dawn_binding_<group>_<binding>". 173 // Also unsets the SPIRV "Binding" decoration as it outputs "layout(binding=)" which 174 // isn't supported on OSX's OpenGL. 175 for (uint32_t group = 0; group < kMaxBindGroups; ++group) { 176 for (const auto& it : bindingInfo[group]) { 177 BindingNumber bindingNumber = it.first; 178 const auto& info = it.second; 179 180 if (GetDevice()->IsToggleEnabled(Toggle::UseSpvc)) { 181 mSpvcContext.SetName(info.base_type_id, GetBindingName(group, bindingNumber)); 182 mSpvcContext.UnsetDecoration(info.id, shaderc_spvc_decoration_binding); 183 mSpvcContext.UnsetDecoration(info.id, shaderc_spvc_decoration_descriptorset); 184 } else { 185 compiler->set_name(info.base_type_id, GetBindingName(group, bindingNumber)); 186 compiler->unset_decoration(info.id, spv::DecorationBinding); 187 compiler->unset_decoration(info.id, spv::DecorationDescriptorSet); 188 } 189 } 190 } 191 192 if (GetDevice()->IsToggleEnabled(Toggle::UseSpvc)) { 193 shaderc_spvc::CompilationResult result; 194 DAWN_TRY(CheckSpvcSuccess(mSpvcContext.CompileShader(&result), 195 "Unable to compile GLSL shader using spvc")); 196 DAWN_TRY(CheckSpvcSuccess(result.GetStringOutput(&mGlslSource), 197 "Unable to get GLSL shader text")); 198 } else { 199 mGlslSource = compiler->compile(); 200 } 201 return {}; 202 } 203 204 }} // namespace dawn_native::opengl 205