mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-06-05 06:03:34 +00:00
Deprecates the computeStage member of the descriptor in favor of compute as described by the spec. In order to support both variants without breaking backwards compatibility some code had to be manually added to the wire client to copy from the deprecated member to the new one and visa versa. Change-Id: I9d5c2fc9c446c927c5792c9af9ed56c90060b65b Bug: dawn:800 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/53884 Commit-Queue: Brandon Jones <bajones@chromium.org> Reviewed-by: Corentin Wallez <cwallez@chromium.org>
314 lines
11 KiB
C++
314 lines
11 KiB
C++
// Copyright 2021 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 "tests/DawnTest.h"
|
|
|
|
#include "utils/ComboRenderPipelineDescriptor.h"
|
|
#include "utils/WGPUHelpers.h"
|
|
|
|
#include <vector>
|
|
|
|
class ShaderTests : public DawnTest {};
|
|
|
|
// Test that log2 is being properly calculated, base on crbug.com/1046622
|
|
TEST_P(ShaderTests, ComputeLog2) {
|
|
uint32_t const kSteps = 19;
|
|
std::vector<uint32_t> data(kSteps, 0);
|
|
std::vector<uint32_t> expected{0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 32};
|
|
uint64_t bufferSize = static_cast<uint64_t>(data.size() * sizeof(uint32_t));
|
|
wgpu::Buffer buffer = utils::CreateBufferFromData(
|
|
device, data.data(), bufferSize, wgpu::BufferUsage::Storage | wgpu::BufferUsage::CopySrc);
|
|
|
|
std::string shader = R"(
|
|
[[block]] struct Buf {
|
|
data : array<u32, 19>;
|
|
};
|
|
|
|
[[group(0), binding(0)]] var<storage, read_write> buf : Buf;
|
|
|
|
[[stage(compute)]] fn main() {
|
|
let factor : f32 = 1.0001;
|
|
|
|
buf.data[0] = u32(log2(1.0 * factor));
|
|
buf.data[1] = u32(log2(2.0 * factor));
|
|
buf.data[2] = u32(log2(3.0 * factor));
|
|
buf.data[3] = u32(log2(4.0 * factor));
|
|
buf.data[4] = u32(log2(7.0 * factor));
|
|
buf.data[5] = u32(log2(8.0 * factor));
|
|
buf.data[6] = u32(log2(15.0 * factor));
|
|
buf.data[7] = u32(log2(16.0 * factor));
|
|
buf.data[8] = u32(log2(31.0 * factor));
|
|
buf.data[9] = u32(log2(32.0 * factor));
|
|
buf.data[10] = u32(log2(63.0 * factor));
|
|
buf.data[11] = u32(log2(64.0 * factor));
|
|
buf.data[12] = u32(log2(127.0 * factor));
|
|
buf.data[13] = u32(log2(128.0 * factor));
|
|
buf.data[14] = u32(log2(255.0 * factor));
|
|
buf.data[15] = u32(log2(256.0 * factor));
|
|
buf.data[16] = u32(log2(511.0 * factor));
|
|
buf.data[17] = u32(log2(512.0 * factor));
|
|
buf.data[18] = u32(log2(4294967295.0 * factor));
|
|
})";
|
|
|
|
wgpu::ComputePipelineDescriptor csDesc;
|
|
csDesc.compute.module = utils::CreateShaderModule(device, shader.c_str());
|
|
csDesc.compute.entryPoint = "main";
|
|
wgpu::ComputePipeline pipeline = device.CreateComputePipeline(&csDesc);
|
|
|
|
wgpu::BindGroup bindGroup =
|
|
utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0), {{0, buffer}});
|
|
|
|
wgpu::CommandBuffer commands;
|
|
{
|
|
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
|
wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
|
|
pass.SetPipeline(pipeline);
|
|
pass.SetBindGroup(0, bindGroup);
|
|
pass.Dispatch(1);
|
|
pass.EndPass();
|
|
|
|
commands = encoder.Finish();
|
|
}
|
|
|
|
queue.Submit(1, &commands);
|
|
|
|
EXPECT_BUFFER_U32_RANGE_EQ(expected.data(), buffer, 0, kSteps);
|
|
}
|
|
|
|
TEST_P(ShaderTests, BadWGSL) {
|
|
DAWN_TEST_UNSUPPORTED_IF(HasToggleEnabled("skip_validation"));
|
|
|
|
std::string shader = R"(
|
|
I am an invalid shader and should never pass validation!
|
|
})";
|
|
ASSERT_DEVICE_ERROR(utils::CreateShaderModule(device, shader.c_str()));
|
|
}
|
|
|
|
// Tests that shaders using non-struct function parameters and return values for shader stage I/O
|
|
// can compile and link successfully.
|
|
TEST_P(ShaderTests, WGSLParamIO) {
|
|
std::string vertexShader = R"(
|
|
[[stage(vertex)]]
|
|
fn main([[builtin(vertex_index)]] VertexIndex : u32) -> [[builtin(position)]] vec4<f32> {
|
|
let pos : array<vec2<f32>, 3> = array<vec2<f32>, 3>(
|
|
vec2<f32>(-1.0, 1.0),
|
|
vec2<f32>( 1.0, 1.0),
|
|
vec2<f32>( 0.0, -1.0));
|
|
return vec4<f32>(pos[VertexIndex], 0.0, 1.0);
|
|
})";
|
|
wgpu::ShaderModule vsModule = utils::CreateShaderModule(device, vertexShader.c_str());
|
|
|
|
std::string fragmentShader = R"(
|
|
[[stage(fragment)]]
|
|
fn main([[builtin(position)]] fragCoord : vec4<f32>) -> [[location(0)]] vec4<f32> {
|
|
return vec4<f32>(fragCoord.xy, 0.0, 1.0);
|
|
})";
|
|
wgpu::ShaderModule fsModule = utils::CreateShaderModule(device, fragmentShader.c_str());
|
|
|
|
utils::ComboRenderPipelineDescriptor rpDesc;
|
|
rpDesc.vertex.module = vsModule;
|
|
rpDesc.cFragment.module = fsModule;
|
|
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&rpDesc);
|
|
}
|
|
|
|
// Tests that a vertex shader using struct function parameters and return values for shader stage
|
|
// I/O can compile and link successfully against a fragement shader using compatible non-struct I/O.
|
|
TEST_P(ShaderTests, WGSLMixedStructParamIO) {
|
|
std::string vertexShader = R"(
|
|
struct VertexIn {
|
|
[[location(0)]] position : vec3<f32>;
|
|
[[location(1)]] color : vec4<f32>;
|
|
};
|
|
|
|
struct VertexOut {
|
|
[[location(0)]] color : vec4<f32>;
|
|
[[builtin(position)]] position : vec4<f32>;
|
|
};
|
|
|
|
[[stage(vertex)]]
|
|
fn main(input : VertexIn) -> VertexOut {
|
|
var output : VertexOut;
|
|
output.position = vec4<f32>(input.position, 1.0);
|
|
output.color = input.color;
|
|
return output;
|
|
})";
|
|
wgpu::ShaderModule vsModule = utils::CreateShaderModule(device, vertexShader.c_str());
|
|
|
|
std::string fragmentShader = R"(
|
|
[[stage(fragment)]]
|
|
fn main([[location(0)]] color : vec4<f32>) -> [[location(0)]] vec4<f32> {
|
|
return color;
|
|
})";
|
|
wgpu::ShaderModule fsModule = utils::CreateShaderModule(device, fragmentShader.c_str());
|
|
|
|
utils::ComboRenderPipelineDescriptor rpDesc;
|
|
rpDesc.vertex.module = vsModule;
|
|
rpDesc.cFragment.module = fsModule;
|
|
rpDesc.vertex.bufferCount = 1;
|
|
rpDesc.cBuffers[0].attributeCount = 2;
|
|
rpDesc.cBuffers[0].arrayStride = 28;
|
|
rpDesc.cAttributes[0].shaderLocation = 0;
|
|
rpDesc.cAttributes[0].format = wgpu::VertexFormat::Float32x3;
|
|
rpDesc.cAttributes[1].shaderLocation = 1;
|
|
rpDesc.cAttributes[1].format = wgpu::VertexFormat::Float32x4;
|
|
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&rpDesc);
|
|
}
|
|
|
|
// Tests that shaders using struct function parameters and return values for shader stage I/O
|
|
// can compile and link successfully.
|
|
TEST_P(ShaderTests, WGSLStructIO) {
|
|
std::string vertexShader = R"(
|
|
struct VertexIn {
|
|
[[location(0)]] position : vec3<f32>;
|
|
[[location(1)]] color : vec4<f32>;
|
|
};
|
|
|
|
struct VertexOut {
|
|
[[location(0)]] color : vec4<f32>;
|
|
[[builtin(position)]] position : vec4<f32>;
|
|
};
|
|
|
|
[[stage(vertex)]]
|
|
fn main(input : VertexIn) -> VertexOut {
|
|
var output : VertexOut;
|
|
output.position = vec4<f32>(input.position, 1.0);
|
|
output.color = input.color;
|
|
return output;
|
|
})";
|
|
wgpu::ShaderModule vsModule = utils::CreateShaderModule(device, vertexShader.c_str());
|
|
|
|
std::string fragmentShader = R"(
|
|
struct FragmentIn {
|
|
[[location(0)]] color : vec4<f32>;
|
|
[[builtin(position)]] fragCoord : vec4<f32>;
|
|
};
|
|
|
|
[[stage(fragment)]]
|
|
fn main(input : FragmentIn) -> [[location(0)]] vec4<f32> {
|
|
return input.color * input.fragCoord;
|
|
})";
|
|
wgpu::ShaderModule fsModule = utils::CreateShaderModule(device, fragmentShader.c_str());
|
|
|
|
utils::ComboRenderPipelineDescriptor rpDesc;
|
|
rpDesc.vertex.module = vsModule;
|
|
rpDesc.cFragment.module = fsModule;
|
|
rpDesc.vertex.bufferCount = 1;
|
|
rpDesc.cBuffers[0].attributeCount = 2;
|
|
rpDesc.cBuffers[0].arrayStride = 28;
|
|
rpDesc.cAttributes[0].shaderLocation = 0;
|
|
rpDesc.cAttributes[0].format = wgpu::VertexFormat::Float32x3;
|
|
rpDesc.cAttributes[1].shaderLocation = 1;
|
|
rpDesc.cAttributes[1].format = wgpu::VertexFormat::Float32x4;
|
|
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&rpDesc);
|
|
}
|
|
|
|
// Tests that shaders I/O structs that us compatible locations but are not sorted by hand can link.
|
|
TEST_P(ShaderTests, WGSLUnsortedStructIO) {
|
|
std::string vertexShader = R"(
|
|
struct VertexIn {
|
|
[[location(0)]] position : vec3<f32>;
|
|
[[location(1)]] color : vec4<f32>;
|
|
};
|
|
|
|
struct VertexOut {
|
|
[[builtin(position)]] position : vec4<f32>;
|
|
[[location(0)]] color : vec4<f32>;
|
|
};
|
|
|
|
[[stage(vertex)]]
|
|
fn main(input : VertexIn) -> VertexOut {
|
|
var output : VertexOut;
|
|
output.position = vec4<f32>(input.position, 1.0);
|
|
output.color = input.color;
|
|
return output;
|
|
})";
|
|
wgpu::ShaderModule vsModule = utils::CreateShaderModule(device, vertexShader.c_str());
|
|
|
|
std::string fragmentShader = R"(
|
|
struct FragmentIn {
|
|
[[location(0)]] color : vec4<f32>;
|
|
[[builtin(position)]] fragCoord : vec4<f32>;
|
|
};
|
|
|
|
[[stage(fragment)]]
|
|
fn main(input : FragmentIn) -> [[location(0)]] vec4<f32> {
|
|
return input.color * input.fragCoord;
|
|
})";
|
|
wgpu::ShaderModule fsModule = utils::CreateShaderModule(device, fragmentShader.c_str());
|
|
|
|
utils::ComboRenderPipelineDescriptor rpDesc;
|
|
rpDesc.vertex.module = vsModule;
|
|
rpDesc.cFragment.module = fsModule;
|
|
rpDesc.vertex.bufferCount = 1;
|
|
rpDesc.cBuffers[0].attributeCount = 2;
|
|
rpDesc.cBuffers[0].arrayStride = 28;
|
|
rpDesc.cAttributes[0].shaderLocation = 0;
|
|
rpDesc.cAttributes[0].format = wgpu::VertexFormat::Float32x3;
|
|
rpDesc.cAttributes[1].shaderLocation = 1;
|
|
rpDesc.cAttributes[1].format = wgpu::VertexFormat::Float32x4;
|
|
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&rpDesc);
|
|
}
|
|
|
|
// Tests that shaders I/O structs can be shared between vertex and fragment shaders.
|
|
TEST_P(ShaderTests, WGSLSharedStructIO) {
|
|
// TODO(tint:714): Not yet implemeneted in tint yet, but intended to work.
|
|
DAWN_SUPPRESS_TEST_IF(IsD3D12() || IsVulkan() || IsMetal() || IsOpenGL() || IsOpenGLES());
|
|
|
|
std::string shader = R"(
|
|
struct VertexIn {
|
|
[[location(0)]] position : vec3<f32>;
|
|
[[location(1)]] color : vec4<f32>;
|
|
};
|
|
|
|
struct VertexOut {
|
|
[[location(0)]] color : vec4<f32>;
|
|
[[builtin(position)]] position : vec4<f32>;
|
|
};
|
|
|
|
[[stage(vertex)]]
|
|
fn vertexMain(input : VertexIn) -> VertexOut {
|
|
var output : VertexOut;
|
|
output.position = vec4<f32>(input.position, 1.0);
|
|
output.color = input.color;
|
|
return output;
|
|
}
|
|
|
|
[[stage(fragment)]]
|
|
fn fragmentMain(input : VertexOut) -> [[location(0)]] vec4<f32> {
|
|
return input.color;
|
|
})";
|
|
wgpu::ShaderModule shaderModule = utils::CreateShaderModule(device, shader.c_str());
|
|
|
|
utils::ComboRenderPipelineDescriptor rpDesc;
|
|
rpDesc.vertex.module = shaderModule;
|
|
rpDesc.vertex.entryPoint = "vertexMain";
|
|
rpDesc.cFragment.module = shaderModule;
|
|
rpDesc.cFragment.entryPoint = "fragmentMain";
|
|
rpDesc.vertex.bufferCount = 1;
|
|
rpDesc.cBuffers[0].attributeCount = 2;
|
|
rpDesc.cBuffers[0].arrayStride = 28;
|
|
rpDesc.cAttributes[0].shaderLocation = 0;
|
|
rpDesc.cAttributes[0].format = wgpu::VertexFormat::Float32x3;
|
|
rpDesc.cAttributes[1].shaderLocation = 1;
|
|
rpDesc.cAttributes[1].format = wgpu::VertexFormat::Float32x4;
|
|
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&rpDesc);
|
|
}
|
|
|
|
DAWN_INSTANTIATE_TEST(ShaderTests,
|
|
D3D12Backend(),
|
|
MetalBackend(),
|
|
OpenGLBackend(),
|
|
OpenGLESBackend(),
|
|
VulkanBackend());
|