blob: e1138420a040c5c6a0648a54b260e9ed5a4e411f [file] [log] [blame]
// 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 "common/Assert.h"
#include "common/Platform.h"
#include "dawn_native/opengl/DeviceGL.h"
#include <spirv_glsl.hpp>
#include <sstream>
namespace dawn_native { namespace opengl {
std::string GetBindingName(uint32_t group, uint32_t binding) {
std::ostringstream o;
o << "dawn_binding_" << group << "_" << binding;
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.samplerLocation, a.textureLocation) <
std::tie(b.samplerLocation, b.textureLocation);
}
std::string CombinedSampler::GetName() const {
std::ostringstream o;
o << "dawn_combined";
o << "_" << samplerLocation.group << "_" << samplerLocation.binding;
o << "_with_" << textureLocation.group << "_" << textureLocation.binding;
return o.str();
}
// static
ResultOrError<ShaderModule*> ShaderModule::Create(Device* device,
const ShaderModuleDescriptor* descriptor) {
std::unique_ptr<ShaderModule> module(new ShaderModule(device, descriptor));
if (!module)
return DAWN_VALIDATION_ERROR("Unable to create ShaderModule");
DAWN_TRY(module->Initialize(descriptor));
return module.release();
}
const char* ShaderModule::GetSource() const {
return mGlslSource.c_str();
}
const ShaderModule::CombinedSamplerInfo& ShaderModule::GetCombinedSamplerInfo() const {
return mCombinedInfo;
}
ShaderModule::ShaderModule(Device* device, const ShaderModuleDescriptor* descriptor)
: ShaderModuleBase(device, descriptor) {
}
MaybeError ShaderModule::Initialize(const ShaderModuleDescriptor* descriptor) {
std::unique_ptr<spirv_cross::CompilerGLSL> compiler_impl;
spirv_cross::CompilerGLSL* compiler;
if (GetDevice()->IsToggleEnabled(Toggle::UseSpvc)) {
// If these options are changed, the values in DawnSPIRVCrossGLSLFastFuzzer.cpp need to
// be updated.
shaderc_spvc::CompileOptions options;
// The range of Z-coordinate in the clipping volume of OpenGL is [-w, w], while it is
// [0, w] in D3D12, Metal and Vulkan, so we should normalize it in shaders in all
// backends. See the documentation of
// spirv_cross::CompilerGLSL::Options::vertex::fixup_clipspace for more details.
options.SetFlipVertY(true);
options.SetFixupClipspace(true);
// TODO(cwallez@chromium.org): discover the backing context version and use that.
#if defined(DAWN_PLATFORM_APPLE)
options.SetGLSLLanguageVersion(410);
#else
options.SetGLSLLanguageVersion(440);
#endif
shaderc_spvc_status status =
mSpvcContext.InitializeForGlsl(descriptor->code, descriptor->codeSize, options);
if (status != shaderc_spvc_status_success)
return DAWN_VALIDATION_ERROR("Unable to initialize instance of spvc");
compiler = reinterpret_cast<spirv_cross::CompilerGLSL*>(mSpvcContext.GetCompiler());
} else {
// If these options are changed, the values in DawnSPIRVCrossGLSLFastFuzzer.cpp need to
// be updated.
spirv_cross::CompilerGLSL::Options options;
// The range of Z-coordinate in the clipping volume of OpenGL is [-w, w], while it is
// [0, w] in D3D12, Metal and Vulkan, so we should normalize it in shaders in all
// backends. See the documentation of
// spirv_cross::CompilerGLSL::Options::vertex::fixup_clipspace for more details.
options.vertex.flip_vert_y = true;
options.vertex.fixup_clipspace = true;
// TODO(cwallez@chromium.org): discover the backing context version and use that.
#if defined(DAWN_PLATFORM_APPLE)
options.version = 410;
#else
options.version = 440;
#endif
compiler_impl =
std::make_unique<spirv_cross::CompilerGLSL>(descriptor->code, descriptor->codeSize);
compiler = compiler_impl.get();
compiler->set_common_options(options);
}
ExtractSpirvInfo(*compiler);
const auto& bindingInfo = GetBindingInfo();
// Extract bindings names so that it can be used to get its location in program.
// Now translate the separate sampler / textures into combined ones and store their info.
// We need to do this before removing the set and binding decorations.
compiler->build_combined_image_samplers();
for (const auto& combined : compiler->get_combined_image_samplers()) {
mCombinedInfo.emplace_back();
auto& info = mCombinedInfo.back();
info.samplerLocation.group =
compiler->get_decoration(combined.sampler_id, spv::DecorationDescriptorSet);
info.samplerLocation.binding =
compiler->get_decoration(combined.sampler_id, spv::DecorationBinding);
info.textureLocation.group =
compiler->get_decoration(combined.image_id, spv::DecorationDescriptorSet);
info.textureLocation.binding =
compiler->get_decoration(combined.image_id, spv::DecorationBinding);
compiler->set_name(combined.combined_id, info.GetName());
}
// Change binding names to be "dawn_binding_<group>_<binding>".
// Also unsets the SPIRV "Binding" decoration as it outputs "layout(binding=)" which
// isn't supported on OSX's OpenGL.
for (uint32_t group = 0; group < kMaxBindGroups; ++group) {
for (uint32_t binding = 0; binding < kMaxBindingsPerGroup; ++binding) {
const auto& info = bindingInfo[group][binding];
if (info.used) {
compiler->set_name(info.base_type_id, GetBindingName(group, binding));
compiler->unset_decoration(info.id, spv::DecorationBinding);
compiler->unset_decoration(info.id, spv::DecorationDescriptorSet);
}
}
}
if (GetDevice()->IsToggleEnabled(Toggle::UseSpvc)) {
shaderc_spvc::CompilationResult result;
shaderc_spvc_status status = mSpvcContext.CompileShader(&result);
if (status != shaderc_spvc_status_success)
return DAWN_VALIDATION_ERROR("Unable to compile shader using spvc");
mGlslSource = result.GetStringOutput();
} else {
mGlslSource = compiler->compile();
}
return {};
}
}} // namespace dawn_native::opengl