• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // 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 
24 class SwapChainTests : public DawnTest {
25   public:
SetUp()26     void SetUp() override {
27         DawnTest::SetUp();
28         DAWN_TEST_UNSUPPORTED_IF(UsesWire());
29 
30         glfwSetErrorCallback([](int code, const char* message) {
31             dawn::ErrorLog() << "GLFW error " << code << " " << message;
32         });
33 
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         }
39 
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;
56         baseDescriptor.usage = wgpu::TextureUsage::RenderAttachment;
57         baseDescriptor.format = wgpu::TextureFormat::BGRA8Unorm;
58         baseDescriptor.presentMode = wgpu::PresentMode::Mailbox;
59     }
60 
TearDown()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         }
67         DawnTest::TearDown();
68     }
69 
ClearTexture(wgpu::TextureView view,wgpu::Color color)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.
TEST_P(SwapChainTests,Basic)91 TEST_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
TEST_P(SwapChainTests,ReplaceBasic)98 TEST_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
TEST_P(SwapChainTests,ReplaceAfterGet)109 TEST_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
TEST_P(SwapChainTests,DestroyAfterGet)119 TEST_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
TEST_P(SwapChainTests,DestroySurface)125 TEST_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
TEST_P(SwapChainTests,DestroySurfaceAfterGet)131 TEST_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.
TEST_P(SwapChainTests,SwitchPresentMode)138 TEST_P(SwapChainTests, SwitchPresentMode) {
139     // Fails with "internal drawable creation failed" on the Windows NVIDIA CQ builders but not
140     // locally.
141     DAWN_SUPPRESS_TEST_IF(IsWindows() && IsVulkan() && IsNvidia());
142 
143     // TODO(jiawei.shao@intel.com): find out why this test sometimes hangs on the latest Linux Intel
144     // Vulkan drivers.
145     DAWN_SUPPRESS_TEST_IF(IsLinux() && IsVulkan() && IsIntel());
146 
147     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.
TEST_P(SwapChainTests,ResizingSwapChainOnly)171 TEST_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);
178         ClearTexture(swapchain.GetCurrentTextureView(), {0.05f * i, 0.0f, 0.0f, 1.0f});
179         swapchain.Present();
180     }
181 }
182 
183 // Test resizing the window but not the swapchain.
TEST_P(SwapChainTests,ResizingWindowOnly)184 TEST_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 
191         ClearTexture(swapchain.GetCurrentTextureView(), {0.05f * i, 0.0f, 0.0f, 1.0f});
192         swapchain.Present();
193     }
194 }
195 
196 // Test resizing both the window and the swapchain at the same time.
TEST_P(SwapChainTests,ResizingWindowAndSwapChain)197 TEST_P(SwapChainTests, ResizingWindowAndSwapChain) {
198     // TODO(crbug.com/dawn/1205) Currently failing on new NVIDIA GTX 1660s on Linux/Vulkan.
199     DAWN_SUPPRESS_TEST_IF(IsLinux() && IsVulkan() && IsNvidia());
200     for (int i = 0; i < 10; i++) {
201         glfwSetWindowSize(window, 400 - 10 * i, 400 + 10 * i);
202         glfwPollEvents();
203 
204         int width;
205         int height;
206         glfwGetFramebufferSize(window, &width, &height);
207 
208         wgpu::SwapChainDescriptor desc = baseDescriptor;
209         desc.width = width;
210         desc.height = height;
211 
212         wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &desc);
213         ClearTexture(swapchain.GetCurrentTextureView(), {0.05f * i, 0.0f, 0.0f, 1.0f});
214         swapchain.Present();
215     }
216 }
217 
218 // Test switching devices on the same adapter.
TEST_P(SwapChainTests,SwitchingDevice)219 TEST_P(SwapChainTests, SwitchingDevice) {
220     // The Vulkan Validation Layers incorrectly disallow gracefully passing a swapchain between two
221     // VkDevices using "vkSwapchainCreateInfoKHR::oldSwapchain".
222     // See https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/2256
223     DAWN_SUPPRESS_TEST_IF(IsVulkan() && IsBackendValidationEnabled());
224 
225     wgpu::Device device2 = wgpu::Device::Acquire(GetAdapter().CreateDevice());
226 
227     for (int i = 0; i < 3; i++) {
228         wgpu::Device deviceToUse;
229         if (i % 2 == 0) {
230             deviceToUse = device;
231         } else {
232             deviceToUse = device2;
233         }
234 
235         wgpu::SwapChain swapchain = deviceToUse.CreateSwapChain(surface, &baseDescriptor);
236         swapchain.GetCurrentTextureView();
237         swapchain.Present();
238     }
239 }
240 
241 DAWN_INSTANTIATE_TEST(SwapChainTests, MetalBackend(), VulkanBackend());
242