blob: 1f5d95468aaf3eceb9817c2009aa15be2af14ac7 [file] [log] [blame]
Corentin Wallez11652ff2020-03-20 17:07:20 +00001// Copyright 2020 The Dawn Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "tests/DawnTest.h"
16
17#include "common/Constants.h"
18#include "common/Log.h"
19#include "utils/GLFWUtils.h"
20#include "utils/WGPUHelpers.h"
21
22#include "GLFW/glfw3.h"
23
24class SwapChainTests : public DawnTest {
25 public:
Austin Eng40dc5d32020-05-15 22:06:35 +000026 void SetUp() override {
27 DawnTest::SetUp();
Jiawei Shao44fc6e32021-05-26 01:04:32 +000028 DAWN_TEST_UNSUPPORTED_IF(UsesWire());
Corentin Wallez11652ff2020-03-20 17:07:20 +000029
30 glfwSetErrorCallback([](int code, const char* message) {
31 dawn::ErrorLog() << "GLFW error " << code << " " << message;
32 });
Corentin Wallez2ce1d922020-10-22 17:07:49 +000033
34 // GLFW can fail to start in headless environments, in which SwapChainTests are
35 // inapplicable. Skip this cases without producing a test failure.
36 if (glfwInit() == GLFW_FALSE) {
37 GTEST_SKIP();
38 }
Corentin Wallez11652ff2020-03-20 17:07:20 +000039
40 // The SwapChainTests don't create OpenGL contexts so we don't need to call
41 // SetupGLFWWindowHintsForBackend. Set GLFW_NO_API anyway to avoid GLFW bringing up a GL
42 // context that we won't use.
43 ASSERT_TRUE(!IsOpenGL());
44 glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
45 window = glfwCreateWindow(400, 400, "SwapChainValidationTests window", nullptr, nullptr);
46
47 int width;
48 int height;
49 glfwGetFramebufferSize(window, &width, &height);
50
51 surface = utils::CreateSurfaceForWindow(GetInstance(), window);
52 ASSERT_NE(surface, nullptr);
53
54 baseDescriptor.width = width;
55 baseDescriptor.height = height;
Corentin Wallez6b087812020-10-27 15:35:56 +000056 baseDescriptor.usage = wgpu::TextureUsage::RenderAttachment;
Corentin Wallez11652ff2020-03-20 17:07:20 +000057 baseDescriptor.format = wgpu::TextureFormat::BGRA8Unorm;
58 baseDescriptor.presentMode = wgpu::PresentMode::Mailbox;
59 }
60
61 void TearDown() override {
62 // Destroy the surface before the window as required by webgpu-native.
63 surface = wgpu::Surface();
64 if (window != nullptr) {
65 glfwDestroyWindow(window);
66 }
Austin Eng40dc5d32020-05-15 22:06:35 +000067 DawnTest::TearDown();
Corentin Wallez11652ff2020-03-20 17:07:20 +000068 }
69
70 void ClearTexture(wgpu::TextureView view, wgpu::Color color) {
71 utils::ComboRenderPassDescriptor desc({view});
72 desc.cColorAttachments[0].loadOp = wgpu::LoadOp::Clear;
73 desc.cColorAttachments[0].clearColor = color;
74
75 wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
76 wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&desc);
77 pass.EndPass();
78
79 wgpu::CommandBuffer commands = encoder.Finish();
80 queue.Submit(1, &commands);
81 }
82
83 protected:
84 GLFWwindow* window = nullptr;
85 wgpu::Surface surface;
86
87 wgpu::SwapChainDescriptor baseDescriptor;
88};
89
90// Basic test for creating a swapchain and presenting one frame.
91TEST_P(SwapChainTests, Basic) {
92 wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &baseDescriptor);
93 ClearTexture(swapchain.GetCurrentTextureView(), {1.0, 0.0, 0.0, 1.0});
94 swapchain.Present();
95}
96
97// Test replacing the swapchain
98TEST_P(SwapChainTests, ReplaceBasic) {
99 wgpu::SwapChain swapchain1 = device.CreateSwapChain(surface, &baseDescriptor);
100 ClearTexture(swapchain1.GetCurrentTextureView(), {1.0, 0.0, 0.0, 1.0});
101 swapchain1.Present();
102
103 wgpu::SwapChain swapchain2 = device.CreateSwapChain(surface, &baseDescriptor);
104 ClearTexture(swapchain2.GetCurrentTextureView(), {0.0, 1.0, 0.0, 1.0});
105 swapchain2.Present();
106}
107
108// Test replacing the swapchain after GetCurrentTextureView
109TEST_P(SwapChainTests, ReplaceAfterGet) {
110 wgpu::SwapChain swapchain1 = device.CreateSwapChain(surface, &baseDescriptor);
111 ClearTexture(swapchain1.GetCurrentTextureView(), {1.0, 0.0, 0.0, 1.0});
112
113 wgpu::SwapChain swapchain2 = device.CreateSwapChain(surface, &baseDescriptor);
114 ClearTexture(swapchain2.GetCurrentTextureView(), {0.0, 1.0, 0.0, 1.0});
115 swapchain2.Present();
116}
117
118// Test destroying the swapchain after GetCurrentTextureView
119TEST_P(SwapChainTests, DestroyAfterGet) {
120 wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &baseDescriptor);
121 ClearTexture(swapchain.GetCurrentTextureView(), {1.0, 0.0, 0.0, 1.0});
122}
123
124// Test destroying the surface before the swapchain
125TEST_P(SwapChainTests, DestroySurface) {
126 wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &baseDescriptor);
127 surface = nullptr;
128}
129
130// Test destroying the surface before the swapchain but after GetCurrentTextureView
131TEST_P(SwapChainTests, DestroySurfaceAfterGet) {
132 wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &baseDescriptor);
133 ClearTexture(swapchain.GetCurrentTextureView(), {1.0, 0.0, 0.0, 1.0});
134 surface = nullptr;
135}
136
137// Test switching between present modes.
138TEST_P(SwapChainTests, SwitchPresentMode) {
Corentin Wallez25eeaa32020-10-27 11:31:26 +0000139 // Fails with "internal drawable creation failed" on the Windows NVIDIA CQ builders but not
140 // locally.
Jiawei Shao44fc6e32021-05-26 01:04:32 +0000141 DAWN_SUPPRESS_TEST_IF(IsWindows() && IsVulkan() && IsNvidia());
Corentin Wallez2ce1d922020-10-22 17:07:49 +0000142
Jiawei Shaodad44f42020-11-19 09:19:43 +0000143 // TODO(jiawei.shao@intel.com): find out why this test sometimes hangs on the latest Linux Intel
144 // Vulkan drivers.
Jiawei Shao44fc6e32021-05-26 01:04:32 +0000145 DAWN_SUPPRESS_TEST_IF(IsLinux() && IsVulkan() && IsIntel());
Jiawei Shaodad44f42020-11-19 09:19:43 +0000146
Corentin Wallez11652ff2020-03-20 17:07:20 +0000147 constexpr wgpu::PresentMode kAllPresentModes[] = {
148 wgpu::PresentMode::Immediate,
149 wgpu::PresentMode::Fifo,
150 wgpu::PresentMode::Mailbox,
151 };
152
153 for (wgpu::PresentMode mode1 : kAllPresentModes) {
154 for (wgpu::PresentMode mode2 : kAllPresentModes) {
155 wgpu::SwapChainDescriptor desc = baseDescriptor;
156
157 desc.presentMode = mode1;
158 wgpu::SwapChain swapchain1 = device.CreateSwapChain(surface, &desc);
159 ClearTexture(swapchain1.GetCurrentTextureView(), {0.0, 0.0, 0.0, 1.0});
160 swapchain1.Present();
161
162 desc.presentMode = mode2;
163 wgpu::SwapChain swapchain2 = device.CreateSwapChain(surface, &desc);
164 ClearTexture(swapchain2.GetCurrentTextureView(), {0.0, 0.0, 0.0, 1.0});
165 swapchain2.Present();
166 }
167 }
168}
169
170// Test resizing the swapchain and without resizing the window.
171TEST_P(SwapChainTests, ResizingSwapChainOnly) {
172 for (int i = 0; i < 10; i++) {
173 wgpu::SwapChainDescriptor desc = baseDescriptor;
174 desc.width += i * 10;
175 desc.height -= i * 10;
176
177 wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &desc);
Austin Eng80a18682020-03-23 20:10:53 +0000178 ClearTexture(swapchain.GetCurrentTextureView(), {0.05f * i, 0.0f, 0.0f, 1.0f});
Corentin Wallez11652ff2020-03-20 17:07:20 +0000179 swapchain.Present();
180 }
181}
182
183// Test resizing the window but not the swapchain.
184TEST_P(SwapChainTests, ResizingWindowOnly) {
185 wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &baseDescriptor);
186
187 for (int i = 0; i < 10; i++) {
188 glfwSetWindowSize(window, 400 - 10 * i, 400 + 10 * i);
189 glfwPollEvents();
190
Austin Eng80a18682020-03-23 20:10:53 +0000191 ClearTexture(swapchain.GetCurrentTextureView(), {0.05f * i, 0.0f, 0.0f, 1.0f});
Corentin Wallez11652ff2020-03-20 17:07:20 +0000192 swapchain.Present();
193 }
194}
195
196// Test resizing both the window and the swapchain at the same time.
197TEST_P(SwapChainTests, ResizingWindowAndSwapChain) {
198 for (int i = 0; i < 10; i++) {
199 glfwSetWindowSize(window, 400 - 10 * i, 400 + 10 * i);
200 glfwPollEvents();
201
202 int width;
203 int height;
204 glfwGetFramebufferSize(window, &width, &height);
205
206 wgpu::SwapChainDescriptor desc = baseDescriptor;
207 desc.width = width;
208 desc.height = height;
209
210 wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &desc);
Austin Eng80a18682020-03-23 20:10:53 +0000211 ClearTexture(swapchain.GetCurrentTextureView(), {0.05f * i, 0.0f, 0.0f, 1.0f});
Corentin Wallez11652ff2020-03-20 17:07:20 +0000212 swapchain.Present();
213 }
214}
215
216// Test switching devices on the same adapter.
217TEST_P(SwapChainTests, SwitchingDevice) {
Corentin Wallez25eeaa32020-10-27 11:31:26 +0000218 // The Vulkan Validation Layers incorrectly disallow gracefully passing a swapchain between two
219 // VkDevices using "vkSwapchainCreateInfoKHR::oldSwapchain".
220 // See https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/2256
Jiawei Shao44fc6e32021-05-26 01:04:32 +0000221 DAWN_SUPPRESS_TEST_IF(IsVulkan() && IsBackendValidationEnabled());
Corentin Wallez2ce1d922020-10-22 17:07:49 +0000222
223 wgpu::Device device2 = wgpu::Device::Acquire(GetAdapter().CreateDevice());
Corentin Wallez11652ff2020-03-20 17:07:20 +0000224
225 for (int i = 0; i < 3; i++) {
226 wgpu::Device deviceToUse;
227 if (i % 2 == 0) {
228 deviceToUse = device;
229 } else {
230 deviceToUse = device2;
231 }
232
233 wgpu::SwapChain swapchain = deviceToUse.CreateSwapChain(surface, &baseDescriptor);
234 swapchain.GetCurrentTextureView();
235 swapchain.Present();
236 }
237}
238
Corentin Wallez2ce1d922020-10-22 17:07:49 +0000239DAWN_INSTANTIATE_TEST(SwapChainTests, MetalBackend(), VulkanBackend());