OpenGL: use Tint for GLSL generation.

Change-Id: Ibced679fa6568f1eb33707f0157d03505e6f8a1c
Bug: dawn:1263
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/67540
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Stephen White <senorblanco@chromium.org>
This commit is contained in:
Stephen White 2022-02-10 22:17:41 +00:00 committed by Dawn LUCI CQ
parent 31f60e3a40
commit 96b72c262c
5 changed files with 129 additions and 106 deletions

View File

@ -269,137 +269,84 @@ namespace dawn::native::opengl {
bool* needsDummySampler) const {
TRACE_EVENT0(GetDevice()->GetPlatform(), General, "TranslateToGLSL");
tint::transform::Manager transformManager;
transformManager.append(std::make_unique<tint::transform::SingleEntryPoint>());
tint::transform::DataMap transformInputs;
transformInputs.Add<tint::transform::SingleEntryPoint::Config>(entryPointName);
AddExternalTextureTransform(layout, &transformManager, &transformInputs);
tint::Program program;
{
TRACE_EVENT0(GetDevice()->GetPlatform(), General, "RunTransforms");
DAWN_TRY_ASSIGN(program, RunTransforms(&transformManager, GetTintProgram(),
transformInputs, nullptr, nullptr));
}
tint::writer::spirv::Options tintOptions;
tintOptions.disable_workgroup_init =
GetDevice()->IsToggleEnabled(Toggle::DisableWorkgroupInit);
std::vector<uint32_t> spirv;
{
TRACE_EVENT0(GetDevice()->GetPlatform(), General, "tint::writer::spirv::Generate");
auto result = tint::writer::spirv::Generate(&program, tintOptions);
DAWN_INVALID_IF(!result.success, "An error occured while generating SPIR-V: %s.",
result.error);
spirv = std::move(result.spirv);
}
DAWN_TRY(
ValidateSpirv(GetDevice(), spirv, GetDevice()->IsToggleEnabled(Toggle::DumpShaders)));
// 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;
DAWN_TRY_ASSIGN(program, RunTransforms(&transformManager, GetTintProgram(), transformInputs,
nullptr, nullptr));
const OpenGLVersion& version = ToBackend(GetDevice())->gl.GetVersion();
if (version.IsDesktop()) {
// The computation of GLSL version below only works for 3.3 and above.
ASSERT(version.IsAtLeast(3, 3));
}
options.es = version.IsES();
options.version = version.GetMajor() * 100 + version.GetMinor() * 10;
spirv_cross::CompilerGLSL compiler(std::move(spirv));
compiler.set_common_options(options);
compiler.set_entry_point(entryPointName, ShaderStageToExecutionModel(stage));
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());
// Analyzes all OpImageFetch opcodes and checks if there are instances where
// said instruction is used without a combined image sampler.
// GLSL does not support texelFetch without a sampler.
// To workaround this, we must inject a dummy sampler which can be used to form a sampler2D
// at the call-site of texelFetch as necessary.
spirv_cross::VariableID dummySamplerId = compiler.build_dummy_sampler_for_combined_images();
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};
// 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()) {
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 (combined.sampler_id == dummySamplerId) {
*needsDummySampler = true;
if (use.sampler_binding_point == placeholderBindingPoint) {
info->useDummySampler = true;
info->samplerLocation = {};
*needsDummySampler = true;
} else {
info->useDummySampler = false;
info->samplerLocation.group = BindGroupIndex(
compiler.get_decoration(combined.sampler_id, spv::DecorationDescriptorSet));
info->samplerLocation.binding = BindingNumber(
compiler.get_decoration(combined.sampler_id, spv::DecorationBinding));
}
info->textureLocation.group = BindGroupIndex(
compiler.get_decoration(combined.image_id, spv::DecorationDescriptorSet));
info->textureLocation.binding =
BindingNumber(compiler.get_decoration(combined.image_id, spv::DecorationBinding));
compiler.set_name(combined.combined_id, info->GetName());
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;
}
const BindingInfoArray& bindingInfo = *(mGLBindings.at(entryPointName));
// 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.
const PipelineLayout::BindingIndexInfo& indices = layout->GetBindingIndexInfo();
// Modify the decoration of variables so that SPIRV-Cross outputs only
// layout(binding=<index>) for interface variables.
//
// Tint is used for the reflection of bindings for the implicit pipeline layout and
// pipeline/layout validation, but bindingInfo is set to mGLEntryPoints which is the
// SPIRV-Cross reflection. Tint reflects bindings used more precisely than SPIRV-Cross so
// some bindings in bindingInfo might not exist in the layout and querying the layout for
// them would cause an ASSERT. That's why we defensively check that bindings are in the
// layout before modifying them. This slight hack is ok because in the long term we will use
// Tint to produce GLSL.
// 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())) {
for (const auto& it : bindingInfo[group]) {
const BindGroupLayoutBase* bgl = layout->GetBindGroupLayout(group);
const BindGroupLayoutBase::BindingMap& bindingMap =
layout->GetBindGroupLayout(group)->GetBindingMap();
for (const auto& it : bindingMap) {
BindingNumber bindingNumber = it.first;
const auto& info = it.second;
if (!bgl->HasBinding(bindingNumber)) {
BindingIndex bindingIndex = it.second;
const BindingInfo& bindingInfo =
layout->GetBindGroupLayout(group)->GetBindingInfo(bindingIndex);
if (!(bindingInfo.visibility & StageBit(stage))) {
continue;
}
// Remove the name of the base type. This works around an issue where if the SPIRV
// has two uniform/storage interface variables that point to the same base type,
// then SPIRV-Cross would emit two bindings with type names that conflict:
//
// layout(binding=0) uniform Buf {...} binding0;
// layout(binding=1) uniform Buf {...} binding1;
compiler.set_name(info.base_type_id, "");
BindingIndex bindingIndex = bgl->GetBindingIndex(bindingNumber);
compiler.unset_decoration(info.id, spv::DecorationDescriptorSet);
compiler.set_decoration(info.id, spv::DecorationBinding,
indices[group][bindingIndex]);
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;
}
std::string glsl = compiler.compile();
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;

View File

@ -1274,6 +1274,10 @@ TEST_P(BufferZeroInitTest, IndirectBufferForDrawIndirect) {
// Test the buffer will be lazily initialized correctly when its first use is an indirect buffer for
// DrawIndexedIndirect.
TEST_P(BufferZeroInitTest, IndirectBufferForDrawIndexedIndirect) {
// TODO(crbug.com/dawn/1292): Some Intel OpenGL drivers don't seem to like
// the offset= that Tint/GLSL produces.
DAWN_SUPPRESS_TEST_IF(IsIntel() && IsOpenGL());
// Bind the whole buffer as an indirect buffer.
{
constexpr uint64_t kOffset = 0u;

View File

@ -444,6 +444,10 @@ TEST_P(DepthCopyTests, FromDepthAspect) {
DAWN_TEST_UNSUPPORTED_IF(GetParam().mTextureFormat == wgpu::TextureFormat::Depth16Unorm &&
(IsOpenGL() || IsOpenGLES()));
// TODO(crbug.com/dawn/1291): These tests are failing on NVidia GLES
// when using Tint/GLSL.
DAWN_TEST_UNSUPPORTED_IF(IsOpenGLES() && IsNvidia());
constexpr uint32_t kWidth = 4;
constexpr uint32_t kHeight = 4;
@ -483,6 +487,10 @@ TEST_P(DepthCopyTests, FromNonZeroMipDepthAspect) {
DAWN_TEST_UNSUPPORTED_IF(GetParam().mTextureFormat == wgpu::TextureFormat::Depth16Unorm &&
(IsOpenGL() || IsOpenGLES()));
// TODO(crbug.com/dawn/1291): These tests are failing on NVidia GLES
// when using Tint/GLSL.
DAWN_TEST_UNSUPPORTED_IF(IsOpenGLES() && IsNvidia());
wgpu::Texture depthTexture = CreateDepthTexture(
9, 9, wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc, 2);

View File

@ -120,6 +120,10 @@ TEST_P(DrawIndexedIndirectTest, Uint32) {
// TODO(crbug.com/dawn/789): Test is failing after a roll on SwANGLE on Windows only.
DAWN_SUPPRESS_TEST_IF(IsANGLE() && IsWindows());
// TODO(crbug.com/dawn/1292): Some Intel OpenGL drivers don't seem to like
// the offsets that Tint/GLSL produces.
DAWN_SUPPRESS_TEST_IF(IsIntel() && IsOpenGL() && IsLinux());
RGBA8 filled(0, 255, 0, 255);
RGBA8 notFilled(0, 0, 0, 0);
@ -147,6 +151,10 @@ TEST_P(DrawIndexedIndirectTest, BaseVertex) {
// doesn't take into account BaseVertex, which breaks programmable vertex pulling.
DAWN_SUPPRESS_TEST_IF(IsMetal() && IsIntel());
// TODO(crbug.com/dawn/1292): Some Intel OpenGL drivers don't seem to like
// the offsets that Tint/GLSL produces.
DAWN_SUPPRESS_TEST_IF(IsIntel() && IsOpenGL() && IsLinux());
RGBA8 filled(0, 255, 0, 255);
RGBA8 notFilled(0, 0, 0, 0);
@ -176,6 +184,10 @@ TEST_P(DrawIndexedIndirectTest, IndirectOffset) {
// doesn't take into account BaseVertex, which breaks programmable vertex pulling.
DAWN_SUPPRESS_TEST_IF(IsMetal() && IsIntel());
// TODO(crbug.com/dawn/1292): Some Intel OpenGL drivers don't seem to like
// the offsets that Tint/GLSL produces.
DAWN_SUPPRESS_TEST_IF(IsIntel() && IsOpenGL() && IsLinux());
RGBA8 filled(0, 255, 0, 255);
RGBA8 notFilled(0, 0, 0, 0);
@ -194,6 +206,10 @@ TEST_P(DrawIndexedIndirectTest, BasicValidation) {
// TODO(crbug.com/dawn/789): Test is failing under SwANGLE on Windows only.
DAWN_SUPPRESS_TEST_IF(IsANGLE() && IsWindows());
// TODO(crbug.com/dawn/1292): Some Intel OpenGL drivers don't seem to like
// the offsets that Tint/GLSL produces.
DAWN_SUPPRESS_TEST_IF(IsIntel() && IsOpenGL() && IsLinux());
// It doesn't make sense to test invalid inputs when validation is disabled.
DAWN_SUPPRESS_TEST_IF(HasToggleEnabled("skip_validation"));
@ -217,6 +233,10 @@ TEST_P(DrawIndexedIndirectTest, ValidateWithOffsets) {
// yet.
DAWN_SUPPRESS_TEST_IF(IsOpenGL() || IsOpenGLES());
// TODO(crbug.com/dawn/1292): Some Intel OpenGL drivers don't seem to like
// the offsets that Tint/GLSL produces.
DAWN_SUPPRESS_TEST_IF(IsIntel() && IsOpenGL() && IsLinux());
// It doesn't make sense to test invalid inputs when validation is disabled.
DAWN_SUPPRESS_TEST_IF(HasToggleEnabled("skip_validation"));
@ -245,6 +265,10 @@ TEST_P(DrawIndexedIndirectTest, ValidateMultiplePasses) {
// TODO(crbug.com/dawn/789): Test is failing under SwANGLE on Windows only.
DAWN_SUPPRESS_TEST_IF(IsANGLE() && IsWindows());
// TODO(crbug.com/dawn/1292): Some Intel OpenGL drivers don't seem to like
// the offsets that Tint/GLSL produces.
DAWN_SUPPRESS_TEST_IF(IsIntel() && IsOpenGL() && IsLinux());
// It doesn't make sense to test invalid inputs when validation is disabled.
DAWN_SUPPRESS_TEST_IF(HasToggleEnabled("skip_validation"));
@ -269,6 +293,10 @@ TEST_P(DrawIndexedIndirectTest, ValidateMultipleDraws) {
// TODO(crbug.com/dawn/789): Test is failing under SwANGLE on Windows only.
DAWN_SUPPRESS_TEST_IF(IsANGLE() && IsWindows());
// TODO(crbug.com/dawn/1292): Some Intel OpenGL drivers don't seem to like
// the offsets that Tint/GLSL produces.
DAWN_SUPPRESS_TEST_IF(IsIntel() && IsOpenGL() && IsLinux());
// It doesn't make sense to test invalid inputs when validation is disabled.
DAWN_SUPPRESS_TEST_IF(HasToggleEnabled("skip_validation"));
@ -365,6 +393,10 @@ TEST_P(DrawIndexedIndirectTest, ValidateEncodeMultipleThenSubmitInOrder) {
// TODO(crbug.com/dawn/789): Test is failing under SwANGLE on Windows only.
DAWN_SUPPRESS_TEST_IF(IsANGLE() && IsWindows());
// TODO(crbug.com/dawn/1292): Some Intel OpenGL drivers don't seem to like
// the offsets that Tint/GLSL produces.
DAWN_SUPPRESS_TEST_IF(IsIntel() && IsOpenGL() && IsLinux());
// It doesn't make sense to test invalid inputs when validation is disabled.
DAWN_SUPPRESS_TEST_IF(HasToggleEnabled("skip_validation"));
@ -399,6 +431,10 @@ TEST_P(DrawIndexedIndirectTest, ValidateEncodeMultipleThenSubmitAtOnce) {
// older than 27.20.100.8587, which bots are actively using.
DAWN_SUPPRESS_TEST_IF(IsIntel() && IsVulkan() && IsWindows());
// TODO(crbug.com/dawn/1292): Some Intel OpenGL drivers don't seem to like
// the offsets that Tint/GLSL produces.
DAWN_SUPPRESS_TEST_IF(IsIntel() && IsOpenGL() && IsLinux());
// It doesn't make sense to test invalid inputs when validation is disabled.
DAWN_SUPPRESS_TEST_IF(HasToggleEnabled("skip_validation"));
@ -423,6 +459,10 @@ TEST_P(DrawIndexedIndirectTest, ValidateEncodeMultipleThenSubmitOutOfOrder) {
// TODO(crbug.com/dawn/789): Test is failing under SwANGLE on Windows only.
DAWN_SUPPRESS_TEST_IF(IsANGLE() && IsWindows());
// TODO(crbug.com/dawn/1292): Some Intel OpenGL drivers don't seem to like
// the offsets that Tint/GLSL produces.
DAWN_SUPPRESS_TEST_IF(IsIntel() && IsOpenGL() && IsLinux());
// It doesn't make sense to test invalid inputs when validation is disabled.
DAWN_SUPPRESS_TEST_IF(HasToggleEnabled("skip_validation"));
@ -453,6 +493,10 @@ TEST_P(DrawIndexedIndirectTest, ValidateWithBundlesInSamePass) {
// TODO(crbug.com/dawn/789): Test is failing under SwANGLE on Windows only.
DAWN_SUPPRESS_TEST_IF(IsANGLE() && IsWindows());
// TODO(crbug.com/dawn/1292): Some Intel OpenGL drivers don't seem to like
// the offsets that Tint/GLSL produces.
DAWN_SUPPRESS_TEST_IF(IsIntel() && IsOpenGL() && IsLinux());
// It doesn't make sense to test invalid inputs when validation is disabled.
DAWN_SUPPRESS_TEST_IF(HasToggleEnabled("skip_validation"));
@ -504,6 +548,10 @@ TEST_P(DrawIndexedIndirectTest, ValidateWithBundlesInDifferentPasses) {
// TODO(crbug.com/dawn/789): Test is failing under SwANGLE on Windows only.
DAWN_SUPPRESS_TEST_IF(IsANGLE() && IsWindows());
// TODO(crbug.com/dawn/1292): Some Intel OpenGL drivers don't seem to like
// the offsets that Tint/GLSL produces.
DAWN_SUPPRESS_TEST_IF(IsIntel() && IsOpenGL() && IsLinux());
// It doesn't make sense to test invalid inputs when validation is disabled.
DAWN_SUPPRESS_TEST_IF(HasToggleEnabled("skip_validation"));
@ -572,6 +620,10 @@ TEST_P(DrawIndexedIndirectTest, ValidateReusedBundleWithChangingParams) {
// older than 27.20.100.8587, which bots are actively using.
DAWN_SUPPRESS_TEST_IF(IsIntel() && IsVulkan() && IsWindows());
// TODO(crbug.com/dawn/1292): Some Intel OpenGL drivers don't seem to like
// the offsets that Tint/GLSL produces.
DAWN_SUPPRESS_TEST_IF(IsIntel() && IsOpenGL() && IsLinux());
// It doesn't make sense to test invalid inputs when validation is disabled.
DAWN_SUPPRESS_TEST_IF(HasToggleEnabled("skip_validation"));

View File

@ -97,6 +97,10 @@ TEST_P(OpArrayLengthTest, Compute) {
// Nvidia OpenGL.
DAWN_SUPPRESS_TEST_IF(IsNvidia() && (IsOpenGL() || IsOpenGLES()));
// TODO(crbug.com/dawn/1292): Some Intel drivers don't seem to like the
// (spurious but harmless) offset=64 that Tint/GLSL produces.
DAWN_SUPPRESS_TEST_IF(IsIntel() && IsOpenGL());
// Create a buffer to hold the result sizes and create a bindgroup for it.
wgpu::BufferDescriptor bufferDesc;
bufferDesc.usage = wgpu::BufferUsage::Storage | wgpu::BufferUsage::CopySrc;
@ -154,6 +158,10 @@ TEST_P(OpArrayLengthTest, Fragment) {
// Nvidia OpenGL.
DAWN_SUPPRESS_TEST_IF(IsNvidia() && (IsOpenGL() || IsOpenGLES()));
// TODO(crbug.com/dawn/1292): Some Intel drivers don't seem to like the
// (spurious but harmless) offset=64 that Tint/GLSL produces.
DAWN_SUPPRESS_TEST_IF(IsIntel() && IsOpenGL());
utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, 1, 1);
// Create the pipeline that computes the length of the buffers and writes it to the only render
@ -206,6 +214,10 @@ TEST_P(OpArrayLengthTest, Vertex) {
DAWN_SUPPRESS_TEST_IF(IsNvidia() && IsOpenGL());
DAWN_SUPPRESS_TEST_IF(IsOpenGLES());
// TODO(crbug.com/dawn/1292): Some Intel drivers don't seem to like the
// (spurious but harmless) offset=64 that Tint/GLSL produces.
DAWN_SUPPRESS_TEST_IF(IsIntel() && IsOpenGL());
utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, 1, 1);
// Create the pipeline that computes the length of the buffers and writes it to the only render