220 lines
7.6 KiB
C++
220 lines
7.6 KiB
C++
// Copyright 2020 The Dawn Authors
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#include "tests/DawnTest.h"
|
|
|
|
#include "common/Constants.h"
|
|
#include "common/Log.h"
|
|
#include "utils/GLFWUtils.h"
|
|
#include "utils/WGPUHelpers.h"
|
|
|
|
#include "GLFW/glfw3.h"
|
|
|
|
class SwapChainTests : public DawnTest {
|
|
public:
|
|
void TestSetUp() override {
|
|
DAWN_SKIP_TEST_IF(UsesWire());
|
|
|
|
glfwSetErrorCallback([](int code, const char* message) {
|
|
dawn::ErrorLog() << "GLFW error " << code << " " << message;
|
|
});
|
|
glfwInit();
|
|
|
|
// The SwapChainTests don't create OpenGL contexts so we don't need to call
|
|
// SetupGLFWWindowHintsForBackend. Set GLFW_NO_API anyway to avoid GLFW bringing up a GL
|
|
// context that we won't use.
|
|
ASSERT_TRUE(!IsOpenGL());
|
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
|
window = glfwCreateWindow(400, 400, "SwapChainValidationTests window", nullptr, nullptr);
|
|
|
|
int width;
|
|
int height;
|
|
glfwGetFramebufferSize(window, &width, &height);
|
|
|
|
surface = utils::CreateSurfaceForWindow(GetInstance(), window);
|
|
ASSERT_NE(surface, nullptr);
|
|
|
|
baseDescriptor.width = width;
|
|
baseDescriptor.height = height;
|
|
baseDescriptor.usage = wgpu::TextureUsage::OutputAttachment;
|
|
baseDescriptor.format = wgpu::TextureFormat::BGRA8Unorm;
|
|
baseDescriptor.presentMode = wgpu::PresentMode::Mailbox;
|
|
}
|
|
|
|
void TearDown() override {
|
|
// Destroy the surface before the window as required by webgpu-native.
|
|
surface = wgpu::Surface();
|
|
if (window != nullptr) {
|
|
glfwDestroyWindow(window);
|
|
}
|
|
}
|
|
|
|
void ClearTexture(wgpu::TextureView view, wgpu::Color color) {
|
|
utils::ComboRenderPassDescriptor desc({view});
|
|
desc.cColorAttachments[0].loadOp = wgpu::LoadOp::Clear;
|
|
desc.cColorAttachments[0].clearColor = color;
|
|
|
|
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
|
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&desc);
|
|
pass.EndPass();
|
|
|
|
wgpu::CommandBuffer commands = encoder.Finish();
|
|
queue.Submit(1, &commands);
|
|
}
|
|
|
|
protected:
|
|
GLFWwindow* window = nullptr;
|
|
wgpu::Surface surface;
|
|
|
|
wgpu::SwapChainDescriptor baseDescriptor;
|
|
};
|
|
|
|
// Basic test for creating a swapchain and presenting one frame.
|
|
TEST_P(SwapChainTests, Basic) {
|
|
wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &baseDescriptor);
|
|
ClearTexture(swapchain.GetCurrentTextureView(), {1.0, 0.0, 0.0, 1.0});
|
|
swapchain.Present();
|
|
}
|
|
|
|
// Test replacing the swapchain
|
|
TEST_P(SwapChainTests, ReplaceBasic) {
|
|
wgpu::SwapChain swapchain1 = device.CreateSwapChain(surface, &baseDescriptor);
|
|
ClearTexture(swapchain1.GetCurrentTextureView(), {1.0, 0.0, 0.0, 1.0});
|
|
swapchain1.Present();
|
|
|
|
wgpu::SwapChain swapchain2 = device.CreateSwapChain(surface, &baseDescriptor);
|
|
ClearTexture(swapchain2.GetCurrentTextureView(), {0.0, 1.0, 0.0, 1.0});
|
|
swapchain2.Present();
|
|
}
|
|
|
|
// Test replacing the swapchain after GetCurrentTextureView
|
|
TEST_P(SwapChainTests, ReplaceAfterGet) {
|
|
wgpu::SwapChain swapchain1 = device.CreateSwapChain(surface, &baseDescriptor);
|
|
ClearTexture(swapchain1.GetCurrentTextureView(), {1.0, 0.0, 0.0, 1.0});
|
|
|
|
wgpu::SwapChain swapchain2 = device.CreateSwapChain(surface, &baseDescriptor);
|
|
ClearTexture(swapchain2.GetCurrentTextureView(), {0.0, 1.0, 0.0, 1.0});
|
|
swapchain2.Present();
|
|
}
|
|
|
|
// Test destroying the swapchain after GetCurrentTextureView
|
|
TEST_P(SwapChainTests, DestroyAfterGet) {
|
|
wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &baseDescriptor);
|
|
ClearTexture(swapchain.GetCurrentTextureView(), {1.0, 0.0, 0.0, 1.0});
|
|
}
|
|
|
|
// Test destroying the surface before the swapchain
|
|
TEST_P(SwapChainTests, DestroySurface) {
|
|
wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &baseDescriptor);
|
|
surface = nullptr;
|
|
}
|
|
|
|
// Test destroying the surface before the swapchain but after GetCurrentTextureView
|
|
TEST_P(SwapChainTests, DestroySurfaceAfterGet) {
|
|
wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &baseDescriptor);
|
|
ClearTexture(swapchain.GetCurrentTextureView(), {1.0, 0.0, 0.0, 1.0});
|
|
surface = nullptr;
|
|
}
|
|
|
|
// Test switching between present modes.
|
|
TEST_P(SwapChainTests, SwitchPresentMode) {
|
|
constexpr wgpu::PresentMode kAllPresentModes[] = {
|
|
wgpu::PresentMode::Immediate,
|
|
wgpu::PresentMode::Fifo,
|
|
wgpu::PresentMode::Mailbox,
|
|
};
|
|
|
|
for (wgpu::PresentMode mode1 : kAllPresentModes) {
|
|
for (wgpu::PresentMode mode2 : kAllPresentModes) {
|
|
wgpu::SwapChainDescriptor desc = baseDescriptor;
|
|
|
|
desc.presentMode = mode1;
|
|
wgpu::SwapChain swapchain1 = device.CreateSwapChain(surface, &desc);
|
|
ClearTexture(swapchain1.GetCurrentTextureView(), {0.0, 0.0, 0.0, 1.0});
|
|
swapchain1.Present();
|
|
|
|
desc.presentMode = mode2;
|
|
wgpu::SwapChain swapchain2 = device.CreateSwapChain(surface, &desc);
|
|
ClearTexture(swapchain2.GetCurrentTextureView(), {0.0, 0.0, 0.0, 1.0});
|
|
swapchain2.Present();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Test resizing the swapchain and without resizing the window.
|
|
TEST_P(SwapChainTests, ResizingSwapChainOnly) {
|
|
for (int i = 0; i < 10; i++) {
|
|
wgpu::SwapChainDescriptor desc = baseDescriptor;
|
|
desc.width += i * 10;
|
|
desc.height -= i * 10;
|
|
|
|
wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &desc);
|
|
ClearTexture(swapchain.GetCurrentTextureView(), {0.05f * i, 0.0f, 0.0f, 1.0f});
|
|
swapchain.Present();
|
|
}
|
|
}
|
|
|
|
// Test resizing the window but not the swapchain.
|
|
TEST_P(SwapChainTests, ResizingWindowOnly) {
|
|
wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &baseDescriptor);
|
|
|
|
for (int i = 0; i < 10; i++) {
|
|
glfwSetWindowSize(window, 400 - 10 * i, 400 + 10 * i);
|
|
glfwPollEvents();
|
|
|
|
ClearTexture(swapchain.GetCurrentTextureView(), {0.05f * i, 0.0f, 0.0f, 1.0f});
|
|
swapchain.Present();
|
|
}
|
|
}
|
|
|
|
// Test resizing both the window and the swapchain at the same time.
|
|
TEST_P(SwapChainTests, ResizingWindowAndSwapChain) {
|
|
for (int i = 0; i < 10; i++) {
|
|
glfwSetWindowSize(window, 400 - 10 * i, 400 + 10 * i);
|
|
glfwPollEvents();
|
|
|
|
int width;
|
|
int height;
|
|
glfwGetFramebufferSize(window, &width, &height);
|
|
|
|
wgpu::SwapChainDescriptor desc = baseDescriptor;
|
|
desc.width = width;
|
|
desc.height = height;
|
|
|
|
wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &desc);
|
|
ClearTexture(swapchain.GetCurrentTextureView(), {0.05f * i, 0.0f, 0.0f, 1.0f});
|
|
swapchain.Present();
|
|
}
|
|
}
|
|
|
|
// Test switching devices on the same adapter.
|
|
TEST_P(SwapChainTests, SwitchingDevice) {
|
|
wgpu::Device device2 = GetAdapter().CreateDevice();
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
wgpu::Device deviceToUse;
|
|
if (i % 2 == 0) {
|
|
deviceToUse = device;
|
|
} else {
|
|
deviceToUse = device2;
|
|
}
|
|
|
|
wgpu::SwapChain swapchain = deviceToUse.CreateSwapChain(surface, &baseDescriptor);
|
|
swapchain.GetCurrentTextureView();
|
|
swapchain.Present();
|
|
}
|
|
}
|
|
|
|
DAWN_INSTANTIATE_TEST(SwapChainTests, MetalBackend());
|