| // Copyright 2017 The Dawn Authors |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "dawn/native/opengl/ShaderModuleGL.h" |
| |
| #include "dawn/native/BindGroupLayout.h" |
| #include "dawn/native/TintUtils.h" |
| #include "dawn/native/opengl/DeviceGL.h" |
| #include "dawn/native/opengl/PipelineLayoutGL.h" |
| #include "dawn/platform/DawnPlatform.h" |
| #include "dawn/platform/tracing/TraceEvent.h" |
| |
| #include <tint/tint.h> |
| |
| #include <sstream> |
| |
| namespace dawn::native::opengl { |
| |
| std::string GetBindingName(BindGroupIndex group, BindingNumber bindingNumber) { |
| std::ostringstream o; |
| o << "dawn_binding_" << static_cast<uint32_t>(group) << "_" |
| << static_cast<uint32_t>(bindingNumber); |
| return o.str(); |
| } |
| |
| bool operator<(const BindingLocation& a, const BindingLocation& b) { |
| return std::tie(a.group, a.binding) < std::tie(b.group, b.binding); |
| } |
| |
| bool operator<(const CombinedSampler& a, const CombinedSampler& b) { |
| return std::tie(a.useDummySampler, a.samplerLocation, a.textureLocation) < |
| std::tie(b.useDummySampler, a.samplerLocation, b.textureLocation); |
| } |
| |
| std::string CombinedSampler::GetName() const { |
| std::ostringstream o; |
| o << "dawn_combined"; |
| if (useDummySampler) { |
| o << "_dummy_sampler"; |
| } else { |
| o << "_" << static_cast<uint32_t>(samplerLocation.group) << "_" |
| << static_cast<uint32_t>(samplerLocation.binding); |
| } |
| o << "_with_" << static_cast<uint32_t>(textureLocation.group) << "_" |
| << static_cast<uint32_t>(textureLocation.binding); |
| return o.str(); |
| } |
| |
| // static |
| ResultOrError<Ref<ShaderModule>> ShaderModule::Create(Device* device, |
| const ShaderModuleDescriptor* descriptor, |
| ShaderModuleParseResult* parseResult) { |
| Ref<ShaderModule> module = AcquireRef(new ShaderModule(device, descriptor)); |
| DAWN_TRY(module->Initialize(parseResult)); |
| return module; |
| } |
| |
| ShaderModule::ShaderModule(Device* device, const ShaderModuleDescriptor* descriptor) |
| : ShaderModuleBase(device, descriptor) { |
| } |
| |
| MaybeError ShaderModule::Initialize(ShaderModuleParseResult* parseResult) { |
| ScopedTintICEHandler scopedICEHandler(GetDevice()); |
| |
| DAWN_TRY(InitializeBase(parseResult)); |
| |
| return {}; |
| } |
| |
| ResultOrError<std::string> ShaderModule::TranslateToGLSL(const char* entryPointName, |
| SingleShaderStage stage, |
| CombinedSamplerInfo* combinedSamplers, |
| const PipelineLayout* layout, |
| bool* needsDummySampler) const { |
| TRACE_EVENT0(GetDevice()->GetPlatform(), General, "TranslateToGLSL"); |
| tint::transform::Manager transformManager; |
| tint::transform::DataMap transformInputs; |
| |
| AddExternalTextureTransform(layout, &transformManager, &transformInputs); |
| |
| tint::Program program; |
| DAWN_TRY_ASSIGN(program, RunTransforms(&transformManager, GetTintProgram(), transformInputs, |
| nullptr, nullptr)); |
| const OpenGLVersion& version = ToBackend(GetDevice())->gl.GetVersion(); |
| |
| tint::writer::glsl::Options tintOptions; |
| using Version = tint::writer::glsl::Version; |
| tintOptions.version = |
| Version(version.IsDesktop() ? Version::Standard::kDesktop : Version::Standard::kES, |
| version.GetMajor(), version.GetMinor()); |
| |
| using tint::transform::BindingPoint; |
| // When textures are accessed without a sampler (e.g., textureLoad()), |
| // GetSamplerTextureUses() will return this sentinel value. |
| BindingPoint placeholderBindingPoint{static_cast<uint32_t>(kMaxBindGroupsTyped), 0}; |
| |
| tint::inspector::Inspector inspector(&program); |
| // Find all the sampler/texture pairs for this entry point, and create |
| // CombinedSamplers for them. CombinedSampler records the binding points |
| // of the original texture and sampler, and generates a unique name. The |
| // corresponding uniforms will be retrieved by these generated names |
| // in PipelineGL. Any texture-only references will have |
| // "useDummySampler" set to true, and only the texture binding point |
| // will be used in naming them. In addition, Dawn will bind a |
| // non-filtering sampler for them (see PipelineGL). |
| auto uses = inspector.GetSamplerTextureUses(entryPointName, placeholderBindingPoint); |
| for (const auto& use : uses) { |
| combinedSamplers->emplace_back(); |
| |
| CombinedSampler* info = &combinedSamplers->back(); |
| if (use.sampler_binding_point == placeholderBindingPoint) { |
| info->useDummySampler = true; |
| *needsDummySampler = true; |
| } else { |
| info->useDummySampler = false; |
| } |
| info->samplerLocation.group = BindGroupIndex(use.sampler_binding_point.group); |
| info->samplerLocation.binding = BindingNumber(use.sampler_binding_point.binding); |
| info->textureLocation.group = BindGroupIndex(use.texture_binding_point.group); |
| info->textureLocation.binding = BindingNumber(use.texture_binding_point.binding); |
| tintOptions.binding_map[use] = info->GetName(); |
| } |
| if (*needsDummySampler) { |
| tintOptions.placeholder_binding_point = placeholderBindingPoint; |
| } |
| |
| // Since (non-Vulkan) GLSL does not support descriptor sets, generate a |
| // mapping from the original group/binding pair to a binding-only |
| // value. This mapping will be used by Tint to remap all global |
| // variables to the 1D space. |
| for (BindGroupIndex group : IterateBitSet(layout->GetBindGroupLayoutsMask())) { |
| const BindGroupLayoutBase::BindingMap& bindingMap = |
| layout->GetBindGroupLayout(group)->GetBindingMap(); |
| for (const auto& it : bindingMap) { |
| BindingNumber bindingNumber = it.first; |
| BindingIndex bindingIndex = it.second; |
| const BindingInfo& bindingInfo = |
| layout->GetBindGroupLayout(group)->GetBindingInfo(bindingIndex); |
| if (!(bindingInfo.visibility & StageBit(stage))) { |
| continue; |
| } |
| |
| uint32_t shaderIndex = layout->GetBindingIndexInfo()[group][bindingIndex]; |
| BindingPoint srcBindingPoint{static_cast<uint32_t>(group), |
| static_cast<uint32_t>(bindingNumber)}; |
| BindingPoint dstBindingPoint{0, shaderIndex}; |
| tintOptions.binding_points.emplace(srcBindingPoint, dstBindingPoint); |
| } |
| tintOptions.allow_collisions = true; |
| } |
| auto result = tint::writer::glsl::Generate(&program, tintOptions, entryPointName); |
| DAWN_INVALID_IF(!result.success, "An error occured while generating GLSL: %s.", |
| result.error); |
| std::string glsl = std::move(result.glsl); |
| |
| if (GetDevice()->IsToggleEnabled(Toggle::DumpShaders)) { |
| std::ostringstream dumpedMsg; |
| dumpedMsg << "/* Dumped generated GLSL */" << std::endl << glsl; |
| |
| GetDevice()->EmitLog(WGPULoggingType_Info, dumpedMsg.str().c_str()); |
| } |
| |
| return glsl; |
| } |
| |
| } // namespace dawn::native::opengl |