Autoformat all tests and examples

Bug: none
Change-Id: I69904944db1d4c2fbcca74bb8b66b5a7524e76bb
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/24642
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Kai Ninomiya <kainino@chromium.org>
This commit is contained in:
Kai Ninomiya 2020-07-10 20:33:08 +00:00 committed by Commit Bot service account
parent 3d80b5c378
commit 2afea0c671
83 changed files with 3604 additions and 3481 deletions

View File

@ -18,8 +18,8 @@
#include "utils/SystemUtils.h" #include "utils/SystemUtils.h"
#include "utils/WGPUHelpers.h" #include "utils/WGPUHelpers.h"
#include <cstdlib>
#include <cstdio> #include <cstdio>
#include <cstdlib>
#include <vector> #include <vector>
wgpu::Device device; wgpu::Device device;
@ -138,8 +138,7 @@ void init() {
bufferDesc.usage = wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::Uniform; bufferDesc.usage = wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::Uniform;
ubo = device.CreateBuffer(&bufferDesc); ubo = device.CreateBuffer(&bufferDesc);
bindGroup = bindGroup = utils::MakeBindGroup(device, bgl, {{0, ubo, 0, sizeof(ShaderData)}});
utils::MakeBindGroup(device, bgl, {{0, ubo, 0, sizeof(ShaderData)}});
} }
void frame() { void frame() {

View File

@ -49,9 +49,7 @@ static_library("dawn_sample_utils") {
# Template for samples to avoid listing dawn_sample_utils as a dep every time # Template for samples to avoid listing dawn_sample_utils as a dep every time
template("dawn_sample") { template("dawn_sample") {
executable(target_name) { executable(target_name) {
deps = [ deps = [ ":dawn_sample_utils" ]
":dawn_sample_utils",
]
forward_variables_from(invoker, "*", [ "deps" ]) forward_variables_from(invoker, "*", [ "deps" ])
if (defined(invoker.deps)) { if (defined(invoker.deps)) {
@ -61,43 +59,27 @@ template("dawn_sample") {
} }
dawn_sample("CppHelloTriangle") { dawn_sample("CppHelloTriangle") {
sources = [ sources = [ "CppHelloTriangle.cpp" ]
"CppHelloTriangle.cpp",
]
} }
dawn_sample("CHelloTriangle") { dawn_sample("CHelloTriangle") {
sources = [ sources = [ "CHelloTriangle.cpp" ]
"CHelloTriangle.cpp",
]
} }
dawn_sample("ComputeBoids") { dawn_sample("ComputeBoids") {
sources = [ sources = [ "ComputeBoids.cpp" ]
"ComputeBoids.cpp", deps = [ "${dawn_root}/third_party/gn/glm" ]
]
deps = [
"${dawn_root}/third_party/gn/glm",
]
} }
dawn_sample("Animometer") { dawn_sample("Animometer") {
sources = [ sources = [ "Animometer.cpp" ]
"Animometer.cpp",
]
} }
dawn_sample("CubeReflection") { dawn_sample("CubeReflection") {
sources = [ sources = [ "CubeReflection.cpp" ]
"CubeReflection.cpp", deps = [ "${dawn_root}/third_party/gn/glm" ]
]
deps = [
"${dawn_root}/third_party/gn/glm",
]
} }
dawn_sample("ManualSwapChainTest") { dawn_sample("ManualSwapChainTest") {
sources = [ sources = [ "ManualSwapChainTest.cpp" ]
"ManualSwapChainTest.cpp",
]
} }

View File

@ -120,7 +120,7 @@ void frame() {
{ {
colorAttachment.attachment = backbufferView; colorAttachment.attachment = backbufferView;
colorAttachment.resolveTarget = nullptr; colorAttachment.resolveTarget = nullptr;
colorAttachment.clearColor = { 0.0f, 0.0f, 0.0f, 0.0f }; colorAttachment.clearColor = {0.0f, 0.0f, 0.0f, 0.0f};
colorAttachment.loadOp = WGPULoadOp_Clear; colorAttachment.loadOp = WGPULoadOp_Clear;
colorAttachment.storeOp = WGPUStoreOp_Store; colorAttachment.storeOp = WGPUStoreOp_Store;
renderpassInfo.colorAttachmentCount = 1; renderpassInfo.colorAttachmentCount = 1;

View File

@ -67,7 +67,7 @@ void initBuffers() {
modelBuffer = modelBuffer =
utils::CreateBufferFromData(device, model, sizeof(model), wgpu::BufferUsage::Vertex); utils::CreateBufferFromData(device, model, sizeof(model), wgpu::BufferUsage::Vertex);
SimParams params = { 0.04f, 0.1f, 0.025f, 0.025f, 0.02f, 0.05f, 0.005f, kNumParticles }; SimParams params = {0.04f, 0.1f, 0.025f, 0.025f, 0.02f, 0.05f, 0.005f, kNumParticles};
updateParams = updateParams =
utils::CreateBufferFromData(device, &params, sizeof(params), wgpu::BufferUsage::Uniform); utils::CreateBufferFromData(device, &params, sizeof(params), wgpu::BufferUsage::Uniform);
@ -75,8 +75,7 @@ void initBuffers() {
{ {
std::mt19937 generator; std::mt19937 generator;
std::uniform_real_distribution<float> dist(-1.0f, 1.0f); std::uniform_real_distribution<float> dist(-1.0f, 1.0f);
for (auto& p : initialParticles) for (auto& p : initialParticles) {
{
p.pos = glm::vec2(dist(generator), dist(generator)); p.pos = glm::vec2(dist(generator), dist(generator));
p.vel = glm::vec2(dist(generator), dist(generator)) * 0.1f; p.vel = glm::vec2(dist(generator), dist(generator)) * 0.1f;
} }
@ -253,11 +252,13 @@ void initSim() {
updatePipeline = device.CreateComputePipeline(&csDesc); updatePipeline = device.CreateComputePipeline(&csDesc);
for (uint32_t i = 0; i < 2; ++i) { for (uint32_t i = 0; i < 2; ++i) {
updateBGs[i] = utils::MakeBindGroup(device, bgl, { updateBGs[i] = utils::MakeBindGroup(
{0, updateParams, 0, sizeof(SimParams)}, device, bgl,
{1, particleBuffers[i], 0, kNumParticles * sizeof(Particle)}, {
{2, particleBuffers[(i + 1) % 2], 0, kNumParticles * sizeof(Particle)}, {0, updateParams, 0, sizeof(SimParams)},
}); {1, particleBuffers[i], 0, kNumParticles * sizeof(Particle)},
{2, particleBuffers[(i + 1) % 2], 0, kNumParticles * sizeof(Particle)},
});
} }
} }

View File

@ -36,15 +36,15 @@ wgpu::BindGroup bindGroup;
void initBuffers() { void initBuffers() {
static const uint32_t indexData[3] = { static const uint32_t indexData[3] = {
0, 1, 2, 0,
1,
2,
}; };
indexBuffer = indexBuffer =
utils::CreateBufferFromData(device, indexData, sizeof(indexData), wgpu::BufferUsage::Index); utils::CreateBufferFromData(device, indexData, sizeof(indexData), wgpu::BufferUsage::Index);
static const float vertexData[12] = { static const float vertexData[12] = {
0.0f, 0.5f, 0.0f, 1.0f, 0.0f, 0.5f, 0.0f, 1.0f, -0.5f, -0.5f, 0.0f, 1.0f, 0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, 0.0f, 1.0f,
}; };
vertexBuffer = utils::CreateBufferFromData(device, vertexData, sizeof(vertexData), vertexBuffer = utils::CreateBufferFromData(device, vertexData, sizeof(vertexData),
wgpu::BufferUsage::Vertex); wgpu::BufferUsage::Vertex);
@ -141,17 +141,19 @@ void init() {
wgpu::TextureView view = texture.CreateView(); wgpu::TextureView view = texture.CreateView();
bindGroup = utils::MakeBindGroup(device, bgl, { bindGroup = utils::MakeBindGroup(device, bgl, {{0, sampler}, {1, view}});
{0, sampler},
{1, view}
});
} }
struct {uint32_t a; float b;} s; struct {
uint32_t a;
float b;
} s;
void frame() { void frame() {
s.a = (s.a + 1) % 256; s.a = (s.a + 1) % 256;
s.b += 0.02f; s.b += 0.02f;
if (s.b >= 1.0f) {s.b = 0.0f;} if (s.b >= 1.0f) {
s.b = 0.0f;
}
wgpu::TextureView backbufferView = swapchain.GetCurrentTextureView(); wgpu::TextureView backbufferView = swapchain.GetCurrentTextureView();
utils::ComboRenderPassDescriptor renderPass({backbufferView}, depthStencilView); utils::ComboRenderPassDescriptor renderPass({backbufferView}, depthStencilView);

View File

@ -18,10 +18,10 @@
#include "utils/SystemUtils.h" #include "utils/SystemUtils.h"
#include "utils/WGPUHelpers.h" #include "utils/WGPUHelpers.h"
#include <vector>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp> #include <glm/gtc/type_ptr.hpp>
#include <vector>
wgpu::Device device; wgpu::Device device;
@ -43,67 +43,44 @@ wgpu::RenderPipeline planePipeline;
wgpu::RenderPipeline reflectionPipeline; wgpu::RenderPipeline reflectionPipeline;
void initBuffers() { void initBuffers() {
static const uint32_t indexData[6*6] = { static const uint32_t indexData[6 * 6] = {0, 1, 2, 0, 2, 3,
0, 1, 2,
0, 2, 3,
4, 5, 6, 4, 5, 6, 4, 6, 7,
4, 6, 7,
8, 9, 10, 8, 9, 10, 8, 10, 11,
8, 10, 11,
12, 13, 14, 12, 13, 14, 12, 14, 15,
12, 14, 15,
16, 17, 18, 16, 17, 18, 16, 18, 19,
16, 18, 19,
20, 21, 22, 20, 21, 22, 20, 22, 23};
20, 22, 23
};
indexBuffer = indexBuffer =
utils::CreateBufferFromData(device, indexData, sizeof(indexData), wgpu::BufferUsage::Index); utils::CreateBufferFromData(device, indexData, sizeof(indexData), wgpu::BufferUsage::Index);
static const float vertexData[6 * 4 * 6] = { static const float vertexData[6 * 4 * 6] = {
-1.0, -1.0, 1.0, 1.0, 0.0, 0.0, -1.0, -1.0, 1.0, 1.0, 0.0, 0.0, 1.0, -1.0, 1.0, 1.0, 0.0, 0.0,
1.0, -1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, -1.0, 1.0, 1.0, 1.0, 0.0, 0.0,
1.0, 1.0, 1.0, 1.0, 0.0, 0.0,
-1.0, 1.0, 1.0, 1.0, 0.0, 0.0,
-1.0, -1.0, -1.0, 1.0, 1.0, 0.0, -1.0, -1.0, -1.0, 1.0, 1.0, 0.0, -1.0, 1.0, -1.0, 1.0, 1.0, 0.0,
-1.0, 1.0, -1.0, 1.0, 1.0, 0.0, 1.0, 1.0, -1.0, 1.0, 1.0, 0.0, 1.0, -1.0, -1.0, 1.0, 1.0, 0.0,
1.0, 1.0, -1.0, 1.0, 1.0, 0.0,
1.0, -1.0, -1.0, 1.0, 1.0, 0.0,
-1.0, 1.0, -1.0, 1.0, 0.0, 1.0, -1.0, 1.0, -1.0, 1.0, 0.0, 1.0, -1.0, 1.0, 1.0, 1.0, 0.0, 1.0,
-1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, -1.0, 1.0, 0.0, 1.0,
1.0, 1.0, 1.0, 1.0, 0.0, 1.0,
1.0, 1.0, -1.0, 1.0, 0.0, 1.0,
-1.0, -1.0, -1.0, 0.0, 1.0, 0.0, -1.0, -1.0, -1.0, 0.0, 1.0, 0.0, 1.0, -1.0, -1.0, 0.0, 1.0, 0.0,
1.0, -1.0, -1.0, 0.0, 1.0, 0.0, 1.0, -1.0, 1.0, 0.0, 1.0, 0.0, -1.0, -1.0, 1.0, 0.0, 1.0, 0.0,
1.0, -1.0, 1.0, 0.0, 1.0, 0.0,
-1.0, -1.0, 1.0, 0.0, 1.0, 0.0,
1.0, -1.0, -1.0, 0.0, 1.0, 1.0, 1.0, -1.0, -1.0, 0.0, 1.0, 1.0, 1.0, 1.0, -1.0, 0.0, 1.0, 1.0,
1.0, 1.0, -1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, -1.0, 1.0, 0.0, 1.0, 1.0,
1.0, 1.0, 1.0, 0.0, 1.0, 1.0,
1.0, -1.0, 1.0, 0.0, 1.0, 1.0,
-1.0, -1.0, -1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0,
-1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0};
-1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
-1.0, 1.0, -1.0, 1.0, 1.0, 1.0
};
vertexBuffer = utils::CreateBufferFromData(device, vertexData, sizeof(vertexData), vertexBuffer = utils::CreateBufferFromData(device, vertexData, sizeof(vertexData),
wgpu::BufferUsage::Vertex); wgpu::BufferUsage::Vertex);
static const float planeData[6 * 4] = { static const float planeData[6 * 4] = {
-2.0, -1.0, -2.0, 0.5, 0.5, 0.5, -2.0, -1.0, -2.0, 0.5, 0.5, 0.5, 2.0, -1.0, -2.0, 0.5, 0.5, 0.5,
2.0, -1.0, -2.0, 0.5, 0.5, 0.5, 2.0, -1.0, 2.0, 0.5, 0.5, 0.5, -2.0, -1.0, 2.0, 0.5, 0.5, 0.5,
2.0, -1.0, 2.0, 0.5, 0.5, 0.5,
-2.0, -1.0, 2.0, 0.5, 0.5, 0.5,
}; };
planeBuffer = utils::CreateBufferFromData(device, planeData, sizeof(planeData), planeBuffer = utils::CreateBufferFromData(device, planeData, sizeof(planeData),
wgpu::BufferUsage::Vertex); wgpu::BufferUsage::Vertex);
@ -191,15 +168,13 @@ void init() {
transformBuffer[1] = utils::CreateBufferFromData(device, &transform, sizeof(glm::mat4), transformBuffer[1] = utils::CreateBufferFromData(device, &transform, sizeof(glm::mat4),
wgpu::BufferUsage::Uniform); wgpu::BufferUsage::Uniform);
bindGroup[0] = utils::MakeBindGroup(device, bgl, { bindGroup[0] = utils::MakeBindGroup(
{0, cameraBuffer, 0, sizeof(CameraData)}, device, bgl,
{1, transformBuffer[0], 0, sizeof(glm::mat4)} {{0, cameraBuffer, 0, sizeof(CameraData)}, {1, transformBuffer[0], 0, sizeof(glm::mat4)}});
});
bindGroup[1] = utils::MakeBindGroup(device, bgl, { bindGroup[1] = utils::MakeBindGroup(
{0, cameraBuffer, 0, sizeof(CameraData)}, device, bgl,
{1, transformBuffer[1], 0, sizeof(glm::mat4)} {{0, cameraBuffer, 0, sizeof(CameraData)}, {1, transformBuffer[1], 0, sizeof(glm::mat4)}});
});
depthStencilView = CreateDefaultDepthStencilView(device); depthStencilView = CreateDefaultDepthStencilView(device);
@ -250,17 +225,20 @@ void init() {
cameraData.proj = glm::perspective(glm::radians(45.0f), 1.f, 1.0f, 100.0f); cameraData.proj = glm::perspective(glm::radians(45.0f), 1.f, 1.0f, 100.0f);
} }
struct {uint32_t a; float b;} s; struct {
uint32_t a;
float b;
} s;
void frame() { void frame() {
s.a = (s.a + 1) % 256; s.a = (s.a + 1) % 256;
s.b += 0.01f; s.b += 0.01f;
if (s.b >= 1.0f) {s.b = 0.0f;} if (s.b >= 1.0f) {
s.b = 0.0f;
}
cameraData.view = glm::lookAt( cameraData.view = glm::lookAt(glm::vec3(8.f * std::sin(glm::radians(s.b * 360.f)), 2.f,
glm::vec3(8.f * std::sin(glm::radians(s.b * 360.f)), 2.f, 8.f * std::cos(glm::radians(s.b * 360.f))), 8.f * std::cos(glm::radians(s.b * 360.f))),
glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
glm::vec3(0.0f, 1.0f, 0.0f)
);
queue.WriteBuffer(cameraBuffer, 0, &cameraData, sizeof(CameraData)); queue.WriteBuffer(cameraBuffer, 0, &cameraData, sizeof(CameraData));

View File

@ -150,7 +150,8 @@ void DoRender(WindowData* data) {
utils::ComboRenderPassDescriptor desc({view}); utils::ComboRenderPassDescriptor desc({view});
desc.cColorAttachments[0].loadOp = wgpu::LoadOp::Clear; desc.cColorAttachments[0].loadOp = wgpu::LoadOp::Clear;
desc.cColorAttachments[0].clearColor = {data->clearCycle, 1.0f - data->clearCycle, 0.0f, 1.0f}; desc.cColorAttachments[0].clearColor = {data->clearCycle, 1.0f - data->clearCycle, 0.0f,
1.0f};
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&desc); wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&desc);
pass.EndPass(); pass.EndPass();

View File

@ -60,7 +60,7 @@ void PrintGLFWError(int code, const char* message) {
enum class CmdBufType { enum class CmdBufType {
None, None,
Terrible, Terrible,
//TODO(cwallez@chromium.org) double terrible cmdbuf // TODO(cwallez@chromium.org): double terrible cmdbuf
}; };
// Default to D3D12, Metal, Vulkan, OpenGL in that order as D3D12 and Metal are the preferred on // Default to D3D12, Metal, Vulkan, OpenGL in that order as D3D12 and Metal are the preferred on
@ -74,7 +74,7 @@ static wgpu::BackendType backendType = wgpu::BackendType::Vulkan;
#elif defined(DAWN_ENABLE_BACKEND_OPENGL) #elif defined(DAWN_ENABLE_BACKEND_OPENGL)
static wgpu::BackendType backendType = wgpu::BackendType::OpenGL; static wgpu::BackendType backendType = wgpu::BackendType::OpenGL;
#else #else
#error # error
#endif #endif
static CmdBufType cmdBufType = CmdBufType::Terrible; static CmdBufType cmdBufType = CmdBufType::Terrible;
@ -136,31 +136,29 @@ wgpu::Device CreateCppDawnDevice() {
cDevice = backendDevice; cDevice = backendDevice;
break; break;
case CmdBufType::Terrible: case CmdBufType::Terrible: {
{ c2sBuf = new utils::TerribleCommandBuffer();
c2sBuf = new utils::TerribleCommandBuffer(); s2cBuf = new utils::TerribleCommandBuffer();
s2cBuf = new utils::TerribleCommandBuffer();
dawn_wire::WireServerDescriptor serverDesc = {}; dawn_wire::WireServerDescriptor serverDesc = {};
serverDesc.device = backendDevice; serverDesc.device = backendDevice;
serverDesc.procs = &backendProcs; serverDesc.procs = &backendProcs;
serverDesc.serializer = s2cBuf; serverDesc.serializer = s2cBuf;
wireServer = new dawn_wire::WireServer(serverDesc); wireServer = new dawn_wire::WireServer(serverDesc);
c2sBuf->SetHandler(wireServer); c2sBuf->SetHandler(wireServer);
dawn_wire::WireClientDescriptor clientDesc = {}; dawn_wire::WireClientDescriptor clientDesc = {};
clientDesc.serializer = c2sBuf; clientDesc.serializer = c2sBuf;
wireClient = new dawn_wire::WireClient(clientDesc); wireClient = new dawn_wire::WireClient(clientDesc);
WGPUDevice clientDevice = wireClient->GetDevice(); WGPUDevice clientDevice = wireClient->GetDevice();
DawnProcTable clientProcs = dawn_wire::WireClient::GetProcs(); DawnProcTable clientProcs = dawn_wire::WireClient::GetProcs();
s2cBuf->SetHandler(wireClient); s2cBuf->SetHandler(wireClient);
procs = clientProcs; procs = clientProcs;
cDevice = clientDevice; cDevice = clientDevice;
} } break;
break;
} }
dawnProcSetProcs(&procs); dawnProcSetProcs(&procs);
@ -221,7 +219,8 @@ bool InitSample(int argc, const char** argv) {
backendType = wgpu::BackendType::Vulkan; backendType = wgpu::BackendType::Vulkan;
continue; continue;
} }
fprintf(stderr, "--backend expects a backend name (opengl, metal, d3d12, null, vulkan)\n"); fprintf(stderr,
"--backend expects a backend name (opengl, metal, d3d12, null, vulkan)\n");
return false; return false;
} }
if (std::string("-c") == argv[i] || std::string("--command-buffer") == argv[i]) { if (std::string("-c") == argv[i] || std::string("--command-buffer") == argv[i]) {

View File

@ -16,8 +16,7 @@
#include "utils/WGPUHelpers.h" #include "utils/WGPUHelpers.h"
class BasicTests : public DawnTest { class BasicTests : public DawnTest {};
};
// Test adapter filter by vendor id. // Test adapter filter by vendor id.
TEST_P(BasicTests, VendorIdFilter) { TEST_P(BasicTests, VendorIdFilter) {

View File

@ -22,102 +22,102 @@
constexpr static uint32_t kRTSize = 8; constexpr static uint32_t kRTSize = 8;
class BindGroupTests : public DawnTest { class BindGroupTests : public DawnTest {
protected: protected:
wgpu::CommandBuffer CreateSimpleComputeCommandBuffer(const wgpu::ComputePipeline& pipeline, wgpu::CommandBuffer CreateSimpleComputeCommandBuffer(const wgpu::ComputePipeline& pipeline,
const wgpu::BindGroup& bindGroup) { const wgpu::BindGroup& bindGroup) {
wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::ComputePassEncoder pass = encoder.BeginComputePass(); wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
pass.SetPipeline(pipeline); pass.SetPipeline(pipeline);
pass.SetBindGroup(0, bindGroup); pass.SetBindGroup(0, bindGroup);
pass.Dispatch(1); pass.Dispatch(1);
pass.EndPass(); pass.EndPass();
return encoder.Finish(); return encoder.Finish();
} }
wgpu::PipelineLayout MakeBasicPipelineLayout( wgpu::PipelineLayout MakeBasicPipelineLayout(
std::vector<wgpu::BindGroupLayout> bindingInitializer) const { std::vector<wgpu::BindGroupLayout> bindingInitializer) const {
wgpu::PipelineLayoutDescriptor descriptor; wgpu::PipelineLayoutDescriptor descriptor;
descriptor.bindGroupLayoutCount = bindingInitializer.size(); descriptor.bindGroupLayoutCount = bindingInitializer.size();
descriptor.bindGroupLayouts = bindingInitializer.data(); descriptor.bindGroupLayouts = bindingInitializer.data();
return device.CreatePipelineLayout(&descriptor); return device.CreatePipelineLayout(&descriptor);
} }
wgpu::ShaderModule MakeSimpleVSModule() const { wgpu::ShaderModule MakeSimpleVSModule() const {
return utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, R"( return utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, R"(
#version 450 #version 450
void main() { void main() {
const vec2 pos[3] = vec2[3](vec2(-1.f, 1.f), vec2(1.f, 1.f), vec2(-1.f, -1.f)); const vec2 pos[3] = vec2[3](vec2(-1.f, 1.f), vec2(1.f, 1.f), vec2(-1.f, -1.f));
gl_Position = vec4(pos[gl_VertexIndex], 0.f, 1.f); gl_Position = vec4(pos[gl_VertexIndex], 0.f, 1.f);
})"); })");
} }
wgpu::ShaderModule MakeFSModule(std::vector<wgpu::BindingType> bindingTypes) const { wgpu::ShaderModule MakeFSModule(std::vector<wgpu::BindingType> bindingTypes) const {
ASSERT(bindingTypes.size() <= kMaxBindGroups); ASSERT(bindingTypes.size() <= kMaxBindGroups);
std::ostringstream fs; std::ostringstream fs;
fs << R"( fs << R"(
#version 450 #version 450
layout(location = 0) out vec4 fragColor; layout(location = 0) out vec4 fragColor;
)"; )";
for (size_t i = 0; i < bindingTypes.size(); ++i) { for (size_t i = 0; i < bindingTypes.size(); ++i) {
switch (bindingTypes[i]) { switch (bindingTypes[i]) {
case wgpu::BindingType::UniformBuffer: case wgpu::BindingType::UniformBuffer:
fs << "layout (std140, set = " << i << ", binding = 0) uniform UniformBuffer" << i fs << "layout (std140, set = " << i << ", binding = 0) uniform UniformBuffer"
<< R"( { << i << R"( {
vec4 color; vec4 color;
} buffer)" } buffer)"
<< i << ";\n"; << i << ";\n";
break; break;
case wgpu::BindingType::StorageBuffer: case wgpu::BindingType::StorageBuffer:
fs << "layout (std430, set = " << i << ", binding = 0) buffer StorageBuffer" << i fs << "layout (std430, set = " << i << ", binding = 0) buffer StorageBuffer"
<< R"( { << i << R"( {
vec4 color; vec4 color;
} buffer)" } buffer)"
<< i << ";\n"; << i << ";\n";
break; break;
default: default:
UNREACHABLE(); UNREACHABLE();
} }
} }
fs << R"( fs << R"(
void main() { void main() {
fragColor = vec4(0.0); fragColor = vec4(0.0);
)"; )";
for (size_t i = 0; i < bindingTypes.size(); ++i) { for (size_t i = 0; i < bindingTypes.size(); ++i) {
fs << "fragColor += buffer" << i << ".color;\n"; fs << "fragColor += buffer" << i << ".color;\n";
} }
fs << "}\n"; fs << "}\n";
return utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment, return utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment,
fs.str().c_str()); fs.str().c_str());
} }
wgpu::RenderPipeline MakeTestPipeline(const utils::BasicRenderPass& renderPass, wgpu::RenderPipeline MakeTestPipeline(const utils::BasicRenderPass& renderPass,
std::vector<wgpu::BindingType> bindingTypes, std::vector<wgpu::BindingType> bindingTypes,
std::vector<wgpu::BindGroupLayout> bindGroupLayouts) { std::vector<wgpu::BindGroupLayout> bindGroupLayouts) {
wgpu::ShaderModule vsModule = MakeSimpleVSModule(); wgpu::ShaderModule vsModule = MakeSimpleVSModule();
wgpu::ShaderModule fsModule = MakeFSModule(bindingTypes); wgpu::ShaderModule fsModule = MakeFSModule(bindingTypes);
wgpu::PipelineLayout pipelineLayout = MakeBasicPipelineLayout(bindGroupLayouts); wgpu::PipelineLayout pipelineLayout = MakeBasicPipelineLayout(bindGroupLayouts);
utils::ComboRenderPipelineDescriptor pipelineDescriptor(device); utils::ComboRenderPipelineDescriptor pipelineDescriptor(device);
pipelineDescriptor.layout = pipelineLayout; pipelineDescriptor.layout = pipelineLayout;
pipelineDescriptor.vertexStage.module = vsModule; pipelineDescriptor.vertexStage.module = vsModule;
pipelineDescriptor.cFragmentStage.module = fsModule; pipelineDescriptor.cFragmentStage.module = fsModule;
pipelineDescriptor.cColorStates[0].format = renderPass.colorFormat; pipelineDescriptor.cColorStates[0].format = renderPass.colorFormat;
pipelineDescriptor.cColorStates[0].colorBlend.operation = wgpu::BlendOperation::Add; pipelineDescriptor.cColorStates[0].colorBlend.operation = wgpu::BlendOperation::Add;
pipelineDescriptor.cColorStates[0].colorBlend.srcFactor = wgpu::BlendFactor::One; pipelineDescriptor.cColorStates[0].colorBlend.srcFactor = wgpu::BlendFactor::One;
pipelineDescriptor.cColorStates[0].colorBlend.dstFactor = wgpu::BlendFactor::One; pipelineDescriptor.cColorStates[0].colorBlend.dstFactor = wgpu::BlendFactor::One;
pipelineDescriptor.cColorStates[0].alphaBlend.operation = wgpu::BlendOperation::Add; pipelineDescriptor.cColorStates[0].alphaBlend.operation = wgpu::BlendOperation::Add;
pipelineDescriptor.cColorStates[0].alphaBlend.srcFactor = wgpu::BlendFactor::One; pipelineDescriptor.cColorStates[0].alphaBlend.srcFactor = wgpu::BlendFactor::One;
pipelineDescriptor.cColorStates[0].alphaBlend.dstFactor = wgpu::BlendFactor::One; pipelineDescriptor.cColorStates[0].alphaBlend.dstFactor = wgpu::BlendFactor::One;
return device.CreateRenderPipeline(&pipelineDescriptor); return device.CreateRenderPipeline(&pipelineDescriptor);
} }
}; };
// Test a bindgroup reused in two command buffers in the same call to queue.Submit(). // Test a bindgroup reused in two command buffers in the same call to queue.Submit().
@ -195,10 +195,10 @@ TEST_P(BindGroupTests, ReusedUBO) {
}; };
ASSERT(offsetof(Data, color) == 256); ASSERT(offsetof(Data, color) == 256);
constexpr float dummy = 0.0f; constexpr float dummy = 0.0f;
Data data { Data data{
{ 1.f, 0.f, dummy, dummy, 0.f, 1.0f, dummy, dummy }, {1.f, 0.f, dummy, dummy, 0.f, 1.0f, dummy, dummy},
{ 0 }, {0},
{ 0.f, 1.f, 0.f, 1.f }, {0.f, 1.f, 0.f, 1.f},
}; };
wgpu::Buffer buffer = wgpu::Buffer buffer =
utils::CreateBufferFromData(device, &data, sizeof(data), wgpu::BufferUsage::Uniform); utils::CreateBufferFromData(device, &data, sizeof(data), wgpu::BufferUsage::Uniform);
@ -219,15 +219,15 @@ TEST_P(BindGroupTests, ReusedUBO) {
RGBA8 filled(0, 255, 0, 255); RGBA8 filled(0, 255, 0, 255);
RGBA8 notFilled(0, 0, 0, 0); RGBA8 notFilled(0, 0, 0, 0);
uint32_t min = 1, max = kRTSize - 3; uint32_t min = 1, max = kRTSize - 3;
EXPECT_PIXEL_RGBA8_EQ(filled, renderPass.color, min, min); EXPECT_PIXEL_RGBA8_EQ(filled, renderPass.color, min, min);
EXPECT_PIXEL_RGBA8_EQ(filled, renderPass.color, max, min); EXPECT_PIXEL_RGBA8_EQ(filled, renderPass.color, max, min);
EXPECT_PIXEL_RGBA8_EQ(filled, renderPass.color, min, max); EXPECT_PIXEL_RGBA8_EQ(filled, renderPass.color, min, max);
EXPECT_PIXEL_RGBA8_EQ(notFilled, renderPass.color, max, max); EXPECT_PIXEL_RGBA8_EQ(notFilled, renderPass.color, max, max);
} }
// Test a bindgroup containing a UBO in the vertex shader and a sampler and texture in the fragment shader. // Test a bindgroup containing a UBO in the vertex shader and a sampler and texture in the fragment
// In D3D12 for example, these different types of bindings end up in different namespaces, but the register // shader. In D3D12 for example, these different types of bindings end up in different namespaces,
// offsets used must match between the shader module and descriptor range. // but the register offsets used must match between the shader module and descriptor range.
TEST_P(BindGroupTests, UBOSamplerAndTexture) { TEST_P(BindGroupTests, UBOSamplerAndTexture) {
utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize); utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize);
@ -260,7 +260,7 @@ TEST_P(BindGroupTests, UBOSamplerAndTexture) {
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&pipelineDescriptor); wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&pipelineDescriptor);
constexpr float dummy = 0.0f; constexpr float dummy = 0.0f;
constexpr float transform[] = { 1.f, 0.f, dummy, dummy, 0.f, 1.f, dummy, dummy }; constexpr float transform[] = {1.f, 0.f, dummy, dummy, 0.f, 1.f, dummy, dummy};
wgpu::Buffer buffer = utils::CreateBufferFromData(device, &transform, sizeof(transform), wgpu::Buffer buffer = utils::CreateBufferFromData(device, &transform, sizeof(transform),
wgpu::BufferUsage::Uniform); wgpu::BufferUsage::Uniform);
@ -320,9 +320,9 @@ TEST_P(BindGroupTests, UBOSamplerAndTexture) {
RGBA8 filled(0, 255, 0, 255); RGBA8 filled(0, 255, 0, 255);
RGBA8 notFilled(0, 0, 0, 0); RGBA8 notFilled(0, 0, 0, 0);
uint32_t min = 1, max = kRTSize - 3; uint32_t min = 1, max = kRTSize - 3;
EXPECT_PIXEL_RGBA8_EQ(filled, renderPass.color, min, min); EXPECT_PIXEL_RGBA8_EQ(filled, renderPass.color, min, min);
EXPECT_PIXEL_RGBA8_EQ(filled, renderPass.color, max, min); EXPECT_PIXEL_RGBA8_EQ(filled, renderPass.color, max, min);
EXPECT_PIXEL_RGBA8_EQ(filled, renderPass.color, min, max); EXPECT_PIXEL_RGBA8_EQ(filled, renderPass.color, min, max);
EXPECT_PIXEL_RGBA8_EQ(notFilled, renderPass.color, max, max); EXPECT_PIXEL_RGBA8_EQ(notFilled, renderPass.color, max, max);
} }
@ -1091,4 +1091,8 @@ TEST_P(BindGroupTests, ReadonlyStorage) {
EXPECT_PIXEL_RGBA8_EQ(RGBA8::kGreen, renderPass.color, 0, 0); EXPECT_PIXEL_RGBA8_EQ(RGBA8::kGreen, renderPass.color, 0, 0);
} }
DAWN_INSTANTIATE_TEST(BindGroupTests, D3D12Backend(), MetalBackend(), OpenGLBackend(), VulkanBackend()); DAWN_INSTANTIATE_TEST(BindGroupTests,
D3D12Backend(),
MetalBackend(),
OpenGLBackend(),
VulkanBackend());

View File

@ -17,34 +17,34 @@
#include <cstring> #include <cstring>
class BufferMapReadTests : public DawnTest { class BufferMapReadTests : public DawnTest {
protected: protected:
static void MapReadCallback(WGPUBufferMapAsyncStatus status, static void MapReadCallback(WGPUBufferMapAsyncStatus status,
const void* data, const void* data,
uint64_t, uint64_t,
void* userdata) { void* userdata) {
ASSERT_EQ(WGPUBufferMapAsyncStatus_Success, status); ASSERT_EQ(WGPUBufferMapAsyncStatus_Success, status);
ASSERT_NE(nullptr, data); ASSERT_NE(nullptr, data);
static_cast<BufferMapReadTests*>(userdata)->mappedData = data; static_cast<BufferMapReadTests*>(userdata)->mappedData = data;
} }
const void* MapReadAsyncAndWait(const wgpu::Buffer& buffer) { const void* MapReadAsyncAndWait(const wgpu::Buffer& buffer) {
buffer.MapReadAsync(MapReadCallback, this); buffer.MapReadAsync(MapReadCallback, this);
while (mappedData == nullptr) { while (mappedData == nullptr) {
WaitABit(); WaitABit();
} }
return mappedData; return mappedData;
} }
void UnmapBuffer(const wgpu::Buffer& buffer) { void UnmapBuffer(const wgpu::Buffer& buffer) {
buffer.Unmap(); buffer.Unmap();
mappedData = nullptr; mappedData = nullptr;
} }
private: private:
const void* mappedData = nullptr; const void* mappedData = nullptr;
}; };
// Test that the simplest map read works. // Test that the simplest map read works.
@ -145,41 +145,45 @@ TEST_P(BufferMapReadTests, GetMappedRangeZeroSized) {
UnmapBuffer(buffer); UnmapBuffer(buffer);
} }
DAWN_INSTANTIATE_TEST(BufferMapReadTests, D3D12Backend(), MetalBackend(), OpenGLBackend(), VulkanBackend()); DAWN_INSTANTIATE_TEST(BufferMapReadTests,
D3D12Backend(),
MetalBackend(),
OpenGLBackend(),
VulkanBackend());
class BufferMapWriteTests : public DawnTest { class BufferMapWriteTests : public DawnTest {
protected: protected:
static void MapWriteCallback(WGPUBufferMapAsyncStatus status, static void MapWriteCallback(WGPUBufferMapAsyncStatus status,
void* data, void* data,
uint64_t, uint64_t,
void* userdata) { void* userdata) {
ASSERT_EQ(WGPUBufferMapAsyncStatus_Success, status); ASSERT_EQ(WGPUBufferMapAsyncStatus_Success, status);
ASSERT_NE(nullptr, data); ASSERT_NE(nullptr, data);
static_cast<BufferMapWriteTests*>(userdata)->mappedData = data; static_cast<BufferMapWriteTests*>(userdata)->mappedData = data;
} }
void* MapWriteAsyncAndWait(const wgpu::Buffer& buffer) { void* MapWriteAsyncAndWait(const wgpu::Buffer& buffer) {
buffer.MapWriteAsync(MapWriteCallback, this); buffer.MapWriteAsync(MapWriteCallback, this);
while (mappedData == nullptr) { while (mappedData == nullptr) {
WaitABit(); WaitABit();
} }
// Ensure the prior write's status is updated. // Ensure the prior write's status is updated.
void* resultPointer = mappedData; void* resultPointer = mappedData;
mappedData = nullptr; mappedData = nullptr;
return resultPointer; return resultPointer;
} }
void UnmapBuffer(const wgpu::Buffer& buffer) { void UnmapBuffer(const wgpu::Buffer& buffer) {
buffer.Unmap(); buffer.Unmap();
mappedData = nullptr; mappedData = nullptr;
} }
private: private:
void* mappedData = nullptr; void* mappedData = nullptr;
}; };
// Test that the simplest map write works. // Test that the simplest map write works.
@ -307,64 +311,68 @@ TEST_P(BufferMapWriteTests, GetMappedRangeZeroSized) {
UnmapBuffer(buffer); UnmapBuffer(buffer);
} }
DAWN_INSTANTIATE_TEST(BufferMapWriteTests, D3D12Backend(), MetalBackend(), OpenGLBackend(), VulkanBackend()); DAWN_INSTANTIATE_TEST(BufferMapWriteTests,
D3D12Backend(),
MetalBackend(),
OpenGLBackend(),
VulkanBackend());
class CreateBufferMappedTests : public DawnTest { class CreateBufferMappedTests : public DawnTest {
protected: protected:
static void MapReadCallback(WGPUBufferMapAsyncStatus status, static void MapReadCallback(WGPUBufferMapAsyncStatus status,
const void* data, const void* data,
uint64_t, uint64_t,
void* userdata) { void* userdata) {
ASSERT_EQ(WGPUBufferMapAsyncStatus_Success, status); ASSERT_EQ(WGPUBufferMapAsyncStatus_Success, status);
ASSERT_NE(nullptr, data); ASSERT_NE(nullptr, data);
static_cast<CreateBufferMappedTests*>(userdata)->mappedData = data; static_cast<CreateBufferMappedTests*>(userdata)->mappedData = data;
} }
const void* MapReadAsyncAndWait(const wgpu::Buffer& buffer) { const void* MapReadAsyncAndWait(const wgpu::Buffer& buffer) {
buffer.MapReadAsync(MapReadCallback, this); buffer.MapReadAsync(MapReadCallback, this);
while (mappedData == nullptr) { while (mappedData == nullptr) {
WaitABit(); WaitABit();
} }
return mappedData; return mappedData;
} }
void UnmapBuffer(const wgpu::Buffer& buffer) { void UnmapBuffer(const wgpu::Buffer& buffer) {
buffer.Unmap(); buffer.Unmap();
mappedData = nullptr; mappedData = nullptr;
} }
void CheckResultStartsZeroed(const wgpu::CreateBufferMappedResult& result, uint64_t size) { void CheckResultStartsZeroed(const wgpu::CreateBufferMappedResult& result, uint64_t size) {
ASSERT_EQ(result.dataLength, size); ASSERT_EQ(result.dataLength, size);
for (uint64_t i = 0; i < result.dataLength; ++i) { for (uint64_t i = 0; i < result.dataLength; ++i) {
uint8_t value = *(reinterpret_cast<uint8_t*>(result.data) + i); uint8_t value = *(reinterpret_cast<uint8_t*>(result.data) + i);
ASSERT_EQ(value, 0u); ASSERT_EQ(value, 0u);
} }
} }
wgpu::CreateBufferMappedResult CreateBufferMapped(wgpu::BufferUsage usage, uint64_t size) { wgpu::CreateBufferMappedResult CreateBufferMapped(wgpu::BufferUsage usage, uint64_t size) {
wgpu::BufferDescriptor descriptor = {}; wgpu::BufferDescriptor descriptor = {};
descriptor.size = size; descriptor.size = size;
descriptor.usage = usage; descriptor.usage = usage;
wgpu::CreateBufferMappedResult result = device.CreateBufferMapped(&descriptor); wgpu::CreateBufferMappedResult result = device.CreateBufferMapped(&descriptor);
CheckResultStartsZeroed(result, size); CheckResultStartsZeroed(result, size);
return result; return result;
} }
wgpu::CreateBufferMappedResult CreateBufferMappedWithData(wgpu::BufferUsage usage, wgpu::CreateBufferMappedResult CreateBufferMappedWithData(wgpu::BufferUsage usage,
const std::vector<uint32_t>& data) { const std::vector<uint32_t>& data) {
size_t byteLength = data.size() * sizeof(uint32_t); size_t byteLength = data.size() * sizeof(uint32_t);
wgpu::CreateBufferMappedResult result = CreateBufferMapped(usage, byteLength); wgpu::CreateBufferMappedResult result = CreateBufferMapped(usage, byteLength);
memcpy(result.data, data.data(), byteLength); memcpy(result.data, data.data(), byteLength);
return result; return result;
} }
private: private:
const void* mappedData = nullptr; const void* mappedData = nullptr;
}; };
// Test that the simplest CreateBufferMapped works for MapWrite buffers. // Test that the simplest CreateBufferMapped works for MapWrite buffers.

View File

@ -97,4 +97,8 @@ TEST_P(ClipSpaceTest, ClipSpace) {
EXPECT_PIXEL_RGBA8_EQ(RGBA8::kGreen, colorTexture, 0, 0); EXPECT_PIXEL_RGBA8_EQ(RGBA8::kGreen, colorTexture, 0, 0);
} }
DAWN_INSTANTIATE_TEST(ClipSpaceTest, D3D12Backend(), MetalBackend(), OpenGLBackend(), VulkanBackend()); DAWN_INSTANTIATE_TEST(ClipSpaceTest,
D3D12Backend(),
MetalBackend(),
OpenGLBackend(),
VulkanBackend());

View File

@ -758,8 +758,8 @@ TEST_P(ColorStateTest, IndependentColorState) {
renderTargetViews[i] = renderTargets[i].CreateView(); renderTargetViews[i] = renderTargets[i].CreateView();
} }
utils::ComboRenderPassDescriptor renderPass({renderTargetViews[0], renderTargetViews[1], utils::ComboRenderPassDescriptor renderPass(
renderTargetViews[2], renderTargetViews[3]}); {renderTargetViews[0], renderTargetViews[1], renderTargetViews[2], renderTargetViews[3]});
wgpu::ShaderModule fsModule = wgpu::ShaderModule fsModule =
utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment, R"( utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment, R"(
@ -1047,4 +1047,8 @@ TEST_P(ColorStateTest, ColorWriteMaskDoesNotAffectRenderPassLoadOpClear) {
EXPECT_PIXEL_RGBA8_EQ(expected, renderPass.color, kRTSize / 2, kRTSize / 2); EXPECT_PIXEL_RGBA8_EQ(expected, renderPass.color, kRTSize / 2, kRTSize / 2);
} }
DAWN_INSTANTIATE_TEST(ColorStateTest, D3D12Backend(), MetalBackend(), OpenGLBackend(), VulkanBackend()); DAWN_INSTANTIATE_TEST(ColorStateTest,
D3D12Backend(),
MetalBackend(),
OpenGLBackend(),
VulkanBackend());

View File

@ -173,7 +173,7 @@ TEST_P(ComputeCopyStorageBufferTests, DISABLED_UnsizedDescriptorArray) {
} }
DAWN_INSTANTIATE_TEST(ComputeCopyStorageBufferTests, DAWN_INSTANTIATE_TEST(ComputeCopyStorageBufferTests,
D3D12Backend(), D3D12Backend(),
MetalBackend(), MetalBackend(),
OpenGLBackend(), OpenGLBackend(),
VulkanBackend()); VulkanBackend());

View File

@ -98,7 +98,7 @@ TEST_P(ComputeSharedMemoryTests, Basic) {
} }
DAWN_INSTANTIATE_TEST(ComputeSharedMemoryTests, DAWN_INSTANTIATE_TEST(ComputeSharedMemoryTests,
D3D12Backend(), D3D12Backend(),
MetalBackend(), MetalBackend(),
OpenGLBackend(), OpenGLBackend(),
VulkanBackend()); VulkanBackend());

View File

@ -21,164 +21,164 @@
#include "utils/WGPUHelpers.h" #include "utils/WGPUHelpers.h"
class CopyTests : public DawnTest { class CopyTests : public DawnTest {
protected: protected:
static constexpr wgpu::TextureFormat kTextureFormat = wgpu::TextureFormat::RGBA8Unorm; static constexpr wgpu::TextureFormat kTextureFormat = wgpu::TextureFormat::RGBA8Unorm;
struct TextureSpec { struct TextureSpec {
wgpu::Origin3D copyOrigin; wgpu::Origin3D copyOrigin;
wgpu::Extent3D textureSize; wgpu::Extent3D textureSize;
uint32_t level; uint32_t level;
}; };
struct BufferSpec { struct BufferSpec {
uint64_t size; uint64_t size;
uint64_t offset; uint64_t offset;
uint32_t bytesPerRow; uint32_t bytesPerRow;
uint32_t rowsPerImage; uint32_t rowsPerImage;
}; };
static std::vector<RGBA8> GetExpectedTextureData( static std::vector<RGBA8> GetExpectedTextureData(const utils::BufferTextureCopyLayout& layout) {
const utils::BufferTextureCopyLayout& layout) { std::vector<RGBA8> textureData(layout.texelBlockCount);
std::vector<RGBA8> textureData(layout.texelBlockCount); for (uint32_t layer = 0; layer < layout.mipSize.depth; ++layer) {
for (uint32_t layer = 0; layer < layout.mipSize.depth; ++layer) { const uint32_t texelIndexOffsetPerSlice = layout.texelBlocksPerImage * layer;
const uint32_t texelIndexOffsetPerSlice = layout.texelBlocksPerImage * layer; for (uint32_t y = 0; y < layout.mipSize.height; ++y) {
for (uint32_t y = 0; y < layout.mipSize.height; ++y) { for (uint32_t x = 0; x < layout.mipSize.width; ++x) {
for (uint32_t x = 0; x < layout.mipSize.width; ++x) { uint32_t i = x + y * layout.texelBlocksPerRow;
uint32_t i = x + y * layout.texelBlocksPerRow; textureData[texelIndexOffsetPerSlice + i] =
textureData[texelIndexOffsetPerSlice + i] = RGBA8(static_cast<uint8_t>((x + layer * x) % 256),
RGBA8(static_cast<uint8_t>((x + layer * x) % 256), static_cast<uint8_t>((y + layer * y) % 256),
static_cast<uint8_t>((y + layer * y) % 256), static_cast<uint8_t>(x / 256), static_cast<uint8_t>(y / 256));
static_cast<uint8_t>(x / 256), static_cast<uint8_t>(y / 256));
}
}
}
return textureData;
}
static BufferSpec MinimumBufferSpec(uint32_t width,
uint32_t rowsPerImage,
uint32_t arrayLayer = 1,
bool testZeroRowsPerImage = true) {
const uint32_t bytesPerRow = utils::GetMinimumBytesPerRow(kTextureFormat, width);
const uint32_t totalBufferSize = utils::GetBytesInBufferTextureCopy(
kTextureFormat, width, bytesPerRow, rowsPerImage, arrayLayer);
uint32_t appliedRowsPerImage = testZeroRowsPerImage ? 0 : rowsPerImage;
return {totalBufferSize, 0, bytesPerRow, appliedRowsPerImage};
}
static void PackTextureData(const RGBA8* srcData, uint32_t width, uint32_t height, uint32_t srcTexelsPerRow, RGBA8* dstData, uint32_t dstTexelsPerRow) {
for (unsigned int y = 0; y < height; ++y) {
for (unsigned int x = 0; x < width; ++x) {
unsigned int src = x + y * srcTexelsPerRow;
unsigned int dst = x + y * dstTexelsPerRow;
dstData[dst] = srcData[src];
} }
} }
} }
return textureData;
}
static BufferSpec MinimumBufferSpec(uint32_t width,
uint32_t rowsPerImage,
uint32_t arrayLayer = 1,
bool testZeroRowsPerImage = true) {
const uint32_t bytesPerRow = utils::GetMinimumBytesPerRow(kTextureFormat, width);
const uint32_t totalBufferSize = utils::GetBytesInBufferTextureCopy(
kTextureFormat, width, bytesPerRow, rowsPerImage, arrayLayer);
uint32_t appliedRowsPerImage = testZeroRowsPerImage ? 0 : rowsPerImage;
return {totalBufferSize, 0, bytesPerRow, appliedRowsPerImage};
}
static void PackTextureData(const RGBA8* srcData,
uint32_t width,
uint32_t height,
uint32_t srcTexelsPerRow,
RGBA8* dstData,
uint32_t dstTexelsPerRow) {
for (unsigned int y = 0; y < height; ++y) {
for (unsigned int x = 0; x < width; ++x) {
unsigned int src = x + y * srcTexelsPerRow;
unsigned int dst = x + y * dstTexelsPerRow;
dstData[dst] = srcData[src];
}
}
}
}; };
class CopyTests_T2B : public CopyTests { class CopyTests_T2B : public CopyTests {
protected: protected:
void DoTest(const TextureSpec& textureSpec, void DoTest(const TextureSpec& textureSpec,
const BufferSpec& bufferSpec, const BufferSpec& bufferSpec,
const wgpu::Extent3D& copySize) { const wgpu::Extent3D& copySize) {
// Create a texture that is `width` x `height` with (`level` + 1) mip levels. // Create a texture that is `width` x `height` with (`level` + 1) mip levels.
wgpu::TextureDescriptor descriptor; wgpu::TextureDescriptor descriptor;
descriptor.dimension = wgpu::TextureDimension::e2D; descriptor.dimension = wgpu::TextureDimension::e2D;
descriptor.size = textureSpec.textureSize; descriptor.size = textureSpec.textureSize;
descriptor.sampleCount = 1; descriptor.sampleCount = 1;
descriptor.format = kTextureFormat; descriptor.format = kTextureFormat;
descriptor.mipLevelCount = textureSpec.level + 1; descriptor.mipLevelCount = textureSpec.level + 1;
descriptor.usage = wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::CopySrc; descriptor.usage = wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::CopySrc;
wgpu::Texture texture = device.CreateTexture(&descriptor); wgpu::Texture texture = device.CreateTexture(&descriptor);
const utils::BufferTextureCopyLayout copyLayout = const utils::BufferTextureCopyLayout copyLayout =
utils::GetBufferTextureCopyLayoutForTexture2DAtLevel( utils::GetBufferTextureCopyLayoutForTexture2DAtLevel(
kTextureFormat, textureSpec.textureSize, textureSpec.level, kTextureFormat, textureSpec.textureSize, textureSpec.level,
bufferSpec.rowsPerImage); bufferSpec.rowsPerImage);
wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
// Initialize the source texture // Initialize the source texture
std::vector<RGBA8> textureArrayData = GetExpectedTextureData(copyLayout); std::vector<RGBA8> textureArrayData = GetExpectedTextureData(copyLayout);
{ {
wgpu::Buffer uploadBuffer = wgpu::Buffer uploadBuffer = utils::CreateBufferFromData(
utils::CreateBufferFromData(device, textureArrayData.data(), device, textureArrayData.data(), copyLayout.byteLength, wgpu::BufferUsage::CopySrc);
copyLayout.byteLength, wgpu::BufferUsage::CopySrc); wgpu::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(
wgpu::BufferCopyView bufferCopyView = utils::CreateBufferCopyView( uploadBuffer, 0, copyLayout.bytesPerRow, bufferSpec.rowsPerImage);
uploadBuffer, 0, copyLayout.bytesPerRow, bufferSpec.rowsPerImage); wgpu::TextureCopyView textureCopyView =
wgpu::TextureCopyView textureCopyView = utils::CreateTextureCopyView(texture, textureSpec.level, {0, 0, 0});
utils::CreateTextureCopyView(texture, textureSpec.level, {0, 0, 0}); encoder.CopyBufferToTexture(&bufferCopyView, &textureCopyView, &copyLayout.mipSize);
encoder.CopyBufferToTexture(&bufferCopyView, &textureCopyView, &copyLayout.mipSize); }
}
// Create a buffer of `size` and populate it with empty data (0,0,0,0) Note: // Create a buffer of `size` and populate it with empty data (0,0,0,0) Note:
// Prepopulating the buffer with empty data ensures that there is not random data in the // Prepopulating the buffer with empty data ensures that there is not random data in the
// expectation and helps ensure that the padding due to the bytes per row is not modified // expectation and helps ensure that the padding due to the bytes per row is not modified
// by the copy. // by the copy.
// TODO(jiawei.shao@intel.com): remove the initialization of the buffer after we support // TODO(jiawei.shao@intel.com): remove the initialization of the buffer after we support
// buffer lazy-initialization. // buffer lazy-initialization.
const uint32_t bytesPerTexel = utils::GetTexelBlockSizeInBytes(kTextureFormat); const uint32_t bytesPerTexel = utils::GetTexelBlockSizeInBytes(kTextureFormat);
const std::vector<RGBA8> emptyData(bufferSpec.size / bytesPerTexel, RGBA8()); const std::vector<RGBA8> emptyData(bufferSpec.size / bytesPerTexel, RGBA8());
wgpu::Buffer buffer = wgpu::Buffer buffer =
utils::CreateBufferFromData(device, emptyData.data(), bufferSpec.size, utils::CreateBufferFromData(device, emptyData.data(), bufferSpec.size,
wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst); wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst);
{ {
wgpu::TextureCopyView textureCopyView = wgpu::TextureCopyView textureCopyView =
utils::CreateTextureCopyView(texture, textureSpec.level, textureSpec.copyOrigin); utils::CreateTextureCopyView(texture, textureSpec.level, textureSpec.copyOrigin);
wgpu::BufferCopyView bufferCopyView = utils::CreateBufferCopyView( wgpu::BufferCopyView bufferCopyView = utils::CreateBufferCopyView(
buffer, bufferSpec.offset, bufferSpec.bytesPerRow, bufferSpec.rowsPerImage); buffer, bufferSpec.offset, bufferSpec.bytesPerRow, bufferSpec.rowsPerImage);
encoder.CopyTextureToBuffer(&textureCopyView, &bufferCopyView, &copySize); encoder.CopyTextureToBuffer(&textureCopyView, &bufferCopyView, &copySize);
} }
wgpu::CommandBuffer commands = encoder.Finish(); wgpu::CommandBuffer commands = encoder.Finish();
queue.Submit(1, &commands); queue.Submit(1, &commands);
uint64_t bufferOffset = bufferSpec.offset; uint64_t bufferOffset = bufferSpec.offset;
const uint32_t texelCountInCopyRegion = const uint32_t texelCountInCopyRegion =
bufferSpec.bytesPerRow / bytesPerTexel * (copySize.height - 1) + copySize.width; bufferSpec.bytesPerRow / bytesPerTexel * (copySize.height - 1) + copySize.width;
const uint32_t maxArrayLayer = textureSpec.copyOrigin.z + copySize.depth; const uint32_t maxArrayLayer = textureSpec.copyOrigin.z + copySize.depth;
std::vector<RGBA8> expected(texelCountInCopyRegion); std::vector<RGBA8> expected(texelCountInCopyRegion);
for (uint32_t slice = textureSpec.copyOrigin.z; slice < maxArrayLayer; ++slice) { for (uint32_t slice = textureSpec.copyOrigin.z; slice < maxArrayLayer; ++slice) {
// Pack the data used to create the upload buffer in the specified copy region to have // Pack the data used to create the upload buffer in the specified copy region to have
// the same format as the expected buffer data. // the same format as the expected buffer data.
std::fill(expected.begin(), expected.end(), RGBA8()); std::fill(expected.begin(), expected.end(), RGBA8());
const uint32_t texelIndexOffset = copyLayout.texelBlocksPerImage * slice; const uint32_t texelIndexOffset = copyLayout.texelBlocksPerImage * slice;
const uint32_t expectedTexelArrayDataStartIndex = const uint32_t expectedTexelArrayDataStartIndex =
texelIndexOffset + (textureSpec.copyOrigin.x + texelIndexOffset + (textureSpec.copyOrigin.x +
textureSpec.copyOrigin.y * copyLayout.texelBlocksPerRow); textureSpec.copyOrigin.y * copyLayout.texelBlocksPerRow);
PackTextureData(&textureArrayData[expectedTexelArrayDataStartIndex], copySize.width, PackTextureData(&textureArrayData[expectedTexelArrayDataStartIndex], copySize.width,
copySize.height, copyLayout.texelBlocksPerRow, expected.data(), copySize.height, copyLayout.texelBlocksPerRow, expected.data(),
bufferSpec.bytesPerRow / bytesPerTexel); bufferSpec.bytesPerRow / bytesPerTexel);
EXPECT_BUFFER_U32_RANGE_EQ(reinterpret_cast<const uint32_t*>(expected.data()), buffer, EXPECT_BUFFER_U32_RANGE_EQ(reinterpret_cast<const uint32_t*>(expected.data()), buffer,
bufferOffset, static_cast<uint32_t>(expected.size())) bufferOffset, static_cast<uint32_t>(expected.size()))
<< "Texture to Buffer copy failed copying region [(" << textureSpec.copyOrigin.x << "Texture to Buffer copy failed copying region [(" << textureSpec.copyOrigin.x
<< ", " << textureSpec.copyOrigin.y << "), (" << ", " << textureSpec.copyOrigin.y << "), ("
<< textureSpec.copyOrigin.x + copySize.width << ", " << textureSpec.copyOrigin.x + copySize.width << ", "
<< textureSpec.copyOrigin.y + copySize.height << ")) from " << textureSpec.copyOrigin.y + copySize.height << ")) from "
<< textureSpec.textureSize.width << " x " << textureSpec.textureSize.height << textureSpec.textureSize.width << " x " << textureSpec.textureSize.height
<< " texture at mip level " << textureSpec.level << " layer " << slice << " to " << " texture at mip level " << textureSpec.level << " layer " << slice << " to "
<< bufferSpec.size << "-byte buffer with offset " << bufferOffset << bufferSpec.size << "-byte buffer with offset " << bufferOffset
<< " and bytes per row " << bufferSpec.bytesPerRow << std::endl; << " and bytes per row " << bufferSpec.bytesPerRow << std::endl;
bufferOffset += copyLayout.bytesPerImage; bufferOffset += copyLayout.bytesPerImage;
} }
} }
}; };
class CopyTests_B2T : public CopyTests { class CopyTests_B2T : public CopyTests {
protected: protected:
static void FillBufferData(RGBA8* data, size_t count) { static void FillBufferData(RGBA8* data, size_t count) {
for (size_t i = 0; i < count; ++i) { for (size_t i = 0; i < count; ++i) {
data[i] = RGBA8( data[i] = RGBA8(static_cast<uint8_t>(i % 256), static_cast<uint8_t>((i / 256) % 256),
static_cast<uint8_t>(i % 256), static_cast<uint8_t>((i / 256 / 256) % 256), 255);
static_cast<uint8_t>((i / 256) % 256),
static_cast<uint8_t>((i / 256 / 256) % 256),
255);
} }
} }
@ -510,7 +510,7 @@ TEST_P(CopyTests_T2B, TextureRegionAligned) {
constexpr uint32_t kWidth = 256; constexpr uint32_t kWidth = 256;
constexpr uint32_t kHeight = 128; constexpr uint32_t kHeight = 128;
for (unsigned int w : {64, 128, 256}) { for (unsigned int w : {64, 128, 256}) {
for (unsigned int h : { 16, 32, 48 }) { for (unsigned int h : {16, 32, 48}) {
TextureSpec textureSpec; TextureSpec textureSpec;
textureSpec.copyOrigin = {0, 0, 0}; textureSpec.copyOrigin = {0, 0, 0};
textureSpec.level = 0; textureSpec.level = 0;
@ -531,7 +531,7 @@ TEST_P(CopyTests_T2B, TextureRegionUnaligned) {
defaultTextureSpec.textureSize = {kWidth, kHeight, 1}; defaultTextureSpec.textureSize = {kWidth, kHeight, 1};
for (unsigned int w : {13, 63, 65}) { for (unsigned int w : {13, 63, 65}) {
for (unsigned int h : { 17, 19, 63 }) { for (unsigned int h : {17, 19, 63}) {
TextureSpec textureSpec = defaultTextureSpec; TextureSpec textureSpec = defaultTextureSpec;
DoTest(textureSpec, MinimumBufferSpec(w, h), {w, h, 1}); DoTest(textureSpec, MinimumBufferSpec(w, h), {w, h, 1});
} }
@ -746,7 +746,11 @@ TEST_P(CopyTests_T2B, Texture2DArrayRegionNonzeroRowsPerImage) {
DoTest(textureSpec, bufferSpec, {kWidth, kHeight, kCopyLayers}); DoTest(textureSpec, bufferSpec, {kWidth, kHeight, kCopyLayers});
} }
DAWN_INSTANTIATE_TEST(CopyTests_T2B, D3D12Backend(), MetalBackend(), OpenGLBackend(), VulkanBackend()); DAWN_INSTANTIATE_TEST(CopyTests_T2B,
D3D12Backend(),
MetalBackend(),
OpenGLBackend(),
VulkanBackend());
// Test that copying an entire texture with 256-byte aligned dimensions works // Test that copying an entire texture with 256-byte aligned dimensions works
TEST_P(CopyTests_B2T, FullTextureAligned) { TEST_P(CopyTests_B2T, FullTextureAligned) {
@ -877,7 +881,7 @@ TEST_P(CopyTests_B2T, TextureRegionAligned) {
constexpr uint32_t kWidth = 256; constexpr uint32_t kWidth = 256;
constexpr uint32_t kHeight = 128; constexpr uint32_t kHeight = 128;
for (unsigned int w : {64, 128, 256}) { for (unsigned int w : {64, 128, 256}) {
for (unsigned int h : { 16, 32, 48 }) { for (unsigned int h : {16, 32, 48}) {
TextureSpec textureSpec; TextureSpec textureSpec;
textureSpec.copyOrigin = {0, 0, 0}; textureSpec.copyOrigin = {0, 0, 0};
textureSpec.level = 0; textureSpec.level = 0;
@ -1090,7 +1094,11 @@ TEST_P(CopyTests_B2T, Texture2DArrayRegionNonzeroRowsPerImage) {
DoTest(textureSpec, bufferSpec, {kWidth, kHeight, kCopyLayers}); DoTest(textureSpec, bufferSpec, {kWidth, kHeight, kCopyLayers});
} }
DAWN_INSTANTIATE_TEST(CopyTests_B2T, D3D12Backend(), MetalBackend(), OpenGLBackend(), VulkanBackend()); DAWN_INSTANTIATE_TEST(CopyTests_B2T,
D3D12Backend(),
MetalBackend(),
OpenGLBackend(),
VulkanBackend());
TEST_P(CopyTests_T2T, Texture) { TEST_P(CopyTests_T2T, Texture) {
constexpr uint32_t kWidth = 256; constexpr uint32_t kWidth = 256;
@ -1310,7 +1318,11 @@ TEST_P(CopyTests_T2T, MultipleMipSrcSingleMipDst) {
} }
} }
DAWN_INSTANTIATE_TEST(CopyTests_T2T, D3D12Backend(), MetalBackend(), OpenGLBackend(), VulkanBackend()); DAWN_INSTANTIATE_TEST(CopyTests_T2T,
D3D12Backend(),
MetalBackend(),
OpenGLBackend(),
VulkanBackend());
static constexpr uint64_t kSmallBufferSize = 4; static constexpr uint64_t kSmallBufferSize = 4;
static constexpr uint64_t kLargeBufferSize = 1 << 16; static constexpr uint64_t kLargeBufferSize = 1 << 16;

View File

@ -127,4 +127,8 @@ TEST_P(CullingTest, CullBackFaceWhenCWIsFrontFace) {
DoTest(wgpu::FrontFace::CW, wgpu::CullMode::Back, true, false); DoTest(wgpu::FrontFace::CW, wgpu::CullMode::Back, true, false);
} }
DAWN_INSTANTIATE_TEST(CullingTest, D3D12Backend(), MetalBackend(), OpenGLBackend(), VulkanBackend()); DAWN_INSTANTIATE_TEST(CullingTest,
D3D12Backend(),
MetalBackend(),
OpenGLBackend(),
VulkanBackend());

View File

@ -130,8 +130,7 @@ namespace {
// A small fixture used to initialize default data for the D3D12Resource validation tests. // A small fixture used to initialize default data for the D3D12Resource validation tests.
// These tests are skipped if the harness is using the wire. // These tests are skipped if the harness is using the wire.
class D3D12SharedHandleValidation : public D3D12ResourceTestBase { class D3D12SharedHandleValidation : public D3D12ResourceTestBase {};
};
// Test a successful wrapping of an D3D12Resource in a texture // Test a successful wrapping of an D3D12Resource in a texture
TEST_P(D3D12SharedHandleValidation, Success) { TEST_P(D3D12SharedHandleValidation, Success) {

View File

@ -42,4 +42,8 @@ TEST_P(DebugMarkerTests, NoFailureWithoutDebugToolAttached) {
queue.Submit(1, &commands); queue.Submit(1, &commands);
} }
DAWN_INSTANTIATE_TEST(DebugMarkerTests, D3D12Backend(), MetalBackend(), OpenGLBackend(), VulkanBackend()); DAWN_INSTANTIATE_TEST(DebugMarkerTests,
D3D12Backend(),
MetalBackend(),
OpenGLBackend(),
VulkanBackend());

View File

@ -20,14 +20,10 @@
namespace { namespace {
constexpr wgpu::CompareFunction kCompareFunctions[] = { constexpr wgpu::CompareFunction kCompareFunctions[] = {
wgpu::CompareFunction::Never, wgpu::CompareFunction::Never, wgpu::CompareFunction::Less,
wgpu::CompareFunction::Less, wgpu::CompareFunction::LessEqual, wgpu::CompareFunction::Greater,
wgpu::CompareFunction::LessEqual, wgpu::CompareFunction::GreaterEqual, wgpu::CompareFunction::Equal,
wgpu::CompareFunction::Greater, wgpu::CompareFunction::NotEqual, wgpu::CompareFunction::Always,
wgpu::CompareFunction::GreaterEqual,
wgpu::CompareFunction::Equal,
wgpu::CompareFunction::NotEqual,
wgpu::CompareFunction::Always,
}; };
// Test a "normal" ref value between 0 and 1; as well as negative and > 1 refs. // Test a "normal" ref value between 0 and 1; as well as negative and > 1 refs.
@ -225,12 +221,11 @@ class DepthSamplingTest : public DawnTest {
wgpu::SamplerDescriptor samplerDesc; wgpu::SamplerDescriptor samplerDesc;
wgpu::Sampler sampler = device.CreateSampler(&samplerDesc); wgpu::Sampler sampler = device.CreateSampler(&samplerDesc);
wgpu::BindGroup bindGroup = wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0),
utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0), {
{ {0, sampler},
{0, sampler}, {1, mInputTexture.CreateView()},
{1, mInputTexture.CreateView()}, });
});
for (float textureValue : textureValues) { for (float textureValue : textureValues) {
// Set the input depth texture to the provided texture value // Set the input depth texture to the provided texture value
@ -258,12 +253,9 @@ class DepthSamplingTest : public DawnTest {
wgpu::SamplerDescriptor samplerDesc; wgpu::SamplerDescriptor samplerDesc;
wgpu::Sampler sampler = device.CreateSampler(&samplerDesc); wgpu::Sampler sampler = device.CreateSampler(&samplerDesc);
wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0), wgpu::BindGroup bindGroup = utils::MakeBindGroup(
{ device, pipeline.GetBindGroupLayout(0),
{0, sampler}, {{0, sampler}, {1, mInputTexture.CreateView()}, {2, mOutputBuffer}});
{1, mInputTexture.CreateView()},
{2, mOutputBuffer}
});
for (float textureValue : textureValues) { for (float textureValue : textureValues) {
// Set the input depth texture to the provided texture value // Set the input depth texture to the provided texture value
@ -321,13 +313,12 @@ class DepthSamplingTest : public DawnTest {
samplerDesc.compare = compare; samplerDesc.compare = compare;
wgpu::Sampler sampler = device.CreateSampler(&samplerDesc); wgpu::Sampler sampler = device.CreateSampler(&samplerDesc);
wgpu::BindGroup bindGroup = wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0),
utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0), {
{ {0, sampler},
{0, sampler}, {1, mInputTexture.CreateView()},
{1, mInputTexture.CreateView()}, {2, mUniformBuffer},
{2, mUniformBuffer}, });
});
for (float textureValue : textureValues) { for (float textureValue : textureValues) {
// Set the input depth texture to the provided texture value // Set the input depth texture to the provided texture value
@ -364,12 +355,10 @@ class DepthSamplingTest : public DawnTest {
wgpu::Sampler sampler = device.CreateSampler(&samplerDesc); wgpu::Sampler sampler = device.CreateSampler(&samplerDesc);
wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0), wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0),
{ {{0, sampler},
{0, sampler}, {1, mInputTexture.CreateView()},
{1, mInputTexture.CreateView()}, {2, mUniformBuffer},
{2, mUniformBuffer}, {3, mOutputBuffer}});
{3, mOutputBuffer}
});
for (float textureValue : textureValues) { for (float textureValue : textureValues) {
// Set the input depth texture to the provided texture value // Set the input depth texture to the provided texture value

View File

@ -21,38 +21,38 @@
constexpr static unsigned int kRTSize = 64; constexpr static unsigned int kRTSize = 64;
class DepthStencilStateTest : public DawnTest { class DepthStencilStateTest : public DawnTest {
protected: protected:
void SetUp() override { void SetUp() override {
DawnTest::SetUp(); DawnTest::SetUp();
wgpu::TextureDescriptor renderTargetDescriptor; wgpu::TextureDescriptor renderTargetDescriptor;
renderTargetDescriptor.dimension = wgpu::TextureDimension::e2D; renderTargetDescriptor.dimension = wgpu::TextureDimension::e2D;
renderTargetDescriptor.size.width = kRTSize; renderTargetDescriptor.size.width = kRTSize;
renderTargetDescriptor.size.height = kRTSize; renderTargetDescriptor.size.height = kRTSize;
renderTargetDescriptor.size.depth = 1; renderTargetDescriptor.size.depth = 1;
renderTargetDescriptor.sampleCount = 1; renderTargetDescriptor.sampleCount = 1;
renderTargetDescriptor.format = wgpu::TextureFormat::RGBA8Unorm; renderTargetDescriptor.format = wgpu::TextureFormat::RGBA8Unorm;
renderTargetDescriptor.mipLevelCount = 1; renderTargetDescriptor.mipLevelCount = 1;
renderTargetDescriptor.usage = renderTargetDescriptor.usage =
wgpu::TextureUsage::OutputAttachment | wgpu::TextureUsage::CopySrc; wgpu::TextureUsage::OutputAttachment | wgpu::TextureUsage::CopySrc;
renderTarget = device.CreateTexture(&renderTargetDescriptor); renderTarget = device.CreateTexture(&renderTargetDescriptor);
renderTargetView = renderTarget.CreateView(); renderTargetView = renderTarget.CreateView();
wgpu::TextureDescriptor depthDescriptor; wgpu::TextureDescriptor depthDescriptor;
depthDescriptor.dimension = wgpu::TextureDimension::e2D; depthDescriptor.dimension = wgpu::TextureDimension::e2D;
depthDescriptor.size.width = kRTSize; depthDescriptor.size.width = kRTSize;
depthDescriptor.size.height = kRTSize; depthDescriptor.size.height = kRTSize;
depthDescriptor.size.depth = 1; depthDescriptor.size.depth = 1;
depthDescriptor.sampleCount = 1; depthDescriptor.sampleCount = 1;
depthDescriptor.format = wgpu::TextureFormat::Depth24PlusStencil8; depthDescriptor.format = wgpu::TextureFormat::Depth24PlusStencil8;
depthDescriptor.mipLevelCount = 1; depthDescriptor.mipLevelCount = 1;
depthDescriptor.usage = wgpu::TextureUsage::OutputAttachment; depthDescriptor.usage = wgpu::TextureUsage::OutputAttachment;
depthTexture = device.CreateTexture(&depthDescriptor); depthTexture = device.CreateTexture(&depthDescriptor);
depthTextureView = depthTexture.CreateView(); depthTextureView = depthTexture.CreateView();
vsModule = utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, R"( vsModule = utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, R"(
#version 450 #version 450
layout(set = 0, binding = 0) uniform myBlock { layout(set = 0, binding = 0) uniform myBlock {
vec3 color; vec3 color;
@ -67,7 +67,7 @@ class DepthStencilStateTest : public DawnTest {
} }
)"); )");
fsModule = utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment, R"( fsModule = utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment, R"(
#version 450 #version 450
layout(set = 0, binding = 0) uniform myBlock { layout(set = 0, binding = 0) uniform myBlock {
vec3 color; vec3 color;
@ -78,235 +78,251 @@ class DepthStencilStateTest : public DawnTest {
fragColor = vec4(myUbo.color, 1.f); fragColor = vec4(myUbo.color, 1.f);
} }
)"); )");
} }
struct TestSpec { struct TestSpec {
const wgpu::DepthStencilStateDescriptor& depthStencilState; const wgpu::DepthStencilStateDescriptor& depthStencilState;
RGBA8 color; RGBA8 color;
float depth; float depth;
uint32_t stencil; uint32_t stencil;
}; };
// Check whether a depth comparison function works as expected // Check whether a depth comparison function works as expected
// The less, equal, greater booleans denote wether the respective triangle should be visible based on the comparison function // The less, equal, greater booleans denote wether the respective triangle should be visible
void CheckDepthCompareFunction(wgpu::CompareFunction compareFunction, // based on the comparison function
bool less, void CheckDepthCompareFunction(wgpu::CompareFunction compareFunction,
bool equal, bool less,
bool greater) { bool equal,
wgpu::StencilStateFaceDescriptor stencilFace; bool greater) {
stencilFace.compare = wgpu::CompareFunction::Always; wgpu::StencilStateFaceDescriptor stencilFace;
stencilFace.failOp = wgpu::StencilOperation::Keep; stencilFace.compare = wgpu::CompareFunction::Always;
stencilFace.depthFailOp = wgpu::StencilOperation::Keep; stencilFace.failOp = wgpu::StencilOperation::Keep;
stencilFace.passOp = wgpu::StencilOperation::Keep; stencilFace.depthFailOp = wgpu::StencilOperation::Keep;
stencilFace.passOp = wgpu::StencilOperation::Keep;
wgpu::DepthStencilStateDescriptor baseState; wgpu::DepthStencilStateDescriptor baseState;
baseState.depthWriteEnabled = true; baseState.depthWriteEnabled = true;
baseState.depthCompare = wgpu::CompareFunction::Always; baseState.depthCompare = wgpu::CompareFunction::Always;
baseState.stencilBack = stencilFace; baseState.stencilBack = stencilFace;
baseState.stencilFront = stencilFace; baseState.stencilFront = stencilFace;
baseState.stencilReadMask = 0xff; baseState.stencilReadMask = 0xff;
baseState.stencilWriteMask = 0xff; baseState.stencilWriteMask = 0xff;
wgpu::DepthStencilStateDescriptor state; wgpu::DepthStencilStateDescriptor state;
state.depthWriteEnabled = true; state.depthWriteEnabled = true;
state.depthCompare = compareFunction; state.depthCompare = compareFunction;
state.stencilBack = stencilFace; state.stencilBack = stencilFace;
state.stencilFront = stencilFace; state.stencilFront = stencilFace;
state.stencilReadMask = 0xff; state.stencilReadMask = 0xff;
state.stencilWriteMask = 0xff; state.stencilWriteMask = 0xff;
RGBA8 baseColor = RGBA8(255, 255, 255, 255); RGBA8 baseColor = RGBA8(255, 255, 255, 255);
RGBA8 lessColor = RGBA8(255, 0, 0, 255); RGBA8 lessColor = RGBA8(255, 0, 0, 255);
RGBA8 equalColor = RGBA8(0, 255, 0, 255); RGBA8 equalColor = RGBA8(0, 255, 0, 255);
RGBA8 greaterColor = RGBA8(0, 0, 255, 255); RGBA8 greaterColor = RGBA8(0, 0, 255, 255);
// Base triangle at depth 0.5, depth always, depth write enabled // Base triangle at depth 0.5, depth always, depth write enabled
TestSpec base = { baseState, baseColor, 0.5f, 0u }; TestSpec base = {baseState, baseColor, 0.5f, 0u};
// Draw the base triangle, then a triangle in stencilFront of the base triangle with the // Draw the base triangle, then a triangle in stencilFront of the base triangle with the
// given depth comparison function // given depth comparison function
DoTest({ base, { state, lessColor, 0.f, 0u } }, less ? lessColor : baseColor); DoTest({base, {state, lessColor, 0.f, 0u}}, less ? lessColor : baseColor);
// Draw the base triangle, then a triangle in at the same depth as the base triangle with the given depth comparison function // Draw the base triangle, then a triangle in at the same depth as the base triangle with
DoTest({ base, { state, equalColor, 0.5f, 0u } }, equal ? equalColor : baseColor); // the given depth comparison function
DoTest({base, {state, equalColor, 0.5f, 0u}}, equal ? equalColor : baseColor);
// Draw the base triangle, then a triangle behind the base triangle with the given depth comparison function // Draw the base triangle, then a triangle behind the base triangle with the given depth
DoTest({ base, { state, greaterColor, 1.0f, 0u } }, greater ? greaterColor : baseColor); // comparison function
} DoTest({base, {state, greaterColor, 1.0f, 0u}}, greater ? greaterColor : baseColor);
}
// Check whether a stencil comparison function works as expected // Check whether a stencil comparison function works as expected
// The less, equal, greater booleans denote wether the respective triangle should be visible based on the comparison function // The less, equal, greater booleans denote wether the respective triangle should be visible
void CheckStencilCompareFunction(wgpu::CompareFunction compareFunction, // based on the comparison function
bool less, void CheckStencilCompareFunction(wgpu::CompareFunction compareFunction,
bool equal, bool less,
bool greater) { bool equal,
wgpu::StencilStateFaceDescriptor baseStencilFaceDescriptor; bool greater) {
baseStencilFaceDescriptor.compare = wgpu::CompareFunction::Always; wgpu::StencilStateFaceDescriptor baseStencilFaceDescriptor;
baseStencilFaceDescriptor.failOp = wgpu::StencilOperation::Keep; baseStencilFaceDescriptor.compare = wgpu::CompareFunction::Always;
baseStencilFaceDescriptor.depthFailOp = wgpu::StencilOperation::Keep; baseStencilFaceDescriptor.failOp = wgpu::StencilOperation::Keep;
baseStencilFaceDescriptor.passOp = wgpu::StencilOperation::Replace; baseStencilFaceDescriptor.depthFailOp = wgpu::StencilOperation::Keep;
wgpu::DepthStencilStateDescriptor baseState; baseStencilFaceDescriptor.passOp = wgpu::StencilOperation::Replace;
baseState.depthWriteEnabled = false; wgpu::DepthStencilStateDescriptor baseState;
baseState.depthCompare = wgpu::CompareFunction::Always; baseState.depthWriteEnabled = false;
baseState.stencilBack = baseStencilFaceDescriptor; baseState.depthCompare = wgpu::CompareFunction::Always;
baseState.stencilFront = baseStencilFaceDescriptor; baseState.stencilBack = baseStencilFaceDescriptor;
baseState.stencilReadMask = 0xff; baseState.stencilFront = baseStencilFaceDescriptor;
baseState.stencilWriteMask = 0xff; baseState.stencilReadMask = 0xff;
baseState.stencilWriteMask = 0xff;
wgpu::StencilStateFaceDescriptor stencilFaceDescriptor; wgpu::StencilStateFaceDescriptor stencilFaceDescriptor;
stencilFaceDescriptor.compare = compareFunction; stencilFaceDescriptor.compare = compareFunction;
stencilFaceDescriptor.failOp = wgpu::StencilOperation::Keep; stencilFaceDescriptor.failOp = wgpu::StencilOperation::Keep;
stencilFaceDescriptor.depthFailOp = wgpu::StencilOperation::Keep; stencilFaceDescriptor.depthFailOp = wgpu::StencilOperation::Keep;
stencilFaceDescriptor.passOp = wgpu::StencilOperation::Keep; stencilFaceDescriptor.passOp = wgpu::StencilOperation::Keep;
wgpu::DepthStencilStateDescriptor state; wgpu::DepthStencilStateDescriptor state;
state.depthWriteEnabled = false; state.depthWriteEnabled = false;
state.depthCompare = wgpu::CompareFunction::Always; state.depthCompare = wgpu::CompareFunction::Always;
state.stencilBack = stencilFaceDescriptor; state.stencilBack = stencilFaceDescriptor;
state.stencilFront = stencilFaceDescriptor; state.stencilFront = stencilFaceDescriptor;
state.stencilReadMask = 0xff; state.stencilReadMask = 0xff;
state.stencilWriteMask = 0xff; state.stencilWriteMask = 0xff;
RGBA8 baseColor = RGBA8(255, 255, 255, 255); RGBA8 baseColor = RGBA8(255, 255, 255, 255);
RGBA8 lessColor = RGBA8(255, 0, 0, 255); RGBA8 lessColor = RGBA8(255, 0, 0, 255);
RGBA8 equalColor = RGBA8(0, 255, 0, 255); RGBA8 equalColor = RGBA8(0, 255, 0, 255);
RGBA8 greaterColor = RGBA8(0, 0, 255, 255); RGBA8 greaterColor = RGBA8(0, 0, 255, 255);
// Base triangle with stencil reference 1 // Base triangle with stencil reference 1
TestSpec base = { baseState, baseColor, 0.0f, 1u }; TestSpec base = {baseState, baseColor, 0.0f, 1u};
// Draw the base triangle, then a triangle with stencil reference 0 with the given stencil comparison function // Draw the base triangle, then a triangle with stencil reference 0 with the given stencil
DoTest({ base, { state, lessColor, 0.f, 0u } }, less ? lessColor : baseColor); // comparison function
DoTest({base, {state, lessColor, 0.f, 0u}}, less ? lessColor : baseColor);
// Draw the base triangle, then a triangle with stencil reference 1 with the given stencil comparison function // Draw the base triangle, then a triangle with stencil reference 1 with the given stencil
DoTest({ base, { state, equalColor, 0.f, 1u } }, equal ? equalColor : baseColor); // comparison function
DoTest({base, {state, equalColor, 0.f, 1u}}, equal ? equalColor : baseColor);
// Draw the base triangle, then a triangle with stencil reference 2 with the given stencil comparison function // Draw the base triangle, then a triangle with stencil reference 2 with the given stencil
DoTest({ base, { state, greaterColor, 0.f, 2u } }, greater ? greaterColor : baseColor); // comparison function
} DoTest({base, {state, greaterColor, 0.f, 2u}}, greater ? greaterColor : baseColor);
}
// Given the provided `initialStencil` and `reference`, check that applying the `stencilOperation` produces the `expectedStencil` // Given the provided `initialStencil` and `reference`, check that applying the
void CheckStencilOperation(wgpu::StencilOperation stencilOperation, // `stencilOperation` produces the `expectedStencil`
uint32_t initialStencil, void CheckStencilOperation(wgpu::StencilOperation stencilOperation,
uint32_t reference, uint32_t initialStencil,
uint32_t expectedStencil) { uint32_t reference,
wgpu::StencilStateFaceDescriptor baseStencilFaceDescriptor; uint32_t expectedStencil) {
baseStencilFaceDescriptor.compare = wgpu::CompareFunction::Always; wgpu::StencilStateFaceDescriptor baseStencilFaceDescriptor;
baseStencilFaceDescriptor.failOp = wgpu::StencilOperation::Keep; baseStencilFaceDescriptor.compare = wgpu::CompareFunction::Always;
baseStencilFaceDescriptor.depthFailOp = wgpu::StencilOperation::Keep; baseStencilFaceDescriptor.failOp = wgpu::StencilOperation::Keep;
baseStencilFaceDescriptor.passOp = wgpu::StencilOperation::Replace; baseStencilFaceDescriptor.depthFailOp = wgpu::StencilOperation::Keep;
wgpu::DepthStencilStateDescriptor baseState; baseStencilFaceDescriptor.passOp = wgpu::StencilOperation::Replace;
baseState.depthWriteEnabled = false; wgpu::DepthStencilStateDescriptor baseState;
baseState.depthCompare = wgpu::CompareFunction::Always; baseState.depthWriteEnabled = false;
baseState.stencilBack = baseStencilFaceDescriptor; baseState.depthCompare = wgpu::CompareFunction::Always;
baseState.stencilFront = baseStencilFaceDescriptor; baseState.stencilBack = baseStencilFaceDescriptor;
baseState.stencilReadMask = 0xff; baseState.stencilFront = baseStencilFaceDescriptor;
baseState.stencilWriteMask = 0xff; baseState.stencilReadMask = 0xff;
baseState.stencilWriteMask = 0xff;
wgpu::StencilStateFaceDescriptor stencilFaceDescriptor; wgpu::StencilStateFaceDescriptor stencilFaceDescriptor;
stencilFaceDescriptor.compare = wgpu::CompareFunction::Always; stencilFaceDescriptor.compare = wgpu::CompareFunction::Always;
stencilFaceDescriptor.failOp = wgpu::StencilOperation::Keep; stencilFaceDescriptor.failOp = wgpu::StencilOperation::Keep;
stencilFaceDescriptor.depthFailOp = wgpu::StencilOperation::Keep; stencilFaceDescriptor.depthFailOp = wgpu::StencilOperation::Keep;
stencilFaceDescriptor.passOp = stencilOperation; stencilFaceDescriptor.passOp = stencilOperation;
wgpu::DepthStencilStateDescriptor state; wgpu::DepthStencilStateDescriptor state;
state.depthWriteEnabled = false; state.depthWriteEnabled = false;
state.depthCompare = wgpu::CompareFunction::Always; state.depthCompare = wgpu::CompareFunction::Always;
state.stencilBack = stencilFaceDescriptor; state.stencilBack = stencilFaceDescriptor;
state.stencilFront = stencilFaceDescriptor; state.stencilFront = stencilFaceDescriptor;
state.stencilReadMask = 0xff; state.stencilReadMask = 0xff;
state.stencilWriteMask = 0xff; state.stencilWriteMask = 0xff;
CheckStencil({ CheckStencil(
{
// Wipe the stencil buffer with the initialStencil value // Wipe the stencil buffer with the initialStencil value
{ baseState, RGBA8(255, 255, 255, 255), 0.f, initialStencil }, {baseState, RGBA8(255, 255, 255, 255), 0.f, initialStencil},
// Draw a triangle with the provided stencil operation and reference // Draw a triangle with the provided stencil operation and reference
{ state, RGBA8(255, 0, 0, 255), 0.f, reference }, {state, RGBA8(255, 0, 0, 255), 0.f, reference},
}, expectedStencil); },
} expectedStencil);
}
// Draw a list of test specs, and check if the stencil value is equal to the expected value // Draw a list of test specs, and check if the stencil value is equal to the expected value
void CheckStencil(std::vector<TestSpec> testParams, uint32_t expectedStencil) { void CheckStencil(std::vector<TestSpec> testParams, uint32_t expectedStencil) {
wgpu::StencilStateFaceDescriptor stencilFaceDescriptor; wgpu::StencilStateFaceDescriptor stencilFaceDescriptor;
stencilFaceDescriptor.compare = wgpu::CompareFunction::Equal; stencilFaceDescriptor.compare = wgpu::CompareFunction::Equal;
stencilFaceDescriptor.failOp = wgpu::StencilOperation::Keep; stencilFaceDescriptor.failOp = wgpu::StencilOperation::Keep;
stencilFaceDescriptor.depthFailOp = wgpu::StencilOperation::Keep; stencilFaceDescriptor.depthFailOp = wgpu::StencilOperation::Keep;
stencilFaceDescriptor.passOp = wgpu::StencilOperation::Keep; stencilFaceDescriptor.passOp = wgpu::StencilOperation::Keep;
wgpu::DepthStencilStateDescriptor state; wgpu::DepthStencilStateDescriptor state;
state.depthWriteEnabled = false; state.depthWriteEnabled = false;
state.depthCompare = wgpu::CompareFunction::Always; state.depthCompare = wgpu::CompareFunction::Always;
state.stencilBack = stencilFaceDescriptor; state.stencilBack = stencilFaceDescriptor;
state.stencilFront = stencilFaceDescriptor; state.stencilFront = stencilFaceDescriptor;
state.stencilReadMask = 0xff; state.stencilReadMask = 0xff;
state.stencilWriteMask = 0xff; state.stencilWriteMask = 0xff;
testParams.push_back({ state, RGBA8(0, 255, 0, 255), 0, expectedStencil }); testParams.push_back({state, RGBA8(0, 255, 0, 255), 0, expectedStencil});
DoTest(testParams, RGBA8(0, 255, 0, 255)); DoTest(testParams, RGBA8(0, 255, 0, 255));
} }
// Each test param represents a pair of triangles with a color, depth, stencil value, and depthStencil state, one frontfacing, one backfacing // Each test param represents a pair of triangles with a color, depth, stencil value, and
// Draw the triangles in order and check the expected colors for the frontfaces and backfaces // depthStencil state, one frontfacing, one backfacing Draw the triangles in order and check the
void DoTest(const std::vector<TestSpec> &testParams, const RGBA8& expectedFront, const RGBA8& expectedBack) { // expected colors for the frontfaces and backfaces
wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); void DoTest(const std::vector<TestSpec>& testParams,
const RGBA8& expectedFront,
const RGBA8& expectedBack) {
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
struct TriangleData { struct TriangleData {
float color[3]; float color[3];
float depth; float depth;
};
utils::ComboRenderPassDescriptor renderPass({renderTargetView}, depthTextureView);
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
for (size_t i = 0; i < testParams.size(); ++i) {
const TestSpec& test = testParams[i];
TriangleData data = {
{static_cast<float>(test.color.r) / 255.f, static_cast<float>(test.color.g) / 255.f,
static_cast<float>(test.color.b) / 255.f},
test.depth,
}; };
// Upload a buffer for each triangle's depth and color data
wgpu::Buffer buffer = utils::CreateBufferFromData(device, &data, sizeof(TriangleData),
wgpu::BufferUsage::Uniform);
utils::ComboRenderPassDescriptor renderPass({renderTargetView}, depthTextureView); // Create a pipeline for the triangles with the test spec's depth stencil state
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
for (size_t i = 0; i < testParams.size(); ++i) { utils::ComboRenderPipelineDescriptor descriptor(device);
const TestSpec& test = testParams[i]; descriptor.vertexStage.module = vsModule;
descriptor.cFragmentStage.module = fsModule;
descriptor.cDepthStencilState = test.depthStencilState;
descriptor.cDepthStencilState.format = wgpu::TextureFormat::Depth24PlusStencil8;
descriptor.depthStencilState = &descriptor.cDepthStencilState;
TriangleData data = { wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&descriptor);
{ static_cast<float>(test.color.r) / 255.f, static_cast<float>(test.color.g) / 255.f, static_cast<float>(test.color.b) / 255.f },
test.depth,
};
// Upload a buffer for each triangle's depth and color data
wgpu::Buffer buffer = utils::CreateBufferFromData(
device, &data, sizeof(TriangleData), wgpu::BufferUsage::Uniform);
// Create a pipeline for the triangles with the test spec's depth stencil state // Create a bind group for the data
wgpu::BindGroup bindGroup = utils::MakeBindGroup(
device, pipeline.GetBindGroupLayout(0), {{0, buffer, 0, sizeof(TriangleData)}});
utils::ComboRenderPipelineDescriptor descriptor(device); pass.SetPipeline(pipeline);
descriptor.vertexStage.module = vsModule; pass.SetStencilReference(test.stencil); // Set the stencil reference
descriptor.cFragmentStage.module = fsModule; pass.SetBindGroup(0,
descriptor.cDepthStencilState = test.depthStencilState; bindGroup); // Set the bind group which contains color and depth data
descriptor.cDepthStencilState.format = wgpu::TextureFormat::Depth24PlusStencil8; pass.Draw(6);
descriptor.depthStencilState = &descriptor.cDepthStencilState;
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&descriptor);
// Create a bind group for the data
wgpu::BindGroup bindGroup = utils::MakeBindGroup(
device, pipeline.GetBindGroupLayout(0), {{0, buffer, 0, sizeof(TriangleData)}});
pass.SetPipeline(pipeline);
pass.SetStencilReference(test.stencil); // Set the stencil reference
pass.SetBindGroup(
0, bindGroup); // Set the bind group which contains color and depth data
pass.Draw(6);
}
pass.EndPass();
wgpu::CommandBuffer commands = encoder.Finish();
queue.Submit(1, &commands);
EXPECT_PIXEL_RGBA8_EQ(expectedFront, renderTarget, kRTSize / 4, kRTSize / 2) << "Front face check failed";
EXPECT_PIXEL_RGBA8_EQ(expectedBack, renderTarget, 3 * kRTSize / 4, kRTSize / 2) << "Back face check failed";
} }
pass.EndPass();
void DoTest(const std::vector<TestSpec> &testParams, const RGBA8& expected) { wgpu::CommandBuffer commands = encoder.Finish();
DoTest(testParams, expected, expected); queue.Submit(1, &commands);
}
wgpu::Texture renderTarget; EXPECT_PIXEL_RGBA8_EQ(expectedFront, renderTarget, kRTSize / 4, kRTSize / 2)
wgpu::Texture depthTexture; << "Front face check failed";
wgpu::TextureView renderTargetView; EXPECT_PIXEL_RGBA8_EQ(expectedBack, renderTarget, 3 * kRTSize / 4, kRTSize / 2)
wgpu::TextureView depthTextureView; << "Back face check failed";
wgpu::ShaderModule vsModule; }
wgpu::ShaderModule fsModule;
void DoTest(const std::vector<TestSpec>& testParams, const RGBA8& expected) {
DoTest(testParams, expected, expected);
}
wgpu::Texture renderTarget;
wgpu::Texture depthTexture;
wgpu::TextureView renderTargetView;
wgpu::TextureView depthTextureView;
wgpu::ShaderModule vsModule;
wgpu::ShaderModule fsModule;
}; };
// Test compilation and usage of the fixture // Test compilation and usage of the fixture
@ -325,9 +341,11 @@ TEST_P(DepthStencilStateTest, Basic) {
state.stencilReadMask = 0xff; state.stencilReadMask = 0xff;
state.stencilWriteMask = 0xff; state.stencilWriteMask = 0xff;
DoTest({ DoTest(
{ state, RGBA8(0, 255, 0, 255), 0.5f, 0u }, {
}, RGBA8(0, 255, 0, 255)); {state, RGBA8(0, 255, 0, 255), 0.5f, 0u},
},
RGBA8(0, 255, 0, 255));
} }
// Test defaults: depth and stencil tests disabled // Test defaults: depth and stencil tests disabled
@ -347,9 +365,9 @@ TEST_P(DepthStencilStateTest, DepthStencilDisabled) {
state.stencilWriteMask = 0xff; state.stencilWriteMask = 0xff;
TestSpec specs[3] = { TestSpec specs[3] = {
{ state, RGBA8(255, 0, 0, 255), 0.0f, 0u }, {state, RGBA8(255, 0, 0, 255), 0.0f, 0u},
{ state, RGBA8(0, 255, 0, 255), 0.5f, 0u }, {state, RGBA8(0, 255, 0, 255), 0.5f, 0u},
{ state, RGBA8(0, 0, 255, 255), 1.0f, 0u }, {state, RGBA8(0, 0, 255, 255), 1.0f, 0u},
}; };
// Test that for all combinations, the last triangle drawn is the one visible // Test that for all combinations, the last triangle drawn is the one visible
@ -357,8 +375,8 @@ TEST_P(DepthStencilStateTest, DepthStencilDisabled) {
for (uint32_t last = 0; last < 3; ++last) { for (uint32_t last = 0; last < 3; ++last) {
uint32_t i = (last + 1) % 3; uint32_t i = (last + 1) % 3;
uint32_t j = (last + 2) % 3; uint32_t j = (last + 2) % 3;
DoTest({ specs[i], specs[j], specs[last] }, specs[last].color); DoTest({specs[i], specs[j], specs[last]}, specs[last].color);
DoTest({ specs[j], specs[i], specs[last] }, specs[last].color); DoTest({specs[j], specs[i], specs[last]}, specs[last].color);
} }
} }
@ -427,11 +445,17 @@ TEST_P(DepthStencilStateTest, DepthWriteDisabled) {
checkState.stencilReadMask = 0xff; checkState.stencilReadMask = 0xff;
checkState.stencilWriteMask = 0xff; checkState.stencilWriteMask = 0xff;
DoTest({ DoTest(
{ baseState, RGBA8(255, 255, 255, 255), 1.f, 0u }, // Draw a base triangle with depth enabled {
{ noDepthWrite, RGBA8(0, 0, 0, 255), 0.f, 0u }, // Draw a second triangle without depth enabled {baseState, RGBA8(255, 255, 255, 255), 1.f,
{ checkState, RGBA8(0, 255, 0, 255), 1.f, 0u }, // Draw a third triangle which should occlude the second even though it is behind it 0u}, // Draw a base triangle with depth enabled
}, RGBA8(0, 255, 0, 255)); {noDepthWrite, RGBA8(0, 0, 0, 255), 0.f,
0u}, // Draw a second triangle without depth enabled
{checkState, RGBA8(0, 255, 0, 255), 1.f,
0u}, // Draw a third triangle which should occlude the second even though it is behind
// it
},
RGBA8(0, 255, 0, 255));
} }
// The following tests check that each stencil comparison function works // The following tests check that each stencil comparison function works
@ -536,9 +560,11 @@ TEST_P(DepthStencilStateTest, StencilReadMask) {
RGBA8 red = RGBA8(255, 0, 0, 255); RGBA8 red = RGBA8(255, 0, 0, 255);
RGBA8 green = RGBA8(0, 255, 0, 255); RGBA8 green = RGBA8(0, 255, 0, 255);
TestSpec base = { baseState, baseColor, 0.5f, 3u }; // Base triangle to set the stencil to 3 TestSpec base = {baseState, baseColor, 0.5f, 3u}; // Base triangle to set the stencil to 3
DoTest({ base, { state, red, 0.f, 1u } }, baseColor); // Triangle with stencil reference 1 and read mask 2 does not draw because (3 & 2 != 1) DoTest({base, {state, red, 0.f, 1u}}, baseColor); // Triangle with stencil reference 1 and read
DoTest({ base, { state, green, 0.f, 2u } }, green); // Triangle with stencil reference 2 and read mask 2 draws because (3 & 2 == 2) // mask 2 does not draw because (3 & 2 != 1)
DoTest({base, {state, green, 0.f, 2u}},
green); // Triangle with stencil reference 2 and read mask 2 draws because (3 & 2 == 2)
} }
// Check that setting a stencil write mask works // Check that setting a stencil write mask works
@ -572,9 +598,12 @@ TEST_P(DepthStencilStateTest, StencilWriteMask) {
RGBA8 baseColor = RGBA8(255, 255, 255, 255); RGBA8 baseColor = RGBA8(255, 255, 255, 255);
RGBA8 green = RGBA8(0, 255, 0, 255); RGBA8 green = RGBA8(0, 255, 0, 255);
TestSpec base = { baseState, baseColor, 0.5f, 3u }; // Base triangle with stencil reference 3 and mask 1 to set the stencil 1 TestSpec base = {baseState, baseColor, 0.5f,
DoTest({ base, { state, green, 0.f, 2u } }, baseColor); // Triangle with stencil reference 2 does not draw because 2 != (3 & 1) 3u}; // Base triangle with stencil reference 3 and mask 1 to set the stencil 1
DoTest({ base, { state, green, 0.f, 1u } }, green); // Triangle with stencil reference 1 draws because 1 == (3 & 1) DoTest({base, {state, green, 0.f, 2u}},
baseColor); // Triangle with stencil reference 2 does not draw because 2 != (3 & 1)
DoTest({base, {state, green, 0.f, 1u}},
green); // Triangle with stencil reference 1 draws because 1 == (3 & 1)
} }
// Test that the stencil operation is executed on stencil fail // Test that the stencil operation is executed on stencil fail
@ -605,10 +634,13 @@ TEST_P(DepthStencilStateTest, StencilFail) {
state.stencilReadMask = 0xff; state.stencilReadMask = 0xff;
state.stencilWriteMask = 0xff; state.stencilWriteMask = 0xff;
CheckStencil({ CheckStencil(
{ baseState, RGBA8(255, 255, 255, 255), 1.f, 1 }, // Triangle to set stencil value to 1 {
{ state, RGBA8(0, 0, 0, 255), 0.f, 2 } // Triangle with stencil reference 2 fails the Less comparison function {baseState, RGBA8(255, 255, 255, 255), 1.f, 1}, // Triangle to set stencil value to 1
}, 2); // Replace the stencil on failure, so it should be 2 {state, RGBA8(0, 0, 0, 255), 0.f,
2} // Triangle with stencil reference 2 fails the Less comparison function
},
2); // Replace the stencil on failure, so it should be 2
} }
// Test that the stencil operation is executed on stencil pass, depth fail // Test that the stencil operation is executed on stencil pass, depth fail
@ -639,10 +671,12 @@ TEST_P(DepthStencilStateTest, StencilDepthFail) {
state.stencilReadMask = 0xff; state.stencilReadMask = 0xff;
state.stencilWriteMask = 0xff; state.stencilWriteMask = 0xff;
CheckStencil({ CheckStencil({{baseState, RGBA8(255, 255, 255, 255), 0.f,
{ baseState, RGBA8(255, 255, 255, 255), 0.f, 1 }, // Triangle to set stencil value to 1. Depth is 0 1}, // Triangle to set stencil value to 1. Depth is 0
{ state, RGBA8(0, 0, 0, 255), 1.f, 2 } }, // Triangle with stencil reference 2 passes the Greater comparison function. At depth 1, it fails the Less depth test {state, RGBA8(0, 0, 0, 255), 1.f,
2); // Replace the stencil on stencil pass, depth failure, so it should be 2 2}}, // Triangle with stencil reference 2 passes the Greater comparison
// function. At depth 1, it fails the Less depth test
2); // Replace the stencil on stencil pass, depth failure, so it should be 2
} }
// Test that the stencil operation is executed on stencil pass, depth pass // Test that the stencil operation is executed on stencil pass, depth pass
@ -673,10 +707,12 @@ TEST_P(DepthStencilStateTest, StencilDepthPass) {
state.stencilReadMask = 0xff; state.stencilReadMask = 0xff;
state.stencilWriteMask = 0xff; state.stencilWriteMask = 0xff;
CheckStencil({ CheckStencil({{baseState, RGBA8(255, 255, 255, 255), 1.f,
{ baseState, RGBA8(255, 255, 255, 255), 1.f, 1 }, // Triangle to set stencil value to 1. Depth is 0 1}, // Triangle to set stencil value to 1. Depth is 0
{ state, RGBA8(0, 0, 0, 255), 0.f, 2 } }, // Triangle with stencil reference 2 passes the Greater comparison function. At depth 0, it pass the Less depth test {state, RGBA8(0, 0, 0, 255), 0.f,
2); // Replace the stencil on stencil pass, depth pass, so it should be 2 2}}, // Triangle with stencil reference 2 passes the Greater comparison
// function. At depth 0, it pass the Less depth test
2); // Replace the stencil on stencil pass, depth pass, so it should be 2
} }
// Test that creating a render pipeline works with for all depth and combined formats // Test that creating a render pipeline works with for all depth and combined formats

View File

@ -157,4 +157,8 @@ TEST_P(DestroyTest, TextureSubmitDestroySubmit) {
ASSERT_DEVICE_ERROR(queue.Submit(1, &commands)); ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
} }
DAWN_INSTANTIATE_TEST(DestroyTest, D3D12Backend(), MetalBackend(), OpenGLBackend(), VulkanBackend()); DAWN_INSTANTIATE_TEST(DestroyTest,
D3D12Backend(),
MetalBackend(),
OpenGLBackend(),
VulkanBackend());

View File

@ -20,90 +20,89 @@
constexpr uint32_t kRTSize = 4; constexpr uint32_t kRTSize = 4;
class DrawIndexedTest : public DawnTest { class DrawIndexedTest : public DawnTest {
protected: protected:
void SetUp() override { void SetUp() override {
DawnTest::SetUp(); DawnTest::SetUp();
renderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize); renderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize);
wgpu::ShaderModule vsModule = wgpu::ShaderModule vsModule =
utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, R"( utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, R"(
#version 450 #version 450
layout(location = 0) in vec4 pos; layout(location = 0) in vec4 pos;
void main() { void main() {
gl_Position = pos; gl_Position = pos;
})"); })");
wgpu::ShaderModule fsModule = wgpu::ShaderModule fsModule =
utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment, R"( utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment, R"(
#version 450 #version 450
layout(location = 0) out vec4 fragColor; layout(location = 0) out vec4 fragColor;
void main() { void main() {
fragColor = vec4(0.0, 1.0, 0.0, 1.0); fragColor = vec4(0.0, 1.0, 0.0, 1.0);
})"); })");
utils::ComboRenderPipelineDescriptor descriptor(device); utils::ComboRenderPipelineDescriptor descriptor(device);
descriptor.vertexStage.module = vsModule; descriptor.vertexStage.module = vsModule;
descriptor.cFragmentStage.module = fsModule; descriptor.cFragmentStage.module = fsModule;
descriptor.primitiveTopology = wgpu::PrimitiveTopology::TriangleStrip; descriptor.primitiveTopology = wgpu::PrimitiveTopology::TriangleStrip;
descriptor.cVertexState.vertexBufferCount = 1; descriptor.cVertexState.vertexBufferCount = 1;
descriptor.cVertexState.cVertexBuffers[0].arrayStride = 4 * sizeof(float); descriptor.cVertexState.cVertexBuffers[0].arrayStride = 4 * sizeof(float);
descriptor.cVertexState.cVertexBuffers[0].attributeCount = 1; descriptor.cVertexState.cVertexBuffers[0].attributeCount = 1;
descriptor.cVertexState.cAttributes[0].format = wgpu::VertexFormat::Float4; descriptor.cVertexState.cAttributes[0].format = wgpu::VertexFormat::Float4;
descriptor.cColorStates[0].format = renderPass.colorFormat; descriptor.cColorStates[0].format = renderPass.colorFormat;
pipeline = device.CreateRenderPipeline(&descriptor); pipeline = device.CreateRenderPipeline(&descriptor);
vertexBuffer = utils::CreateBufferFromData<float>( vertexBuffer = utils::CreateBufferFromData<float>(
device, wgpu::BufferUsage::Vertex, device, wgpu::BufferUsage::Vertex,
{// First quad: the first 3 vertices represent the bottom left triangle {// First quad: the first 3 vertices represent the bottom left triangle
-1.0f, 1.0f, 0.0f, 1.0f, 1.0f, -1.0f, 0.0f, 1.0f, -1.0f, -1.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, -1.0f, 0.0f, 1.0f, -1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 1.0f,
1.0f, 0.0f, 1.0f, 0.0f, 1.0f,
// Second quad: the first 3 vertices represent the top right triangle // Second quad: the first 3 vertices represent the top right triangle
-1.0f, 1.0f, 0.0f, 1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, -1.0f, -1.0f,
-1.0f, 0.0f, 1.0f}); 0.0f, 1.0f});
indexBuffer = utils::CreateBufferFromData<uint32_t>( indexBuffer = utils::CreateBufferFromData<uint32_t>(
device, wgpu::BufferUsage::Index, device, wgpu::BufferUsage::Index,
{0, 1, 2, 0, 3, 1, {0, 1, 2, 0, 3, 1,
// The indices below are added to test negatve baseVertex // The indices below are added to test negatve baseVertex
0 + 4, 1 + 4, 2 + 4, 0 + 4, 3 + 4, 1 + 4}); 0 + 4, 1 + 4, 2 + 4, 0 + 4, 3 + 4, 1 + 4});
}
utils::BasicRenderPass renderPass;
wgpu::RenderPipeline pipeline;
wgpu::Buffer vertexBuffer;
wgpu::Buffer indexBuffer;
void Test(uint32_t indexCount,
uint32_t instanceCount,
uint32_t firstIndex,
int32_t baseVertex,
uint32_t firstInstance,
uint64_t bufferOffset,
RGBA8 bottomLeftExpected,
RGBA8 topRightExpected) {
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
{
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
pass.SetPipeline(pipeline);
pass.SetVertexBuffer(0, vertexBuffer);
pass.SetIndexBuffer(indexBuffer, bufferOffset);
pass.DrawIndexed(indexCount, instanceCount, firstIndex, baseVertex, firstInstance);
pass.EndPass();
} }
utils::BasicRenderPass renderPass; wgpu::CommandBuffer commands = encoder.Finish();
wgpu::RenderPipeline pipeline; queue.Submit(1, &commands);
wgpu::Buffer vertexBuffer;
wgpu::Buffer indexBuffer;
void Test(uint32_t indexCount, EXPECT_PIXEL_RGBA8_EQ(bottomLeftExpected, renderPass.color, 1, 3);
uint32_t instanceCount, EXPECT_PIXEL_RGBA8_EQ(topRightExpected, renderPass.color, 3, 1);
uint32_t firstIndex, }
int32_t baseVertex,
uint32_t firstInstance,
uint64_t bufferOffset,
RGBA8 bottomLeftExpected,
RGBA8 topRightExpected) {
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
{
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
pass.SetPipeline(pipeline);
pass.SetVertexBuffer(0, vertexBuffer);
pass.SetIndexBuffer(indexBuffer, bufferOffset);
pass.DrawIndexed(indexCount, instanceCount, firstIndex, baseVertex, firstInstance);
pass.EndPass();
}
wgpu::CommandBuffer commands = encoder.Finish();
queue.Submit(1, &commands);
EXPECT_PIXEL_RGBA8_EQ(bottomLeftExpected, renderPass.color, 1, 3);
EXPECT_PIXEL_RGBA8_EQ(topRightExpected, renderPass.color, 3, 1);
}
}; };
// The most basic DrawIndexed triangle draw. // The most basic DrawIndexed triangle draw.
TEST_P(DrawIndexedTest, Uint32) { TEST_P(DrawIndexedTest, Uint32) {
RGBA8 filled(0, 255, 0, 255); RGBA8 filled(0, 255, 0, 255);
RGBA8 notFilled(0, 0, 0, 0); RGBA8 notFilled(0, 0, 0, 0);
@ -134,4 +133,8 @@ TEST_P(DrawIndexedTest, BaseVertex) {
Test(3, 1, 3, -4, 0, 6 * sizeof(uint32_t), notFilled, filled); Test(3, 1, 3, -4, 0, 6 * sizeof(uint32_t), notFilled, filled);
} }
DAWN_INSTANTIATE_TEST(DrawIndexedTest, D3D12Backend(), MetalBackend(), OpenGLBackend(), VulkanBackend()); DAWN_INSTANTIATE_TEST(DrawIndexedTest,
D3D12Backend(),
MetalBackend(),
OpenGLBackend(),
VulkanBackend());

View File

@ -124,4 +124,8 @@ TEST_P(DrawIndirectTest, IndirectOffset) {
Test({3, 1, 0, 0, 3, 1, 3, 0}, 4 * sizeof(uint32_t), notFilled, filled); Test({3, 1, 0, 0, 3, 1, 3, 0}, 4 * sizeof(uint32_t), notFilled, filled);
} }
DAWN_INSTANTIATE_TEST(DrawIndirectTest, D3D12Backend(), MetalBackend(), OpenGLBackend(), VulkanBackend()); DAWN_INSTANTIATE_TEST(DrawIndirectTest,
D3D12Backend(),
MetalBackend(),
OpenGLBackend(),
VulkanBackend());

View File

@ -231,7 +231,11 @@ TEST_P(GpuMemorySyncTests, ComputePassToRenderPass) {
EXPECT_PIXEL_RGBA8_EQ(RGBA8(2, 0, 0, 255), renderPass.color, 0, 0); EXPECT_PIXEL_RGBA8_EQ(RGBA8(2, 0, 0, 255), renderPass.color, 0, 0);
} }
DAWN_INSTANTIATE_TEST(GpuMemorySyncTests, D3D12Backend(), MetalBackend(), OpenGLBackend(), VulkanBackend()); DAWN_INSTANTIATE_TEST(GpuMemorySyncTests,
D3D12Backend(),
MetalBackend(),
OpenGLBackend(),
VulkanBackend());
class StorageToUniformSyncTests : public DawnTest { class StorageToUniformSyncTests : public DawnTest {
protected: protected:

View File

@ -369,7 +369,8 @@ class IOSurfaceUsageTests : public IOSurfaceTestBase {
// Test sampling from a R8 IOSurface // Test sampling from a R8 IOSurface
TEST_P(IOSurfaceUsageTests, SampleFromR8IOSurface) { TEST_P(IOSurfaceUsageTests, SampleFromR8IOSurface) {
DAWN_SKIP_TEST_IF(UsesWire()); DAWN_SKIP_TEST_IF(UsesWire());
ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, kCVPixelFormatType_OneComponent8, 1); ScopedIOSurfaceRef ioSurface =
CreateSinglePlaneIOSurface(1, 1, kCVPixelFormatType_OneComponent8, 1);
uint8_t data = 0x01; uint8_t data = 0x01;
DoSampleTest(ioSurface.get(), wgpu::TextureFormat::R8Unorm, &data, sizeof(data), DoSampleTest(ioSurface.get(), wgpu::TextureFormat::R8Unorm, &data, sizeof(data),
@ -379,7 +380,8 @@ TEST_P(IOSurfaceUsageTests, SampleFromR8IOSurface) {
// Test clearing a R8 IOSurface // Test clearing a R8 IOSurface
TEST_P(IOSurfaceUsageTests, ClearR8IOSurface) { TEST_P(IOSurfaceUsageTests, ClearR8IOSurface) {
DAWN_SKIP_TEST_IF(UsesWire()); DAWN_SKIP_TEST_IF(UsesWire());
ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, kCVPixelFormatType_OneComponent8, 1); ScopedIOSurfaceRef ioSurface =
CreateSinglePlaneIOSurface(1, 1, kCVPixelFormatType_OneComponent8, 1);
uint8_t data = 0x01; uint8_t data = 0x01;
DoClearTest(ioSurface.get(), wgpu::TextureFormat::R8Unorm, &data, sizeof(data)); DoClearTest(ioSurface.get(), wgpu::TextureFormat::R8Unorm, &data, sizeof(data));
@ -388,7 +390,8 @@ TEST_P(IOSurfaceUsageTests, ClearR8IOSurface) {
// Test sampling from a RG8 IOSurface // Test sampling from a RG8 IOSurface
TEST_P(IOSurfaceUsageTests, SampleFromRG8IOSurface) { TEST_P(IOSurfaceUsageTests, SampleFromRG8IOSurface) {
DAWN_SKIP_TEST_IF(UsesWire()); DAWN_SKIP_TEST_IF(UsesWire());
ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, kCVPixelFormatType_TwoComponent8, 2); ScopedIOSurfaceRef ioSurface =
CreateSinglePlaneIOSurface(1, 1, kCVPixelFormatType_TwoComponent8, 2);
uint16_t data = 0x0102; // Stored as (G, R) uint16_t data = 0x0102; // Stored as (G, R)
DoSampleTest(ioSurface.get(), wgpu::TextureFormat::RG8Unorm, &data, sizeof(data), DoSampleTest(ioSurface.get(), wgpu::TextureFormat::RG8Unorm, &data, sizeof(data),
@ -398,7 +401,8 @@ TEST_P(IOSurfaceUsageTests, SampleFromRG8IOSurface) {
// Test clearing a RG8 IOSurface // Test clearing a RG8 IOSurface
TEST_P(IOSurfaceUsageTests, ClearRG8IOSurface) { TEST_P(IOSurfaceUsageTests, ClearRG8IOSurface) {
DAWN_SKIP_TEST_IF(UsesWire()); DAWN_SKIP_TEST_IF(UsesWire());
ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(1, 1, kCVPixelFormatType_TwoComponent8, 2); ScopedIOSurfaceRef ioSurface =
CreateSinglePlaneIOSurface(1, 1, kCVPixelFormatType_TwoComponent8, 2);
uint16_t data = 0x0201; uint16_t data = 0x0201;
DoClearTest(ioSurface.get(), wgpu::TextureFormat::RG8Unorm, &data, sizeof(data)); DoClearTest(ioSurface.get(), wgpu::TextureFormat::RG8Unorm, &data, sizeof(data));

View File

@ -21,45 +21,45 @@
constexpr uint32_t kRTSize = 400; constexpr uint32_t kRTSize = 400;
class IndexFormatTest : public DawnTest { class IndexFormatTest : public DawnTest {
protected: protected:
void SetUp() override { void SetUp() override {
DawnTest::SetUp(); DawnTest::SetUp();
renderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize); renderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize);
} }
utils::BasicRenderPass renderPass; utils::BasicRenderPass renderPass;
wgpu::RenderPipeline MakeTestPipeline(wgpu::IndexFormat format) { wgpu::RenderPipeline MakeTestPipeline(wgpu::IndexFormat format) {
wgpu::ShaderModule vsModule = wgpu::ShaderModule vsModule =
utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, R"( utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, R"(
#version 450 #version 450
layout(location = 0) in vec4 pos; layout(location = 0) in vec4 pos;
void main() { void main() {
gl_Position = pos; gl_Position = pos;
})"); })");
wgpu::ShaderModule fsModule = wgpu::ShaderModule fsModule =
utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment, R"( utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment, R"(
#version 450 #version 450
layout(location = 0) out vec4 fragColor; layout(location = 0) out vec4 fragColor;
void main() { void main() {
fragColor = vec4(0.0, 1.0, 0.0, 1.0); fragColor = vec4(0.0, 1.0, 0.0, 1.0);
})"); })");
utils::ComboRenderPipelineDescriptor descriptor(device); utils::ComboRenderPipelineDescriptor descriptor(device);
descriptor.vertexStage.module = vsModule; descriptor.vertexStage.module = vsModule;
descriptor.cFragmentStage.module = fsModule; descriptor.cFragmentStage.module = fsModule;
descriptor.primitiveTopology = wgpu::PrimitiveTopology::TriangleStrip; descriptor.primitiveTopology = wgpu::PrimitiveTopology::TriangleStrip;
descriptor.cVertexState.indexFormat = format; descriptor.cVertexState.indexFormat = format;
descriptor.cVertexState.vertexBufferCount = 1; descriptor.cVertexState.vertexBufferCount = 1;
descriptor.cVertexState.cVertexBuffers[0].arrayStride = 4 * sizeof(float); descriptor.cVertexState.cVertexBuffers[0].arrayStride = 4 * sizeof(float);
descriptor.cVertexState.cVertexBuffers[0].attributeCount = 1; descriptor.cVertexState.cVertexBuffers[0].attributeCount = 1;
descriptor.cVertexState.cAttributes[0].format = wgpu::VertexFormat::Float4; descriptor.cVertexState.cAttributes[0].format = wgpu::VertexFormat::Float4;
descriptor.cColorStates[0].format = renderPass.colorFormat; descriptor.cColorStates[0].format = renderPass.colorFormat;
return device.CreateRenderPipeline(&descriptor); return device.CreateRenderPipeline(&descriptor);
} }
}; };
// Test that the Uint32 index format is correctly interpreted // Test that the Uint32 index format is correctly interpreted
@ -275,4 +275,8 @@ TEST_P(IndexFormatTest, DISABLED_SetIndexBufferBeforeSetPipeline) {
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), renderPass.color, 100, 300); EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), renderPass.color, 100, 300);
} }
DAWN_INSTANTIATE_TEST(IndexFormatTest, D3D12Backend(), MetalBackend(), OpenGLBackend(), VulkanBackend()); DAWN_INSTANTIATE_TEST(IndexFormatTest,
D3D12Backend(),
MetalBackend(),
OpenGLBackend(),
VulkanBackend());

View File

@ -61,7 +61,6 @@ class MultisampledRenderingTest : public DawnTest {
const char* fs = testDepth ? kFsOneOutputWithDepth : kFsOneOutputWithoutDepth; const char* fs = testDepth ? kFsOneOutputWithDepth : kFsOneOutputWithoutDepth;
return CreateRenderPipelineForTest(fs, 1, testDepth); return CreateRenderPipelineForTest(fs, 1, testDepth);
} }
@ -285,8 +284,8 @@ TEST_P(MultisampledRenderingTest, MultisampledRenderingWithDepthTest) {
utils::ComboRenderPassDescriptor renderPass = utils::ComboRenderPassDescriptor renderPass =
CreateComboRenderPassDescriptorForTest({mMultisampledColorView}, {mResolveView}, CreateComboRenderPassDescriptorForTest({mMultisampledColorView}, {mResolveView},
wgpu::LoadOp::Clear, wgpu::LoadOp::Clear, true); wgpu::LoadOp::Clear, wgpu::LoadOp::Clear, true);
std::array<float, 5> kUniformData = {kGreen.r, kGreen.g, kGreen.b, kGreen.a, // Color std::array<float, 5> kUniformData = {kGreen.r, kGreen.g, kGreen.b, kGreen.a, // Color
0.2f}; // depth 0.2f}; // depth
constexpr uint32_t kSize = sizeof(kUniformData); constexpr uint32_t kSize = sizeof(kUniformData);
EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kUniformData.data(), kSize); EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kUniformData.data(), kSize);
} }
@ -299,8 +298,8 @@ TEST_P(MultisampledRenderingTest, MultisampledRenderingWithDepthTest) {
{mMultisampledColorView}, {mResolveView}, wgpu::LoadOp::Load, wgpu::LoadOp::Load, {mMultisampledColorView}, {mResolveView}, wgpu::LoadOp::Load, wgpu::LoadOp::Load,
kTestDepth); kTestDepth);
std::array<float, 8> kUniformData = {kRed.r, kRed.g, kRed.b, kRed.a, // color std::array<float, 8> kUniformData = {kRed.r, kRed.g, kRed.b, kRed.a, // color
0.5f}; // depth 0.5f}; // depth
constexpr uint32_t kSize = sizeof(kUniformData); constexpr uint32_t kSize = sizeof(kUniformData);
EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kUniformData.data(), kSize); EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kUniformData.data(), kSize);
} }
@ -369,8 +368,8 @@ TEST_P(MultisampledRenderingTest, ResolveIntoMultipleResolveTargets) {
{mMultisampledColorView, multisampledColorView2}, {mResolveView, resolveView2}, {mMultisampledColorView, multisampledColorView2}, {mResolveView, resolveView2},
wgpu::LoadOp::Clear, wgpu::LoadOp::Clear, kTestDepth); wgpu::LoadOp::Clear, wgpu::LoadOp::Clear, kTestDepth);
std::array<float, 8> kUniformData = {kRed.r, kRed.g, kRed.b, kRed.a, // color1 std::array<float, 8> kUniformData = {kRed.r, kRed.g, kRed.b, kRed.a, // color1
kGreen.r, kGreen.g, kGreen.b, kGreen.a}; // color2 kGreen.r, kGreen.g, kGreen.b, kGreen.a}; // color2
constexpr uint32_t kSize = sizeof(kUniformData); constexpr uint32_t kSize = sizeof(kUniformData);
EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kUniformData.data(), kSize); EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kUniformData.data(), kSize);
} }
@ -503,8 +502,8 @@ TEST_P(MultisampledRenderingTest, ResolveInto2DArrayTexture) {
{mMultisampledColorView, multisampledColorView2}, {resolveView1, resolveView2}, {mMultisampledColorView, multisampledColorView2}, {resolveView1, resolveView2},
wgpu::LoadOp::Clear, wgpu::LoadOp::Clear, kTestDepth); wgpu::LoadOp::Clear, wgpu::LoadOp::Clear, kTestDepth);
std::array<float, 8> kUniformData = {kRed.r, kRed.g, kRed.b, kRed.a, // color1 std::array<float, 8> kUniformData = {kRed.r, kRed.g, kRed.b, kRed.a, // color1
kGreen.r, kGreen.g, kGreen.b, kGreen.a}; // color2 kGreen.r, kGreen.g, kGreen.b, kGreen.a}; // color2
constexpr uint32_t kSize = sizeof(kUniformData); constexpr uint32_t kSize = sizeof(kUniformData);
EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kUniformData.data(), kSize); EncodeRenderPassForTest(commandEncoder, renderPass, pipeline, kUniformData.data(), kSize);
} }

View File

@ -292,6 +292,6 @@ DAWN_INSTANTIATE_TEST(NonzeroTextureCreationTests,
MetalBackend({"nonzero_clear_resources_on_creation_for_testing"}, MetalBackend({"nonzero_clear_resources_on_creation_for_testing"},
{"lazy_clear_resource_on_first_use"}), {"lazy_clear_resource_on_first_use"}),
OpenGLBackend({"nonzero_clear_resources_on_creation_for_testing"}, OpenGLBackend({"nonzero_clear_resources_on_creation_for_testing"},
{"lazy_clear_resource_on_first_use"}), {"lazy_clear_resource_on_first_use"}),
VulkanBackend({"nonzero_clear_resources_on_creation_for_testing"}, VulkanBackend({"nonzero_clear_resources_on_creation_for_testing"},
{"lazy_clear_resource_on_first_use"})); {"lazy_clear_resource_on_first_use"}));

View File

@ -400,4 +400,8 @@ TEST_P(ObjectCachingTest, SamplerDeduplication) {
EXPECT_EQ(sampler.Get() == sameSampler.Get(), !UsesWire()); EXPECT_EQ(sampler.Get() == sameSampler.Get(), !UsesWire());
} }
DAWN_INSTANTIATE_TEST(ObjectCachingTest, D3D12Backend(), MetalBackend(), OpenGLBackend(), VulkanBackend()); DAWN_INSTANTIATE_TEST(ObjectCachingTest,
D3D12Backend(),
MetalBackend(),
OpenGLBackend(),
VulkanBackend());

View File

@ -262,4 +262,8 @@ TEST_P(OpArrayLengthTest, Vertex) {
EXPECT_PIXEL_RGBA8_EQ(expectedColor, renderPass.color, 0, 0); EXPECT_PIXEL_RGBA8_EQ(expectedColor, renderPass.color, 0, 0);
} }
DAWN_INSTANTIATE_TEST(OpArrayLengthTest, D3D12Backend(), MetalBackend(), OpenGLBackend(), VulkanBackend()); DAWN_INSTANTIATE_TEST(OpArrayLengthTest,
D3D12Backend(),
MetalBackend(),
OpenGLBackend(),
VulkanBackend());

View File

@ -62,4 +62,4 @@ DAWN_INSTANTIATE_TEST(PipelineLayoutTests,
D3D12Backend(), D3D12Backend(),
MetalBackend(), MetalBackend(),
OpenGLBackend(), OpenGLBackend(),
VulkanBackend()); VulkanBackend());

View File

@ -18,7 +18,8 @@
#include "utils/ComboRenderPipelineDescriptor.h" #include "utils/ComboRenderPipelineDescriptor.h"
#include "utils/WGPUHelpers.h" #include "utils/WGPUHelpers.h"
// Primitive topology tests work by drawing the following vertices with all the different primitive topology states: // Primitive topology tests work by drawing the following vertices with all the different primitive
// topology states:
// ------------------------------------- // -------------------------------------
// | | // | |
// | 1 2 5 | // | 1 2 5 |
@ -81,8 +82,8 @@
// ------------------------------------- // -------------------------------------
// //
// Each of these different states is a superset of some of the previous states, // Each of these different states is a superset of some of the previous states,
// so for every state, we check any new added test locations that are not contained in previous states // so for every state, we check any new added test locations that are not contained in previous
// We also check that the test locations of subsequent states are untouched // states We also check that the test locations of subsequent states are untouched
constexpr static unsigned int kRTSize = 32; constexpr static unsigned int kRTSize = 32;
@ -91,11 +92,13 @@ struct TestLocation {
}; };
constexpr TestLocation GetMidpoint(const TestLocation& a, const TestLocation& b) noexcept { constexpr TestLocation GetMidpoint(const TestLocation& a, const TestLocation& b) noexcept {
return { (a.x + b.x) / 2, (a.y + b.y) / 2 }; return {(a.x + b.x) / 2, (a.y + b.y) / 2};
} }
constexpr TestLocation GetCentroid(const TestLocation& a, const TestLocation& b, const TestLocation& c) noexcept { constexpr TestLocation GetCentroid(const TestLocation& a,
return { (a.x + b.x + c.x) / 3, (a.y + b.y + c.y) / 3 }; const TestLocation& b,
const TestLocation& c) noexcept {
return {(a.x + b.x + c.x) / 3, (a.y + b.y + c.y) / 3};
} }
// clang-format off // clang-format off
@ -144,13 +147,13 @@ constexpr static float kVertices[] = {
// clang-format on // clang-format on
class PrimitiveTopologyTest : public DawnTest { class PrimitiveTopologyTest : public DawnTest {
protected: protected:
void SetUp() override { void SetUp() override {
DawnTest::SetUp(); DawnTest::SetUp();
renderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize); renderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize);
vsModule = utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, R"( vsModule = utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, R"(
#version 450 #version 450
layout(location = 0) in vec4 pos; layout(location = 0) in vec4 pos;
void main() { void main() {
@ -158,69 +161,73 @@ class PrimitiveTopologyTest : public DawnTest {
gl_PointSize = 1.0; gl_PointSize = 1.0;
})"); })");
fsModule = utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment, R"( fsModule = utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment, R"(
#version 450 #version 450
layout(location = 0) out vec4 fragColor; layout(location = 0) out vec4 fragColor;
void main() { void main() {
fragColor = vec4(0.0, 1.0, 0.0, 1.0); fragColor = vec4(0.0, 1.0, 0.0, 1.0);
})"); })");
vertexBuffer = utils::CreateBufferFromData(device, kVertices, sizeof(kVertices), vertexBuffer = utils::CreateBufferFromData(device, kVertices, sizeof(kVertices),
wgpu::BufferUsage::Vertex); wgpu::BufferUsage::Vertex);
}
struct LocationSpec {
const TestLocation* locations;
size_t count;
bool include;
};
template <std::size_t N>
constexpr LocationSpec TestPoints(TestLocation const (&points)[N], bool include) noexcept {
return {points, N, include};
}
// Draw the vertices with the given primitive topology and check the pixel values of the test
// locations
void DoTest(wgpu::PrimitiveTopology primitiveTopology,
const std::vector<LocationSpec>& locationSpecs) {
utils::ComboRenderPipelineDescriptor descriptor(device);
descriptor.vertexStage.module = vsModule;
descriptor.cFragmentStage.module = fsModule;
descriptor.primitiveTopology = primitiveTopology;
descriptor.cVertexState.vertexBufferCount = 1;
descriptor.cVertexState.cVertexBuffers[0].arrayStride = 4 * sizeof(float);
descriptor.cVertexState.cVertexBuffers[0].attributeCount = 1;
descriptor.cVertexState.cAttributes[0].format = wgpu::VertexFormat::Float4;
descriptor.cColorStates[0].format = renderPass.colorFormat;
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&descriptor);
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
{
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
pass.SetPipeline(pipeline);
pass.SetVertexBuffer(0, vertexBuffer);
pass.Draw(6);
pass.EndPass();
} }
struct LocationSpec { wgpu::CommandBuffer commands = encoder.Finish();
const TestLocation* locations; queue.Submit(1, &commands);
size_t count;
bool include;
};
template <std::size_t N> for (auto& locationSpec : locationSpecs) {
constexpr LocationSpec TestPoints(TestLocation const (&points)[N], bool include) noexcept { for (size_t i = 0; i < locationSpec.count; ++i) {
return { points, N, include }; // If this pixel is included, check that it is green. Otherwise, check that it is
} // black
RGBA8 color = locationSpec.include ? RGBA8::kGreen : RGBA8::kZero;
// Draw the vertices with the given primitive topology and check the pixel values of the test locations EXPECT_PIXEL_RGBA8_EQ(color, renderPass.color, locationSpec.locations[i].x,
void DoTest(wgpu::PrimitiveTopology primitiveTopology, locationSpec.locations[i].y)
const std::vector<LocationSpec>& locationSpecs) { << "Expected (" << locationSpec.locations[i].x << ", "
utils::ComboRenderPipelineDescriptor descriptor(device); << locationSpec.locations[i].y << ") to be " << color;
descriptor.vertexStage.module = vsModule;
descriptor.cFragmentStage.module = fsModule;
descriptor.primitiveTopology = primitiveTopology;
descriptor.cVertexState.vertexBufferCount = 1;
descriptor.cVertexState.cVertexBuffers[0].arrayStride = 4 * sizeof(float);
descriptor.cVertexState.cVertexBuffers[0].attributeCount = 1;
descriptor.cVertexState.cAttributes[0].format = wgpu::VertexFormat::Float4;
descriptor.cColorStates[0].format = renderPass.colorFormat;
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&descriptor);
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
{
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
pass.SetPipeline(pipeline);
pass.SetVertexBuffer(0, vertexBuffer);
pass.Draw(6);
pass.EndPass();
}
wgpu::CommandBuffer commands = encoder.Finish();
queue.Submit(1, &commands);
for (auto& locationSpec : locationSpecs) {
for (size_t i = 0; i < locationSpec.count; ++i) {
// If this pixel is included, check that it is green. Otherwise, check that it is black
RGBA8 color = locationSpec.include ? RGBA8::kGreen : RGBA8::kZero;
EXPECT_PIXEL_RGBA8_EQ(color, renderPass.color, locationSpec.locations[i].x, locationSpec.locations[i].y)
<< "Expected (" << locationSpec.locations[i].x << ", " << locationSpec.locations[i].y << ") to be " << color;
}
} }
} }
}
utils::BasicRenderPass renderPass; utils::BasicRenderPass renderPass;
wgpu::ShaderModule vsModule; wgpu::ShaderModule vsModule;
wgpu::ShaderModule fsModule; wgpu::ShaderModule fsModule;
wgpu::Buffer vertexBuffer; wgpu::Buffer vertexBuffer;
}; };
// Test Point primitive topology // Test Point primitive topology
@ -286,4 +293,8 @@ TEST_P(PrimitiveTopologyTest, TriangleStrip) {
}); });
} }
DAWN_INSTANTIATE_TEST(PrimitiveTopologyTest, D3D12Backend(), MetalBackend(), OpenGLBackend(), VulkanBackend()); DAWN_INSTANTIATE_TEST(PrimitiveTopologyTest,
D3D12Backend(),
MetalBackend(),
OpenGLBackend(),
VulkanBackend());

View File

@ -196,4 +196,8 @@ TEST_P(RenderBundleTest, BundleAndRenderPassCommands) {
EXPECT_PIXEL_RGBA8_EQ(kColors[1], renderPass.color, 3, 1); EXPECT_PIXEL_RGBA8_EQ(kColors[1], renderPass.color, 3, 1);
} }
DAWN_INSTANTIATE_TEST(RenderBundleTest, D3D12Backend(), MetalBackend(), OpenGLBackend(), VulkanBackend()); DAWN_INSTANTIATE_TEST(RenderBundleTest,
D3D12Backend(),
MetalBackend(),
OpenGLBackend(),
VulkanBackend());

View File

@ -22,62 +22,61 @@
constexpr static unsigned int kRTSize = 16; constexpr static unsigned int kRTSize = 16;
class DrawQuad { class DrawQuad {
public: public:
DrawQuad() {} DrawQuad() {
DrawQuad(wgpu::Device device, const char* vsSource, const char* fsSource) : device(device) { }
vsModule = DrawQuad(wgpu::Device device, const char* vsSource, const char* fsSource) : device(device) {
utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, vsSource); vsModule = utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, vsSource);
fsModule = fsModule = utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment, fsSource);
utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment, fsSource);
pipelineLayout = utils::MakeBasicPipelineLayout(device, nullptr); pipelineLayout = utils::MakeBasicPipelineLayout(device, nullptr);
} }
void Draw(wgpu::RenderPassEncoder* pass) { void Draw(wgpu::RenderPassEncoder* pass) {
utils::ComboRenderPipelineDescriptor descriptor(device); utils::ComboRenderPipelineDescriptor descriptor(device);
descriptor.layout = pipelineLayout; descriptor.layout = pipelineLayout;
descriptor.vertexStage.module = vsModule; descriptor.vertexStage.module = vsModule;
descriptor.cFragmentStage.module = fsModule; descriptor.cFragmentStage.module = fsModule;
auto renderPipeline = device.CreateRenderPipeline(&descriptor); auto renderPipeline = device.CreateRenderPipeline(&descriptor);
pass->SetPipeline(renderPipeline); pass->SetPipeline(renderPipeline);
pass->Draw(6, 1, 0, 0); pass->Draw(6, 1, 0, 0);
} }
private: private:
wgpu::Device device; wgpu::Device device;
wgpu::ShaderModule vsModule = {}; wgpu::ShaderModule vsModule = {};
wgpu::ShaderModule fsModule = {}; wgpu::ShaderModule fsModule = {};
wgpu::PipelineLayout pipelineLayout = {}; wgpu::PipelineLayout pipelineLayout = {};
}; };
class RenderPassLoadOpTests : public DawnTest { class RenderPassLoadOpTests : public DawnTest {
protected: protected:
void SetUp() override { void SetUp() override {
DawnTest::SetUp(); DawnTest::SetUp();
wgpu::TextureDescriptor descriptor; wgpu::TextureDescriptor descriptor;
descriptor.dimension = wgpu::TextureDimension::e2D; descriptor.dimension = wgpu::TextureDimension::e2D;
descriptor.size.width = kRTSize; descriptor.size.width = kRTSize;
descriptor.size.height = kRTSize; descriptor.size.height = kRTSize;
descriptor.size.depth = 1; descriptor.size.depth = 1;
descriptor.sampleCount = 1; descriptor.sampleCount = 1;
descriptor.format = wgpu::TextureFormat::RGBA8Unorm; descriptor.format = wgpu::TextureFormat::RGBA8Unorm;
descriptor.mipLevelCount = 1; descriptor.mipLevelCount = 1;
descriptor.usage = wgpu::TextureUsage::OutputAttachment | wgpu::TextureUsage::CopySrc; descriptor.usage = wgpu::TextureUsage::OutputAttachment | wgpu::TextureUsage::CopySrc;
renderTarget = device.CreateTexture(&descriptor); renderTarget = device.CreateTexture(&descriptor);
renderTargetView = renderTarget.CreateView(); renderTargetView = renderTarget.CreateView();
std::fill(expectZero.begin(), expectZero.end(), RGBA8::kZero); std::fill(expectZero.begin(), expectZero.end(), RGBA8::kZero);
std::fill(expectGreen.begin(), expectGreen.end(), RGBA8::kGreen); std::fill(expectGreen.begin(), expectGreen.end(), RGBA8::kGreen);
std::fill(expectBlue.begin(), expectBlue.end(), RGBA8::kBlue); std::fill(expectBlue.begin(), expectBlue.end(), RGBA8::kBlue);
// draws a blue quad on the right half of the screen // draws a blue quad on the right half of the screen
const char* vsSource = R"( const char* vsSource = R"(
#version 450 #version 450
void main() { void main() {
const vec2 pos[6] = vec2[6]( const vec2 pos[6] = vec2[6](
@ -86,24 +85,24 @@ class RenderPassLoadOpTests : public DawnTest {
gl_Position = vec4(pos[gl_VertexIndex], 0.f, 1.f); gl_Position = vec4(pos[gl_VertexIndex], 0.f, 1.f);
} }
)"; )";
const char* fsSource = R"( const char* fsSource = R"(
#version 450 #version 450
layout(location = 0) out vec4 color; layout(location = 0) out vec4 color;
void main() { void main() {
color = vec4(0.f, 0.f, 1.f, 1.f); color = vec4(0.f, 0.f, 1.f, 1.f);
} }
)"; )";
blueQuad = DrawQuad(device, vsSource, fsSource); blueQuad = DrawQuad(device, vsSource, fsSource);
} }
wgpu::Texture renderTarget; wgpu::Texture renderTarget;
wgpu::TextureView renderTargetView; wgpu::TextureView renderTargetView;
std::array<RGBA8, kRTSize * kRTSize> expectZero; std::array<RGBA8, kRTSize * kRTSize> expectZero;
std::array<RGBA8, kRTSize * kRTSize> expectGreen; std::array<RGBA8, kRTSize * kRTSize> expectGreen;
std::array<RGBA8, kRTSize * kRTSize> expectBlue; std::array<RGBA8, kRTSize * kRTSize> expectBlue;
DrawQuad blueQuad = {}; DrawQuad blueQuad = {};
}; };
// Tests clearing, loading, and drawing into color attachments // Tests clearing, loading, and drawing into color attachments
@ -144,7 +143,12 @@ TEST_P(RenderPassLoadOpTests, ColorClearThenLoadAndDraw) {
// Left half should still be green // Left half should still be green
EXPECT_TEXTURE_RGBA8_EQ(expectGreen.data(), renderTarget, 0, 0, kRTSize / 2, kRTSize, 0, 0); EXPECT_TEXTURE_RGBA8_EQ(expectGreen.data(), renderTarget, 0, 0, kRTSize / 2, kRTSize, 0, 0);
// Right half should now be blue // Right half should now be blue
EXPECT_TEXTURE_RGBA8_EQ(expectBlue.data(), renderTarget, kRTSize / 2, 0, kRTSize / 2, kRTSize, 0, 0); EXPECT_TEXTURE_RGBA8_EQ(expectBlue.data(), renderTarget, kRTSize / 2, 0, kRTSize / 2, kRTSize,
0, 0);
} }
DAWN_INSTANTIATE_TEST(RenderPassLoadOpTests, D3D12Backend(), MetalBackend(), OpenGLBackend(), VulkanBackend()); DAWN_INSTANTIATE_TEST(RenderPassLoadOpTests,
D3D12Backend(),
MetalBackend(),
OpenGLBackend(),
VulkanBackend());

View File

@ -21,7 +21,7 @@ constexpr uint32_t kRTSize = 16;
constexpr wgpu::TextureFormat kFormat = wgpu::TextureFormat::RGBA8Unorm; constexpr wgpu::TextureFormat kFormat = wgpu::TextureFormat::RGBA8Unorm;
class RenderPassTest : public DawnTest { class RenderPassTest : public DawnTest {
protected: protected:
void SetUp() override { void SetUp() override {
DawnTest::SetUp(); DawnTest::SetUp();
@ -71,9 +71,9 @@ protected:
// Test using two different render passes in one commandBuffer works correctly. // Test using two different render passes in one commandBuffer works correctly.
TEST_P(RenderPassTest, TwoRenderPassesInOneCommandBuffer) { TEST_P(RenderPassTest, TwoRenderPassesInOneCommandBuffer) {
if (IsOpenGL() || IsMetal()) { if (IsOpenGL() || IsMetal()) {
// crbug.com/950768 // crbug.com/950768
// This test is consistently failing on OpenGL and flaky on Metal. // This test is consistently failing on OpenGL and flaky on Metal.
return; return;
} }
wgpu::Texture renderTarget1 = CreateDefault2DTexture(); wgpu::Texture renderTarget1 = CreateDefault2DTexture();

View File

@ -46,10 +46,10 @@ namespace {
255, 255,
}, },
}; };
} } // namespace
class SamplerTest : public DawnTest { class SamplerTest : public DawnTest {
protected: protected:
void SetUp() override { void SetUp() override {
DawnTest::SetUp(); DawnTest::SetUp();
mRenderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize); mRenderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize);
@ -177,4 +177,8 @@ TEST_P(SamplerTest, AddressMode) {
} }
} }
DAWN_INSTANTIATE_TEST(SamplerTest, D3D12Backend(), MetalBackend(), OpenGLBackend(), VulkanBackend()); DAWN_INSTANTIATE_TEST(SamplerTest,
D3D12Backend(),
MetalBackend(),
OpenGLBackend(),
VulkanBackend());

View File

@ -17,7 +17,7 @@
#include "utils/ComboRenderPipelineDescriptor.h" #include "utils/ComboRenderPipelineDescriptor.h"
#include "utils/WGPUHelpers.h" #include "utils/WGPUHelpers.h"
class ScissorTest: public DawnTest { class ScissorTest : public DawnTest {
protected: protected:
wgpu::RenderPipeline CreateQuadPipeline(wgpu::TextureFormat format) { wgpu::RenderPipeline CreateQuadPipeline(wgpu::TextureFormat format) {
wgpu::ShaderModule vsModule = wgpu::ShaderModule vsModule =
@ -152,4 +152,8 @@ TEST_P(ScissorTest, NoInheritanceBetweenRenderPass) {
EXPECT_PIXEL_RGBA8_EQ(RGBA8::kGreen, renderPass.color, 99, 99); EXPECT_PIXEL_RGBA8_EQ(RGBA8::kGreen, renderPass.color, 99, 99);
} }
DAWN_INSTANTIATE_TEST(ScissorTest, D3D12Backend(), MetalBackend(), OpenGLBackend(), VulkanBackend()); DAWN_INSTANTIATE_TEST(ScissorTest,
D3D12Backend(),
MetalBackend(),
OpenGLBackend(),
VulkanBackend());

View File

@ -404,7 +404,7 @@ class TextureFormatTest : public DawnTest {
ASSERT(sizeof(float) * formatInfo.componentCount == formatInfo.texelByteSize); ASSERT(sizeof(float) * formatInfo.componentCount == formatInfo.texelByteSize);
ASSERT(formatInfo.type == wgpu::TextureComponentType::Float); ASSERT(formatInfo.type == wgpu::TextureComponentType::Float);
std::vector<float> textureData = {+0.0f, -0.0f, 1.0f, 1.0e-29f, std::vector<float> textureData = {+0.0f, -0.0f, 1.0f, 1.0e-29f,
1.0e29f, NAN, INFINITY, -INFINITY}; 1.0e29f, NAN, INFINITY, -INFINITY};
DoFloatFormatSamplingTest(formatInfo, textureData, textureData); DoFloatFormatSamplingTest(formatInfo, textureData, textureData);
@ -733,4 +733,8 @@ TEST_P(TextureFormatTest, RG11B10Float) {
// TODO(cwallez@chromium.org): Add tests for depth-stencil formats when we know if they are copyable // TODO(cwallez@chromium.org): Add tests for depth-stencil formats when we know if they are copyable
// in WebGPU. // in WebGPU.
DAWN_INSTANTIATE_TEST(TextureFormatTest, D3D12Backend(), MetalBackend(), OpenGLBackend(), VulkanBackend()); DAWN_INSTANTIATE_TEST(TextureFormatTest,
D3D12Backend(),
MetalBackend(),
OpenGLBackend(),
VulkanBackend());

View File

@ -70,7 +70,7 @@ namespace {
} // anonymous namespace } // anonymous namespace
class TextureViewSamplingTest : public DawnTest { class TextureViewSamplingTest : public DawnTest {
protected: protected:
// Generates an arbitrary pixel value per-layer-per-level, used for the "actual" uploaded // Generates an arbitrary pixel value per-layer-per-level, used for the "actual" uploaded
// textures and the "expected" results. // textures and the "expected" results.
static int GenerateTestPixelValue(uint32_t layer, uint32_t level) { static int GenerateTestPixelValue(uint32_t layer, uint32_t level) {
@ -104,8 +104,8 @@ protected:
const uint32_t textureHeightLevel0 = 1 << mipLevelCount; const uint32_t textureHeightLevel0 = 1 << mipLevelCount;
constexpr wgpu::TextureUsage kUsage = constexpr wgpu::TextureUsage kUsage =
wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::Sampled; wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::Sampled;
mTexture = Create2DTexture( mTexture = Create2DTexture(device, textureWidthLevel0, textureHeightLevel0, arrayLayerCount,
device, textureWidthLevel0, textureHeightLevel0, arrayLayerCount, mipLevelCount, kUsage); mipLevelCount, kUsage);
mDefaultTextureViewDescriptor.dimension = wgpu::TextureViewDimension::e2DArray; mDefaultTextureViewDescriptor.dimension = wgpu::TextureViewDimension::e2DArray;
mDefaultTextureViewDescriptor.format = kDefaultFormat; mDefaultTextureViewDescriptor.format = kDefaultFormat;
@ -145,10 +145,7 @@ protected:
queue.Submit(1, &copy); queue.Submit(1, &copy);
} }
void Verify(const wgpu::TextureView& textureView, void Verify(const wgpu::TextureView& textureView, const char* fragmentShader, int expected) {
const char* fragmentShader,
int expected) {
wgpu::ShaderModule fsModule = wgpu::ShaderModule fsModule =
utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment, fragmentShader); utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment, fragmentShader);
@ -176,8 +173,8 @@ protected:
RGBA8 expectedPixel(0, 0, 0, expected); RGBA8 expectedPixel(0, 0, 0, expected);
EXPECT_PIXEL_RGBA8_EQ(expectedPixel, mRenderPass.color, 0, 0); EXPECT_PIXEL_RGBA8_EQ(expectedPixel, mRenderPass.color, 0, 0);
EXPECT_PIXEL_RGBA8_EQ( EXPECT_PIXEL_RGBA8_EQ(expectedPixel, mRenderPass.color, mRenderPass.width - 1,
expectedPixel, mRenderPass.color, mRenderPass.width - 1, mRenderPass.height - 1); mRenderPass.height - 1);
// TODO(jiawei.shao@intel.com): add tests for 3D textures once Dawn supports 3D textures // TODO(jiawei.shao@intel.com): add tests for 3D textures once Dawn supports 3D textures
} }
@ -262,13 +259,13 @@ protected:
std::string CreateFragmentShaderForCubeMapFace(uint32_t layer, bool isCubeMapArray) { std::string CreateFragmentShaderForCubeMapFace(uint32_t layer, bool isCubeMapArray) {
// Reference: https://en.wikipedia.org/wiki/Cube_mapping // Reference: https://en.wikipedia.org/wiki/Cube_mapping
const std::array<std::string, 6> kCoordsToCubeMapFace = {{ const std::array<std::string, 6> kCoordsToCubeMapFace = {{
" 1.f, tc, -sc", // Positive X " 1.f, tc, -sc", // Positive X
"-1.f, tc, sc", // Negative X "-1.f, tc, sc", // Negative X
" sc, 1.f, -tc", // Positive Y " sc, 1.f, -tc", // Positive Y
" sc, -1.f, tc", // Negative Y " sc, -1.f, tc", // Negative Y
" sc, tc, 1.f", // Positive Z " sc, tc, 1.f", // Positive Z
" -sc, tc, -1.f", // Negative Z " -sc, tc, -1.f", // Negative Z
}}; }};
const std::string textureType = isCubeMapArray ? "textureCubeArray" : "textureCube"; const std::string textureType = isCubeMapArray ? "textureCubeArray" : "textureCube";
const std::string samplerType = isCubeMapArray ? "samplerCubeArray" : "samplerCube"; const std::string samplerType = isCubeMapArray ? "samplerCubeArray" : "samplerCube";
@ -279,13 +276,15 @@ protected:
stream << R"( stream << R"(
#version 450 #version 450
layout(set = 0, binding = 0) uniform sampler sampler0; layout(set = 0, binding = 0) uniform sampler sampler0;
layout(set = 0, binding = 1) uniform )" << textureType << R"( texture0; layout(set = 0, binding = 1) uniform )"
<< textureType << R"( texture0;
layout(location = 0) in vec2 texCoord; layout(location = 0) in vec2 texCoord;
layout(location = 0) out vec4 fragColor; layout(location = 0) out vec4 fragColor;
void main() { void main() {
float sc = 2.f * texCoord.x - 1.f; float sc = 2.f * texCoord.x - 1.f;
float tc = 2.f * texCoord.y - 1.f; float tc = 2.f * texCoord.y - 1.f;
fragColor = texture()" << samplerType << "(texture0, sampler0), "; fragColor = texture()"
<< samplerType << "(texture0, sampler0), ";
if (isCubeMapArray) { if (isCubeMapArray) {
stream << "vec4(" << coordToCubeMapFace << ", " << cubeMapArrayIndex; stream << "vec4(" << coordToCubeMapFace << ", " << cubeMapArrayIndex;
@ -321,7 +320,7 @@ protected:
// Check the data in the every face of the cube map (array) texture view. // Check the data in the every face of the cube map (array) texture view.
for (uint32_t layer = 0; layer < textureViewLayerCount; ++layer) { for (uint32_t layer = 0; layer < textureViewLayerCount; ++layer) {
const std::string &fragmentShader = const std::string& fragmentShader =
CreateFragmentShaderForCubeMapFace(layer, isCubeMapArray); CreateFragmentShaderForCubeMapFace(layer, isCubeMapArray);
int expected = GenerateTestPixelValue(textureViewBaseLayer + layer, 0); int expected = GenerateTestPixelValue(textureViewBaseLayer + layer, 0);
@ -362,8 +361,8 @@ TEST_P(TextureViewSamplingTest, Default2DArrayTexture) {
} }
)"; )";
const int expected = GenerateTestPixelValue(0, 0) + GenerateTestPixelValue(1, 0) + const int expected =
GenerateTestPixelValue(2, 0); GenerateTestPixelValue(0, 0) + GenerateTestPixelValue(1, 0) + GenerateTestPixelValue(2, 0);
Verify(textureView, fragmentShader, expected); Verify(textureView, fragmentShader, expected);
} }
@ -427,7 +426,8 @@ TEST_P(TextureViewSamplingTest, TextureCubeMapArrayViewOnPartOfTexture) {
TextureCubeMapTest(20, 3, 12, true); TextureCubeMapTest(20, 3, 12, true);
} }
// Test sampling from a cube map texture array view that covers the last layer of a 2D array texture. // Test sampling from a cube map texture array view that covers the last layer of a 2D array
// texture.
TEST_P(TextureViewSamplingTest, TextureCubeMapArrayViewCoveringLastLayer) { TEST_P(TextureViewSamplingTest, TextureCubeMapArrayViewCoveringLastLayer) {
// Test failing on the GPU FYI Mac Pro (AMD), see // Test failing on the GPU FYI Mac Pro (AMD), see
// https://bugs.chromium.org/p/dawn/issues/detail?id=58 // https://bugs.chromium.org/p/dawn/issues/detail?id=58
@ -519,9 +519,8 @@ class TextureViewRenderingTest : public DawnTest {
bytesPerRow / kBytesPerTexel * (textureWidthLevel0 - 1) + textureHeightLevel0; bytesPerRow / kBytesPerTexel * (textureWidthLevel0 - 1) + textureHeightLevel0;
constexpr RGBA8 kExpectedPixel(0, 255, 0, 255); constexpr RGBA8 kExpectedPixel(0, 255, 0, 255);
std::vector<RGBA8> expected(expectedDataSize, kExpectedPixel); std::vector<RGBA8> expected(expectedDataSize, kExpectedPixel);
EXPECT_TEXTURE_RGBA8_EQ( EXPECT_TEXTURE_RGBA8_EQ(expected.data(), texture, 0, 0, textureViewWidth, textureViewHeight,
expected.data(), texture, 0, 0, textureViewWidth, textureViewHeight, textureViewBaseLevel, textureViewBaseLayer);
textureViewBaseLevel, textureViewBaseLayer);
} }
}; };
@ -565,7 +564,6 @@ TEST_P(TextureViewRenderingTest, Texture2DViewOnALayerOf2DArrayTextureAsColorAtt
TextureLayerAsColorAttachmentTest(wgpu::TextureViewDimension::e2D, kLayers, kMipLevels, TextureLayerAsColorAttachmentTest(wgpu::TextureViewDimension::e2D, kLayers, kMipLevels,
kBaseLayer, kBaseLevel); kBaseLayer, kBaseLevel);
} }
} }
// Test rendering into a 1-layer 2D array texture view created on a mipmap level of a 2D texture. // Test rendering into a 1-layer 2D array texture view created on a mipmap level of a 2D texture.
@ -610,9 +608,17 @@ TEST_P(TextureViewRenderingTest, Texture2DArrayViewOnALayerOf2DArrayTextureAsCol
} }
} }
DAWN_INSTANTIATE_TEST(TextureViewSamplingTest, D3D12Backend(), MetalBackend(), OpenGLBackend(), VulkanBackend()); DAWN_INSTANTIATE_TEST(TextureViewSamplingTest,
D3D12Backend(),
MetalBackend(),
OpenGLBackend(),
VulkanBackend());
DAWN_INSTANTIATE_TEST(TextureViewRenderingTest, D3D12Backend(), MetalBackend(), OpenGLBackend(), VulkanBackend()); DAWN_INSTANTIATE_TEST(TextureViewRenderingTest,
D3D12Backend(),
MetalBackend(),
OpenGLBackend(),
VulkanBackend());
class TextureViewTest : public DawnTest {}; class TextureViewTest : public DawnTest {};

View File

@ -1144,11 +1144,10 @@ TEST_P(TextureZeroInitTest, CopyTextureToBufferNonRenderableUnaligned) {
EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(texture.Get(), 0, 1, 0, 1)); EXPECT_EQ(true, dawn_native::IsTextureSubresourceInitialized(texture.Get(), 0, 1, 0, 1));
} }
DAWN_INSTANTIATE_TEST( DAWN_INSTANTIATE_TEST(TextureZeroInitTest,
TextureZeroInitTest, D3D12Backend({"nonzero_clear_resources_on_creation_for_testing"}),
D3D12Backend({"nonzero_clear_resources_on_creation_for_testing"}), D3D12Backend({"nonzero_clear_resources_on_creation_for_testing"},
D3D12Backend({"nonzero_clear_resources_on_creation_for_testing"}, {"use_d3d12_render_pass"}),
{"use_d3d12_render_pass"}), OpenGLBackend({"nonzero_clear_resources_on_creation_for_testing"}),
OpenGLBackend({"nonzero_clear_resources_on_creation_for_testing"}), MetalBackend({"nonzero_clear_resources_on_creation_for_testing"}),
MetalBackend({"nonzero_clear_resources_on_creation_for_testing"}), VulkanBackend({"nonzero_clear_resources_on_creation_for_testing"}));
VulkanBackend({"nonzero_clear_resources_on_creation_for_testing"}));

View File

@ -915,4 +915,8 @@ TEST_P(VertexFormatTest, Int4) {
DoVertexFormatTest(wgpu::VertexFormat::Int4, vertexData, vertexData); DoVertexFormatTest(wgpu::VertexFormat::Int4, vertexData, vertexData);
} }
DAWN_INSTANTIATE_TEST(VertexFormatTest, D3D12Backend(), MetalBackend(), OpenGLBackend(), VulkanBackend()); DAWN_INSTANTIATE_TEST(VertexFormatTest,
D3D12Backend(),
MetalBackend(),
OpenGLBackend(),
VulkanBackend());

View File

@ -543,7 +543,7 @@ TEST_P(VertexStateTest, OverlappingVertexAttributes) {
uint16_t halfs[2]; uint16_t halfs[2];
}; };
static_assert(sizeof(Data) == 16, ""); static_assert(sizeof(Data) == 16, "");
Data data {1.f, {2u, 3u}, {Float32ToFloat16(4.f), Float32ToFloat16(5.f)}}; Data data{1.f, {2u, 3u}, {Float32ToFloat16(4.f), Float32ToFloat16(5.f)}};
wgpu::Buffer vertexBuffer = wgpu::Buffer vertexBuffer =
utils::CreateBufferFromData(device, &data, sizeof(data), wgpu::BufferUsage::Vertex); utils::CreateBufferFromData(device, &data, sizeof(data), wgpu::BufferUsage::Vertex);
@ -599,7 +599,11 @@ TEST_P(VertexStateTest, OverlappingVertexAttributes) {
EXPECT_PIXEL_RGBA8_EQ(RGBA8::kGreen, renderPass.color, 1, 1); EXPECT_PIXEL_RGBA8_EQ(RGBA8::kGreen, renderPass.color, 1, 1);
} }
DAWN_INSTANTIATE_TEST(VertexStateTest, D3D12Backend(), MetalBackend(), OpenGLBackend(), VulkanBackend()); DAWN_INSTANTIATE_TEST(VertexStateTest,
D3D12Backend(),
MetalBackend(),
OpenGLBackend(),
VulkanBackend());
// TODO for the input state: // TODO for the input state:
// - Add more vertex formats // - Add more vertex formats

View File

@ -64,4 +64,8 @@ TEST_P(ViewportOrientationTests, OriginAt0x0) {
EXPECT_PIXEL_RGBA8_EQ(RGBA8::kZero, renderPass.color, 1, 1); EXPECT_PIXEL_RGBA8_EQ(RGBA8::kZero, renderPass.color, 1, 1);
} }
DAWN_INSTANTIATE_TEST(ViewportOrientationTests, D3D12Backend(), MetalBackend(), OpenGLBackend(), VulkanBackend()); DAWN_INSTANTIATE_TEST(ViewportOrientationTests,
D3D12Backend(),
MetalBackend(),
OpenGLBackend(),
VulkanBackend());

View File

@ -404,4 +404,8 @@ TEST_P(ViewportTest, DoNotTruncateWidthAndHeight2) {
DoTest(info); DoTest(info);
} }
DAWN_INSTANTIATE_TEST(ViewportTest, D3D12Backend(), MetalBackend(), OpenGLBackend(), VulkanBackend()); DAWN_INSTANTIATE_TEST(ViewportTest,
D3D12Backend(),
MetalBackend(),
OpenGLBackend(),
VulkanBackend());

View File

@ -20,8 +20,8 @@
// This is ANGLE's BitSetIterator_unittests.cpp file. // This is ANGLE's BitSetIterator_unittests.cpp file.
class BitSetIteratorTest : public testing::Test { class BitSetIteratorTest : public testing::Test {
protected: protected:
std::bitset<40> mStateBits; std::bitset<40> mStateBits;
}; };
// Simple iterator test. // Simple iterator test.

View File

@ -324,4 +324,4 @@ TEST(BuddyAllocatorTests, VariousSizeSameAlignment) {
ASSERT_EQ(allocator.Allocate(16, alignment), 16ull); ASSERT_EQ(allocator.Allocate(16, alignment), 16ull);
ASSERT_EQ(allocator.ComputeTotalNumOfFreeBlocksForTesting(), 0u); ASSERT_EQ(allocator.ComputeTotalNumOfFreeBlocksForTesting(), 0u);
} }

View File

@ -355,4 +355,4 @@ TEST(BuddyMemoryAllocatorTests, AllocationOverflow) {
constexpr uint64_t largeBlock = (1ull << 63) + 1; constexpr uint64_t largeBlock = (1ull << 63) + 1;
ResourceMemoryAllocation invalidAllocation = allocator.Allocate(largeBlock); ResourceMemoryAllocation invalidAllocation = allocator.Allocate(largeBlock);
ASSERT_EQ(invalidAllocation.GetInfo().mMethod, AllocationMethod::kInvalid); ASSERT_EQ(invalidAllocation.GetInfo().mMethod, AllocationMethod::kInvalid);
} }

View File

@ -121,7 +121,8 @@ TEST(CommandAllocator, BasicWithData) {
uint32_t myValues[5] = {6, 42, 0xFFFFFFFF, 0, 54}; uint32_t myValues[5] = {6, 42, 0xFFFFFFFF, 0, 54};
{ {
CommandPushConstants* pushConstants = allocator.Allocate<CommandPushConstants>(CommandType::PushConstants); CommandPushConstants* pushConstants =
allocator.Allocate<CommandPushConstants>(CommandType::PushConstants);
pushConstants->size = mySize; pushConstants->size = mySize;
pushConstants->offset = myOffset; pushConstants->offset = myOffset;
@ -209,7 +210,7 @@ TEST(CommandAllocator, LargeCommands) {
for (int i = 0; i < kCommandCount; i++) { for (int i = 0; i < kCommandCount; i++) {
CommandBig* big = allocator.Allocate<CommandBig>(CommandType::Big); CommandBig* big = allocator.Allocate<CommandBig>(CommandType::Big);
for (int j = 0; j < kBigBufferSize; j++) { for (int j = 0; j < kBigBufferSize; j++) {
big->buffer[j] = count ++; big->buffer[j] = count++;
} }
} }
@ -223,9 +224,9 @@ TEST(CommandAllocator, LargeCommands) {
CommandBig* big = iterator.NextCommand<CommandBig>(); CommandBig* big = iterator.NextCommand<CommandBig>();
for (int i = 0; i < kBigBufferSize; i++) { for (int i = 0; i < kBigBufferSize; i++) {
ASSERT_EQ(big->buffer[i], count); ASSERT_EQ(big->buffer[i], count);
count ++; count++;
} }
numCommands ++; numCommands++;
} }
ASSERT_EQ(numCommands, kCommandCount); ASSERT_EQ(numCommands, kCommandCount);
@ -242,7 +243,7 @@ TEST(CommandAllocator, ManySmallCommands) {
uint16_t count = 0; uint16_t count = 0;
for (int i = 0; i < kCommandCount; i++) { for (int i = 0; i < kCommandCount; i++) {
CommandSmall* small = allocator.Allocate<CommandSmall>(CommandType::Small); CommandSmall* small = allocator.Allocate<CommandSmall>(CommandType::Small);
small->data = count ++; small->data = count++;
} }
CommandIterator iterator(std::move(allocator)); CommandIterator iterator(std::move(allocator));
@ -254,8 +255,8 @@ TEST(CommandAllocator, ManySmallCommands) {
CommandSmall* small = iterator.NextCommand<CommandSmall>(); CommandSmall* small = iterator.NextCommand<CommandSmall>();
ASSERT_EQ(small->data, count); ASSERT_EQ(small->data, count);
count ++; count++;
numCommands ++; numCommands++;
} }
ASSERT_EQ(numCommands, kCommandCount); ASSERT_EQ(numCommands, kCommandCount);

View File

@ -25,7 +25,7 @@ namespace wgpu {
A = 8, A = 8,
}; };
template<> template <>
struct IsDawnBitmask<Color> { struct IsDawnBitmask<Color> {
static constexpr bool enable = true; static constexpr bool enable = true;
}; };

View File

@ -21,278 +21,260 @@ using namespace dawn_native;
namespace { namespace {
int dummySuccess = 0xbeef; int dummySuccess = 0xbeef;
const char* dummyErrorMessage = "I am an error message :3"; const char* dummyErrorMessage = "I am an error message :3";
// Check returning a success MaybeError with {}; // Check returning a success MaybeError with {};
TEST(ErrorTests, Error_Success) { TEST(ErrorTests, Error_Success) {
auto ReturnSuccess = []() -> MaybeError { auto ReturnSuccess = []() -> MaybeError { return {}; };
return {};
};
MaybeError result = ReturnSuccess(); MaybeError result = ReturnSuccess();
ASSERT_TRUE(result.IsSuccess()); ASSERT_TRUE(result.IsSuccess());
} }
// Check returning an error MaybeError with "return DAWN_VALIDATION_ERROR" // Check returning an error MaybeError with "return DAWN_VALIDATION_ERROR"
TEST(ErrorTests, Error_Error) { TEST(ErrorTests, Error_Error) {
auto ReturnError = []() -> MaybeError { auto ReturnError = []() -> MaybeError { return DAWN_VALIDATION_ERROR(dummyErrorMessage); };
return DAWN_VALIDATION_ERROR(dummyErrorMessage);
};
MaybeError result = ReturnError(); MaybeError result = ReturnError();
ASSERT_TRUE(result.IsError()); ASSERT_TRUE(result.IsError());
std::unique_ptr<ErrorData> errorData = result.AcquireError(); std::unique_ptr<ErrorData> errorData = result.AcquireError();
ASSERT_EQ(errorData->GetMessage(), dummyErrorMessage); ASSERT_EQ(errorData->GetMessage(), dummyErrorMessage);
} }
// Check returning a success ResultOrError with an implicit conversion // Check returning a success ResultOrError with an implicit conversion
TEST(ErrorTests, ResultOrError_Success) { TEST(ErrorTests, ResultOrError_Success) {
auto ReturnSuccess = []() -> ResultOrError<int*> { auto ReturnSuccess = []() -> ResultOrError<int*> { return &dummySuccess; };
return &dummySuccess;
};
ResultOrError<int*> result = ReturnSuccess(); ResultOrError<int*> result = ReturnSuccess();
ASSERT_TRUE(result.IsSuccess()); ASSERT_TRUE(result.IsSuccess());
ASSERT_EQ(result.AcquireSuccess(), &dummySuccess); ASSERT_EQ(result.AcquireSuccess(), &dummySuccess);
} }
// Check returning an error ResultOrError with "return DAWN_VALIDATION_ERROR" // Check returning an error ResultOrError with "return DAWN_VALIDATION_ERROR"
TEST(ErrorTests, ResultOrError_Error) { TEST(ErrorTests, ResultOrError_Error) {
auto ReturnError = []() -> ResultOrError<int*> { auto ReturnError = []() -> ResultOrError<int*> {
return DAWN_VALIDATION_ERROR(dummyErrorMessage); return DAWN_VALIDATION_ERROR(dummyErrorMessage);
}; };
ResultOrError<int*> result = ReturnError(); ResultOrError<int*> result = ReturnError();
ASSERT_TRUE(result.IsError()); ASSERT_TRUE(result.IsError());
std::unique_ptr<ErrorData> errorData = result.AcquireError(); std::unique_ptr<ErrorData> errorData = result.AcquireError();
ASSERT_EQ(errorData->GetMessage(), dummyErrorMessage); ASSERT_EQ(errorData->GetMessage(), dummyErrorMessage);
} }
// Check DAWN_TRY handles successes correctly. // Check DAWN_TRY handles successes correctly.
TEST(ErrorTests, TRY_Success) { TEST(ErrorTests, TRY_Success) {
auto ReturnSuccess = []() -> MaybeError { auto ReturnSuccess = []() -> MaybeError { return {}; };
return {};
};
// We need to check that DAWN_TRY doesn't return on successes // We need to check that DAWN_TRY doesn't return on successes
bool tryReturned = true; bool tryReturned = true;
auto Try = [ReturnSuccess, &tryReturned]() -> MaybeError { auto Try = [ReturnSuccess, &tryReturned]() -> MaybeError {
DAWN_TRY(ReturnSuccess()); DAWN_TRY(ReturnSuccess());
tryReturned = false; tryReturned = false;
return {}; return {};
}; };
MaybeError result = Try(); MaybeError result = Try();
ASSERT_TRUE(result.IsSuccess()); ASSERT_TRUE(result.IsSuccess());
ASSERT_FALSE(tryReturned); ASSERT_FALSE(tryReturned);
} }
// Check DAWN_TRY handles errors correctly. // Check DAWN_TRY handles errors correctly.
TEST(ErrorTests, TRY_Error) { TEST(ErrorTests, TRY_Error) {
auto ReturnError = []() -> MaybeError { auto ReturnError = []() -> MaybeError { return DAWN_VALIDATION_ERROR(dummyErrorMessage); };
return DAWN_VALIDATION_ERROR(dummyErrorMessage);
};
auto Try = [ReturnError]() -> MaybeError { auto Try = [ReturnError]() -> MaybeError {
DAWN_TRY(ReturnError()); DAWN_TRY(ReturnError());
// DAWN_TRY should return before this point // DAWN_TRY should return before this point
EXPECT_FALSE(true); EXPECT_FALSE(true);
return {}; return {};
}; };
MaybeError result = Try(); MaybeError result = Try();
ASSERT_TRUE(result.IsError()); ASSERT_TRUE(result.IsError());
std::unique_ptr<ErrorData> errorData = result.AcquireError(); std::unique_ptr<ErrorData> errorData = result.AcquireError();
ASSERT_EQ(errorData->GetMessage(), dummyErrorMessage); ASSERT_EQ(errorData->GetMessage(), dummyErrorMessage);
} }
// Check DAWN_TRY adds to the backtrace. // Check DAWN_TRY adds to the backtrace.
TEST(ErrorTests, TRY_AddsToBacktrace) { TEST(ErrorTests, TRY_AddsToBacktrace) {
auto ReturnError = []() -> MaybeError { auto ReturnError = []() -> MaybeError { return DAWN_VALIDATION_ERROR(dummyErrorMessage); };
return DAWN_VALIDATION_ERROR(dummyErrorMessage);
};
auto SingleTry = [ReturnError]() -> MaybeError { auto SingleTry = [ReturnError]() -> MaybeError {
DAWN_TRY(ReturnError()); DAWN_TRY(ReturnError());
return {}; return {};
}; };
auto DoubleTry = [SingleTry]() -> MaybeError { auto DoubleTry = [SingleTry]() -> MaybeError {
DAWN_TRY(SingleTry()); DAWN_TRY(SingleTry());
return {}; return {};
}; };
MaybeError singleResult = SingleTry(); MaybeError singleResult = SingleTry();
ASSERT_TRUE(singleResult.IsError()); ASSERT_TRUE(singleResult.IsError());
MaybeError doubleResult = DoubleTry(); MaybeError doubleResult = DoubleTry();
ASSERT_TRUE(doubleResult.IsError()); ASSERT_TRUE(doubleResult.IsError());
std::unique_ptr<ErrorData> singleData = singleResult.AcquireError(); std::unique_ptr<ErrorData> singleData = singleResult.AcquireError();
std::unique_ptr<ErrorData> doubleData = doubleResult.AcquireError(); std::unique_ptr<ErrorData> doubleData = doubleResult.AcquireError();
ASSERT_EQ(singleData->GetBacktrace().size() + 1, doubleData->GetBacktrace().size()); ASSERT_EQ(singleData->GetBacktrace().size() + 1, doubleData->GetBacktrace().size());
} }
// Check DAWN_TRY_ASSIGN handles successes correctly. // Check DAWN_TRY_ASSIGN handles successes correctly.
TEST(ErrorTests, TRY_RESULT_Success) { TEST(ErrorTests, TRY_RESULT_Success) {
auto ReturnSuccess = []() -> ResultOrError<int*> { auto ReturnSuccess = []() -> ResultOrError<int*> { return &dummySuccess; };
return &dummySuccess;
};
// We need to check that DAWN_TRY doesn't return on successes // We need to check that DAWN_TRY doesn't return on successes
bool tryReturned = true; bool tryReturned = true;
auto Try = [ReturnSuccess, &tryReturned]() -> ResultOrError<int*> { auto Try = [ReturnSuccess, &tryReturned]() -> ResultOrError<int*> {
int* result = nullptr; int* result = nullptr;
DAWN_TRY_ASSIGN(result, ReturnSuccess()); DAWN_TRY_ASSIGN(result, ReturnSuccess());
tryReturned = false; tryReturned = false;
EXPECT_EQ(result, &dummySuccess); EXPECT_EQ(result, &dummySuccess);
return result; return result;
}; };
ResultOrError<int*> result = Try(); ResultOrError<int*> result = Try();
ASSERT_TRUE(result.IsSuccess()); ASSERT_TRUE(result.IsSuccess());
ASSERT_FALSE(tryReturned); ASSERT_FALSE(tryReturned);
ASSERT_EQ(result.AcquireSuccess(), &dummySuccess); ASSERT_EQ(result.AcquireSuccess(), &dummySuccess);
} }
// Check DAWN_TRY_ASSIGN handles errors correctly. // Check DAWN_TRY_ASSIGN handles errors correctly.
TEST(ErrorTests, TRY_RESULT_Error) { TEST(ErrorTests, TRY_RESULT_Error) {
auto ReturnError = []() -> ResultOrError<int*> { auto ReturnError = []() -> ResultOrError<int*> {
return DAWN_VALIDATION_ERROR(dummyErrorMessage); return DAWN_VALIDATION_ERROR(dummyErrorMessage);
}; };
auto Try = [ReturnError]() -> ResultOrError<int*> { auto Try = [ReturnError]() -> ResultOrError<int*> {
int* result = nullptr; int* result = nullptr;
DAWN_TRY_ASSIGN(result, ReturnError()); DAWN_TRY_ASSIGN(result, ReturnError());
DAWN_UNUSED(result); DAWN_UNUSED(result);
// DAWN_TRY should return before this point // DAWN_TRY should return before this point
EXPECT_FALSE(true); EXPECT_FALSE(true);
return &dummySuccess; return &dummySuccess;
}; };
ResultOrError<int*> result = Try(); ResultOrError<int*> result = Try();
ASSERT_TRUE(result.IsError()); ASSERT_TRUE(result.IsError());
std::unique_ptr<ErrorData> errorData = result.AcquireError(); std::unique_ptr<ErrorData> errorData = result.AcquireError();
ASSERT_EQ(errorData->GetMessage(), dummyErrorMessage); ASSERT_EQ(errorData->GetMessage(), dummyErrorMessage);
} }
// Check DAWN_TRY_ASSIGN adds to the backtrace. // Check DAWN_TRY_ASSIGN adds to the backtrace.
TEST(ErrorTests, TRY_RESULT_AddsToBacktrace) { TEST(ErrorTests, TRY_RESULT_AddsToBacktrace) {
auto ReturnError = []() -> ResultOrError<int*> { auto ReturnError = []() -> ResultOrError<int*> {
return DAWN_VALIDATION_ERROR(dummyErrorMessage); return DAWN_VALIDATION_ERROR(dummyErrorMessage);
}; };
auto SingleTry = [ReturnError]() -> ResultOrError<int*> { auto SingleTry = [ReturnError]() -> ResultOrError<int*> {
DAWN_TRY(ReturnError()); DAWN_TRY(ReturnError());
return &dummySuccess; return &dummySuccess;
}; };
auto DoubleTry = [SingleTry]() -> ResultOrError<int*> { auto DoubleTry = [SingleTry]() -> ResultOrError<int*> {
DAWN_TRY(SingleTry()); DAWN_TRY(SingleTry());
return &dummySuccess; return &dummySuccess;
}; };
ResultOrError<int*> singleResult = SingleTry(); ResultOrError<int*> singleResult = SingleTry();
ASSERT_TRUE(singleResult.IsError()); ASSERT_TRUE(singleResult.IsError());
ResultOrError<int*> doubleResult = DoubleTry(); ResultOrError<int*> doubleResult = DoubleTry();
ASSERT_TRUE(doubleResult.IsError()); ASSERT_TRUE(doubleResult.IsError());
std::unique_ptr<ErrorData> singleData = singleResult.AcquireError(); std::unique_ptr<ErrorData> singleData = singleResult.AcquireError();
std::unique_ptr<ErrorData> doubleData = doubleResult.AcquireError(); std::unique_ptr<ErrorData> doubleData = doubleResult.AcquireError();
ASSERT_EQ(singleData->GetBacktrace().size() + 1, doubleData->GetBacktrace().size()); ASSERT_EQ(singleData->GetBacktrace().size() + 1, doubleData->GetBacktrace().size());
} }
// Check a ResultOrError can be DAWN_TRY_ASSIGNED in a function that returns an Error // Check a ResultOrError can be DAWN_TRY_ASSIGNED in a function that returns an Error
TEST(ErrorTests, TRY_RESULT_ConversionToError) { TEST(ErrorTests, TRY_RESULT_ConversionToError) {
auto ReturnError = []() -> ResultOrError<int*> { auto ReturnError = []() -> ResultOrError<int*> {
return DAWN_VALIDATION_ERROR(dummyErrorMessage); return DAWN_VALIDATION_ERROR(dummyErrorMessage);
}; };
auto Try = [ReturnError]() -> MaybeError { auto Try = [ReturnError]() -> MaybeError {
int* result = nullptr; int* result = nullptr;
DAWN_TRY_ASSIGN(result, ReturnError()); DAWN_TRY_ASSIGN(result, ReturnError());
DAWN_UNUSED(result); DAWN_UNUSED(result);
return {}; return {};
}; };
MaybeError result = Try(); MaybeError result = Try();
ASSERT_TRUE(result.IsError()); ASSERT_TRUE(result.IsError());
std::unique_ptr<ErrorData> errorData = result.AcquireError(); std::unique_ptr<ErrorData> errorData = result.AcquireError();
ASSERT_EQ(errorData->GetMessage(), dummyErrorMessage); ASSERT_EQ(errorData->GetMessage(), dummyErrorMessage);
} }
// Check a ResultOrError can be DAWN_TRY_ASSIGNED in a function that returns an Error // Check a ResultOrError can be DAWN_TRY_ASSIGNED in a function that returns an Error
// Version without Result<E*, T*> // Version without Result<E*, T*>
TEST(ErrorTests, TRY_RESULT_ConversionToErrorNonPointer) { TEST(ErrorTests, TRY_RESULT_ConversionToErrorNonPointer) {
auto ReturnError = []() -> ResultOrError<int> { auto ReturnError = []() -> ResultOrError<int> {
return DAWN_VALIDATION_ERROR(dummyErrorMessage); return DAWN_VALIDATION_ERROR(dummyErrorMessage);
}; };
auto Try = [ReturnError]() -> MaybeError { auto Try = [ReturnError]() -> MaybeError {
int result = 0; int result = 0;
DAWN_TRY_ASSIGN(result, ReturnError()); DAWN_TRY_ASSIGN(result, ReturnError());
DAWN_UNUSED(result); DAWN_UNUSED(result);
return {}; return {};
}; };
MaybeError result = Try(); MaybeError result = Try();
ASSERT_TRUE(result.IsError()); ASSERT_TRUE(result.IsError());
std::unique_ptr<ErrorData> errorData = result.AcquireError(); std::unique_ptr<ErrorData> errorData = result.AcquireError();
ASSERT_EQ(errorData->GetMessage(), dummyErrorMessage); ASSERT_EQ(errorData->GetMessage(), dummyErrorMessage);
} }
// Check a MaybeError can be DAWN_TRIED in a function that returns an ResultOrError // Check a MaybeError can be DAWN_TRIED in a function that returns an ResultOrError
// Check DAWN_TRY handles errors correctly. // Check DAWN_TRY handles errors correctly.
TEST(ErrorTests, TRY_ConversionToErrorOrResult) { TEST(ErrorTests, TRY_ConversionToErrorOrResult) {
auto ReturnError = []() -> MaybeError { auto ReturnError = []() -> MaybeError { return DAWN_VALIDATION_ERROR(dummyErrorMessage); };
return DAWN_VALIDATION_ERROR(dummyErrorMessage);
};
auto Try = [ReturnError]() -> ResultOrError<int*>{ auto Try = [ReturnError]() -> ResultOrError<int*> {
DAWN_TRY(ReturnError()); DAWN_TRY(ReturnError());
return &dummySuccess; return &dummySuccess;
}; };
ResultOrError<int*> result = Try(); ResultOrError<int*> result = Try();
ASSERT_TRUE(result.IsError()); ASSERT_TRUE(result.IsError());
std::unique_ptr<ErrorData> errorData = result.AcquireError(); std::unique_ptr<ErrorData> errorData = result.AcquireError();
ASSERT_EQ(errorData->GetMessage(), dummyErrorMessage); ASSERT_EQ(errorData->GetMessage(), dummyErrorMessage);
} }
// Check a MaybeError can be DAWN_TRIED in a function that returns an ResultOrError // Check a MaybeError can be DAWN_TRIED in a function that returns an ResultOrError
// Check DAWN_TRY handles errors correctly. Version without Result<E*, T*> // Check DAWN_TRY handles errors correctly. Version without Result<E*, T*>
TEST(ErrorTests, TRY_ConversionToErrorOrResultNonPointer) { TEST(ErrorTests, TRY_ConversionToErrorOrResultNonPointer) {
auto ReturnError = []() -> MaybeError { auto ReturnError = []() -> MaybeError { return DAWN_VALIDATION_ERROR(dummyErrorMessage); };
return DAWN_VALIDATION_ERROR(dummyErrorMessage);
};
auto Try = [ReturnError]() -> ResultOrError<int>{ auto Try = [ReturnError]() -> ResultOrError<int> {
DAWN_TRY(ReturnError()); DAWN_TRY(ReturnError());
return 42; return 42;
}; };
ResultOrError<int> result = Try(); ResultOrError<int> result = Try();
ASSERT_TRUE(result.IsError()); ASSERT_TRUE(result.IsError());
std::unique_ptr<ErrorData> errorData = result.AcquireError(); std::unique_ptr<ErrorData> errorData = result.AcquireError();
ASSERT_EQ(errorData->GetMessage(), dummyErrorMessage); ASSERT_EQ(errorData->GetMessage(), dummyErrorMessage);
} }
} // anonymous namespace } // anonymous namespace

View File

@ -362,4 +362,4 @@ TEST(LinkedList, IsInList) {
EXPECT_TRUE(n.IsInList()); EXPECT_TRUE(n.IsInList());
n.RemoveFromList(); n.RemoveFromList();
EXPECT_FALSE(n.IsInList()); EXPECT_FALSE(n.IsInList());
} }

View File

@ -194,4 +194,3 @@ TEST(ObjectBase, AssignNullptr) {
obj = nullptr; obj = nullptr;
ASSERT_EQ(refcount, 1); ASSERT_EQ(refcount, 1);
} }

View File

@ -48,7 +48,7 @@ TEST(PerStage, IterateAllStages) {
counts[SingleShaderStage::Compute] = 0; counts[SingleShaderStage::Compute] = 0;
for (auto stage : IterateStages(kAllStages)) { for (auto stage : IterateStages(kAllStages)) {
counts[stage] ++; counts[stage]++;
} }
ASSERT_EQ(counts[wgpu::ShaderStage::Vertex], 1); ASSERT_EQ(counts[wgpu::ShaderStage::Vertex], 1);
@ -64,7 +64,7 @@ TEST(PerStage, IterateOneStage) {
counts[SingleShaderStage::Compute] = 0; counts[SingleShaderStage::Compute] = 0;
for (auto stage : IterateStages(wgpu::ShaderStage::Fragment)) { for (auto stage : IterateStages(wgpu::ShaderStage::Fragment)) {
counts[stage] ++; counts[stage]++;
} }
ASSERT_EQ(counts[wgpu::ShaderStage::Vertex], 0); ASSERT_EQ(counts[wgpu::ShaderStage::Vertex], 0);
@ -80,7 +80,7 @@ TEST(PerStage, IterateNoStages) {
counts[SingleShaderStage::Compute] = 0; counts[SingleShaderStage::Compute] = 0;
for (auto stage : IterateStages(wgpu::ShaderStage::Fragment & wgpu::ShaderStage::Vertex)) { for (auto stage : IterateStages(wgpu::ShaderStage::Fragment & wgpu::ShaderStage::Vertex)) {
counts[stage] ++; counts[stage]++;
} }
ASSERT_EQ(counts[wgpu::ShaderStage::Vertex], 0); ASSERT_EQ(counts[wgpu::ShaderStage::Vertex], 0);

View File

@ -410,4 +410,4 @@ TEST(Ref, MoveAssignmentDerived) {
destination = nullptr; destination = nullptr;
EXPECT_TRUE(deleted); EXPECT_TRUE(deleted);
} }

View File

@ -19,363 +19,367 @@
namespace { namespace {
template<typename T, typename E> template <typename T, typename E>
void TestError(Result<T, E>* result, E expectedError) { void TestError(Result<T, E>* result, E expectedError) {
EXPECT_TRUE(result->IsError()); EXPECT_TRUE(result->IsError());
EXPECT_FALSE(result->IsSuccess()); EXPECT_FALSE(result->IsSuccess());
std::unique_ptr<E> storedError = result->AcquireError(); std::unique_ptr<E> storedError = result->AcquireError();
EXPECT_EQ(*storedError, expectedError); EXPECT_EQ(*storedError, expectedError);
}
template<typename T, typename E>
void TestSuccess(Result<T, E>* result, T expectedSuccess) {
EXPECT_FALSE(result->IsError());
EXPECT_TRUE(result->IsSuccess());
const T storedSuccess = result->AcquireSuccess();
EXPECT_EQ(storedSuccess, expectedSuccess);
// Once the success is acquired, result has an empty
// payload and is neither in the success nor error state.
EXPECT_FALSE(result->IsError());
EXPECT_FALSE(result->IsSuccess());
}
static int dummyError = 0xbeef;
static float dummySuccess = 42.0f;
static const float dummyConstSuccess = 42.0f;
class AClass : public RefCounted {
public:
int a = 0;
};
// Tests using the following overload of TestSuccess make
// local Ref instances to dummySuccessObj. Tests should
// ensure any local Ref objects made along the way continue
// to point to dummySuccessObj.
template <typename T, typename E>
void TestSuccess(Result<Ref<T>, E>* result, T* expectedSuccess) {
EXPECT_FALSE(result->IsError());
EXPECT_TRUE(result->IsSuccess());
// AClass starts with a reference count of 1 and stored
// on the stack in the caller. The result parameter should
// hold the only other reference to the object.
EXPECT_EQ(expectedSuccess->GetRefCountForTesting(), 2u);
const Ref<T> storedSuccess = result->AcquireSuccess();
EXPECT_EQ(storedSuccess.Get(), expectedSuccess);
// Once the success is acquired, result has an empty
// payload and is neither in the success nor error state.
EXPECT_FALSE(result->IsError());
EXPECT_FALSE(result->IsSuccess());
// Once we call AcquireSuccess, result no longer stores
// the object. storedSuccess should contain the only other
// reference to the object.
EXPECT_EQ(storedSuccess->GetRefCountForTesting(), 2u);
}
// Result<void, E*>
// Test constructing an error Result<void, E>
TEST(ResultOnlyPointerError, ConstructingError) {
Result<void, int> result(std::make_unique<int>(dummyError));
TestError(&result, dummyError);
}
// Test moving an error Result<void, E>
TEST(ResultOnlyPointerError, MovingError) {
Result<void, int> result(std::make_unique<int>(dummyError));
Result<void, int> movedResult(std::move(result));
TestError(&movedResult, dummyError);
}
// Test returning an error Result<void, E>
TEST(ResultOnlyPointerError, ReturningError) {
auto CreateError = []() -> Result<void, int> { return {std::make_unique<int>(dummyError)}; };
Result<void, int> result = CreateError();
TestError(&result, dummyError);
}
// Test constructing a success Result<void, E>
TEST(ResultOnlyPointerError, ConstructingSuccess) {
Result<void, int> result;
EXPECT_TRUE(result.IsSuccess());
EXPECT_FALSE(result.IsError());
}
// Test moving a success Result<void, E>
TEST(ResultOnlyPointerError, MovingSuccess) {
Result<void, int> result;
Result<void, int> movedResult(std::move(result));
EXPECT_TRUE(movedResult.IsSuccess());
EXPECT_FALSE(movedResult.IsError());
}
// Test returning a success Result<void, E>
TEST(ResultOnlyPointerError, ReturningSuccess) {
auto CreateError = []() -> Result<void, int> { return {}; };
Result<void, int> result = CreateError();
EXPECT_TRUE(result.IsSuccess());
EXPECT_FALSE(result.IsError());
}
// Result<T*, E*>
// Test constructing an error Result<T*, E>
TEST(ResultBothPointer, ConstructingError) {
Result<float*, int> result(std::make_unique<int>(dummyError));
TestError(&result, dummyError);
}
// Test moving an error Result<T*, E>
TEST(ResultBothPointer, MovingError) {
Result<float*, int> result(std::make_unique<int>(dummyError));
Result<float*, int> movedResult(std::move(result));
TestError(&movedResult, dummyError);
}
// Test returning an error Result<T*, E>
TEST(ResultBothPointer, ReturningError) {
auto CreateError = []() -> Result<float*, int> { return {std::make_unique<int>(dummyError)}; };
Result<float*, int> result = CreateError();
TestError(&result, dummyError);
}
// Test constructing a success Result<T*, E>
TEST(ResultBothPointer, ConstructingSuccess) {
Result<float*, int> result(&dummySuccess);
TestSuccess(&result, &dummySuccess);
}
// Test moving a success Result<T*, E>
TEST(ResultBothPointer, MovingSuccess) {
Result<float*, int> result(&dummySuccess);
Result<float*, int> movedResult(std::move(result));
TestSuccess(&movedResult, &dummySuccess);
}
// Test returning a success Result<T*, E>
TEST(ResultBothPointer, ReturningSuccess) {
auto CreateSuccess = []() -> Result<float*, int*> {
return {&dummySuccess};
};
Result<float*, int*> result = CreateSuccess();
TestSuccess(&result, &dummySuccess);
}
// Tests converting from a Result<TChild*, E>
TEST(ResultBothPointer, ConversionFromChildClass) {
struct T {
int a;
};
struct TChild : T {};
TChild child;
T* childAsT = &child;
{
Result<T*, int> result(&child);
TestSuccess(&result, childAsT);
} }
{
Result<TChild*, int> resultChild(&child); template <typename T, typename E>
Result<T*, int> result(std::move(resultChild)); void TestSuccess(Result<T, E>* result, T expectedSuccess) {
TestSuccess(&result, childAsT); EXPECT_FALSE(result->IsError());
EXPECT_TRUE(result->IsSuccess());
const T storedSuccess = result->AcquireSuccess();
EXPECT_EQ(storedSuccess, expectedSuccess);
// Once the success is acquired, result has an empty
// payload and is neither in the success nor error state.
EXPECT_FALSE(result->IsError());
EXPECT_FALSE(result->IsSuccess());
} }
{
Result<TChild*, int> resultChild(&child); static int dummyError = 0xbeef;
Result<T*, int> result = std::move(resultChild); static float dummySuccess = 42.0f;
TestSuccess(&result, childAsT); static const float dummyConstSuccess = 42.0f;
class AClass : public RefCounted {
public:
int a = 0;
};
// Tests using the following overload of TestSuccess make
// local Ref instances to dummySuccessObj. Tests should
// ensure any local Ref objects made along the way continue
// to point to dummySuccessObj.
template <typename T, typename E>
void TestSuccess(Result<Ref<T>, E>* result, T* expectedSuccess) {
EXPECT_FALSE(result->IsError());
EXPECT_TRUE(result->IsSuccess());
// AClass starts with a reference count of 1 and stored
// on the stack in the caller. The result parameter should
// hold the only other reference to the object.
EXPECT_EQ(expectedSuccess->GetRefCountForTesting(), 2u);
const Ref<T> storedSuccess = result->AcquireSuccess();
EXPECT_EQ(storedSuccess.Get(), expectedSuccess);
// Once the success is acquired, result has an empty
// payload and is neither in the success nor error state.
EXPECT_FALSE(result->IsError());
EXPECT_FALSE(result->IsSuccess());
// Once we call AcquireSuccess, result no longer stores
// the object. storedSuccess should contain the only other
// reference to the object.
EXPECT_EQ(storedSuccess->GetRefCountForTesting(), 2u);
} }
}
// Result<const T*, E> // Result<void, E*>
// Test constructing an error Result<const T*, E> // Test constructing an error Result<void, E>
TEST(ResultBothPointerWithConstResult, ConstructingError) { TEST(ResultOnlyPointerError, ConstructingError) {
Result<const float*, int> result(std::make_unique<int>(dummyError)); Result<void, int> result(std::make_unique<int>(dummyError));
TestError(&result, dummyError); TestError(&result, dummyError);
} }
// Test moving an error Result<const T*, E> // Test moving an error Result<void, E>
TEST(ResultBothPointerWithConstResult, MovingError) { TEST(ResultOnlyPointerError, MovingError) {
Result<const float*, int> result(std::make_unique<int>(dummyError)); Result<void, int> result(std::make_unique<int>(dummyError));
Result<const float*, int> movedResult(std::move(result)); Result<void, int> movedResult(std::move(result));
TestError(&movedResult, dummyError); TestError(&movedResult, dummyError);
} }
// Test returning an error Result<const T*, E*> // Test returning an error Result<void, E>
TEST(ResultBothPointerWithConstResult, ReturningError) { TEST(ResultOnlyPointerError, ReturningError) {
auto CreateError = []() -> Result<const float*, int> { auto CreateError = []() -> Result<void, int> {
return {std::make_unique<int>(dummyError)}; return {std::make_unique<int>(dummyError)};
};
Result<void, int> result = CreateError();
TestError(&result, dummyError);
}
// Test constructing a success Result<void, E>
TEST(ResultOnlyPointerError, ConstructingSuccess) {
Result<void, int> result;
EXPECT_TRUE(result.IsSuccess());
EXPECT_FALSE(result.IsError());
}
// Test moving a success Result<void, E>
TEST(ResultOnlyPointerError, MovingSuccess) {
Result<void, int> result;
Result<void, int> movedResult(std::move(result));
EXPECT_TRUE(movedResult.IsSuccess());
EXPECT_FALSE(movedResult.IsError());
}
// Test returning a success Result<void, E>
TEST(ResultOnlyPointerError, ReturningSuccess) {
auto CreateError = []() -> Result<void, int> { return {}; };
Result<void, int> result = CreateError();
EXPECT_TRUE(result.IsSuccess());
EXPECT_FALSE(result.IsError());
}
// Result<T*, E*>
// Test constructing an error Result<T*, E>
TEST(ResultBothPointer, ConstructingError) {
Result<float*, int> result(std::make_unique<int>(dummyError));
TestError(&result, dummyError);
}
// Test moving an error Result<T*, E>
TEST(ResultBothPointer, MovingError) {
Result<float*, int> result(std::make_unique<int>(dummyError));
Result<float*, int> movedResult(std::move(result));
TestError(&movedResult, dummyError);
}
// Test returning an error Result<T*, E>
TEST(ResultBothPointer, ReturningError) {
auto CreateError = []() -> Result<float*, int> {
return {std::make_unique<int>(dummyError)};
};
Result<float*, int> result = CreateError();
TestError(&result, dummyError);
}
// Test constructing a success Result<T*, E>
TEST(ResultBothPointer, ConstructingSuccess) {
Result<float*, int> result(&dummySuccess);
TestSuccess(&result, &dummySuccess);
}
// Test moving a success Result<T*, E>
TEST(ResultBothPointer, MovingSuccess) {
Result<float*, int> result(&dummySuccess);
Result<float*, int> movedResult(std::move(result));
TestSuccess(&movedResult, &dummySuccess);
}
// Test returning a success Result<T*, E>
TEST(ResultBothPointer, ReturningSuccess) {
auto CreateSuccess = []() -> Result<float*, int*> { return {&dummySuccess}; };
Result<float*, int*> result = CreateSuccess();
TestSuccess(&result, &dummySuccess);
}
// Tests converting from a Result<TChild*, E>
TEST(ResultBothPointer, ConversionFromChildClass) {
struct T {
int a;
};
struct TChild : T {};
TChild child;
T* childAsT = &child;
{
Result<T*, int> result(&child);
TestSuccess(&result, childAsT);
}
{
Result<TChild*, int> resultChild(&child);
Result<T*, int> result(std::move(resultChild));
TestSuccess(&result, childAsT);
}
{
Result<TChild*, int> resultChild(&child);
Result<T*, int> result = std::move(resultChild);
TestSuccess(&result, childAsT);
}
}
// Result<const T*, E>
// Test constructing an error Result<const T*, E>
TEST(ResultBothPointerWithConstResult, ConstructingError) {
Result<const float*, int> result(std::make_unique<int>(dummyError));
TestError(&result, dummyError);
}
// Test moving an error Result<const T*, E>
TEST(ResultBothPointerWithConstResult, MovingError) {
Result<const float*, int> result(std::make_unique<int>(dummyError));
Result<const float*, int> movedResult(std::move(result));
TestError(&movedResult, dummyError);
}
// Test returning an error Result<const T*, E*>
TEST(ResultBothPointerWithConstResult, ReturningError) {
auto CreateError = []() -> Result<const float*, int> {
return {std::make_unique<int>(dummyError)};
};
Result<const float*, int> result = CreateError();
TestError(&result, dummyError);
}
// Test constructing a success Result<const T*, E*>
TEST(ResultBothPointerWithConstResult, ConstructingSuccess) {
Result<const float*, int> result(&dummyConstSuccess);
TestSuccess(&result, &dummyConstSuccess);
}
// Test moving a success Result<const T*, E*>
TEST(ResultBothPointerWithConstResult, MovingSuccess) {
Result<const float*, int> result(&dummyConstSuccess);
Result<const float*, int> movedResult(std::move(result));
TestSuccess(&movedResult, &dummyConstSuccess);
}
// Test returning a success Result<const T*, E*>
TEST(ResultBothPointerWithConstResult, ReturningSuccess) {
auto CreateSuccess = []() -> Result<const float*, int> { return {&dummyConstSuccess}; };
Result<const float*, int> result = CreateSuccess();
TestSuccess(&result, &dummyConstSuccess);
}
// Result<Ref<T>, E>
// Test constructing an error Result<Ref<T>, E>
TEST(ResultRefT, ConstructingError) {
Result<Ref<AClass>, int> result(std::make_unique<int>(dummyError));
TestError(&result, dummyError);
}
// Test moving an error Result<Ref<T>, E>
TEST(ResultRefT, MovingError) {
Result<Ref<AClass>, int> result(std::make_unique<int>(dummyError));
Result<Ref<AClass>, int> movedResult(std::move(result));
TestError(&movedResult, dummyError);
}
// Test returning an error Result<Ref<T>, E>
TEST(ResultRefT, ReturningError) {
auto CreateError = []() -> Result<Ref<AClass>, int> {
return {std::make_unique<int>(dummyError)};
};
Result<Ref<AClass>, int> result = CreateError();
TestError(&result, dummyError);
}
// Test constructing a success Result<Ref<T>, E>
TEST(ResultRefT, ConstructingSuccess) {
AClass success;
Ref<AClass> refObj(&success);
Result<Ref<AClass>, int> result(std::move(refObj));
TestSuccess(&result, &success);
}
// Test moving a success Result<Ref<T>, E>
TEST(ResultRefT, MovingSuccess) {
AClass success;
Ref<AClass> refObj(&success);
Result<Ref<AClass>, int> result(std::move(refObj));
Result<Ref<AClass>, int> movedResult(std::move(result));
TestSuccess(&movedResult, &success);
}
// Test returning a success Result<Ref<T>, E>
TEST(ResultRefT, ReturningSuccess) {
AClass success;
auto CreateSuccess = [&success]() -> Result<Ref<AClass>, int> {
return Ref<AClass>(&success);
};
Result<Ref<AClass>, int> result = CreateSuccess();
TestSuccess(&result, &success);
}
class OtherClass {
public:
int a = 0;
}; };
class Base : public RefCounted {};
class Child : public OtherClass, public Base {};
Result<const float*, int> result = CreateError(); // Test constructing a Result<Ref<TChild>, E>
TestError(&result, dummyError); TEST(ResultRefT, ConversionFromChildConstructor) {
} Child child;
Ref<Child> refChild(&child);
// Test constructing a success Result<const T*, E*> Result<Ref<Base>, int> result(std::move(refChild));
TEST(ResultBothPointerWithConstResult, ConstructingSuccess) { TestSuccess<Base>(&result, &child);
Result<const float*, int> result(&dummyConstSuccess); }
TestSuccess(&result, &dummyConstSuccess);
}
// Test moving a success Result<const T*, E*> // Test copy constructing Result<Ref<TChild>, E>
TEST(ResultBothPointerWithConstResult, MovingSuccess) { TEST(ResultRefT, ConversionFromChildCopyConstructor) {
Result<const float*, int> result(&dummyConstSuccess); Child child;
Result<const float*, int> movedResult(std::move(result)); Ref<Child> refChild(&child);
TestSuccess(&movedResult, &dummyConstSuccess);
}
// Test returning a success Result<const T*, E*> Result<Ref<Child>, int> resultChild(std::move(refChild));
TEST(ResultBothPointerWithConstResult, ReturningSuccess) { Result<Ref<Base>, int> result(std::move(resultChild));
auto CreateSuccess = []() -> Result<const float*, int> { return {&dummyConstSuccess}; }; TestSuccess<Base>(&result, &child);
}
Result<const float*, int> result = CreateSuccess(); // Test assignment operator for Result<Ref<TChild>, E>
TestSuccess(&result, &dummyConstSuccess); TEST(ResultRefT, ConversionFromChildAssignmentOperator) {
} Child child;
Ref<Child> refChild(&child);
// Result<Ref<T>, E> Result<Ref<Child>, int> resultChild(std::move(refChild));
Result<Ref<Base>, int> result = std::move(resultChild);
TestSuccess<Base>(&result, &child);
}
// Test constructing an error Result<Ref<T>, E> // Result<T, E>
TEST(ResultRefT, ConstructingError) {
Result<Ref<AClass>, int> result(std::make_unique<int>(dummyError));
TestError(&result, dummyError);
}
// Test moving an error Result<Ref<T>, E> // Test constructing an error Result<T, E>
TEST(ResultRefT, MovingError) { TEST(ResultGeneric, ConstructingError) {
Result<Ref<AClass>, int> result(std::make_unique<int>(dummyError)); Result<std::vector<float>, int> result(std::make_unique<int>(dummyError));
Result<Ref<AClass>, int> movedResult(std::move(result)); TestError(&result, dummyError);
TestError(&movedResult, dummyError); }
}
// Test returning an error Result<Ref<T>, E> // Test moving an error Result<T, E>
TEST(ResultRefT, ReturningError) { TEST(ResultGeneric, MovingError) {
auto CreateError = []() -> Result<Ref<AClass>, int> { Result<std::vector<float>, int> result(std::make_unique<int>(dummyError));
return {std::make_unique<int>(dummyError)}; Result<std::vector<float>, int> movedResult(std::move(result));
}; TestError(&movedResult, dummyError);
}
Result<Ref<AClass>, int> result = CreateError(); // Test returning an error Result<T, E>
TestError(&result, dummyError); TEST(ResultGeneric, ReturningError) {
} auto CreateError = []() -> Result<std::vector<float>, int> {
return {std::make_unique<int>(dummyError)};
};
// Test constructing a success Result<Ref<T>, E> Result<std::vector<float>, int> result = CreateError();
TEST(ResultRefT, ConstructingSuccess) { TestError(&result, dummyError);
AClass success; }
Ref<AClass> refObj(&success); // Test constructing a success Result<T, E>
Result<Ref<AClass>, int> result(std::move(refObj)); TEST(ResultGeneric, ConstructingSuccess) {
TestSuccess(&result, &success); Result<std::vector<float>, int> result({1.0f});
} TestSuccess(&result, {1.0f});
}
// Test moving a success Result<Ref<T>, E> // Test moving a success Result<T, E>
TEST(ResultRefT, MovingSuccess) { TEST(ResultGeneric, MovingSuccess) {
AClass success; Result<std::vector<float>, int> result({1.0f});
Result<std::vector<float>, int> movedResult(std::move(result));
TestSuccess(&movedResult, {1.0f});
}
Ref<AClass> refObj(&success); // Test returning a success Result<T, E>
Result<Ref<AClass>, int> result(std::move(refObj)); TEST(ResultGeneric, ReturningSuccess) {
Result<Ref<AClass>, int> movedResult(std::move(result)); auto CreateSuccess = []() -> Result<std::vector<float>, int> { return {{1.0f}}; };
TestSuccess(&movedResult, &success);
}
// Test returning a success Result<Ref<T>, E> Result<std::vector<float>, int> result = CreateSuccess();
TEST(ResultRefT, ReturningSuccess) { TestSuccess(&result, {1.0f});
AClass success; }
auto CreateSuccess = [&success]() -> Result<Ref<AClass>, int> { return Ref<AClass>(&success); };
Result<Ref<AClass>, int> result = CreateSuccess();
TestSuccess(&result, &success);
}
class OtherClass {
public:
int a = 0;
};
class Base : public RefCounted {};
class Child : public OtherClass, public Base {};
// Test constructing a Result<Ref<TChild>, E>
TEST(ResultRefT, ConversionFromChildConstructor) {
Child child;
Ref<Child> refChild(&child);
Result<Ref<Base>, int> result(std::move(refChild));
TestSuccess<Base>(&result, &child);
}
// Test copy constructing Result<Ref<TChild>, E>
TEST(ResultRefT, ConversionFromChildCopyConstructor) {
Child child;
Ref<Child> refChild(&child);
Result<Ref<Child>, int> resultChild(std::move(refChild));
Result<Ref<Base>, int> result(std::move(resultChild));
TestSuccess<Base>(&result, &child);
}
// Test assignment operator for Result<Ref<TChild>, E>
TEST(ResultRefT, ConversionFromChildAssignmentOperator) {
Child child;
Ref<Child> refChild(&child);
Result<Ref<Child>, int> resultChild(std::move(refChild));
Result<Ref<Base>, int> result = std::move(resultChild);
TestSuccess<Base>(&result, &child);
}
// Result<T, E>
// Test constructing an error Result<T, E>
TEST(ResultGeneric, ConstructingError) {
Result<std::vector<float>, int> result(std::make_unique<int>(dummyError));
TestError(&result, dummyError);
}
// Test moving an error Result<T, E>
TEST(ResultGeneric, MovingError) {
Result<std::vector<float>, int> result(std::make_unique<int>(dummyError));
Result<std::vector<float>, int> movedResult(std::move(result));
TestError(&movedResult, dummyError);
}
// Test returning an error Result<T, E>
TEST(ResultGeneric, ReturningError) {
auto CreateError = []() -> Result<std::vector<float>, int> {
return {std::make_unique<int>(dummyError)};
};
Result<std::vector<float>, int> result = CreateError();
TestError(&result, dummyError);
}
// Test constructing a success Result<T, E>
TEST(ResultGeneric, ConstructingSuccess) {
Result<std::vector<float>, int> result({1.0f});
TestSuccess(&result, {1.0f});
}
// Test moving a success Result<T, E>
TEST(ResultGeneric, MovingSuccess) {
Result<std::vector<float>, int> result({1.0f});
Result<std::vector<float>, int> movedResult(std::move(result));
TestSuccess(&movedResult, {1.0f});
}
// Test returning a success Result<T, E>
TEST(ResultGeneric, ReturningSuccess) {
auto CreateSuccess = []() -> Result<std::vector<float>, int> { return {{1.0f}}; };
Result<std::vector<float>, int> result = CreateSuccess();
TestSuccess(&result, {1.0f});
}
} // anonymous namespace } // anonymous namespace

View File

@ -174,4 +174,4 @@ TEST(RingBufferAllocatorTests, RingBufferOverflow) {
ASSERT_EQ(allocator.Allocate(1, serial), 0u); ASSERT_EQ(allocator.Allocate(1, serial), 0u);
ASSERT_EQ(allocator.Allocate(std::numeric_limits<uint64_t>::max(), serial + 1), ASSERT_EQ(allocator.Allocate(std::numeric_limits<uint64_t>::max(), serial + 1),
RingBufferAllocator::kInvalidOffset); RingBufferAllocator::kInvalidOffset);
} }

View File

@ -153,4 +153,4 @@ TEST(SerialQueue, LastSerial) {
queue.Enqueue({2}, 1); queue.Enqueue({2}, 1);
EXPECT_EQ(queue.LastSerial(), 1u); EXPECT_EQ(queue.LastSerial(), 1u);
} }

View File

@ -21,21 +21,19 @@
// Make our own Base - Backend object pair, reusing the CommandBuffer name // Make our own Base - Backend object pair, reusing the CommandBuffer name
namespace dawn_native { namespace dawn_native {
class CommandBufferBase : public RefCounted { class CommandBufferBase : public RefCounted {};
}; } // namespace dawn_native
}
using namespace dawn_native; using namespace dawn_native;
class MyCommandBuffer : public CommandBufferBase { class MyCommandBuffer : public CommandBufferBase {};
};
struct MyBackendTraits { struct MyBackendTraits {
using CommandBufferType = MyCommandBuffer; using CommandBufferType = MyCommandBuffer;
}; };
// Instanciate ToBackend for our "backend" // Instanciate ToBackend for our "backend"
template<typename T> template <typename T>
auto ToBackend(T&& common) -> decltype(ToBackendBase<MyBackendTraits>(common)) { auto ToBackend(T&& common) -> decltype(ToBackendBase<MyBackendTraits>(common)) {
return ToBackendBase<MyBackendTraits>(common); return ToBackendBase<MyBackendTraits>(common);
} }
@ -71,7 +69,8 @@ TEST(ToBackend, Ref) {
const Ref<CommandBufferBase> base(cmdBuf); const Ref<CommandBufferBase> base(cmdBuf);
const auto& backendCmdBuf = ToBackend(base); const auto& backendCmdBuf = ToBackend(base);
static_assert(std::is_same<decltype(ToBackend(base)), const Ref<MyCommandBuffer>&>::value, ""); static_assert(std::is_same<decltype(ToBackend(base)), const Ref<MyCommandBuffer>&>::value,
"");
ASSERT_EQ(cmdBuf, backendCmdBuf.Get()); ASSERT_EQ(cmdBuf, backendCmdBuf.Get());
cmdBuf->Release(); cmdBuf->Release();

View File

@ -55,7 +55,8 @@ namespace {
// Check that the offset is aligned // Check that the offset is aligned
void ValidateOffset(const TextureCopySplit& copySplit) { void ValidateOffset(const TextureCopySplit& copySplit) {
ASSERT_TRUE(Align(copySplit.offset, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT) == copySplit.offset); ASSERT_TRUE(Align(copySplit.offset, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT) ==
copySplit.offset);
} }
bool RangesOverlap(uint32_t minA, uint32_t maxA, uint32_t minB, uint32_t maxB) { bool RangesOverlap(uint32_t minA, uint32_t maxA, uint32_t minB, uint32_t maxB) {
@ -68,9 +69,15 @@ namespace {
const auto& a = copySplit.copies[i]; const auto& a = copySplit.copies[i];
for (uint32_t j = i + 1; j < copySplit.count; ++j) { for (uint32_t j = i + 1; j < copySplit.count; ++j) {
const auto& b = copySplit.copies[j]; const auto& b = copySplit.copies[j];
bool overlapX = RangesOverlap(a.textureOffset.x, a.textureOffset.x + a.copySize.width, b.textureOffset.x, b.textureOffset.x + b.copySize.width); bool overlapX =
bool overlapY = RangesOverlap(a.textureOffset.y, a.textureOffset.y + a.copySize.height, b.textureOffset.y, b.textureOffset.y + b.copySize.height); RangesOverlap(a.textureOffset.x, a.textureOffset.x + a.copySize.width,
bool overlapZ = RangesOverlap(a.textureOffset.z, a.textureOffset.z + a.copySize.depth, b.textureOffset.z, b.textureOffset.z + b.copySize.depth); b.textureOffset.x, b.textureOffset.x + b.copySize.width);
bool overlapY =
RangesOverlap(a.textureOffset.y, a.textureOffset.y + a.copySize.height,
b.textureOffset.y, b.textureOffset.y + b.copySize.height);
bool overlapZ =
RangesOverlap(a.textureOffset.z, a.textureOffset.z + a.copySize.depth,
b.textureOffset.z, b.textureOffset.z + b.copySize.depth);
ASSERT_TRUE(!overlapX || !overlapY || !overlapZ); ASSERT_TRUE(!overlapX || !overlapY || !overlapZ);
} }
} }
@ -105,7 +112,8 @@ namespace {
ASSERT_EQ(maxZ, textureSpec.z + textureSpec.depth); ASSERT_EQ(maxZ, textureSpec.z + textureSpec.depth);
} }
// Validate that the number of pixels copied is exactly equal to the number of pixels in the texture region // Validate that the number of pixels copied is exactly equal to the number of pixels in the
// texture region
void ValidatePixelCount(const TextureSpec& textureSpec, const TextureCopySplit& copySplit) { void ValidatePixelCount(const TextureSpec& textureSpec, const TextureCopySplit& copySplit) {
uint32_t count = 0; uint32_t count = 0;
for (uint32_t i = 0; i < copySplit.count; ++i) { for (uint32_t i = 0; i < copySplit.count; ++i) {
@ -116,7 +124,9 @@ namespace {
} }
// Check that every buffer offset is at the correct pixel location // Check that every buffer offset is at the correct pixel location
void ValidateBufferOffset(const TextureSpec& textureSpec, const BufferSpec& bufferSpec, const TextureCopySplit& copySplit) { void ValidateBufferOffset(const TextureSpec& textureSpec,
const BufferSpec& bufferSpec,
const TextureCopySplit& copySplit) {
ASSERT_TRUE(copySplit.count > 0); ASSERT_TRUE(copySplit.count > 0);
uint32_t texelsPerBlock = textureSpec.blockWidth * textureSpec.blockHeight; uint32_t texelsPerBlock = textureSpec.blockWidth * textureSpec.blockHeight;
@ -149,7 +159,9 @@ namespace {
} }
} }
void ValidateCopySplit(const TextureSpec& textureSpec, const BufferSpec& bufferSpec, const TextureCopySplit& copySplit) { void ValidateCopySplit(const TextureSpec& textureSpec,
const BufferSpec& bufferSpec,
const TextureCopySplit& copySplit) {
ValidateFootprints(copySplit); ValidateFootprints(copySplit);
ValidateOffset(copySplit); ValidateOffset(copySplit);
ValidateDisjoint(copySplit); ValidateDisjoint(copySplit);
@ -176,8 +188,13 @@ namespace {
os << "CopySplit" << std::endl; os << "CopySplit" << std::endl;
for (uint32_t i = 0; i < copySplit.count; ++i) { for (uint32_t i = 0; i < copySplit.count; ++i) {
const auto& copy = copySplit.copies[i]; const auto& copy = copySplit.copies[i];
os << " " << i << ": Texture at (" << copy.textureOffset.x << ", " << copy.textureOffset.y << ", " << copy.textureOffset.z << "), size (" << copy.copySize.width << ", " << copy.copySize.height << ", " << copy.copySize.depth << ")" << std::endl; os << " " << i << ": Texture at (" << copy.textureOffset.x << ", "
os << " " << i << ": Buffer at (" << copy.bufferOffset.x << ", " << copy.bufferOffset.y << ", " << copy.bufferOffset.z << "), footprint (" << copy.bufferSize.width << ", " << copy.bufferSize.height << ", " << copy.bufferSize.depth << ")" << std::endl; << copy.textureOffset.y << ", " << copy.textureOffset.z << "), size ("
<< copy.copySize.width << ", " << copy.copySize.height << ", " << copy.copySize.depth
<< ")" << std::endl;
os << " " << i << ": Buffer at (" << copy.bufferOffset.x << ", " << copy.bufferOffset.y
<< ", " << copy.bufferOffset.z << "), footprint (" << copy.bufferSize.width << ", "
<< copy.bufferSize.height << ", " << copy.bufferSize.depth << ")" << std::endl;
} }
return os; return os;
} }
@ -260,42 +277,40 @@ namespace {
} }
// Define a list of values to set properties in the spec structs // Define a list of values to set properties in the spec structs
constexpr uint32_t kCheckValues[] = { constexpr uint32_t kCheckValues[] = {1, 2, 3, 4, 5, 6, 7, 8, // small values
1, 2, 3, 4, 5, 6, 7, 8, // small values 16, 32, 64, 128, 256, 512, 1024, 2048, // powers of 2
16, 32, 64, 128, 256, 512, 1024, 2048, // powers of 2 15, 31, 63, 127, 257, 511, 1023, 2047, // misalignments
15, 31, 63, 127, 257, 511, 1023, 2047, // misalignments 17, 33, 65, 129, 257, 513, 1025, 2049};
17, 33, 65, 129, 257, 513, 1025, 2049
};
} } // namespace
class CopySplitTest : public testing::Test { class CopySplitTest : public testing::Test {
protected: protected:
TextureCopySplit DoTest(const TextureSpec& textureSpec, const BufferSpec& bufferSpec) { TextureCopySplit DoTest(const TextureSpec& textureSpec, const BufferSpec& bufferSpec) {
ASSERT(textureSpec.width % textureSpec.blockWidth == 0 && ASSERT(textureSpec.width % textureSpec.blockWidth == 0 &&
textureSpec.height % textureSpec.blockHeight == 0); textureSpec.height % textureSpec.blockHeight == 0);
dawn_native::Format fakeFormat = {}; dawn_native::Format fakeFormat = {};
fakeFormat.blockWidth = textureSpec.blockWidth; fakeFormat.blockWidth = textureSpec.blockWidth;
fakeFormat.blockHeight = textureSpec.blockHeight; fakeFormat.blockHeight = textureSpec.blockHeight;
fakeFormat.blockByteSize = textureSpec.texelBlockSizeInBytes; fakeFormat.blockByteSize = textureSpec.texelBlockSizeInBytes;
TextureCopySplit copySplit = ComputeTextureCopySplit( TextureCopySplit copySplit = ComputeTextureCopySplit(
{textureSpec.x, textureSpec.y, textureSpec.z}, {textureSpec.x, textureSpec.y, textureSpec.z},
{textureSpec.width, textureSpec.height, textureSpec.depth}, fakeFormat, {textureSpec.width, textureSpec.height, textureSpec.depth}, fakeFormat,
bufferSpec.offset, bufferSpec.bytesPerRow, bufferSpec.rowsPerImage); bufferSpec.offset, bufferSpec.bytesPerRow, bufferSpec.rowsPerImage);
ValidateCopySplit(textureSpec, bufferSpec, copySplit); ValidateCopySplit(textureSpec, bufferSpec, copySplit);
return copySplit; return copySplit;
} }
}; };
TEST_F(CopySplitTest, General) { TEST_F(CopySplitTest, General) {
for (TextureSpec textureSpec : kBaseTextureSpecs) { for (TextureSpec textureSpec : kBaseTextureSpecs) {
for (BufferSpec bufferSpec : BaseBufferSpecs(textureSpec)) { for (BufferSpec bufferSpec : BaseBufferSpecs(textureSpec)) {
TextureCopySplit copySplit = DoTest(textureSpec, bufferSpec); TextureCopySplit copySplit = DoTest(textureSpec, bufferSpec);
if (HasFatalFailure()) { if (HasFatalFailure()) {
std::ostringstream message; std::ostringstream message;
message << "Failed generating splits: " << textureSpec << ", " << bufferSpec << std::endl message << "Failed generating splits: " << textureSpec << ", " << bufferSpec
<< copySplit << std::endl; << std::endl
<< copySplit << std::endl;
FAIL() << message.str(); FAIL() << message.str();
} }
} }
@ -310,12 +325,12 @@ TEST_F(CopySplitTest, TextureWidth) {
} }
textureSpec.width = val; textureSpec.width = val;
for (BufferSpec bufferSpec : BaseBufferSpecs(textureSpec)) { for (BufferSpec bufferSpec : BaseBufferSpecs(textureSpec)) {
TextureCopySplit copySplit = DoTest(textureSpec, bufferSpec); TextureCopySplit copySplit = DoTest(textureSpec, bufferSpec);
if (HasFatalFailure()) { if (HasFatalFailure()) {
std::ostringstream message; std::ostringstream message;
message << "Failed generating splits: " << textureSpec << ", " << bufferSpec << std::endl message << "Failed generating splits: " << textureSpec << ", " << bufferSpec
<< copySplit << std::endl; << std::endl
<< copySplit << std::endl;
FAIL() << message.str(); FAIL() << message.str();
} }
} }
@ -331,12 +346,12 @@ TEST_F(CopySplitTest, TextureHeight) {
} }
textureSpec.height = val; textureSpec.height = val;
for (BufferSpec bufferSpec : BaseBufferSpecs(textureSpec)) { for (BufferSpec bufferSpec : BaseBufferSpecs(textureSpec)) {
TextureCopySplit copySplit = DoTest(textureSpec, bufferSpec); TextureCopySplit copySplit = DoTest(textureSpec, bufferSpec);
if (HasFatalFailure()) { if (HasFatalFailure()) {
std::ostringstream message; std::ostringstream message;
message << "Failed generating splits: " << textureSpec << ", " << bufferSpec << std::endl message << "Failed generating splits: " << textureSpec << ", " << bufferSpec
<< copySplit << std::endl; << std::endl
<< copySplit << std::endl;
FAIL() << message.str(); FAIL() << message.str();
} }
} }
@ -349,12 +364,12 @@ TEST_F(CopySplitTest, TextureX) {
for (uint32_t val : kCheckValues) { for (uint32_t val : kCheckValues) {
textureSpec.x = val; textureSpec.x = val;
for (BufferSpec bufferSpec : BaseBufferSpecs(textureSpec)) { for (BufferSpec bufferSpec : BaseBufferSpecs(textureSpec)) {
TextureCopySplit copySplit = DoTest(textureSpec, bufferSpec); TextureCopySplit copySplit = DoTest(textureSpec, bufferSpec);
if (HasFatalFailure()) { if (HasFatalFailure()) {
std::ostringstream message; std::ostringstream message;
message << "Failed generating splits: " << textureSpec << ", " << bufferSpec << std::endl message << "Failed generating splits: " << textureSpec << ", " << bufferSpec
<< copySplit << std::endl; << std::endl
<< copySplit << std::endl;
FAIL() << message.str(); FAIL() << message.str();
} }
} }
@ -367,12 +382,12 @@ TEST_F(CopySplitTest, TextureY) {
for (uint32_t val : kCheckValues) { for (uint32_t val : kCheckValues) {
textureSpec.y = val; textureSpec.y = val;
for (BufferSpec bufferSpec : BaseBufferSpecs(textureSpec)) { for (BufferSpec bufferSpec : BaseBufferSpecs(textureSpec)) {
TextureCopySplit copySplit = DoTest(textureSpec, bufferSpec); TextureCopySplit copySplit = DoTest(textureSpec, bufferSpec);
if (HasFatalFailure()) { if (HasFatalFailure()) {
std::ostringstream message; std::ostringstream message;
message << "Failed generating splits: " << textureSpec << ", " << bufferSpec << std::endl message << "Failed generating splits: " << textureSpec << ", " << bufferSpec
<< copySplit << std::endl; << std::endl
<< copySplit << std::endl;
FAIL() << message.str(); FAIL() << message.str();
} }
} }
@ -385,12 +400,12 @@ TEST_F(CopySplitTest, TexelSize) {
for (uint32_t texelSize : {4, 8, 16, 32, 64}) { for (uint32_t texelSize : {4, 8, 16, 32, 64}) {
textureSpec.texelBlockSizeInBytes = texelSize; textureSpec.texelBlockSizeInBytes = texelSize;
for (BufferSpec bufferSpec : BaseBufferSpecs(textureSpec)) { for (BufferSpec bufferSpec : BaseBufferSpecs(textureSpec)) {
TextureCopySplit copySplit = DoTest(textureSpec, bufferSpec); TextureCopySplit copySplit = DoTest(textureSpec, bufferSpec);
if (HasFatalFailure()) { if (HasFatalFailure()) {
std::ostringstream message; std::ostringstream message;
message << "Failed generating splits: " << textureSpec << ", " << bufferSpec << std::endl message << "Failed generating splits: " << textureSpec << ", " << bufferSpec
<< copySplit << std::endl; << std::endl
<< copySplit << std::endl;
FAIL() << message.str(); FAIL() << message.str();
} }
} }
@ -407,8 +422,9 @@ TEST_F(CopySplitTest, BufferOffset) {
TextureCopySplit copySplit = DoTest(textureSpec, bufferSpec); TextureCopySplit copySplit = DoTest(textureSpec, bufferSpec);
if (HasFatalFailure()) { if (HasFatalFailure()) {
std::ostringstream message; std::ostringstream message;
message << "Failed generating splits: " << textureSpec << ", " << bufferSpec << std::endl message << "Failed generating splits: " << textureSpec << ", " << bufferSpec
<< copySplit << std::endl; << std::endl
<< copySplit << std::endl;
FAIL() << message.str(); FAIL() << message.str();
} }
} }
@ -426,8 +442,9 @@ TEST_F(CopySplitTest, RowPitch) {
TextureCopySplit copySplit = DoTest(textureSpec, bufferSpec); TextureCopySplit copySplit = DoTest(textureSpec, bufferSpec);
if (HasFatalFailure()) { if (HasFatalFailure()) {
std::ostringstream message; std::ostringstream message;
message << "Failed generating splits: " << textureSpec << ", " << bufferSpec << std::endl message << "Failed generating splits: " << textureSpec << ", " << bufferSpec
<< copySplit << std::endl; << std::endl
<< copySplit << std::endl;
FAIL() << message.str(); FAIL() << message.str();
} }
} }

View File

@ -121,16 +121,10 @@ TEST_F(BindGroupValidationTest, BindingSetTwice) {
{1, wgpu::ShaderStage::Fragment, wgpu::BindingType::Sampler}}); {1, wgpu::ShaderStage::Fragment, wgpu::BindingType::Sampler}});
// Control case: check that different bindings work // Control case: check that different bindings work
utils::MakeBindGroup(device, layout, { utils::MakeBindGroup(device, layout, {{0, mSampler}, {1, mSampler}});
{0, mSampler},
{1, mSampler}
});
// Check that setting the same binding twice is invalid // Check that setting the same binding twice is invalid
ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, layout, { ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, layout, {{0, mSampler}, {0, mSampler}}));
{0, mSampler},
{0, mSampler}
}));
} }
// Check that a sampler binding must contain exactly one sampler // Check that a sampler binding must contain exactly one sampler
@ -406,7 +400,7 @@ TEST_F(BindGroupValidationTest, BufferBindingOOB) {
utils::MakeBindGroup(device, layout, {{0, buffer, 0, 256}}); utils::MakeBindGroup(device, layout, {{0, buffer, 0, 256}});
// Success case, touching the end of the buffer works // Success case, touching the end of the buffer works
utils::MakeBindGroup(device, layout, {{0, buffer, 3*256, 256}}); utils::MakeBindGroup(device, layout, {{0, buffer, 3 * 256, 256}});
// Error case, zero size is invalid. // Error case, zero size is invalid.
ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, layout, {{0, buffer, 1024, 0}})); ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, layout, {{0, buffer, 1024, 0}}));
@ -419,16 +413,17 @@ TEST_F(BindGroupValidationTest, BufferBindingOOB) {
utils::MakeBindGroup(device, layout, {{0, buffer, 256, wgpu::kWholeSize}}); utils::MakeBindGroup(device, layout, {{0, buffer, 256, wgpu::kWholeSize}});
// Error case, offset is OOB // Error case, offset is OOB
ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, layout, {{0, buffer, 256*5, 0}})); ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, layout, {{0, buffer, 256 * 5, 0}}));
// Error case, size is OOB // Error case, size is OOB
ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, layout, {{0, buffer, 0, 256*5}})); ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, layout, {{0, buffer, 0, 256 * 5}}));
// Error case, offset+size is OOB // Error case, offset+size is OOB
ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, layout, {{0, buffer, 1024, 256}})); ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, layout, {{0, buffer, 1024, 256}}));
// Error case, offset+size overflows to be 0 // Error case, offset+size overflows to be 0
ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, layout, {{0, buffer, 256, uint32_t(0) - uint32_t(256)}})); ASSERT_DEVICE_ERROR(
utils::MakeBindGroup(device, layout, {{0, buffer, 256, uint32_t(0) - uint32_t(256)}}));
} }
// Tests constraints to be sure the uniform buffer binding isn't too large // Tests constraints to be sure the uniform buffer binding isn't too large
@ -1191,8 +1186,8 @@ TEST_F(SetBindGroupValidationTest, DynamicOffsetOrder) {
// Create buffers which are 3x, 2x, and 1x the size of the minimum buffer offset, plus 4 bytes // Create buffers which are 3x, 2x, and 1x the size of the minimum buffer offset, plus 4 bytes
// to spare (to avoid zero-sized bindings). We will offset the bindings so they reach the very // to spare (to avoid zero-sized bindings). We will offset the bindings so they reach the very
// end of the buffer. Any mismatch applying too-large of an offset to a smaller buffer will hit the // end of the buffer. Any mismatch applying too-large of an offset to a smaller buffer will hit
// out-of-bounds condition during validation. // the out-of-bounds condition during validation.
wgpu::Buffer buffer3x = wgpu::Buffer buffer3x =
CreateBuffer(3 * kMinDynamicBufferOffsetAlignment + 4, wgpu::BufferUsage::Storage); CreateBuffer(3 * kMinDynamicBufferOffsetAlignment + 4, wgpu::BufferUsage::Storage);
wgpu::Buffer buffer2x = wgpu::Buffer buffer2x =
@ -1487,7 +1482,6 @@ class BindGroupLayoutCompatibilityTest : public ValidationTest {
wgpu::RenderPipeline CreateFSRenderPipeline( wgpu::RenderPipeline CreateFSRenderPipeline(
const char* fsShader, const char* fsShader,
std::vector<wgpu::BindGroupLayout> bindGroupLayout) { std::vector<wgpu::BindGroupLayout> bindGroupLayout) {
wgpu::ShaderModule vsModule = wgpu::ShaderModule vsModule =
utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, R"( utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, R"(
#version 450 #version 450
@ -1520,7 +1514,7 @@ class BindGroupLayoutCompatibilityTest : public ValidationTest {
layout(location = 0) out vec4 fragColor; layout(location = 0) out vec4 fragColor;
void main() { void main() {
})", })",
std::move(bindGroupLayout)); std::move(bindGroupLayout));
} }
wgpu::ComputePipeline CreateComputePipeline( wgpu::ComputePipeline CreateComputePipeline(
@ -1558,7 +1552,7 @@ class BindGroupLayoutCompatibilityTest : public ValidationTest {
} rdst; } rdst;
void main() { void main() {
})", })",
std::move(bindGroupLayout)); std::move(bindGroupLayout));
} }
}; };

View File

@ -21,13 +21,13 @@
using namespace testing; using namespace testing;
class MockBufferMapReadCallback { class MockBufferMapReadCallback {
public: public:
MOCK_METHOD(void, MOCK_METHOD(void,
Call, Call,
(WGPUBufferMapAsyncStatus status, (WGPUBufferMapAsyncStatus status,
const uint32_t* ptr, const uint32_t* ptr,
uint64_t dataLength, uint64_t dataLength,
void* userdata)); void* userdata));
}; };
static std::unique_ptr<MockBufferMapReadCallback> mockBufferMapReadCallback; static std::unique_ptr<MockBufferMapReadCallback> mockBufferMapReadCallback;
@ -41,11 +41,11 @@ static void ToMockBufferMapReadCallback(WGPUBufferMapAsyncStatus status,
} }
class MockBufferMapWriteCallback { class MockBufferMapWriteCallback {
public: public:
MOCK_METHOD( MOCK_METHOD(
void, void,
Call, Call,
(WGPUBufferMapAsyncStatus status, uint32_t* ptr, uint64_t dataLength, void* userdata)); (WGPUBufferMapAsyncStatus status, uint32_t* ptr, uint64_t dataLength, void* userdata));
}; };
static std::unique_ptr<MockBufferMapWriteCallback> mockBufferMapWriteCallback; static std::unique_ptr<MockBufferMapWriteCallback> mockBufferMapWriteCallback;
@ -59,57 +59,57 @@ static void ToMockBufferMapWriteCallback(WGPUBufferMapAsyncStatus status,
} }
class BufferValidationTest : public ValidationTest { class BufferValidationTest : public ValidationTest {
protected: protected:
wgpu::Buffer CreateMapReadBuffer(uint64_t size) { wgpu::Buffer CreateMapReadBuffer(uint64_t size) {
wgpu::BufferDescriptor descriptor; wgpu::BufferDescriptor descriptor;
descriptor.size = size; descriptor.size = size;
descriptor.usage = wgpu::BufferUsage::MapRead; descriptor.usage = wgpu::BufferUsage::MapRead;
return device.CreateBuffer(&descriptor); return device.CreateBuffer(&descriptor);
} }
wgpu::Buffer CreateMapWriteBuffer(uint64_t size) { wgpu::Buffer CreateMapWriteBuffer(uint64_t size) {
wgpu::BufferDescriptor descriptor; wgpu::BufferDescriptor descriptor;
descriptor.size = size; descriptor.size = size;
descriptor.usage = wgpu::BufferUsage::MapWrite; descriptor.usage = wgpu::BufferUsage::MapWrite;
return device.CreateBuffer(&descriptor); return device.CreateBuffer(&descriptor);
} }
wgpu::CreateBufferMappedResult CreateBufferMapped(uint64_t size, wgpu::BufferUsage usage) { wgpu::CreateBufferMappedResult CreateBufferMapped(uint64_t size, wgpu::BufferUsage usage) {
wgpu::BufferDescriptor descriptor; wgpu::BufferDescriptor descriptor;
descriptor.size = size; descriptor.size = size;
descriptor.usage = usage; descriptor.usage = usage;
return device.CreateBufferMapped(&descriptor); return device.CreateBufferMapped(&descriptor);
} }
wgpu::Buffer BufferMappedAtCreation(uint64_t size, wgpu::BufferUsage usage) { wgpu::Buffer BufferMappedAtCreation(uint64_t size, wgpu::BufferUsage usage) {
wgpu::BufferDescriptor descriptor; wgpu::BufferDescriptor descriptor;
descriptor.size = size; descriptor.size = size;
descriptor.usage = usage; descriptor.usage = usage;
descriptor.mappedAtCreation = true; descriptor.mappedAtCreation = true;
return device.CreateBuffer(&descriptor); return device.CreateBuffer(&descriptor);
} }
wgpu::Queue queue; wgpu::Queue queue;
private: private:
void SetUp() override { void SetUp() override {
ValidationTest::SetUp(); ValidationTest::SetUp();
mockBufferMapReadCallback = std::make_unique<MockBufferMapReadCallback>(); mockBufferMapReadCallback = std::make_unique<MockBufferMapReadCallback>();
mockBufferMapWriteCallback = std::make_unique<MockBufferMapWriteCallback>(); mockBufferMapWriteCallback = std::make_unique<MockBufferMapWriteCallback>();
queue = device.GetDefaultQueue(); queue = device.GetDefaultQueue();
} }
void TearDown() override { void TearDown() override {
// Delete mocks so that expectations are checked // Delete mocks so that expectations are checked
mockBufferMapReadCallback = nullptr; mockBufferMapReadCallback = nullptr;
mockBufferMapWriteCallback = nullptr; mockBufferMapWriteCallback = nullptr;
ValidationTest::TearDown(); ValidationTest::TearDown();
} }
}; };
// Test case where creation should succeed // Test case where creation should succeed
@ -416,7 +416,8 @@ TEST_F(BufferValidationTest, UnmapInsideMapWriteCallback) {
WaitForAllOperations(device); WaitForAllOperations(device);
} }
// Test that the MapReadCallback isn't fired twice the buffer external refcount reaches 0 in the callback // Test that the MapReadCallback isn't fired twice the buffer external refcount reaches 0 in the
// callback
TEST_F(BufferValidationTest, DestroyInsideMapReadCallback) { TEST_F(BufferValidationTest, DestroyInsideMapReadCallback) {
wgpu::Buffer buf = CreateMapReadBuffer(4); wgpu::Buffer buf = CreateMapReadBuffer(4);
@ -429,7 +430,8 @@ TEST_F(BufferValidationTest, DestroyInsideMapReadCallback) {
WaitForAllOperations(device); WaitForAllOperations(device);
} }
// Test that the MapWriteCallback isn't fired twice the buffer external refcount reaches 0 in the callback // Test that the MapWriteCallback isn't fired twice the buffer external refcount reaches 0 in the
// callback
TEST_F(BufferValidationTest, DestroyInsideMapWriteCallback) { TEST_F(BufferValidationTest, DestroyInsideMapWriteCallback) {
wgpu::Buffer buf = CreateMapWriteBuffer(4); wgpu::Buffer buf = CreateMapWriteBuffer(4);

View File

@ -16,8 +16,7 @@
#include "utils/WGPUHelpers.h" #include "utils/WGPUHelpers.h"
class CommandBufferValidationTest : public ValidationTest { class CommandBufferValidationTest : public ValidationTest {};
};
// Test for an empty command buffer // Test for an empty command buffer
TEST_F(CommandBufferValidationTest, Empty) { TEST_F(CommandBufferValidationTest, Empty) {

View File

@ -14,7 +14,7 @@
#include "tests/unittests/validation/ValidationTest.h" #include "tests/unittests/validation/ValidationTest.h"
class ComputeValidationTest : public ValidationTest { class ComputeValidationTest : public ValidationTest {};
};
//TODO(cwallez@chromium.org): Add a regression test for Disptach validation trying to acces the input state. // TODO(cwallez@chromium.org): Add a regression test for Disptach validation trying to acces the
// input state.

View File

@ -1168,8 +1168,8 @@ TEST_F(CopyCommandTest_T2T, 2DTextureDepthStencil) {
TEST_F(CopyCommandTest_T2T, 2DTextureArrayDepthStencil) { TEST_F(CopyCommandTest_T2T, 2DTextureArrayDepthStencil) {
{ {
wgpu::Texture source = Create2DTexture(16, 16, 1, 3, wgpu::TextureFormat::Depth24PlusStencil8, wgpu::Texture source = Create2DTexture(
wgpu::TextureUsage::CopySrc); 16, 16, 1, 3, wgpu::TextureFormat::Depth24PlusStencil8, wgpu::TextureUsage::CopySrc);
wgpu::Texture destination = Create2DTexture( wgpu::Texture destination = Create2DTexture(
16, 16, 1, 1, wgpu::TextureFormat::Depth24PlusStencil8, wgpu::TextureUsage::CopyDst); 16, 16, 1, 1, wgpu::TextureFormat::Depth24PlusStencil8, wgpu::TextureUsage::CopyDst);
@ -1179,8 +1179,8 @@ TEST_F(CopyCommandTest_T2T, 2DTextureArrayDepthStencil) {
} }
{ {
wgpu::Texture source = Create2DTexture(16, 16, 1, 1, wgpu::TextureFormat::Depth24PlusStencil8, wgpu::Texture source = Create2DTexture(
wgpu::TextureUsage::CopySrc); 16, 16, 1, 1, wgpu::TextureFormat::Depth24PlusStencil8, wgpu::TextureUsage::CopySrc);
wgpu::Texture destination = Create2DTexture( wgpu::Texture destination = Create2DTexture(
16, 16, 1, 3, wgpu::TextureFormat::Depth24PlusStencil8, wgpu::TextureUsage::CopyDst); 16, 16, 1, 3, wgpu::TextureFormat::Depth24PlusStencil8, wgpu::TextureUsage::CopyDst);
@ -1190,8 +1190,8 @@ TEST_F(CopyCommandTest_T2T, 2DTextureArrayDepthStencil) {
} }
{ {
wgpu::Texture source = Create2DTexture(16, 16, 1, 3, wgpu::TextureFormat::Depth24PlusStencil8, wgpu::Texture source = Create2DTexture(
wgpu::TextureUsage::CopySrc); 16, 16, 1, 3, wgpu::TextureFormat::Depth24PlusStencil8, wgpu::TextureUsage::CopySrc);
wgpu::Texture destination = Create2DTexture( wgpu::Texture destination = Create2DTexture(
16, 16, 1, 3, wgpu::TextureFormat::Depth24PlusStencil8, wgpu::TextureUsage::CopyDst); 16, 16, 1, 3, wgpu::TextureFormat::Depth24PlusStencil8, wgpu::TextureUsage::CopyDst);
@ -1659,4 +1659,4 @@ TEST_F(CopyCommandTest_CompressedTextureFormats, CopyToMultipleArrayLayers) {
{0, 0, 0}); {0, 0, 0});
} }
} }
} }

View File

@ -223,8 +223,7 @@ TEST_F(SetViewportTest, MinDepthEqualOrGreaterThanMaxDepth) {
} }
} }
class SetScissorRectTest : public ValidationTest { class SetScissorRectTest : public ValidationTest {};
};
// Test to check basic use of SetScissor // Test to check basic use of SetScissor
TEST_F(SetScissorRectTest, Success) { TEST_F(SetScissorRectTest, Success) {
@ -284,8 +283,7 @@ TEST_F(SetScissorRectTest, ScissorLargerThanFramebuffer) {
encoder.Finish(); encoder.Finish();
} }
class SetBlendColorTest : public ValidationTest { class SetBlendColorTest : public ValidationTest {};
};
// Test to check basic use of SetBlendColor // Test to check basic use of SetBlendColor
TEST_F(SetBlendColorTest, Success) { TEST_F(SetBlendColorTest, Success) {
@ -315,8 +313,7 @@ TEST_F(SetBlendColorTest, AnyValueAllowed) {
encoder.Finish(); encoder.Finish();
} }
class SetStencilReferenceTest : public ValidationTest { class SetStencilReferenceTest : public ValidationTest {};
};
// Test to check basic use of SetStencilReferenceTest // Test to check basic use of SetStencilReferenceTest
TEST_F(SetStencilReferenceTest, Success) { TEST_F(SetStencilReferenceTest, Success) {

View File

@ -18,181 +18,180 @@
namespace { namespace {
class QueueSubmitValidationTest : public ValidationTest { class QueueSubmitValidationTest : public ValidationTest {};
};
// Test submitting with a mapped buffer is disallowed // Test submitting with a mapped buffer is disallowed
TEST_F(QueueSubmitValidationTest, SubmitWithMappedBuffer) { TEST_F(QueueSubmitValidationTest, SubmitWithMappedBuffer) {
// Create a map-write buffer. // Create a map-write buffer.
wgpu::BufferDescriptor descriptor;
descriptor.usage = wgpu::BufferUsage::MapWrite | wgpu::BufferUsage::CopySrc;
descriptor.size = 4;
wgpu::Buffer buffer = device.CreateBuffer(&descriptor);
// Create a fake copy destination buffer
descriptor.usage = wgpu::BufferUsage::CopyDst;
wgpu::Buffer targetBuffer = device.CreateBuffer(&descriptor);
// Create a command buffer that reads from the mappable buffer.
wgpu::CommandBuffer commands;
{
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
encoder.CopyBufferToBuffer(buffer, 0, targetBuffer, 0, 4);
commands = encoder.Finish();
}
wgpu::Queue queue = device.GetDefaultQueue();
// Submitting when the buffer has never been mapped should succeed
queue.Submit(1, &commands);
// Map the buffer, submitting when the buffer is mapped should fail
buffer.MapWriteAsync(nullptr, nullptr);
// Try submitting before the callback is fired.
ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
WaitForAllOperations(device);
// Try submitting after the callback is fired.
ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
// Unmap the buffer, queue submit should succeed
buffer.Unmap();
queue.Submit(1, &commands);
}
class QueueWriteBufferValidationTest : public ValidationTest {
private:
void SetUp() override {
ValidationTest::SetUp();
queue = device.GetDefaultQueue();
}
protected:
wgpu::Buffer CreateBuffer(uint64_t size) {
wgpu::BufferDescriptor descriptor;
descriptor.size = size;
descriptor.usage = wgpu::BufferUsage::CopyDst;
return device.CreateBuffer(&descriptor);
}
wgpu::Queue queue;
};
// Test the success case for WriteBuffer
TEST_F(QueueWriteBufferValidationTest, Success) {
wgpu::Buffer buf = CreateBuffer(4);
uint32_t foo = 0x01020304;
queue.WriteBuffer(buf, 0, &foo, sizeof(foo));
}
// Test error case for WriteBuffer out of bounds
TEST_F(QueueWriteBufferValidationTest, OutOfBounds) {
wgpu::Buffer buf = CreateBuffer(4);
uint32_t foo[2] = {0, 0};
ASSERT_DEVICE_ERROR(queue.WriteBuffer(buf, 0, foo, 8));
}
// Test error case for WriteBuffer out of bounds with an overflow
TEST_F(QueueWriteBufferValidationTest, OutOfBoundsOverflow) {
wgpu::Buffer buf = CreateBuffer(1024);
uint32_t foo[2] = {0, 0};
// An offset that when added to "4" would overflow to be zero and pass validation without
// overflow checks.
uint64_t offset = uint64_t(int64_t(0) - int64_t(4));
ASSERT_DEVICE_ERROR(queue.WriteBuffer(buf, offset, foo, 4));
}
// Test error case for WriteBuffer with the wrong usage
TEST_F(QueueWriteBufferValidationTest, WrongUsage) {
wgpu::BufferDescriptor descriptor;
descriptor.size = 4;
descriptor.usage = wgpu::BufferUsage::Vertex;
wgpu::Buffer buf = device.CreateBuffer(&descriptor);
uint32_t foo = 0;
ASSERT_DEVICE_ERROR(queue.WriteBuffer(buf, 0, &foo, sizeof(foo)));
}
// Test WriteBuffer with unaligned size
TEST_F(QueueWriteBufferValidationTest, UnalignedSize) {
wgpu::Buffer buf = CreateBuffer(4);
uint16_t value = 123;
ASSERT_DEVICE_ERROR(queue.WriteBuffer(buf, 0, &value, sizeof(value)));
}
// Test WriteBuffer with unaligned offset
TEST_F(QueueWriteBufferValidationTest, UnalignedOffset) {
wgpu::Buffer buf = CreateBuffer(8);
uint32_t value = 0x01020304;
ASSERT_DEVICE_ERROR(queue.WriteBuffer(buf, 2, &value, sizeof(value)));
}
// Test WriteBuffer with destroyed buffer
TEST_F(QueueWriteBufferValidationTest, DestroyedBuffer) {
wgpu::Buffer buf = CreateBuffer(4);
buf.Destroy();
uint32_t value = 0;
ASSERT_DEVICE_ERROR(queue.WriteBuffer(buf, 0, &value, sizeof(value)));
}
// Test WriteBuffer with mapped buffer
TEST_F(QueueWriteBufferValidationTest, MappedBuffer) {
// CreateBufferMapped
{
wgpu::BufferDescriptor descriptor; wgpu::BufferDescriptor descriptor;
descriptor.usage = wgpu::BufferUsage::MapWrite | wgpu::BufferUsage::CopySrc;
descriptor.size = 4; descriptor.size = 4;
descriptor.usage = wgpu::BufferUsage::CopyDst;
wgpu::CreateBufferMappedResult result = device.CreateBufferMapped(&descriptor);
uint32_t value = 0;
ASSERT_DEVICE_ERROR(queue.WriteBuffer(result.buffer, 0, &value, sizeof(value)));
}
// mappedAtCreation
{
wgpu::BufferDescriptor descriptor;
descriptor.size = 4;
descriptor.usage = wgpu::BufferUsage::CopyDst;
descriptor.mappedAtCreation = true;
wgpu::Buffer buffer = device.CreateBuffer(&descriptor); wgpu::Buffer buffer = device.CreateBuffer(&descriptor);
uint32_t value = 0; // Create a fake copy destination buffer
ASSERT_DEVICE_ERROR(queue.WriteBuffer(buffer, 0, &value, sizeof(value))); descriptor.usage = wgpu::BufferUsage::CopyDst;
wgpu::Buffer targetBuffer = device.CreateBuffer(&descriptor);
// Create a command buffer that reads from the mappable buffer.
wgpu::CommandBuffer commands;
{
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
encoder.CopyBufferToBuffer(buffer, 0, targetBuffer, 0, 4);
commands = encoder.Finish();
}
wgpu::Queue queue = device.GetDefaultQueue();
// Submitting when the buffer has never been mapped should succeed
queue.Submit(1, &commands);
// Map the buffer, submitting when the buffer is mapped should fail
buffer.MapWriteAsync(nullptr, nullptr);
// Try submitting before the callback is fired.
ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
WaitForAllOperations(device);
// Try submitting after the callback is fired.
ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
// Unmap the buffer, queue submit should succeed
buffer.Unmap();
queue.Submit(1, &commands);
} }
// MapReadAsync class QueueWriteBufferValidationTest : public ValidationTest {
{ private:
void SetUp() override {
ValidationTest::SetUp();
queue = device.GetDefaultQueue();
}
protected:
wgpu::Buffer CreateBuffer(uint64_t size) {
wgpu::BufferDescriptor descriptor;
descriptor.size = size;
descriptor.usage = wgpu::BufferUsage::CopyDst;
return device.CreateBuffer(&descriptor);
}
wgpu::Queue queue;
};
// Test the success case for WriteBuffer
TEST_F(QueueWriteBufferValidationTest, Success) {
wgpu::Buffer buf = CreateBuffer(4);
uint32_t foo = 0x01020304;
queue.WriteBuffer(buf, 0, &foo, sizeof(foo));
}
// Test error case for WriteBuffer out of bounds
TEST_F(QueueWriteBufferValidationTest, OutOfBounds) {
wgpu::Buffer buf = CreateBuffer(4);
uint32_t foo[2] = {0, 0};
ASSERT_DEVICE_ERROR(queue.WriteBuffer(buf, 0, foo, 8));
}
// Test error case for WriteBuffer out of bounds with an overflow
TEST_F(QueueWriteBufferValidationTest, OutOfBoundsOverflow) {
wgpu::Buffer buf = CreateBuffer(1024);
uint32_t foo[2] = {0, 0};
// An offset that when added to "4" would overflow to be zero and pass validation without
// overflow checks.
uint64_t offset = uint64_t(int64_t(0) - int64_t(4));
ASSERT_DEVICE_ERROR(queue.WriteBuffer(buf, offset, foo, 4));
}
// Test error case for WriteBuffer with the wrong usage
TEST_F(QueueWriteBufferValidationTest, WrongUsage) {
wgpu::BufferDescriptor descriptor; wgpu::BufferDescriptor descriptor;
descriptor.size = 4; descriptor.size = 4;
descriptor.usage = wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::MapRead; descriptor.usage = wgpu::BufferUsage::Vertex;
wgpu::Buffer buf = device.CreateBuffer(&descriptor); wgpu::Buffer buf = device.CreateBuffer(&descriptor);
buf.MapReadAsync(nullptr, nullptr); uint32_t foo = 0;
ASSERT_DEVICE_ERROR(queue.WriteBuffer(buf, 0, &foo, sizeof(foo)));
}
// Test WriteBuffer with unaligned size
TEST_F(QueueWriteBufferValidationTest, UnalignedSize) {
wgpu::Buffer buf = CreateBuffer(4);
uint16_t value = 123;
ASSERT_DEVICE_ERROR(queue.WriteBuffer(buf, 0, &value, sizeof(value)));
}
// Test WriteBuffer with unaligned offset
TEST_F(QueueWriteBufferValidationTest, UnalignedOffset) {
wgpu::Buffer buf = CreateBuffer(8);
uint32_t value = 0x01020304;
ASSERT_DEVICE_ERROR(queue.WriteBuffer(buf, 2, &value, sizeof(value)));
}
// Test WriteBuffer with destroyed buffer
TEST_F(QueueWriteBufferValidationTest, DestroyedBuffer) {
wgpu::Buffer buf = CreateBuffer(4);
buf.Destroy();
uint32_t value = 0; uint32_t value = 0;
ASSERT_DEVICE_ERROR(queue.WriteBuffer(buf, 0, &value, sizeof(value))); ASSERT_DEVICE_ERROR(queue.WriteBuffer(buf, 0, &value, sizeof(value)));
} }
// MapWriteAsync // Test WriteBuffer with mapped buffer
{ TEST_F(QueueWriteBufferValidationTest, MappedBuffer) {
wgpu::BufferDescriptor descriptor; // CreateBufferMapped
descriptor.size = 4; {
descriptor.usage = wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::MapWrite; wgpu::BufferDescriptor descriptor;
wgpu::Buffer buf = device.CreateBuffer(&descriptor); descriptor.size = 4;
descriptor.usage = wgpu::BufferUsage::CopyDst;
wgpu::CreateBufferMappedResult result = device.CreateBufferMapped(&descriptor);
buf.MapWriteAsync(nullptr, nullptr); uint32_t value = 0;
uint32_t value = 0; ASSERT_DEVICE_ERROR(queue.WriteBuffer(result.buffer, 0, &value, sizeof(value)));
ASSERT_DEVICE_ERROR(queue.WriteBuffer(buf, 0, &value, sizeof(value))); }
// mappedAtCreation
{
wgpu::BufferDescriptor descriptor;
descriptor.size = 4;
descriptor.usage = wgpu::BufferUsage::CopyDst;
descriptor.mappedAtCreation = true;
wgpu::Buffer buffer = device.CreateBuffer(&descriptor);
uint32_t value = 0;
ASSERT_DEVICE_ERROR(queue.WriteBuffer(buffer, 0, &value, sizeof(value)));
}
// MapReadAsync
{
wgpu::BufferDescriptor descriptor;
descriptor.size = 4;
descriptor.usage = wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::MapRead;
wgpu::Buffer buf = device.CreateBuffer(&descriptor);
buf.MapReadAsync(nullptr, nullptr);
uint32_t value = 0;
ASSERT_DEVICE_ERROR(queue.WriteBuffer(buf, 0, &value, sizeof(value)));
}
// MapWriteAsync
{
wgpu::BufferDescriptor descriptor;
descriptor.size = 4;
descriptor.usage = wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::MapWrite;
wgpu::Buffer buf = device.CreateBuffer(&descriptor);
buf.MapWriteAsync(nullptr, nullptr);
uint32_t value = 0;
ASSERT_DEVICE_ERROR(queue.WriteBuffer(buf, 0, &value, sizeof(value)));
}
} }
}
} // anonymous namespace } // anonymous namespace

View File

@ -636,4 +636,4 @@ namespace {
} }
} }
} // anonymous namespace } // anonymous namespace

View File

@ -22,26 +22,26 @@
#include <sstream> #include <sstream>
class RenderPipelineValidationTest : public ValidationTest { class RenderPipelineValidationTest : public ValidationTest {
protected: protected:
void SetUp() override { void SetUp() override {
ValidationTest::SetUp(); ValidationTest::SetUp();
vsModule = utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, R"( vsModule = utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, R"(
#version 450 #version 450
void main() { void main() {
gl_Position = vec4(0.0, 0.0, 0.0, 1.0); gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
})"); })");
fsModule = utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment, R"( fsModule = utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment, R"(
#version 450 #version 450
layout(location = 0) out vec4 fragColor; layout(location = 0) out vec4 fragColor;
void main() { void main() {
fragColor = vec4(0.0, 1.0, 0.0, 1.0); fragColor = vec4(0.0, 1.0, 0.0, 1.0);
})"); })");
} }
wgpu::ShaderModule vsModule; wgpu::ShaderModule vsModule;
wgpu::ShaderModule fsModule; wgpu::ShaderModule fsModule;
}; };
// Test cases where creation should succeed // Test cases where creation should succeed

View File

@ -20,8 +20,7 @@
#include <sstream> #include <sstream>
class ShaderModuleValidationTest : public ValidationTest { class ShaderModuleValidationTest : public ValidationTest {};
};
// Test case with a simpler shader that should successfully be created // Test case with a simpler shader that should successfully be created
TEST_F(ShaderModuleValidationTest, CreationSuccess) { TEST_F(ShaderModuleValidationTest, CreationSuccess) {
@ -112,8 +111,8 @@ TEST_F(ShaderModuleValidationTest, FragmentOutputLocationExceedsMaxColorAttachme
// Test that it is invalid to create a shader module with no chained descriptor. (It must be // Test that it is invalid to create a shader module with no chained descriptor. (It must be
// WGSL or SPIRV, not empty) // WGSL or SPIRV, not empty)
TEST_F(ShaderModuleValidationTest, NoChainedDescriptor) { TEST_F(ShaderModuleValidationTest, NoChainedDescriptor) {
wgpu::ShaderModuleDescriptor desc = {}; wgpu::ShaderModuleDescriptor desc = {};
ASSERT_DEVICE_ERROR(device.CreateShaderModule(&desc)); ASSERT_DEVICE_ERROR(device.CreateShaderModule(&desc));
} }
// Test that it is not allowed to use combined texture and sampler. // Test that it is not allowed to use combined texture and sampler.

View File

@ -21,474 +21,476 @@
namespace { namespace {
class TextureValidationTest : public ValidationTest { class TextureValidationTest : public ValidationTest {
protected: protected:
void SetUp() override { void SetUp() override {
queue = device.GetDefaultQueue(); queue = device.GetDefaultQueue();
} }
wgpu::TextureDescriptor CreateDefaultTextureDescriptor() { wgpu::TextureDescriptor CreateDefaultTextureDescriptor() {
wgpu::TextureDescriptor descriptor; wgpu::TextureDescriptor descriptor;
descriptor.size.width = kWidth; descriptor.size.width = kWidth;
descriptor.size.height = kHeight; descriptor.size.height = kHeight;
descriptor.size.depth = kDefaultDepth; descriptor.size.depth = kDefaultDepth;
descriptor.mipLevelCount = kDefaultMipLevels; descriptor.mipLevelCount = kDefaultMipLevels;
descriptor.sampleCount = kDefaultSampleCount; descriptor.sampleCount = kDefaultSampleCount;
descriptor.dimension = wgpu::TextureDimension::e2D; descriptor.dimension = wgpu::TextureDimension::e2D;
descriptor.format = kDefaultTextureFormat; descriptor.format = kDefaultTextureFormat;
descriptor.usage = wgpu::TextureUsage::OutputAttachment | wgpu::TextureUsage::Sampled; descriptor.usage = wgpu::TextureUsage::OutputAttachment | wgpu::TextureUsage::Sampled;
return descriptor; return descriptor;
} }
wgpu::Queue queue; wgpu::Queue queue;
private: private:
static constexpr uint32_t kWidth = 32; static constexpr uint32_t kWidth = 32;
static constexpr uint32_t kHeight = 32; static constexpr uint32_t kHeight = 32;
static constexpr uint32_t kDefaultDepth = 1; static constexpr uint32_t kDefaultDepth = 1;
static constexpr uint32_t kDefaultMipLevels = 1; static constexpr uint32_t kDefaultMipLevels = 1;
static constexpr uint32_t kDefaultSampleCount = 1; static constexpr uint32_t kDefaultSampleCount = 1;
static constexpr wgpu::TextureFormat kDefaultTextureFormat = wgpu::TextureFormat::RGBA8Unorm; static constexpr wgpu::TextureFormat kDefaultTextureFormat =
}; wgpu::TextureFormat::RGBA8Unorm;
// Test the validation of sample count
TEST_F(TextureValidationTest, SampleCount) {
wgpu::TextureDescriptor defaultDescriptor = CreateDefaultTextureDescriptor();
// sampleCount == 1 is allowed.
{
wgpu::TextureDescriptor descriptor = defaultDescriptor;
descriptor.sampleCount = 1;
device.CreateTexture(&descriptor);
}
// sampleCount == 4 is allowed.
{
wgpu::TextureDescriptor descriptor = defaultDescriptor;
descriptor.sampleCount = 4;
device.CreateTexture(&descriptor);
}
// It is an error to create a texture with an invalid sampleCount.
{
wgpu::TextureDescriptor descriptor = defaultDescriptor;
descriptor.sampleCount = 3;
ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
}
// It is an error to create a multisampled texture with mipLevelCount > 1.
{
wgpu::TextureDescriptor descriptor = defaultDescriptor;
descriptor.sampleCount = 4;
descriptor.mipLevelCount = 2;
ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
}
// Currently we do not support multisampled 2D array textures.
{
wgpu::TextureDescriptor descriptor = defaultDescriptor;
descriptor.sampleCount = 4;
descriptor.size.depth = 2;
ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
}
// It is an error to set TextureUsage::Storage when sampleCount > 1.
{
wgpu::TextureDescriptor descriptor = defaultDescriptor;
descriptor.sampleCount = 4;
descriptor.usage |= wgpu::TextureUsage::Storage;
ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
}
}
// Test the validation of the mip level count
TEST_F(TextureValidationTest, MipLevelCount) {
wgpu::TextureDescriptor defaultDescriptor = CreateDefaultTextureDescriptor();
// mipLevelCount == 1 is allowed
{
wgpu::TextureDescriptor descriptor = defaultDescriptor;
descriptor.size.width = 32;
descriptor.size.height = 32;
descriptor.mipLevelCount = 1;
device.CreateTexture(&descriptor);
}
// mipLevelCount == 0 is an error
{
wgpu::TextureDescriptor descriptor = defaultDescriptor;
descriptor.size.width = 32;
descriptor.size.height = 32;
descriptor.mipLevelCount = 0;
ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
}
// Full mip chains are allowed
{
wgpu::TextureDescriptor descriptor = defaultDescriptor;
descriptor.size.width = 32;
descriptor.size.height = 32;
// Mip level sizes: 32, 16, 8, 4, 2, 1
descriptor.mipLevelCount = 6;
device.CreateTexture(&descriptor);
}
// Too big mip chains on width are disallowed
{
wgpu::TextureDescriptor descriptor = defaultDescriptor;
descriptor.size.width = 31;
descriptor.size.height = 32;
// Mip level width: 31, 15, 7, 3, 1, 1
descriptor.mipLevelCount = 7;
ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
}
// Too big mip chains on height are disallowed
{
wgpu::TextureDescriptor descriptor = defaultDescriptor;
descriptor.size.width = 32;
descriptor.size.height = 31;
// Mip level height: 31, 15, 7, 3, 1, 1
descriptor.mipLevelCount = 7;
ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
}
// Undefined shift check if miplevel is bigger than the integer bit width.
{
wgpu::TextureDescriptor descriptor = defaultDescriptor;
descriptor.size.width = 32;
descriptor.size.height = 32;
descriptor.mipLevelCount = 100;
ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
}
// Non square mip map halves the resolution until a 1x1 dimension.
{
wgpu::TextureDescriptor descriptor = defaultDescriptor;
descriptor.size.width = 32;
descriptor.size.height = 8;
// Mip maps: 32 * 8, 16 * 4, 8 * 2, 4 * 1, 2 * 1, 1 * 1
descriptor.mipLevelCount = 6;
device.CreateTexture(&descriptor);
}
// Mip level exceeding kMaxTexture2DMipLevels not allowed
{
wgpu::TextureDescriptor descriptor = defaultDescriptor;
descriptor.size.width = 1 >> kMaxTexture2DMipLevels;
descriptor.size.height = 1 >> kMaxTexture2DMipLevels;
descriptor.mipLevelCount = kMaxTexture2DMipLevels + 1u;
ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
}
}
// Test the validation of array layer count
TEST_F(TextureValidationTest, ArrayLayerCount) {
wgpu::TextureDescriptor defaultDescriptor = CreateDefaultTextureDescriptor();
// Array layer count exceeding kMaxTexture2DArrayLayers is not allowed
{
wgpu::TextureDescriptor descriptor = defaultDescriptor;
descriptor.size.depth = kMaxTexture2DArrayLayers + 1u;
ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
}
// Array layer count less than kMaxTexture2DArrayLayers is allowed;
{
wgpu::TextureDescriptor descriptor = defaultDescriptor;
descriptor.size.depth = kMaxTexture2DArrayLayers >> 1;
device.CreateTexture(&descriptor);
}
// Array layer count equal to kMaxTexture2DArrayLayers is allowed;
{
wgpu::TextureDescriptor descriptor = defaultDescriptor;
descriptor.size.depth = kMaxTexture2DArrayLayers;
device.CreateTexture(&descriptor);
}
}
// Test the validation of texture size
TEST_F(TextureValidationTest, TextureSize) {
wgpu::TextureDescriptor defaultDescriptor = CreateDefaultTextureDescriptor();
// Texture size exceeding kMaxTextureSize is not allowed
{
wgpu::TextureDescriptor descriptor = defaultDescriptor;
descriptor.size.width = kMaxTextureSize + 1u;
descriptor.size.height = kMaxTextureSize + 1u;
ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
}
// Texture size less than kMaxTextureSize is allowed
{
wgpu::TextureDescriptor descriptor = defaultDescriptor;
descriptor.size.width = kMaxTextureSize >> 1;
descriptor.size.height = kMaxTextureSize >> 1;
device.CreateTexture(&descriptor);
}
// Texture equal to kMaxTextureSize is allowed
{
wgpu::TextureDescriptor descriptor = defaultDescriptor;
descriptor.size.width = kMaxTextureSize;
descriptor.size.height = kMaxTextureSize;
device.CreateTexture(&descriptor);
}
}
// Test that it is valid to destroy a texture
TEST_F(TextureValidationTest, DestroyTexture) {
wgpu::TextureDescriptor descriptor = CreateDefaultTextureDescriptor();
wgpu::Texture texture = device.CreateTexture(&descriptor);
texture.Destroy();
}
// Test that it's valid to destroy a destroyed texture
TEST_F(TextureValidationTest, DestroyDestroyedTexture) {
wgpu::TextureDescriptor descriptor = CreateDefaultTextureDescriptor();
wgpu::Texture texture = device.CreateTexture(&descriptor);
texture.Destroy();
texture.Destroy();
}
// Test that it's invalid to submit a destroyed texture in a queue
// in the case of destroy, encode, submit
TEST_F(TextureValidationTest, DestroyEncodeSubmit) {
wgpu::TextureDescriptor descriptor = CreateDefaultTextureDescriptor();
wgpu::Texture texture = device.CreateTexture(&descriptor);
wgpu::TextureView textureView = texture.CreateView();
utils::ComboRenderPassDescriptor renderPass({textureView});
// Destroy the texture
texture.Destroy();
wgpu::CommandEncoder encoder_post_destroy = device.CreateCommandEncoder();
{
wgpu::RenderPassEncoder pass = encoder_post_destroy.BeginRenderPass(&renderPass);
pass.EndPass();
}
wgpu::CommandBuffer commands = encoder_post_destroy.Finish();
// Submit should fail due to destroyed texture
ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
}
// Test that it's invalid to submit a destroyed texture in a queue
// in the case of encode, destroy, submit
TEST_F(TextureValidationTest, EncodeDestroySubmit) {
wgpu::TextureDescriptor descriptor = CreateDefaultTextureDescriptor();
wgpu::Texture texture = device.CreateTexture(&descriptor);
wgpu::TextureView textureView = texture.CreateView();
utils::ComboRenderPassDescriptor renderPass({textureView});
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
{
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
pass.EndPass();
}
wgpu::CommandBuffer commands = encoder.Finish();
// Destroy the texture
texture.Destroy();
// Submit should fail due to destroyed texture
ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
}
// Test it is an error to create an OutputAttachment texture with a non-renderable format.
TEST_F(TextureValidationTest, NonRenderableAndOutputAttachment) {
wgpu::TextureDescriptor descriptor;
descriptor.size = {1, 1, 1};
descriptor.usage = wgpu::TextureUsage::OutputAttachment;
// Succeeds because RGBA8Unorm is renderable
descriptor.format = wgpu::TextureFormat::RGBA8Unorm;
device.CreateTexture(&descriptor);
wgpu::TextureFormat nonRenderableFormats[] = {
wgpu::TextureFormat::RG11B10Float,
wgpu::TextureFormat::R8Snorm,
wgpu::TextureFormat::RG8Snorm,
wgpu::TextureFormat::RGBA8Snorm,
}; };
for (wgpu::TextureFormat format : nonRenderableFormats) { // Test the validation of sample count
// Fails because `format` is non-renderable TEST_F(TextureValidationTest, SampleCount) {
descriptor.format = format; wgpu::TextureDescriptor defaultDescriptor = CreateDefaultTextureDescriptor();
ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
}
}
// Test it is an error to create a Storage texture with any format that doesn't support // sampleCount == 1 is allowed.
// TextureUsage::Storage texture usages.
TEST_F(TextureValidationTest, TextureFormatNotSupportTextureUsageStorage) {
wgpu::TextureDescriptor descriptor;
descriptor.size = {1, 1, 1};
descriptor.usage = wgpu::TextureUsage::Storage;
for (wgpu::TextureFormat format : utils::kAllTextureFormats) {
descriptor.format = format;
if (utils::TextureFormatSupportsStorageTexture(format)) {
device.CreateTexture(&descriptor);
} else {
ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
}
}
}
// Test it is an error to create a texture with format "Undefined".
TEST_F(TextureValidationTest, TextureFormatUndefined) {
wgpu::TextureDescriptor descriptor = CreateDefaultTextureDescriptor();
descriptor.format = wgpu::TextureFormat::Undefined;
ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
}
// TODO(jiawei.shao@intel.com): add tests to verify we cannot create 1D or 3D textures with
// compressed texture formats.
class CompressedTextureFormatsValidationTests : public TextureValidationTest {
public:
CompressedTextureFormatsValidationTests() : TextureValidationTest() {
device = CreateDeviceFromAdapter(adapter, {"texture_compression_bc"});
}
protected:
wgpu::TextureDescriptor CreateDefaultTextureDescriptor() {
wgpu::TextureDescriptor descriptor =
TextureValidationTest::CreateDefaultTextureDescriptor();
descriptor.usage =
wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::Sampled;
return descriptor;
}
const std::array<wgpu::TextureFormat, 14> kBCFormats = {
wgpu::TextureFormat::BC1RGBAUnorm, wgpu::TextureFormat::BC1RGBAUnormSrgb,
wgpu::TextureFormat::BC2RGBAUnorm, wgpu::TextureFormat::BC2RGBAUnormSrgb,
wgpu::TextureFormat::BC3RGBAUnorm, wgpu::TextureFormat::BC3RGBAUnormSrgb,
wgpu::TextureFormat::BC4RUnorm, wgpu::TextureFormat::BC4RSnorm,
wgpu::TextureFormat::BC5RGUnorm, wgpu::TextureFormat::BC5RGSnorm,
wgpu::TextureFormat::BC6HRGBUfloat, wgpu::TextureFormat::BC6HRGBSfloat,
wgpu::TextureFormat::BC7RGBAUnorm, wgpu::TextureFormat::BC7RGBAUnormSrgb};
};
// Test the validation of texture size when creating textures in compressed texture formats.
TEST_F(CompressedTextureFormatsValidationTests, TextureSize) {
// Test that it is invalid to use a number that is not a multiple of 4 (the compressed block
// width and height of all BC formats) as the width or height of textures in BC formats.
for (wgpu::TextureFormat format : kBCFormats) {
{ {
wgpu::TextureDescriptor descriptor = CreateDefaultTextureDescriptor(); wgpu::TextureDescriptor descriptor = defaultDescriptor;
descriptor.format = format; descriptor.sampleCount = 1;
ASSERT_TRUE(descriptor.size.width % 4 == 0 && descriptor.size.height % 4 == 0);
device.CreateTexture(&descriptor); device.CreateTexture(&descriptor);
} }
// sampleCount == 4 is allowed.
{ {
wgpu::TextureDescriptor descriptor = CreateDefaultTextureDescriptor(); wgpu::TextureDescriptor descriptor = defaultDescriptor;
descriptor.format = format; descriptor.sampleCount = 4;
descriptor.size.width = 31;
device.CreateTexture(&descriptor);
}
// It is an error to create a texture with an invalid sampleCount.
{
wgpu::TextureDescriptor descriptor = defaultDescriptor;
descriptor.sampleCount = 3;
ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor)); ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
} }
// It is an error to create a multisampled texture with mipLevelCount > 1.
{ {
wgpu::TextureDescriptor descriptor = CreateDefaultTextureDescriptor(); wgpu::TextureDescriptor descriptor = defaultDescriptor;
descriptor.format = format; descriptor.sampleCount = 4;
descriptor.size.height = 31; descriptor.mipLevelCount = 2;
ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor)); ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
} }
// Currently we do not support multisampled 2D array textures.
{ {
wgpu::TextureDescriptor descriptor = CreateDefaultTextureDescriptor(); wgpu::TextureDescriptor descriptor = defaultDescriptor;
descriptor.format = format; descriptor.sampleCount = 4;
descriptor.size.width = 12; descriptor.size.depth = 2;
ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
}
// It is an error to set TextureUsage::Storage when sampleCount > 1.
{
wgpu::TextureDescriptor descriptor = defaultDescriptor;
descriptor.sampleCount = 4;
descriptor.usage |= wgpu::TextureUsage::Storage;
ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
}
}
// Test the validation of the mip level count
TEST_F(TextureValidationTest, MipLevelCount) {
wgpu::TextureDescriptor defaultDescriptor = CreateDefaultTextureDescriptor();
// mipLevelCount == 1 is allowed
{
wgpu::TextureDescriptor descriptor = defaultDescriptor;
descriptor.size.width = 32;
descriptor.size.height = 32; descriptor.size.height = 32;
descriptor.mipLevelCount = 1;
device.CreateTexture(&descriptor);
}
// mipLevelCount == 0 is an error
{
wgpu::TextureDescriptor descriptor = defaultDescriptor;
descriptor.size.width = 32;
descriptor.size.height = 32;
descriptor.mipLevelCount = 0;
ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
}
// Full mip chains are allowed
{
wgpu::TextureDescriptor descriptor = defaultDescriptor;
descriptor.size.width = 32;
descriptor.size.height = 32;
// Mip level sizes: 32, 16, 8, 4, 2, 1
descriptor.mipLevelCount = 6;
device.CreateTexture(&descriptor);
}
// Too big mip chains on width are disallowed
{
wgpu::TextureDescriptor descriptor = defaultDescriptor;
descriptor.size.width = 31;
descriptor.size.height = 32;
// Mip level width: 31, 15, 7, 3, 1, 1
descriptor.mipLevelCount = 7;
ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
}
// Too big mip chains on height are disallowed
{
wgpu::TextureDescriptor descriptor = defaultDescriptor;
descriptor.size.width = 32;
descriptor.size.height = 31;
// Mip level height: 31, 15, 7, 3, 1, 1
descriptor.mipLevelCount = 7;
ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
}
// Undefined shift check if miplevel is bigger than the integer bit width.
{
wgpu::TextureDescriptor descriptor = defaultDescriptor;
descriptor.size.width = 32;
descriptor.size.height = 32;
descriptor.mipLevelCount = 100;
ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
}
// Non square mip map halves the resolution until a 1x1 dimension.
{
wgpu::TextureDescriptor descriptor = defaultDescriptor;
descriptor.size.width = 32;
descriptor.size.height = 8;
// Mip maps: 32 * 8, 16 * 4, 8 * 2, 4 * 1, 2 * 1, 1 * 1
descriptor.mipLevelCount = 6;
device.CreateTexture(&descriptor);
}
// Mip level exceeding kMaxTexture2DMipLevels not allowed
{
wgpu::TextureDescriptor descriptor = defaultDescriptor;
descriptor.size.width = 1 >> kMaxTexture2DMipLevels;
descriptor.size.height = 1 >> kMaxTexture2DMipLevels;
descriptor.mipLevelCount = kMaxTexture2DMipLevels + 1u;
ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
}
}
// Test the validation of array layer count
TEST_F(TextureValidationTest, ArrayLayerCount) {
wgpu::TextureDescriptor defaultDescriptor = CreateDefaultTextureDescriptor();
// Array layer count exceeding kMaxTexture2DArrayLayers is not allowed
{
wgpu::TextureDescriptor descriptor = defaultDescriptor;
descriptor.size.depth = kMaxTexture2DArrayLayers + 1u;
ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
}
// Array layer count less than kMaxTexture2DArrayLayers is allowed;
{
wgpu::TextureDescriptor descriptor = defaultDescriptor;
descriptor.size.depth = kMaxTexture2DArrayLayers >> 1;
device.CreateTexture(&descriptor);
}
// Array layer count equal to kMaxTexture2DArrayLayers is allowed;
{
wgpu::TextureDescriptor descriptor = defaultDescriptor;
descriptor.size.depth = kMaxTexture2DArrayLayers;
device.CreateTexture(&descriptor); device.CreateTexture(&descriptor);
} }
} }
}
// Test the creation of a texture with BC format will fail when the extension textureCompressionBC // Test the validation of texture size
// is not enabled. TEST_F(TextureValidationTest, TextureSize) {
TEST_F(CompressedTextureFormatsValidationTests, UseBCFormatWithoutEnablingExtension) { wgpu::TextureDescriptor defaultDescriptor = CreateDefaultTextureDescriptor();
const std::vector<const char*> kEmptyVector;
wgpu::Device deviceWithoutExtension = CreateDeviceFromAdapter(adapter, kEmptyVector); // Texture size exceeding kMaxTextureSize is not allowed
for (wgpu::TextureFormat format : kBCFormats) { {
wgpu::TextureDescriptor descriptor = CreateDefaultTextureDescriptor(); wgpu::TextureDescriptor descriptor = defaultDescriptor;
descriptor.format = format; descriptor.size.width = kMaxTextureSize + 1u;
ASSERT_DEVICE_ERROR(deviceWithoutExtension.CreateTexture(&descriptor)); descriptor.size.height = kMaxTextureSize + 1u;
ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
}
// Texture size less than kMaxTextureSize is allowed
{
wgpu::TextureDescriptor descriptor = defaultDescriptor;
descriptor.size.width = kMaxTextureSize >> 1;
descriptor.size.height = kMaxTextureSize >> 1;
device.CreateTexture(&descriptor);
}
// Texture equal to kMaxTextureSize is allowed
{
wgpu::TextureDescriptor descriptor = defaultDescriptor;
descriptor.size.width = kMaxTextureSize;
descriptor.size.height = kMaxTextureSize;
device.CreateTexture(&descriptor);
}
} }
}
// Test the validation of texture usages when creating textures in compressed texture formats. // Test that it is valid to destroy a texture
TEST_F(CompressedTextureFormatsValidationTests, TextureUsage) { TEST_F(TextureValidationTest, DestroyTexture) {
// Test that only CopySrc, CopyDst and Sampled are accepted as the texture usage of the wgpu::TextureDescriptor descriptor = CreateDefaultTextureDescriptor();
// textures in BC formats. wgpu::Texture texture = device.CreateTexture(&descriptor);
for (wgpu::TextureFormat format : kBCFormats) { texture.Destroy();
}
// Test that it's valid to destroy a destroyed texture
TEST_F(TextureValidationTest, DestroyDestroyedTexture) {
wgpu::TextureDescriptor descriptor = CreateDefaultTextureDescriptor();
wgpu::Texture texture = device.CreateTexture(&descriptor);
texture.Destroy();
texture.Destroy();
}
// Test that it's invalid to submit a destroyed texture in a queue
// in the case of destroy, encode, submit
TEST_F(TextureValidationTest, DestroyEncodeSubmit) {
wgpu::TextureDescriptor descriptor = CreateDefaultTextureDescriptor();
wgpu::Texture texture = device.CreateTexture(&descriptor);
wgpu::TextureView textureView = texture.CreateView();
utils::ComboRenderPassDescriptor renderPass({textureView});
// Destroy the texture
texture.Destroy();
wgpu::CommandEncoder encoder_post_destroy = device.CreateCommandEncoder();
{ {
wgpu::TextureDescriptor descriptor = CreateDefaultTextureDescriptor(); wgpu::RenderPassEncoder pass = encoder_post_destroy.BeginRenderPass(&renderPass);
descriptor.format = format; pass.EndPass();
descriptor.usage = wgpu::TextureUsage::OutputAttachment;
ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
} }
wgpu::CommandBuffer commands = encoder_post_destroy.Finish();
// Submit should fail due to destroyed texture
ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
}
// Test that it's invalid to submit a destroyed texture in a queue
// in the case of encode, destroy, submit
TEST_F(TextureValidationTest, EncodeDestroySubmit) {
wgpu::TextureDescriptor descriptor = CreateDefaultTextureDescriptor();
wgpu::Texture texture = device.CreateTexture(&descriptor);
wgpu::TextureView textureView = texture.CreateView();
utils::ComboRenderPassDescriptor renderPass({textureView});
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
{ {
wgpu::TextureDescriptor descriptor = CreateDefaultTextureDescriptor(); wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
descriptor.format = format; pass.EndPass();
descriptor.usage = wgpu::TextureUsage::Storage;
ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
} }
wgpu::CommandBuffer commands = encoder.Finish();
{ // Destroy the texture
wgpu::TextureDescriptor descriptor = CreateDefaultTextureDescriptor(); texture.Destroy();
// Submit should fail due to destroyed texture
ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
}
// Test it is an error to create an OutputAttachment texture with a non-renderable format.
TEST_F(TextureValidationTest, NonRenderableAndOutputAttachment) {
wgpu::TextureDescriptor descriptor;
descriptor.size = {1, 1, 1};
descriptor.usage = wgpu::TextureUsage::OutputAttachment;
// Succeeds because RGBA8Unorm is renderable
descriptor.format = wgpu::TextureFormat::RGBA8Unorm;
device.CreateTexture(&descriptor);
wgpu::TextureFormat nonRenderableFormats[] = {
wgpu::TextureFormat::RG11B10Float,
wgpu::TextureFormat::R8Snorm,
wgpu::TextureFormat::RG8Snorm,
wgpu::TextureFormat::RGBA8Snorm,
};
for (wgpu::TextureFormat format : nonRenderableFormats) {
// Fails because `format` is non-renderable
descriptor.format = format; descriptor.format = format;
descriptor.usage = wgpu::TextureUsage::Present;
ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor)); ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
} }
} }
}
// Test the validation of sample count when creating textures in compressed texture formats. // Test it is an error to create a Storage texture with any format that doesn't support
TEST_F(CompressedTextureFormatsValidationTests, SampleCount) { // TextureUsage::Storage texture usages.
// Test that it is invalid to specify SampleCount > 1 when we create a texture in BC formats. TEST_F(TextureValidationTest, TextureFormatNotSupportTextureUsageStorage) {
for (wgpu::TextureFormat format : kBCFormats) { wgpu::TextureDescriptor descriptor;
descriptor.size = {1, 1, 1};
descriptor.usage = wgpu::TextureUsage::Storage;
for (wgpu::TextureFormat format : utils::kAllTextureFormats) {
descriptor.format = format;
if (utils::TextureFormatSupportsStorageTexture(format)) {
device.CreateTexture(&descriptor);
} else {
ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
}
}
}
// Test it is an error to create a texture with format "Undefined".
TEST_F(TextureValidationTest, TextureFormatUndefined) {
wgpu::TextureDescriptor descriptor = CreateDefaultTextureDescriptor(); wgpu::TextureDescriptor descriptor = CreateDefaultTextureDescriptor();
descriptor.format = format; descriptor.format = wgpu::TextureFormat::Undefined;
descriptor.sampleCount = 4;
ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor)); ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
} }
}
// Test the validation of creating 2D array textures in compressed texture formats. // TODO(jiawei.shao@intel.com): add tests to verify we cannot create 1D or 3D textures with
TEST_F(CompressedTextureFormatsValidationTests, 2DArrayTexture) { // compressed texture formats.
// Test that it is allowed to create a 2D array texture in BC formats. class CompressedTextureFormatsValidationTests : public TextureValidationTest {
for (wgpu::TextureFormat format : kBCFormats) { public:
wgpu::TextureDescriptor descriptor = CreateDefaultTextureDescriptor(); CompressedTextureFormatsValidationTests() : TextureValidationTest() {
descriptor.format = format; device = CreateDeviceFromAdapter(adapter, {"texture_compression_bc"});
descriptor.size.depth = 6; }
device.CreateTexture(&descriptor);
protected:
wgpu::TextureDescriptor CreateDefaultTextureDescriptor() {
wgpu::TextureDescriptor descriptor =
TextureValidationTest::CreateDefaultTextureDescriptor();
descriptor.usage = wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst |
wgpu::TextureUsage::Sampled;
return descriptor;
}
const std::array<wgpu::TextureFormat, 14> kBCFormats = {
wgpu::TextureFormat::BC1RGBAUnorm, wgpu::TextureFormat::BC1RGBAUnormSrgb,
wgpu::TextureFormat::BC2RGBAUnorm, wgpu::TextureFormat::BC2RGBAUnormSrgb,
wgpu::TextureFormat::BC3RGBAUnorm, wgpu::TextureFormat::BC3RGBAUnormSrgb,
wgpu::TextureFormat::BC4RUnorm, wgpu::TextureFormat::BC4RSnorm,
wgpu::TextureFormat::BC5RGUnorm, wgpu::TextureFormat::BC5RGSnorm,
wgpu::TextureFormat::BC6HRGBUfloat, wgpu::TextureFormat::BC6HRGBSfloat,
wgpu::TextureFormat::BC7RGBAUnorm, wgpu::TextureFormat::BC7RGBAUnormSrgb};
};
// Test the validation of texture size when creating textures in compressed texture formats.
TEST_F(CompressedTextureFormatsValidationTests, TextureSize) {
// Test that it is invalid to use a number that is not a multiple of 4 (the compressed block
// width and height of all BC formats) as the width or height of textures in BC formats.
for (wgpu::TextureFormat format : kBCFormats) {
{
wgpu::TextureDescriptor descriptor = CreateDefaultTextureDescriptor();
descriptor.format = format;
ASSERT_TRUE(descriptor.size.width % 4 == 0 && descriptor.size.height % 4 == 0);
device.CreateTexture(&descriptor);
}
{
wgpu::TextureDescriptor descriptor = CreateDefaultTextureDescriptor();
descriptor.format = format;
descriptor.size.width = 31;
ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
}
{
wgpu::TextureDescriptor descriptor = CreateDefaultTextureDescriptor();
descriptor.format = format;
descriptor.size.height = 31;
ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
}
{
wgpu::TextureDescriptor descriptor = CreateDefaultTextureDescriptor();
descriptor.format = format;
descriptor.size.width = 12;
descriptor.size.height = 32;
device.CreateTexture(&descriptor);
}
}
}
// Test the creation of a texture with BC format will fail when the extension
// textureCompressionBC is not enabled.
TEST_F(CompressedTextureFormatsValidationTests, UseBCFormatWithoutEnablingExtension) {
const std::vector<const char*> kEmptyVector;
wgpu::Device deviceWithoutExtension = CreateDeviceFromAdapter(adapter, kEmptyVector);
for (wgpu::TextureFormat format : kBCFormats) {
wgpu::TextureDescriptor descriptor = CreateDefaultTextureDescriptor();
descriptor.format = format;
ASSERT_DEVICE_ERROR(deviceWithoutExtension.CreateTexture(&descriptor));
}
}
// Test the validation of texture usages when creating textures in compressed texture formats.
TEST_F(CompressedTextureFormatsValidationTests, TextureUsage) {
// Test that only CopySrc, CopyDst and Sampled are accepted as the texture usage of the
// textures in BC formats.
for (wgpu::TextureFormat format : kBCFormats) {
{
wgpu::TextureDescriptor descriptor = CreateDefaultTextureDescriptor();
descriptor.format = format;
descriptor.usage = wgpu::TextureUsage::OutputAttachment;
ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
}
{
wgpu::TextureDescriptor descriptor = CreateDefaultTextureDescriptor();
descriptor.format = format;
descriptor.usage = wgpu::TextureUsage::Storage;
ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
}
{
wgpu::TextureDescriptor descriptor = CreateDefaultTextureDescriptor();
descriptor.format = format;
descriptor.usage = wgpu::TextureUsage::Present;
ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
}
}
}
// Test the validation of sample count when creating textures in compressed texture formats.
TEST_F(CompressedTextureFormatsValidationTests, SampleCount) {
// Test that it is invalid to specify SampleCount > 1 when we create a texture in BC
// formats.
for (wgpu::TextureFormat format : kBCFormats) {
wgpu::TextureDescriptor descriptor = CreateDefaultTextureDescriptor();
descriptor.format = format;
descriptor.sampleCount = 4;
ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
}
}
// Test the validation of creating 2D array textures in compressed texture formats.
TEST_F(CompressedTextureFormatsValidationTests, 2DArrayTexture) {
// Test that it is allowed to create a 2D array texture in BC formats.
for (wgpu::TextureFormat format : kBCFormats) {
wgpu::TextureDescriptor descriptor = CreateDefaultTextureDescriptor();
descriptor.format = format;
descriptor.size.depth = 6;
device.CreateTexture(&descriptor);
}
} }
}
} // namespace } // namespace

View File

@ -16,349 +16,348 @@
namespace { namespace {
class TextureViewValidationTest : public ValidationTest { class TextureViewValidationTest : public ValidationTest {};
};
constexpr uint32_t kWidth = 32u; constexpr uint32_t kWidth = 32u;
constexpr uint32_t kHeight = 32u; constexpr uint32_t kHeight = 32u;
constexpr uint32_t kDefaultMipLevels = 6u; constexpr uint32_t kDefaultMipLevels = 6u;
constexpr wgpu::TextureFormat kDefaultTextureFormat = wgpu::TextureFormat::RGBA8Unorm; constexpr wgpu::TextureFormat kDefaultTextureFormat = wgpu::TextureFormat::RGBA8Unorm;
wgpu::Texture Create2DArrayTexture(wgpu::Device& device, wgpu::Texture Create2DArrayTexture(wgpu::Device& device,
uint32_t arrayLayerCount, uint32_t arrayLayerCount,
uint32_t width = kWidth, uint32_t width = kWidth,
uint32_t height = kHeight, uint32_t height = kHeight,
uint32_t mipLevelCount = kDefaultMipLevels, uint32_t mipLevelCount = kDefaultMipLevels,
uint32_t sampleCount = 1) { uint32_t sampleCount = 1) {
wgpu::TextureDescriptor descriptor; wgpu::TextureDescriptor descriptor;
descriptor.dimension = wgpu::TextureDimension::e2D; descriptor.dimension = wgpu::TextureDimension::e2D;
descriptor.size.width = width; descriptor.size.width = width;
descriptor.size.height = height; descriptor.size.height = height;
descriptor.size.depth = arrayLayerCount; descriptor.size.depth = arrayLayerCount;
descriptor.sampleCount = sampleCount; descriptor.sampleCount = sampleCount;
descriptor.format = kDefaultTextureFormat; descriptor.format = kDefaultTextureFormat;
descriptor.mipLevelCount = mipLevelCount; descriptor.mipLevelCount = mipLevelCount;
descriptor.usage = wgpu::TextureUsage::Sampled; descriptor.usage = wgpu::TextureUsage::Sampled;
return device.CreateTexture(&descriptor); return device.CreateTexture(&descriptor);
}
wgpu::TextureViewDescriptor CreateDefaultViewDescriptor(wgpu::TextureViewDimension dimension) {
wgpu::TextureViewDescriptor descriptor;
descriptor.format = kDefaultTextureFormat;
descriptor.dimension = dimension;
descriptor.baseMipLevel = 0;
descriptor.mipLevelCount = kDefaultMipLevels;
descriptor.baseArrayLayer = 0;
descriptor.arrayLayerCount = 1;
return descriptor;
}
// Test creating texture view on a 2D non-array texture
TEST_F(TextureViewValidationTest, CreateTextureViewOnTexture2D) {
wgpu::Texture texture = Create2DArrayTexture(device, 1);
wgpu::TextureViewDescriptor base2DTextureViewDescriptor =
CreateDefaultViewDescriptor(wgpu::TextureViewDimension::e2D);
// It is OK to create a 2D texture view on a 2D texture.
{
wgpu::TextureViewDescriptor descriptor = base2DTextureViewDescriptor;
descriptor.arrayLayerCount = 1;
texture.CreateView(&descriptor);
} }
// It is an error to view a layer past the end of the texture. wgpu::TextureViewDescriptor CreateDefaultViewDescriptor(wgpu::TextureViewDimension dimension) {
{ wgpu::TextureViewDescriptor descriptor;
wgpu::TextureViewDescriptor descriptor = base2DTextureViewDescriptor; descriptor.format = kDefaultTextureFormat;
descriptor.arrayLayerCount = 2; descriptor.dimension = dimension;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
}
// It is OK to create a 1-layer 2D array texture view on a 2D texture.
{
wgpu::TextureViewDescriptor descriptor = base2DTextureViewDescriptor;
descriptor.dimension = wgpu::TextureViewDimension::e2DArray;
descriptor.arrayLayerCount = 1;
texture.CreateView(&descriptor);
}
// baseMipLevel == k && mipLevelCount == 0 means to use levels k..end.
{
wgpu::TextureViewDescriptor descriptor = base2DTextureViewDescriptor;
descriptor.mipLevelCount = 0;
descriptor.baseMipLevel = 0; descriptor.baseMipLevel = 0;
texture.CreateView(&descriptor);
descriptor.baseMipLevel = 1;
texture.CreateView(&descriptor);
descriptor.baseMipLevel = kDefaultMipLevels - 1;
texture.CreateView(&descriptor);
descriptor.baseMipLevel = kDefaultMipLevels;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
}
// It is an error to make the mip level out of range.
{
wgpu::TextureViewDescriptor descriptor = base2DTextureViewDescriptor;
descriptor.baseMipLevel = 0;
descriptor.mipLevelCount = kDefaultMipLevels + 1;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
descriptor.baseMipLevel = 1;
descriptor.mipLevelCount = kDefaultMipLevels; descriptor.mipLevelCount = kDefaultMipLevels;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
descriptor.baseMipLevel = kDefaultMipLevels - 1;
descriptor.mipLevelCount = 2;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
descriptor.baseMipLevel = kDefaultMipLevels;
descriptor.mipLevelCount = 1;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
}
}
// Test creating texture view on a 2D array texture
TEST_F(TextureViewValidationTest, CreateTextureViewOnTexture2DArray) {
constexpr uint32_t kDefaultArrayLayers = 6;
wgpu::Texture texture = Create2DArrayTexture(device, kDefaultArrayLayers);
wgpu::TextureViewDescriptor base2DArrayTextureViewDescriptor =
CreateDefaultViewDescriptor(wgpu::TextureViewDimension::e2DArray);
// It is OK to create a 2D texture view on a 2D array texture.
{
wgpu::TextureViewDescriptor descriptor = base2DArrayTextureViewDescriptor;
descriptor.dimension = wgpu::TextureViewDimension::e2D;
descriptor.arrayLayerCount = 1;
texture.CreateView(&descriptor);
}
// It is OK to create a 2D array texture view on a 2D array texture.
{
wgpu::TextureViewDescriptor descriptor = base2DArrayTextureViewDescriptor;
descriptor.arrayLayerCount = kDefaultArrayLayers;
texture.CreateView(&descriptor);
}
// baseArrayLayer == k && arrayLayerCount == 0 means to use layers k..end.
{
wgpu::TextureViewDescriptor descriptor = base2DArrayTextureViewDescriptor;
descriptor.arrayLayerCount = 0;
descriptor.baseArrayLayer = 0; descriptor.baseArrayLayer = 0;
texture.CreateView(&descriptor);
descriptor.baseArrayLayer = 1;
texture.CreateView(&descriptor);
descriptor.baseArrayLayer = kDefaultArrayLayers - 1;
texture.CreateView(&descriptor);
descriptor.baseArrayLayer = kDefaultArrayLayers;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
}
// It is an error for the array layer range of the view to exceed that of the texture.
{
wgpu::TextureViewDescriptor descriptor = base2DArrayTextureViewDescriptor;
descriptor.baseArrayLayer = 0;
descriptor.arrayLayerCount = kDefaultArrayLayers + 1;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
descriptor.baseArrayLayer = 1;
descriptor.arrayLayerCount = kDefaultArrayLayers;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
descriptor.baseArrayLayer = kDefaultArrayLayers - 1;
descriptor.arrayLayerCount = 2;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
descriptor.baseArrayLayer = kDefaultArrayLayers;
descriptor.arrayLayerCount = 1; descriptor.arrayLayerCount = 1;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); return descriptor;
}
}
// Using the "none" ("default") values validates the same as explicitly
// specifying the values they're supposed to default to.
// Variant for a texture with more than 1 array layer.
TEST_F(TextureViewValidationTest, TextureViewDescriptorDefaultsArray) {
constexpr uint32_t kDefaultArrayLayers = 6;
wgpu::Texture texture = Create2DArrayTexture(device, kDefaultArrayLayers);
{ texture.CreateView(); }
{
wgpu::TextureViewDescriptor descriptor;
descriptor.format = wgpu::TextureFormat::Undefined;
texture.CreateView(&descriptor);
descriptor.format = wgpu::TextureFormat::RGBA8Unorm;
texture.CreateView(&descriptor);
descriptor.format = wgpu::TextureFormat::R8Unorm;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
}
{
wgpu::TextureViewDescriptor descriptor;
descriptor.dimension = wgpu::TextureViewDimension::Undefined;
texture.CreateView(&descriptor);
descriptor.dimension = wgpu::TextureViewDimension::e2DArray;
texture.CreateView(&descriptor);
descriptor.dimension = wgpu::TextureViewDimension::e2D;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
}
{
wgpu::TextureViewDescriptor descriptor;
// Setting array layers to non-0 means the dimensionality will
// default to 2D so by itself it causes an error.
descriptor.arrayLayerCount = kDefaultArrayLayers;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
descriptor.dimension = wgpu::TextureViewDimension::e2DArray;
texture.CreateView(&descriptor);
descriptor.mipLevelCount = kDefaultMipLevels;
texture.CreateView(&descriptor);
}
}
// Using the "none" ("default") values validates the same as explicitly
// specifying the values they're supposed to default to.
// Variant for a texture with only 1 array layer.
TEST_F(TextureViewValidationTest, TextureViewDescriptorDefaultsNonArray) {
constexpr uint32_t kDefaultArrayLayers = 1;
wgpu::Texture texture = Create2DArrayTexture(device, kDefaultArrayLayers);
{ texture.CreateView(); }
{
wgpu::TextureViewDescriptor descriptor;
descriptor.format = wgpu::TextureFormat::Undefined;
texture.CreateView(&descriptor);
descriptor.format = wgpu::TextureFormat::RGBA8Unorm;
texture.CreateView(&descriptor);
descriptor.format = wgpu::TextureFormat::R8Unorm;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
}
{
wgpu::TextureViewDescriptor descriptor;
descriptor.dimension = wgpu::TextureViewDimension::Undefined;
texture.CreateView(&descriptor);
descriptor.dimension = wgpu::TextureViewDimension::e2D;
texture.CreateView(&descriptor);
descriptor.dimension = wgpu::TextureViewDimension::e2DArray;
texture.CreateView(&descriptor);
}
{
wgpu::TextureViewDescriptor descriptor;
descriptor.arrayLayerCount = 0;
texture.CreateView(&descriptor);
descriptor.arrayLayerCount = 1;
texture.CreateView(&descriptor);
descriptor.arrayLayerCount = 2;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
}
{
wgpu::TextureViewDescriptor descriptor;
descriptor.mipLevelCount = kDefaultMipLevels;
texture.CreateView(&descriptor);
descriptor.arrayLayerCount = kDefaultArrayLayers;
texture.CreateView(&descriptor);
}
}
// Test creating cube map texture view
TEST_F(TextureViewValidationTest, CreateCubeMapTextureView) {
constexpr uint32_t kDefaultArrayLayers = 16;
wgpu::Texture texture = Create2DArrayTexture(device, kDefaultArrayLayers);
wgpu::TextureViewDescriptor base2DArrayTextureViewDescriptor =
CreateDefaultViewDescriptor(wgpu::TextureViewDimension::e2DArray);
// It is OK to create a cube map texture view with arrayLayerCount == 6.
{
wgpu::TextureViewDescriptor descriptor = base2DArrayTextureViewDescriptor;
descriptor.dimension = wgpu::TextureViewDimension::Cube;
descriptor.arrayLayerCount = 6;
texture.CreateView(&descriptor);
} }
// It is an error to create a cube map texture view with arrayLayerCount != 6. // Test creating texture view on a 2D non-array texture
{ TEST_F(TextureViewValidationTest, CreateTextureViewOnTexture2D) {
wgpu::TextureViewDescriptor descriptor = base2DArrayTextureViewDescriptor; wgpu::Texture texture = Create2DArrayTexture(device, 1);
descriptor.dimension = wgpu::TextureViewDimension::Cube;
descriptor.arrayLayerCount = 3; wgpu::TextureViewDescriptor base2DTextureViewDescriptor =
CreateDefaultViewDescriptor(wgpu::TextureViewDimension::e2D);
// It is OK to create a 2D texture view on a 2D texture.
{
wgpu::TextureViewDescriptor descriptor = base2DTextureViewDescriptor;
descriptor.arrayLayerCount = 1;
texture.CreateView(&descriptor);
}
// It is an error to view a layer past the end of the texture.
{
wgpu::TextureViewDescriptor descriptor = base2DTextureViewDescriptor;
descriptor.arrayLayerCount = 2;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
}
// It is OK to create a 1-layer 2D array texture view on a 2D texture.
{
wgpu::TextureViewDescriptor descriptor = base2DTextureViewDescriptor;
descriptor.dimension = wgpu::TextureViewDimension::e2DArray;
descriptor.arrayLayerCount = 1;
texture.CreateView(&descriptor);
}
// baseMipLevel == k && mipLevelCount == 0 means to use levels k..end.
{
wgpu::TextureViewDescriptor descriptor = base2DTextureViewDescriptor;
descriptor.mipLevelCount = 0;
descriptor.baseMipLevel = 0;
texture.CreateView(&descriptor);
descriptor.baseMipLevel = 1;
texture.CreateView(&descriptor);
descriptor.baseMipLevel = kDefaultMipLevels - 1;
texture.CreateView(&descriptor);
descriptor.baseMipLevel = kDefaultMipLevels;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
}
// It is an error to make the mip level out of range.
{
wgpu::TextureViewDescriptor descriptor = base2DTextureViewDescriptor;
descriptor.baseMipLevel = 0;
descriptor.mipLevelCount = kDefaultMipLevels + 1;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
descriptor.baseMipLevel = 1;
descriptor.mipLevelCount = kDefaultMipLevels;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
descriptor.baseMipLevel = kDefaultMipLevels - 1;
descriptor.mipLevelCount = 2;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
descriptor.baseMipLevel = kDefaultMipLevels;
descriptor.mipLevelCount = 1;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
}
}
// Test creating texture view on a 2D array texture
TEST_F(TextureViewValidationTest, CreateTextureViewOnTexture2DArray) {
constexpr uint32_t kDefaultArrayLayers = 6;
wgpu::Texture texture = Create2DArrayTexture(device, kDefaultArrayLayers);
wgpu::TextureViewDescriptor base2DArrayTextureViewDescriptor =
CreateDefaultViewDescriptor(wgpu::TextureViewDimension::e2DArray);
// It is OK to create a 2D texture view on a 2D array texture.
{
wgpu::TextureViewDescriptor descriptor = base2DArrayTextureViewDescriptor;
descriptor.dimension = wgpu::TextureViewDimension::e2D;
descriptor.arrayLayerCount = 1;
texture.CreateView(&descriptor);
}
// It is OK to create a 2D array texture view on a 2D array texture.
{
wgpu::TextureViewDescriptor descriptor = base2DArrayTextureViewDescriptor;
descriptor.arrayLayerCount = kDefaultArrayLayers;
texture.CreateView(&descriptor);
}
// baseArrayLayer == k && arrayLayerCount == 0 means to use layers k..end.
{
wgpu::TextureViewDescriptor descriptor = base2DArrayTextureViewDescriptor;
descriptor.arrayLayerCount = 0;
descriptor.baseArrayLayer = 0;
texture.CreateView(&descriptor);
descriptor.baseArrayLayer = 1;
texture.CreateView(&descriptor);
descriptor.baseArrayLayer = kDefaultArrayLayers - 1;
texture.CreateView(&descriptor);
descriptor.baseArrayLayer = kDefaultArrayLayers;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
}
// It is an error for the array layer range of the view to exceed that of the texture.
{
wgpu::TextureViewDescriptor descriptor = base2DArrayTextureViewDescriptor;
descriptor.baseArrayLayer = 0;
descriptor.arrayLayerCount = kDefaultArrayLayers + 1;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
descriptor.baseArrayLayer = 1;
descriptor.arrayLayerCount = kDefaultArrayLayers;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
descriptor.baseArrayLayer = kDefaultArrayLayers - 1;
descriptor.arrayLayerCount = 2;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
descriptor.baseArrayLayer = kDefaultArrayLayers;
descriptor.arrayLayerCount = 1;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
}
}
// Using the "none" ("default") values validates the same as explicitly
// specifying the values they're supposed to default to.
// Variant for a texture with more than 1 array layer.
TEST_F(TextureViewValidationTest, TextureViewDescriptorDefaultsArray) {
constexpr uint32_t kDefaultArrayLayers = 6;
wgpu::Texture texture = Create2DArrayTexture(device, kDefaultArrayLayers);
{ texture.CreateView(); }
{
wgpu::TextureViewDescriptor descriptor;
descriptor.format = wgpu::TextureFormat::Undefined;
texture.CreateView(&descriptor);
descriptor.format = wgpu::TextureFormat::RGBA8Unorm;
texture.CreateView(&descriptor);
descriptor.format = wgpu::TextureFormat::R8Unorm;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
}
{
wgpu::TextureViewDescriptor descriptor;
descriptor.dimension = wgpu::TextureViewDimension::Undefined;
texture.CreateView(&descriptor);
descriptor.dimension = wgpu::TextureViewDimension::e2DArray;
texture.CreateView(&descriptor);
descriptor.dimension = wgpu::TextureViewDimension::e2D;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
}
{
wgpu::TextureViewDescriptor descriptor;
// Setting array layers to non-0 means the dimensionality will
// default to 2D so by itself it causes an error.
descriptor.arrayLayerCount = kDefaultArrayLayers;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
descriptor.dimension = wgpu::TextureViewDimension::e2DArray;
texture.CreateView(&descriptor);
descriptor.mipLevelCount = kDefaultMipLevels;
texture.CreateView(&descriptor);
}
}
// Using the "none" ("default") values validates the same as explicitly
// specifying the values they're supposed to default to.
// Variant for a texture with only 1 array layer.
TEST_F(TextureViewValidationTest, TextureViewDescriptorDefaultsNonArray) {
constexpr uint32_t kDefaultArrayLayers = 1;
wgpu::Texture texture = Create2DArrayTexture(device, kDefaultArrayLayers);
{ texture.CreateView(); }
{
wgpu::TextureViewDescriptor descriptor;
descriptor.format = wgpu::TextureFormat::Undefined;
texture.CreateView(&descriptor);
descriptor.format = wgpu::TextureFormat::RGBA8Unorm;
texture.CreateView(&descriptor);
descriptor.format = wgpu::TextureFormat::R8Unorm;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
}
{
wgpu::TextureViewDescriptor descriptor;
descriptor.dimension = wgpu::TextureViewDimension::Undefined;
texture.CreateView(&descriptor);
descriptor.dimension = wgpu::TextureViewDimension::e2D;
texture.CreateView(&descriptor);
descriptor.dimension = wgpu::TextureViewDimension::e2DArray;
texture.CreateView(&descriptor);
}
{
wgpu::TextureViewDescriptor descriptor;
descriptor.arrayLayerCount = 0;
texture.CreateView(&descriptor);
descriptor.arrayLayerCount = 1;
texture.CreateView(&descriptor);
descriptor.arrayLayerCount = 2;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
}
{
wgpu::TextureViewDescriptor descriptor;
descriptor.mipLevelCount = kDefaultMipLevels;
texture.CreateView(&descriptor);
descriptor.arrayLayerCount = kDefaultArrayLayers;
texture.CreateView(&descriptor);
}
}
// Test creating cube map texture view
TEST_F(TextureViewValidationTest, CreateCubeMapTextureView) {
constexpr uint32_t kDefaultArrayLayers = 16;
wgpu::Texture texture = Create2DArrayTexture(device, kDefaultArrayLayers);
wgpu::TextureViewDescriptor base2DArrayTextureViewDescriptor =
CreateDefaultViewDescriptor(wgpu::TextureViewDimension::e2DArray);
// It is OK to create a cube map texture view with arrayLayerCount == 6.
{
wgpu::TextureViewDescriptor descriptor = base2DArrayTextureViewDescriptor;
descriptor.dimension = wgpu::TextureViewDimension::Cube;
descriptor.arrayLayerCount = 6;
texture.CreateView(&descriptor);
}
// It is an error to create a cube map texture view with arrayLayerCount != 6.
{
wgpu::TextureViewDescriptor descriptor = base2DArrayTextureViewDescriptor;
descriptor.dimension = wgpu::TextureViewDimension::Cube;
descriptor.arrayLayerCount = 3;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
}
// It is OK to create a cube map array texture view with arrayLayerCount % 6 == 0.
{
wgpu::TextureViewDescriptor descriptor = base2DArrayTextureViewDescriptor;
descriptor.dimension = wgpu::TextureViewDimension::CubeArray;
descriptor.arrayLayerCount = 12;
texture.CreateView(&descriptor);
}
// It is an error to create a cube map array texture view with arrayLayerCount % 6 != 0.
{
wgpu::TextureViewDescriptor descriptor = base2DArrayTextureViewDescriptor;
descriptor.dimension = wgpu::TextureViewDimension::CubeArray;
descriptor.arrayLayerCount = 11;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
}
// It is an error to create a cube map texture view with width != height.
{
wgpu::Texture nonSquareTexture = Create2DArrayTexture(device, 18, 32, 16, 5);
wgpu::TextureViewDescriptor descriptor = base2DArrayTextureViewDescriptor;
descriptor.dimension = wgpu::TextureViewDimension::Cube;
descriptor.arrayLayerCount = 6;
ASSERT_DEVICE_ERROR(nonSquareTexture.CreateView(&descriptor));
}
// It is an error to create a cube map array texture view with width != height.
{
wgpu::Texture nonSquareTexture = Create2DArrayTexture(device, 18, 32, 16, 5);
wgpu::TextureViewDescriptor descriptor = base2DArrayTextureViewDescriptor;
descriptor.dimension = wgpu::TextureViewDimension::CubeArray;
descriptor.arrayLayerCount = 12;
ASSERT_DEVICE_ERROR(nonSquareTexture.CreateView(&descriptor));
}
}
// Test the format compatibility rules when creating a texture view.
// TODO(jiawei.shao@intel.com): add more tests when the rules are fully implemented.
TEST_F(TextureViewValidationTest, TextureViewFormatCompatibility) {
wgpu::Texture texture = Create2DArrayTexture(device, 1);
wgpu::TextureViewDescriptor base2DTextureViewDescriptor =
CreateDefaultViewDescriptor(wgpu::TextureViewDimension::e2D);
// It is an error to create a texture view in depth-stencil format on a RGBA texture.
{
wgpu::TextureViewDescriptor descriptor = base2DTextureViewDescriptor;
descriptor.format = wgpu::TextureFormat::Depth24PlusStencil8;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
}
}
// Test that it's invalid to create a texture view from a destroyed texture
TEST_F(TextureViewValidationTest, DestroyCreateTextureView) {
wgpu::Texture texture = Create2DArrayTexture(device, 1);
wgpu::TextureViewDescriptor descriptor =
CreateDefaultViewDescriptor(wgpu::TextureViewDimension::e2D);
texture.Destroy();
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor)); ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
} }
// It is OK to create a cube map array texture view with arrayLayerCount % 6 == 0. // Test that only TextureAspect::All is supported
{ TEST_F(TextureViewValidationTest, AspectMustBeAll) {
wgpu::TextureViewDescriptor descriptor = base2DArrayTextureViewDescriptor; wgpu::TextureDescriptor descriptor = {};
descriptor.dimension = wgpu::TextureViewDimension::CubeArray; descriptor.size = {1, 1, 1};
descriptor.arrayLayerCount = 12; descriptor.format = wgpu::TextureFormat::Depth32Float;
texture.CreateView(&descriptor); descriptor.usage = wgpu::TextureUsage::Sampled | wgpu::TextureUsage::OutputAttachment;
wgpu::Texture texture = device.CreateTexture(&descriptor);
wgpu::TextureViewDescriptor viewDescriptor = {};
viewDescriptor.aspect = wgpu::TextureAspect::All;
texture.CreateView(&viewDescriptor);
viewDescriptor.aspect = wgpu::TextureAspect::DepthOnly;
ASSERT_DEVICE_ERROR(texture.CreateView(&viewDescriptor));
} }
// It is an error to create a cube map array texture view with arrayLayerCount % 6 != 0.
{
wgpu::TextureViewDescriptor descriptor = base2DArrayTextureViewDescriptor;
descriptor.dimension = wgpu::TextureViewDimension::CubeArray;
descriptor.arrayLayerCount = 11;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
}
// It is an error to create a cube map texture view with width != height.
{
wgpu::Texture nonSquareTexture = Create2DArrayTexture(device, 18, 32, 16, 5);
wgpu::TextureViewDescriptor descriptor = base2DArrayTextureViewDescriptor;
descriptor.dimension = wgpu::TextureViewDimension::Cube;
descriptor.arrayLayerCount = 6;
ASSERT_DEVICE_ERROR(nonSquareTexture.CreateView(&descriptor));
}
// It is an error to create a cube map array texture view with width != height.
{
wgpu::Texture nonSquareTexture = Create2DArrayTexture(device, 18, 32, 16, 5);
wgpu::TextureViewDescriptor descriptor = base2DArrayTextureViewDescriptor;
descriptor.dimension = wgpu::TextureViewDimension::CubeArray;
descriptor.arrayLayerCount = 12;
ASSERT_DEVICE_ERROR(nonSquareTexture.CreateView(&descriptor));
}
}
// Test the format compatibility rules when creating a texture view.
// TODO(jiawei.shao@intel.com): add more tests when the rules are fully implemented.
TEST_F(TextureViewValidationTest, TextureViewFormatCompatibility) {
wgpu::Texture texture = Create2DArrayTexture(device, 1);
wgpu::TextureViewDescriptor base2DTextureViewDescriptor =
CreateDefaultViewDescriptor(wgpu::TextureViewDimension::e2D);
// It is an error to create a texture view in depth-stencil format on a RGBA texture.
{
wgpu::TextureViewDescriptor descriptor = base2DTextureViewDescriptor;
descriptor.format = wgpu::TextureFormat::Depth24PlusStencil8;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
}
}
// Test that it's invalid to create a texture view from a destroyed texture
TEST_F(TextureViewValidationTest, DestroyCreateTextureView) {
wgpu::Texture texture = Create2DArrayTexture(device, 1);
wgpu::TextureViewDescriptor descriptor =
CreateDefaultViewDescriptor(wgpu::TextureViewDimension::e2D);
texture.Destroy();
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
}
// Test that only TextureAspect::All is supported
TEST_F(TextureViewValidationTest, AspectMustBeAll) {
wgpu::TextureDescriptor descriptor = {};
descriptor.size = {1, 1, 1};
descriptor.format = wgpu::TextureFormat::Depth32Float;
descriptor.usage = wgpu::TextureUsage::Sampled | wgpu::TextureUsage::OutputAttachment;
wgpu::Texture texture = device.CreateTexture(&descriptor);
wgpu::TextureViewDescriptor viewDescriptor = {};
viewDescriptor.aspect = wgpu::TextureAspect::All;
texture.CreateView(&viewDescriptor);
viewDescriptor.aspect = wgpu::TextureAspect::DepthOnly;
ASSERT_DEVICE_ERROR(texture.CreateView(&viewDescriptor));
}
} // anonymous namespace } // anonymous namespace

View File

@ -16,34 +16,67 @@
namespace { namespace {
class ToggleValidationTest : public ValidationTest { class ToggleValidationTest : public ValidationTest {};
};
// Tests querying the detail of a toggle from dawn_native::InstanceBase works correctly. // Tests querying the detail of a toggle from dawn_native::InstanceBase works correctly.
TEST_F(ToggleValidationTest, QueryToggleInfo) { TEST_F(ToggleValidationTest, QueryToggleInfo) {
// Query with a valid toggle name // Query with a valid toggle name
{ {
const char* kValidToggleName = "emulate_store_and_msaa_resolve"; const char* kValidToggleName = "emulate_store_and_msaa_resolve";
const dawn_native::ToggleInfo* toggleInfo = instance->GetToggleInfo(kValidToggleName); const dawn_native::ToggleInfo* toggleInfo = instance->GetToggleInfo(kValidToggleName);
ASSERT_NE(nullptr, toggleInfo); ASSERT_NE(nullptr, toggleInfo);
ASSERT_NE(nullptr, toggleInfo->name); ASSERT_NE(nullptr, toggleInfo->name);
ASSERT_NE(nullptr, toggleInfo->description); ASSERT_NE(nullptr, toggleInfo->description);
ASSERT_NE(nullptr, toggleInfo->url); ASSERT_NE(nullptr, toggleInfo->url);
}
// Query with an invalid toggle name
{
const char* kInvalidToggleName = "!@#$%^&*";
const dawn_native::ToggleInfo* toggleInfo = instance->GetToggleInfo(kInvalidToggleName);
ASSERT_EQ(nullptr, toggleInfo);
}
} }
// Query with an invalid toggle name // Tests overriding toggles when creating a device works correctly.
{ TEST_F(ToggleValidationTest, OverrideToggleUsage) {
const char* kInvalidToggleName = "!@#$%^&*"; // Create device with a valid name of a toggle
const dawn_native::ToggleInfo* toggleInfo = instance->GetToggleInfo(kInvalidToggleName); {
ASSERT_EQ(nullptr, toggleInfo); const char* kValidToggleName = "emulate_store_and_msaa_resolve";
} dawn_native::DeviceDescriptor descriptor;
} descriptor.forceEnabledToggles.push_back(kValidToggleName);
// Tests overriding toggles when creating a device works correctly. WGPUDevice deviceWithToggle = adapter.CreateDevice(&descriptor);
TEST_F(ToggleValidationTest, OverrideToggleUsage) { std::vector<const char*> toggleNames = dawn_native::GetTogglesUsed(deviceWithToggle);
// Create device with a valid name of a toggle bool validToggleExists = false;
{ for (const char* toggle : toggleNames) {
const char* kValidToggleName = "emulate_store_and_msaa_resolve"; if (strcmp(toggle, kValidToggleName) == 0) {
validToggleExists = true;
}
}
ASSERT_EQ(validToggleExists, true);
}
// Create device with an invalid toggle name
{
const char* kInvalidToggleName = "!@#$%^&*";
dawn_native::DeviceDescriptor descriptor;
descriptor.forceEnabledToggles.push_back(kInvalidToggleName);
WGPUDevice deviceWithToggle = adapter.CreateDevice(&descriptor);
std::vector<const char*> toggleNames = dawn_native::GetTogglesUsed(deviceWithToggle);
bool InvalidToggleExists = false;
for (const char* toggle : toggleNames) {
if (strcmp(toggle, kInvalidToggleName) == 0) {
InvalidToggleExists = true;
}
}
ASSERT_EQ(InvalidToggleExists, false);
}
}
TEST_F(ToggleValidationTest, TurnOffVsyncWithToggle) {
const char* kValidToggleName = "turn_off_vsync";
dawn_native::DeviceDescriptor descriptor; dawn_native::DeviceDescriptor descriptor;
descriptor.forceEnabledToggles.push_back(kValidToggleName); descriptor.forceEnabledToggles.push_back(kValidToggleName);
@ -57,38 +90,4 @@ TEST_F(ToggleValidationTest, OverrideToggleUsage) {
} }
ASSERT_EQ(validToggleExists, true); ASSERT_EQ(validToggleExists, true);
} }
// Create device with an invalid toggle name
{
const char* kInvalidToggleName = "!@#$%^&*";
dawn_native::DeviceDescriptor descriptor;
descriptor.forceEnabledToggles.push_back(kInvalidToggleName);
WGPUDevice deviceWithToggle = adapter.CreateDevice(&descriptor);
std::vector<const char*> toggleNames = dawn_native::GetTogglesUsed(deviceWithToggle);
bool InvalidToggleExists = false;
for (const char* toggle : toggleNames) {
if (strcmp(toggle, kInvalidToggleName) == 0) {
InvalidToggleExists = true;
}
}
ASSERT_EQ(InvalidToggleExists, false);
}
}
TEST_F(ToggleValidationTest, TurnOffVsyncWithToggle) {
const char* kValidToggleName = "turn_off_vsync";
dawn_native::DeviceDescriptor descriptor;
descriptor.forceEnabledToggles.push_back(kValidToggleName);
WGPUDevice deviceWithToggle = adapter.CreateDevice(&descriptor);
std::vector<const char*> toggleNames = dawn_native::GetTogglesUsed(deviceWithToggle);
bool validToggleExists = false;
for (const char* toggle : toggleNames) {
if (strcmp(toggle, kValidToggleName) == 0) {
validToggleExists = true;
}
}
ASSERT_EQ(validToggleExists, true);
}
} // anonymous namespace } // anonymous namespace

View File

@ -27,7 +27,7 @@ ValidationTest::ValidationTest() {
// Validation tests run against the null backend, find the corresponding adapter // Validation tests run against the null backend, find the corresponding adapter
bool foundNullAdapter = false; bool foundNullAdapter = false;
for (auto &currentAdapter : adapters) { for (auto& currentAdapter : adapters) {
wgpu::AdapterProperties adapterProperties; wgpu::AdapterProperties adapterProperties;
currentAdapter.GetProperties(&adapterProperties); currentAdapter.GetProperties(&adapterProperties);
@ -129,7 +129,7 @@ ValidationTest::DummyRenderPass::DummyRenderPass(const wgpu::Device& device)
wgpu::TextureView view = attachment.CreateView(); wgpu::TextureView view = attachment.CreateView();
mColorAttachment.attachment = view; mColorAttachment.attachment = view;
mColorAttachment.resolveTarget = nullptr; mColorAttachment.resolveTarget = nullptr;
mColorAttachment.clearColor = { 0.0f, 0.0f, 0.0f, 0.0f }; mColorAttachment.clearColor = {0.0f, 0.0f, 0.0f, 0.0f};
mColorAttachment.loadOp = wgpu::LoadOp::Clear; mColorAttachment.loadOp = wgpu::LoadOp::Clear;
mColorAttachment.storeOp = wgpu::StoreOp::Store; mColorAttachment.storeOp = wgpu::StoreOp::Store;

View File

@ -70,4 +70,4 @@ class ValidationTest : public testing::Test {
bool mError = false; bool mError = false;
}; };
#endif // TESTS_UNITTESTS_VALIDATIONTEST_H_ #endif // TESTS_UNITTESTS_VALIDATIONTEST_H_

View File

@ -21,68 +21,68 @@
#include "utils/WGPUHelpers.h" #include "utils/WGPUHelpers.h"
class VertexBufferValidationTest : public ValidationTest { class VertexBufferValidationTest : public ValidationTest {
protected: protected:
void SetUp() override { void SetUp() override {
ValidationTest::SetUp(); ValidationTest::SetUp();
fsModule = utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment, R"( fsModule = utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment, R"(
#version 450 #version 450
layout(location = 0) out vec4 fragColor; layout(location = 0) out vec4 fragColor;
void main() { void main() {
fragColor = vec4(0.0, 1.0, 0.0, 1.0); fragColor = vec4(0.0, 1.0, 0.0, 1.0);
})"); })");
}
wgpu::Buffer MakeVertexBuffer() {
wgpu::BufferDescriptor descriptor;
descriptor.size = 256;
descriptor.usage = wgpu::BufferUsage::Vertex;
return device.CreateBuffer(&descriptor);
}
wgpu::ShaderModule MakeVertexShader(unsigned int bufferCount) {
std::ostringstream vs;
vs << "#version 450\n";
for (unsigned int i = 0; i < bufferCount; ++i) {
vs << "layout(location = " << i << ") in vec3 a_position" << i << ";\n";
} }
vs << "void main() {\n";
wgpu::Buffer MakeVertexBuffer() { vs << "gl_Position = vec4(";
wgpu::BufferDescriptor descriptor; for (unsigned int i = 0; i < bufferCount; ++i) {
descriptor.size = 256; vs << "a_position" << i;
descriptor.usage = wgpu::BufferUsage::Vertex; if (i != bufferCount - 1) {
vs << " + ";
return device.CreateBuffer(&descriptor);
}
wgpu::ShaderModule MakeVertexShader(unsigned int bufferCount) {
std::ostringstream vs;
vs << "#version 450\n";
for (unsigned int i = 0; i < bufferCount; ++i) {
vs << "layout(location = " << i << ") in vec3 a_position" << i << ";\n";
} }
vs << "void main() {\n";
vs << "gl_Position = vec4(";
for (unsigned int i = 0; i < bufferCount; ++i) {
vs << "a_position" << i;
if (i != bufferCount - 1) {
vs << " + ";
}
}
vs << ", 1.0);";
vs << "}\n";
return utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex,
vs.str().c_str());
} }
vs << ", 1.0);";
wgpu::RenderPipeline MakeRenderPipeline(const wgpu::ShaderModule& vsModule, vs << "}\n";
unsigned int bufferCount) {
utils::ComboRenderPipelineDescriptor descriptor(device);
descriptor.vertexStage.module = vsModule;
descriptor.cFragmentStage.module = fsModule;
for (unsigned int i = 0; i < bufferCount; ++i) { return utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex,
descriptor.cVertexState.cVertexBuffers[i].attributeCount = 1; vs.str().c_str());
descriptor.cVertexState.cVertexBuffers[i].attributes = }
&descriptor.cVertexState.cAttributes[i];
descriptor.cVertexState.cAttributes[i].shaderLocation = i;
descriptor.cVertexState.cAttributes[i].format = wgpu::VertexFormat::Float3;
}
descriptor.cVertexState.vertexBufferCount = bufferCount;
return device.CreateRenderPipeline(&descriptor); wgpu::RenderPipeline MakeRenderPipeline(const wgpu::ShaderModule& vsModule,
unsigned int bufferCount) {
utils::ComboRenderPipelineDescriptor descriptor(device);
descriptor.vertexStage.module = vsModule;
descriptor.cFragmentStage.module = fsModule;
for (unsigned int i = 0; i < bufferCount; ++i) {
descriptor.cVertexState.cVertexBuffers[i].attributeCount = 1;
descriptor.cVertexState.cVertexBuffers[i].attributes =
&descriptor.cVertexState.cAttributes[i];
descriptor.cVertexState.cAttributes[i].shaderLocation = i;
descriptor.cVertexState.cAttributes[i].format = wgpu::VertexFormat::Float3;
} }
descriptor.cVertexState.vertexBufferCount = bufferCount;
wgpu::ShaderModule fsModule; return device.CreateRenderPipeline(&descriptor);
}
wgpu::ShaderModule fsModule;
}; };
TEST_F(VertexBufferValidationTest, VertexBuffersInheritedBetweenPipelines) { TEST_F(VertexBufferValidationTest, VertexBuffersInheritedBetweenPipelines) {

View File

@ -185,7 +185,6 @@ TEST_F(WireArgumentTests, CStringArgument) {
FlushClient(); FlushClient();
} }
// Test that the wire is able to send objects as value arguments // Test that the wire is able to send objects as value arguments
TEST_F(WireArgumentTests, ObjectAsValueArgument) { TEST_F(WireArgumentTests, ObjectAsValueArgument) {
WGPUCommandEncoder cmdBufEncoder = wgpuDeviceCreateCommandEncoder(device, nullptr); WGPUCommandEncoder cmdBufEncoder = wgpuDeviceCreateCommandEncoder(device, nullptr);

View File

@ -613,4 +613,3 @@ TEST_F(WireBufferMappingTests, CreateBufferMappedThenMapFailure) {
FlushClient(); FlushClient();
} }

View File

@ -64,7 +64,8 @@ class WireErrorCallbackTests : public WireTest {
WireTest::SetUp(); WireTest::SetUp();
mockDeviceErrorCallback = std::make_unique<StrictMock<MockDeviceErrorCallback>>(); mockDeviceErrorCallback = std::make_unique<StrictMock<MockDeviceErrorCallback>>();
mockDevicePopErrorScopeCallback = std::make_unique<StrictMock<MockDevicePopErrorScopeCallback>>(); mockDevicePopErrorScopeCallback =
std::make_unique<StrictMock<MockDevicePopErrorScopeCallback>>();
mockDeviceLostCallback = std::make_unique<StrictMock<MockDeviceLostCallback>>(); mockDeviceLostCallback = std::make_unique<StrictMock<MockDeviceLostCallback>>();
} }
@ -206,8 +207,7 @@ TEST_F(WireErrorCallbackTests, PopErrorScopeDeviceDestroyed) {
EXPECT_TRUE(wgpuDevicePopErrorScope(device, ToMockDevicePopErrorScopeCallback, this)); EXPECT_TRUE(wgpuDevicePopErrorScope(device, ToMockDevicePopErrorScopeCallback, this));
EXPECT_CALL(api, OnDevicePopErrorScopeCallback(apiDevice, _, _)) EXPECT_CALL(api, OnDevicePopErrorScopeCallback(apiDevice, _, _)).WillOnce(Return(true));
.WillOnce(Return(true));
FlushClient(); FlushClient();
// Incomplete callback called in Device destructor. // Incomplete callback called in Device destructor.

View File

@ -40,8 +40,9 @@ TEST_F(WireExtensionTests, ChainedStruct) {
.WillOnce(Invoke([&](Unused, const WGPUSamplerDescriptor* serverDesc) -> WGPUSampler { .WillOnce(Invoke([&](Unused, const WGPUSamplerDescriptor* serverDesc) -> WGPUSampler {
EXPECT_STREQ(serverDesc->label, clientDesc.label); EXPECT_STREQ(serverDesc->label, clientDesc.label);
const auto* ext = reinterpret_cast<const WGPUSamplerDescriptorDummyAnisotropicFiltering*>( const auto* ext =
serverDesc->nextInChain); reinterpret_cast<const WGPUSamplerDescriptorDummyAnisotropicFiltering*>(
serverDesc->nextInChain);
EXPECT_EQ(ext->chain.sType, clientExt.chain.sType); EXPECT_EQ(ext->chain.sType, clientExt.chain.sType);
EXPECT_EQ(ext->maxAnisotropy, clientExt.maxAnisotropy); EXPECT_EQ(ext->maxAnisotropy, clientExt.maxAnisotropy);
@ -73,13 +74,15 @@ TEST_F(WireExtensionTests, MutlipleChainedStructs) {
.WillOnce(Invoke([&](Unused, const WGPUSamplerDescriptor* serverDesc) -> WGPUSampler { .WillOnce(Invoke([&](Unused, const WGPUSamplerDescriptor* serverDesc) -> WGPUSampler {
EXPECT_STREQ(serverDesc->label, clientDesc.label); EXPECT_STREQ(serverDesc->label, clientDesc.label);
const auto* ext1 = reinterpret_cast<const WGPUSamplerDescriptorDummyAnisotropicFiltering*>( const auto* ext1 =
serverDesc->nextInChain); reinterpret_cast<const WGPUSamplerDescriptorDummyAnisotropicFiltering*>(
serverDesc->nextInChain);
EXPECT_EQ(ext1->chain.sType, clientExt1.chain.sType); EXPECT_EQ(ext1->chain.sType, clientExt1.chain.sType);
EXPECT_EQ(ext1->maxAnisotropy, clientExt1.maxAnisotropy); EXPECT_EQ(ext1->maxAnisotropy, clientExt1.maxAnisotropy);
const auto* ext2 = reinterpret_cast<const WGPUSamplerDescriptorDummyAnisotropicFiltering*>( const auto* ext2 =
ext1->chain.next); reinterpret_cast<const WGPUSamplerDescriptorDummyAnisotropicFiltering*>(
ext1->chain.next);
EXPECT_EQ(ext2->chain.sType, clientExt2.chain.sType); EXPECT_EQ(ext2->chain.sType, clientExt2.chain.sType);
EXPECT_EQ(ext2->maxAnisotropy, clientExt2.maxAnisotropy); EXPECT_EQ(ext2->maxAnisotropy, clientExt2.maxAnisotropy);
@ -99,13 +102,15 @@ TEST_F(WireExtensionTests, MutlipleChainedStructs) {
.WillOnce(Invoke([&](Unused, const WGPUSamplerDescriptor* serverDesc) -> WGPUSampler { .WillOnce(Invoke([&](Unused, const WGPUSamplerDescriptor* serverDesc) -> WGPUSampler {
EXPECT_STREQ(serverDesc->label, clientDesc.label); EXPECT_STREQ(serverDesc->label, clientDesc.label);
const auto* ext2 = reinterpret_cast<const WGPUSamplerDescriptorDummyAnisotropicFiltering*>( const auto* ext2 =
serverDesc->nextInChain); reinterpret_cast<const WGPUSamplerDescriptorDummyAnisotropicFiltering*>(
serverDesc->nextInChain);
EXPECT_EQ(ext2->chain.sType, clientExt2.chain.sType); EXPECT_EQ(ext2->chain.sType, clientExt2.chain.sType);
EXPECT_EQ(ext2->maxAnisotropy, clientExt2.maxAnisotropy); EXPECT_EQ(ext2->maxAnisotropy, clientExt2.maxAnisotropy);
const auto* ext1 = reinterpret_cast<const WGPUSamplerDescriptorDummyAnisotropicFiltering*>( const auto* ext1 =
ext2->chain.next); reinterpret_cast<const WGPUSamplerDescriptorDummyAnisotropicFiltering*>(
ext2->chain.next);
EXPECT_EQ(ext1->chain.sType, clientExt1.chain.sType); EXPECT_EQ(ext1->chain.sType, clientExt1.chain.sType);
EXPECT_EQ(ext1->maxAnisotropy, clientExt1.maxAnisotropy); EXPECT_EQ(ext1->maxAnisotropy, clientExt1.maxAnisotropy);

View File

@ -180,9 +180,7 @@ class WireMemoryTransferServiceTests : public WireTest {
ClientReadHandle* handle = clientMemoryTransferService.NewReadHandle(); ClientReadHandle* handle = clientMemoryTransferService.NewReadHandle();
EXPECT_CALL(clientMemoryTransferService, OnCreateReadHandle(sizeof(mBufferContent))) EXPECT_CALL(clientMemoryTransferService, OnCreateReadHandle(sizeof(mBufferContent)))
.WillOnce(InvokeWithoutArgs([=]() { .WillOnce(InvokeWithoutArgs([=]() { return handle; }));
return handle;
}));
return handle; return handle;
} }
@ -259,9 +257,7 @@ class WireMemoryTransferServiceTests : public WireTest {
ClientWriteHandle* handle = clientMemoryTransferService.NewWriteHandle(); ClientWriteHandle* handle = clientMemoryTransferService.NewWriteHandle();
EXPECT_CALL(clientMemoryTransferService, OnCreateWriteHandle(sizeof(mBufferContent))) EXPECT_CALL(clientMemoryTransferService, OnCreateWriteHandle(sizeof(mBufferContent)))
.WillOnce(InvokeWithoutArgs([=]() { .WillOnce(InvokeWithoutArgs([=]() { return handle; }));
return handle;
}));
return handle; return handle;
} }
@ -300,22 +296,18 @@ class WireMemoryTransferServiceTests : public WireTest {
EXPECT_CALL(serverMemoryTransferService, EXPECT_CALL(serverMemoryTransferService,
OnDeserializeWriteHandle(Pointee(Eq(mSerializeCreateInfo)), OnDeserializeWriteHandle(Pointee(Eq(mSerializeCreateInfo)),
sizeof(mSerializeCreateInfo), _)) sizeof(mSerializeCreateInfo), _))
.WillOnce(InvokeWithoutArgs([&]() { .WillOnce(InvokeWithoutArgs([&]() { return false; }));
return false;
}));
} }
void ExpectClientWriteHandleOpen(ClientWriteHandle* handle, uint32_t* mappedData) { void ExpectClientWriteHandleOpen(ClientWriteHandle* handle, uint32_t* mappedData) {
EXPECT_CALL(clientMemoryTransferService, OnWriteHandleOpen(handle)) EXPECT_CALL(clientMemoryTransferService, OnWriteHandleOpen(handle))
.WillOnce(InvokeWithoutArgs([=]() { .WillOnce(InvokeWithoutArgs(
return std::make_pair(mappedData, sizeof(*mappedData)); [=]() { return std::make_pair(mappedData, sizeof(*mappedData)); }));
}));
} }
void MockClientWriteHandleOpenFailure(ClientWriteHandle* handle) { void MockClientWriteHandleOpenFailure(ClientWriteHandle* handle) {
EXPECT_CALL(clientMemoryTransferService, OnWriteHandleOpen(handle)) EXPECT_CALL(clientMemoryTransferService, OnWriteHandleOpen(handle))
.WillOnce(InvokeWithoutArgs( .WillOnce(InvokeWithoutArgs([&]() { return std::make_pair(nullptr, 0); }));
[&]() { return std::make_pair(nullptr, 0); }));
} }
void ExpectClientWriteHandleSerializeFlush(ClientWriteHandle* handle) { void ExpectClientWriteHandleSerializeFlush(ClientWriteHandle* handle) {
@ -348,8 +340,8 @@ class WireMemoryTransferServiceTests : public WireTest {
// Arbitrary values used within tests to check if serialized data is correctly passed // Arbitrary values used within tests to check if serialized data is correctly passed
// between the client and server. The static data changes between runs of the tests and // between the client and server. The static data changes between runs of the tests and
// test expectations will check that serialized values are passed to the respective deserialization // test expectations will check that serialized values are passed to the respective
// function. // deserialization function.
static uint32_t mSerializeCreateInfo; static uint32_t mSerializeCreateInfo;
static uint32_t mSerializeInitialDataInfo; static uint32_t mSerializeInitialDataInfo;
static uint32_t mSerializeFlushInfo; static uint32_t mSerializeFlushInfo;
@ -360,8 +352,9 @@ class WireMemoryTransferServiceTests : public WireTest {
// The client's zero-initialized buffer for writing. // The client's zero-initialized buffer for writing.
uint32_t mMappedBufferContent = 0; uint32_t mMappedBufferContent = 0;
// |mMappedBufferContent| should be set equal to |mUpdatedBufferContent| when the client performs a write. // |mMappedBufferContent| should be set equal to |mUpdatedBufferContent| when the client
// Test expectations should check that |mBufferContent == mUpdatedBufferContent| after all writes are flushed. // performs a write. Test expectations should check that |mBufferContent ==
// mUpdatedBufferContent| after all writes are flushed.
static uint32_t mUpdatedBufferContent; static uint32_t mUpdatedBufferContent;
testing::StrictMock<dawn_wire::server::MockMemoryTransferService> serverMemoryTransferService; testing::StrictMock<dawn_wire::server::MockMemoryTransferService> serverMemoryTransferService;

View File

@ -68,9 +68,11 @@ inline testing::Matcher<MatcherLambdaArgument<Lambda>> MatchesLambda(Lambda lamb
class StringMessageMatcher : public testing::MatcherInterface<const char*> { class StringMessageMatcher : public testing::MatcherInterface<const char*> {
public: public:
explicit StringMessageMatcher() {} explicit StringMessageMatcher() {
}
bool MatchAndExplain(const char* message, testing::MatchResultListener* listener) const override { bool MatchAndExplain(const char* message,
testing::MatchResultListener* listener) const override {
if (message == nullptr) { if (message == nullptr) {
*listener << "missing error message"; *listener << "missing error message";
return false; return false;
@ -83,11 +85,11 @@ class StringMessageMatcher : public testing::MatcherInterface<const char*> {
} }
void DescribeTo(std::ostream* os) const override { void DescribeTo(std::ostream* os) const override {
*os << "valid error message"; *os << "valid error message";
} }
void DescribeNegationTo(std::ostream* os) const override { void DescribeNegationTo(std::ostream* os) const override {
*os << "invalid error message"; *os << "invalid error message";
} }
}; };