• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 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 "utils/ComboRenderPipelineDescriptor.h"
18 #include "utils/DawnHelpers.h"
19 
20 class ViewportTest : public DawnTest {
21   protected:
CreatePipelineForTest(dawn::CompareFunction depthCompare)22     dawn::RenderPipeline CreatePipelineForTest(dawn::CompareFunction depthCompare) {
23         utils::ComboRenderPipelineDescriptor pipelineDescriptor(device);
24 
25         // Draw two triangles:
26         // 1. The top-left triangle is red. Its depth values are >= 0.5. After viewport is applied,
27         // the depth might be >= 0.25 if minDepth is 0 and maxDepth is 0.5.
28         // 2. The bottom-right triangle is green. Its depth values are <= 0.5. After viewport is
29         // applied, the depth might be <= 0.25 if minDepth is 0 and maxDepth is 0.5.
30         const char* vs =
31             R"(#version 450
32             layout(location = 0) out vec4 color;
33             const vec3 pos[6] = vec3[6](vec3(-1.0f, -1.0f, 1.0f),
34                                         vec3(-1.0f,  1.0f, 0.5f),
35                                         vec3( 1.0f, -1.0f, 0.5f),
36                                         vec3( 1.0f, -1.0f, 0.5f),
37                                         vec3(-1.0f,  1.0f, 0.5f),
38                                         vec3( 1.0f,  1.0f, 0.0f));
39             void main() {
40                 gl_Position = vec4(pos[gl_VertexIndex], 1.0);
41                 if (gl_VertexIndex < 3) {
42                     color = vec4(1.0, 0.0, 0.0, 1.0);
43                 } else {
44                     color = vec4(0.0, 1.0, 0.0, 1.0);
45                 }
46             })";
47         pipelineDescriptor.cVertexStage.module =
48             utils::CreateShaderModule(device, utils::ShaderStage::Vertex, vs);
49 
50         const char* fs =
51             R"(#version 450
52             layout(location = 0) in vec4 color;
53             layout(location = 0) out vec4 fragColor;
54             void main() {
55                fragColor = color;
56             })";
57         pipelineDescriptor.cFragmentStage.module =
58             utils::CreateShaderModule(device, utils::ShaderStage::Fragment, fs);
59 
60         pipelineDescriptor.cDepthStencilState.depthCompare = depthCompare;
61         pipelineDescriptor.depthStencilState = &pipelineDescriptor.cDepthStencilState;
62 
63         return device.CreateRenderPipeline(&pipelineDescriptor);
64     }
65 
Create2DTextureForTest(dawn::TextureFormat format)66     dawn::Texture Create2DTextureForTest(dawn::TextureFormat format) {
67         dawn::TextureDescriptor textureDescriptor;
68         textureDescriptor.dimension = dawn::TextureDimension::e2D;
69         textureDescriptor.format = format;
70         textureDescriptor.usage =
71             dawn::TextureUsageBit::OutputAttachment | dawn::TextureUsageBit::CopySrc;
72         textureDescriptor.arrayLayerCount = 1;
73         textureDescriptor.mipLevelCount = 1;
74         textureDescriptor.sampleCount = 1;
75         textureDescriptor.size = {kSize, kSize, 1};
76         return device.CreateTexture(&textureDescriptor);
77     }
78 
79     enum ColorType {
80         TopLeftTriangleColor,
81         BottomRightTriangleColor,
82         BackgroundColor,
83 
84         ColorTypeCount,
85     };
86 
87     struct ViewportParams {
88         float x, y, width, height, minDepth, maxDepth;
89     };
90 
91     struct TestInfo {
92         ViewportParams viewport;
93         ColorType topLeftPoint;
94         ColorType bottomRightPoint;
95         float clearDepth = 1.0f;
96         bool setViewport = true;
97     };
98 
DoTest(const TestInfo & info)99     void DoTest(const TestInfo& info) {
100         dawn::CommandEncoder commandEncoder = device.CreateCommandEncoder();
101 
102         // Create render targets for 2 render passes.
103         dawn::Texture colorTexture1 = Create2DTextureForTest(dawn::TextureFormat::RGBA8Unorm);
104         dawn::Texture depthStencilTexture1 =
105             Create2DTextureForTest(dawn::TextureFormat::Depth24PlusStencil8);
106 
107         dawn::Texture colorTexture2 = Create2DTextureForTest(dawn::TextureFormat::RGBA8Unorm);
108         dawn::Texture depthStencilTexture2 =
109             Create2DTextureForTest(dawn::TextureFormat::Depth24PlusStencil8);
110 
111         // Create render pass 1
112         // Note that we may explicitly call SetViewport() in this pass
113         {
114             utils::ComboRenderPassDescriptor renderPassDescriptor1(
115                 {colorTexture1.CreateDefaultView()}, depthStencilTexture1.CreateDefaultView());
116             renderPassDescriptor1.cColorAttachmentsInfoPtr[0]->clearColor = {0.0, 0.0, 1.0, 1.0};
117             renderPassDescriptor1.cColorAttachmentsInfoPtr[0]->loadOp = dawn::LoadOp::Clear;
118 
119             renderPassDescriptor1.cDepthStencilAttachmentInfo.clearDepth = info.clearDepth;
120             renderPassDescriptor1.cDepthStencilAttachmentInfo.depthLoadOp = dawn::LoadOp::Clear;
121 
122             dawn::RenderPassEncoder renderPass1 =
123                 commandEncoder.BeginRenderPass(&renderPassDescriptor1);
124             renderPass1.SetPipeline(CreatePipelineForTest(dawn::CompareFunction::Less));
125             if (info.setViewport) {
126                 ViewportParams viewport = info.viewport;
127                 renderPass1.SetViewport(viewport.x, viewport.y, viewport.width, viewport.height,
128                                         viewport.minDepth, viewport.maxDepth);
129             }
130             renderPass1.Draw(6, 1, 0, 0);
131             renderPass1.EndPass();
132         }
133 
134         // Create render pass 2
135         // Note that we never explicitly call SetViewport() in this pass.
136         // Its viewport(x, y, width, height, minDepth, maxDepth) should be
137         // (0, 0, rendertarget's width, rendertarget's height, 0.0, 1.0) by default.
138         {
139             utils::ComboRenderPassDescriptor renderPassDescriptor2(
140                 {colorTexture2.CreateDefaultView()}, depthStencilTexture2.CreateDefaultView());
141             renderPassDescriptor2.cColorAttachmentsInfoPtr[0]->clearColor = {0.0, 0.0, 1.0, 1.0};
142             renderPassDescriptor2.cColorAttachmentsInfoPtr[0]->loadOp = dawn::LoadOp::Clear;
143 
144             renderPassDescriptor2.cDepthStencilAttachmentInfo.clearDepth = 0.5;
145             renderPassDescriptor2.cDepthStencilAttachmentInfo.depthLoadOp = dawn::LoadOp::Clear;
146 
147             dawn::RenderPassEncoder renderPass2 =
148                 commandEncoder.BeginRenderPass(&renderPassDescriptor2);
149             renderPass2.SetPipeline(CreatePipelineForTest(dawn::CompareFunction::Greater));
150             renderPass2.Draw(6, 1, 0, 0);
151             renderPass2.EndPass();
152         }
153 
154         dawn::CommandBuffer commandBuffer = commandEncoder.Finish();
155         dawn::Queue queue = device.CreateQueue();
156         queue.Submit(1, &commandBuffer);
157 
158         constexpr RGBA8 kColor[ColorTypeCount] = {
159             RGBA8(255, 0, 0, 255),  // top-left triangle is red
160             RGBA8(0, 255, 0, 255),  // bottom-right triangle is green
161             RGBA8(0, 0, 255, 255),  // background is blue
162         };
163 
164         EXPECT_PIXEL_RGBA8_EQ(kColor[info.topLeftPoint], colorTexture1, 0, 0);
165         EXPECT_PIXEL_RGBA8_EQ(kColor[info.bottomRightPoint], colorTexture1, kSize - 1, kSize - 1);
166 
167         // In render pass 2. Point(0, 0) is tend to be covered by the top-left triangle. Point(3, 3)
168         // is tend to be covered by the bottom-right triangle. However, the bottom-right triangle's
169         // depth values are <= 0.5. And the depthCompare is Greater. As a result, point(0, 0) will
170         // be drawn as usual, its color is the top-left triangle's color. But point(3, 3) will not
171         // be drawn by any triangles. Its color is the backgroud color.
172         EXPECT_PIXEL_RGBA8_EQ(kColor[TopLeftTriangleColor], colorTexture2, 0, 0);
173         EXPECT_PIXEL_RGBA8_EQ(kColor[BackgroundColor], colorTexture2, kSize - 1, kSize - 1);
174     }
175 
176     static constexpr uint32_t kSize = 4;
177 };
178 
179 // The viewport is the same size as the backbuffer if it is not explicitly specified. And minDepth
180 // and maxDepth are 0.0 and 1.0 respectively. The viewport parameters below are not really used.
181 // Point(0, 0) is covered by the top-left triangle. Likewise, point(3, 3) is covered by the
182 // bottom-right triangle.
TEST_P(ViewportTest,Default)183 TEST_P(ViewportTest, Default) {
184     ViewportParams viewport = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
185     TestInfo info = {viewport, TopLeftTriangleColor, BottomRightTriangleColor, 1.0, false};
186     DoTest(info);
187 }
188 
189 // Explicitly specify the viewport as its default value. The result is the same as it is in the test
190 // above.
TEST_P(ViewportTest,Basic)191 TEST_P(ViewportTest, Basic) {
192     ViewportParams viewport = {0.0, 0.0, 4.0, 4.0, 0.0, 1.0};
193     TestInfo info = {viewport, TopLeftTriangleColor, BottomRightTriangleColor};
194     DoTest(info);
195 }
196 
197 // Shift the viewport toward top-left by (2, 2). So the top-left triangle is outside of the back
198 // buffer. We can't see it. And point(0, 0) is covered by the bottom-right triangle now. Point(3, 3)
199 // is not covered by any triangles.
TEST_P(ViewportTest,ShiftToTopLeft)200 TEST_P(ViewportTest, ShiftToTopLeft) {
201     ViewportParams viewport = {-2.0, -2.0, 4.0, 4.0, 0.0, 1.0};
202     TestInfo info = {viewport, BottomRightTriangleColor, BackgroundColor};
203     DoTest(info);
204 }
205 
206 // Shift the viewport toward bottom-right by (2, 2). So Point(0, 0) is not covered by any triangles.
207 // The top-left triangle is moved to the bottom-right of back buffer. Point(3, 3) is covered by it.
208 // While the bottom-right triangle is moved outside of back buffer now.
TEST_P(ViewportTest,ShiftToBottomRight)209 TEST_P(ViewportTest, ShiftToBottomRight) {
210     ViewportParams viewport = {2.0, 2.0, 4.0, 4.0, 0.0, 1.0};
211     TestInfo info = {viewport, BackgroundColor, TopLeftTriangleColor};
212     DoTest(info);
213 }
214 
215 // After applying the minDepth/maxDepth value in viewport and projecting to framebuffer coordinate,
216 // depth values of the top-left triangle are >= 0.25. They are greater than the depth values in
217 // depth buffer, so it is not drawn at all. As a result, point(0, 0) is not covered by any
218 // triangles. But the bottom-right triangle is drawn as usual.
TEST_P(ViewportTest,ApplyDepth)219 TEST_P(ViewportTest, ApplyDepth) {
220     ViewportParams viewport = {0.0, 0.0, 4.0, 4.0, 0.0, 0.5};
221     TestInfo info = {viewport, BackgroundColor, BottomRightTriangleColor, 0.25};
222     DoTest(info);
223 }
224 
225 // Shift the viewport toward top-left by (2, 2). So the top-left triangle is outside of the back
226 // buffer. We can't see it. And point(0, 0) is covered by the bottom-right triangle now. Its depth
227 // value is < 0.25. So it is drawn as usual. Point(3, 3) is not covered by any triangles.
TEST_P(ViewportTest,ShiftToTopLeftAndApplyDepth)228 TEST_P(ViewportTest, ShiftToTopLeftAndApplyDepth) {
229     // Test failing on Linux Vulkan Intel.
230     // See https://bugs.chromium.org/p/dawn/issues/detail?id=187
231     DAWN_SKIP_TEST_IF(IsLinux() && IsVulkan() && IsIntel());
232 
233     ViewportParams viewport = {-2.0, -2.0, 4.0, 4.0, 0.0, 0.5};
234     TestInfo info = {viewport, BottomRightTriangleColor, BackgroundColor, 0.25};
235     DoTest(info);
236 }
237 
238 // Shift the viewport toward bottom-right by (2, 2). So point(0, 0) is not covered by any triangles.
239 // The top-left triangle is moved to the bottom-right of back buffer. However, depth values of the
240 // top-left triangle are >= 0.25. They are greater than the depth values in depth buffer, so it is
241 // not drawn at all. So point(3, 3) is not covered by any triangle, either.
TEST_P(ViewportTest,ShiftToBottomRightAndApplyDepth)242 TEST_P(ViewportTest, ShiftToBottomRightAndApplyDepth) {
243     ViewportParams viewport = {2.0, 2.0, 4.0, 4.0, 0.0, 0.5};
244     TestInfo info = {viewport, BackgroundColor, BackgroundColor, 0.25};
245     DoTest(info);
246 }
247 
248 // Enlarge the viewport by 2 times. So the entire back buffer is covered by the top-left triangle.
TEST_P(ViewportTest,EnlargeViewport)249 TEST_P(ViewportTest, EnlargeViewport) {
250     ViewportParams viewport = {0.0, 0.0, 8.0, 8.0, 0.0, 1.0};
251     TestInfo info = {viewport, TopLeftTriangleColor, TopLeftTriangleColor};
252     DoTest(info);
253 }
254 
255 // Enlarge the viewport by 2 times and shift toward top-left by (2, 2). back buffer sits exactly
256 // at the center of the whole viewport. So, point(0, 0) is covered by the top-left triangle, and
257 // point(3, 3) is covered by the bottom-right triangle.
TEST_P(ViewportTest,EnlargeViewportAndShiftToTopLeft)258 TEST_P(ViewportTest, EnlargeViewportAndShiftToTopLeft) {
259     ViewportParams viewport = {-2.0, -2.0, 8.0, 8.0, 0.0, 1.0};
260     TestInfo info = {viewport, TopLeftTriangleColor, BottomRightTriangleColor};
261     DoTest(info);
262 }
263 
264 // Enlarge the viewport by 2 times and shift toward bottom-right by (2, 2). Point(0, 0) is not
265 // covered by any triangle. Point(3, 3) is covered by the top-left triangle.
TEST_P(ViewportTest,EnlargeViewportAndShiftToBottomRight)266 TEST_P(ViewportTest, EnlargeViewportAndShiftToBottomRight) {
267     ViewportParams viewport = {2.0, 2.0, 8.0, 8.0, 0.0, 1.0};
268     TestInfo info = {viewport, BackgroundColor, TopLeftTriangleColor};
269     DoTest(info);
270 }
271 
272 // Enlarge the viewport by 2 times. So the entire back buffer tend to be covered by the top-left
273 // triangle. However, depth values of the top-left triangle are >= 0.25. They are greater than the
274 // depth values in depth buffer, so the top-left triangle is not drawn at all. As a result, neither
275 // point(0, 0) nor point(3, 3) is covered by any triangles.
TEST_P(ViewportTest,EnlargeViewportAndApplyDepth)276 TEST_P(ViewportTest, EnlargeViewportAndApplyDepth) {
277     ViewportParams viewport = {0.0, 0.0, 8.0, 8.0, 0.0, 0.5};
278     TestInfo info = {viewport, BackgroundColor, BackgroundColor, 0.25};
279     DoTest(info);
280 }
281 
282 // Enlarge the viewport by 2 times and shift toward top-left by (2, 2). The back buffer sits exactly
283 // at the center of the whole viewport. However, depth values of the top-left triangle are >= 0.25.
284 // They are greater than the depth values in depth buffer, so the top-left triangle is not drawn at
285 // all. As a result, point(0, 0) is not covered by it. The bottom-right triangle is drawn because
286 // its depth values are < 0.25. So point(3, 3) is covered by it as usual.
TEST_P(ViewportTest,EnlargeViewportAndShiftToTopLeftAndApplyDepth)287 TEST_P(ViewportTest, EnlargeViewportAndShiftToTopLeftAndApplyDepth) {
288     // Test failing on Linux Vulkan Intel.
289     // See https://bugs.chromium.org/p/dawn/issues/detail?id=187
290     DAWN_SKIP_TEST_IF(IsLinux() && IsVulkan() && IsIntel());
291 
292     ViewportParams viewport = {-2.0, -2.0, 8.0, 8.0, 0.0, 0.5};
293     TestInfo info = {viewport, BackgroundColor, BottomRightTriangleColor, 0.25};
294     DoTest(info);
295 }
296 
297 // Enlarge the viewport by 2 times and shift toward bottom-right by (2, 2). Point(0, 0) is not
298 // covered by any triangle. The point(3, 3) tend to be covered by the top-left triangle. However,
299 // depth values of the top-left triangle are >= 0.25. They are greater than the depth values in
300 // depth buffer, so the top-left triangle is not drawn at all. As a result, point(3, 3) is not
301 // covered by any triangle, either.
TEST_P(ViewportTest,EnlargeViewportAndShiftToBottomRightAndApplyDepth)302 TEST_P(ViewportTest, EnlargeViewportAndShiftToBottomRightAndApplyDepth) {
303     ViewportParams viewport = {2.0, 2.0, 8.0, 8.0, 0.0, 0.5};
304     TestInfo info = {viewport, BackgroundColor, BackgroundColor, 0.25};
305     DoTest(info);
306 }
307 
308 // Shrink the viewport to its half. So point(0, 0) is covered by the top-left triangle, while
309 // point(3, 3) is not covered by any triangles because the drawing area is too small to cover the
310 // entire back buffer.
TEST_P(ViewportTest,ShrinkViewport)311 TEST_P(ViewportTest, ShrinkViewport) {
312     ViewportParams viewport = {0.0, 0.0, 2.0, 2.0, 0.0, 1.0};
313     TestInfo info = {viewport, TopLeftTriangleColor, BackgroundColor};
314     DoTest(info);
315 }
316 
317 // Shrink the viewport to its half and move toward top-left by (1, 1), So point(0, 0) is covered by
318 // bottom-right triangle, while point(3, 3) is not covered by any triangles.
TEST_P(ViewportTest,ShrinkViewportAndShiftToTopLeft)319 TEST_P(ViewportTest, ShrinkViewportAndShiftToTopLeft) {
320     ViewportParams viewport = {-1.0, -1.0, 2.0, 2.0, 0.0, 1.0};
321     TestInfo info = {viewport, BottomRightTriangleColor, BackgroundColor};
322     DoTest(info);
323 }
324 
325 // Shrink the viewport to its half and move toward bottom-right by (3, 3), So point(0, 0) is not
326 // covered by any triangles, and point(3, 3) is covered by the bottom-right triangle.
TEST_P(ViewportTest,ShrinkViewportAndShiftToBottomRight)327 TEST_P(ViewportTest, ShrinkViewportAndShiftToBottomRight) {
328     ViewportParams viewport = {3.0, 3.0, 2.0, 2.0, 0.0, 1.0};
329     TestInfo info = {viewport, BackgroundColor, TopLeftTriangleColor};
330     DoTest(info);
331 }
332 
333 // Shrink the viewport to its half. So point(0, 0) is tend to be covered by top-left triangle.
334 // However, depth values of the top-left triangle are >= 0.25. They are greater than the depth
335 // values in depth buffer, so the top-left triangle is not drawn at all. As a result, point(0, 0)
336 // is not covered by any triangle. Point(3, 3) is not covered by any triangles, either. Because the
337 // drawing area is too small to cover the entire back buffer.
TEST_P(ViewportTest,ShrinkViewportAndApplyDepth)338 TEST_P(ViewportTest, ShrinkViewportAndApplyDepth) {
339     ViewportParams viewport = {0.0, 0.0, 2.0, 2.0, 0.0, 0.5};
340     TestInfo info = {viewport, BackgroundColor, BackgroundColor, 0.25};
341     DoTest(info);
342 }
343 
344 // Shrink the viewport to its half and move toward top-left by (1, 1), So point(0, 0) is covered by
345 // the bottom-right triangle, while point(3, 3) is not covered by any triangles.
TEST_P(ViewportTest,ShrinkViewportAndShiftToTopLeftAndApplyDepth)346 TEST_P(ViewportTest, ShrinkViewportAndShiftToTopLeftAndApplyDepth) {
347     // Test failing on Linux Vulkan Intel.
348     // See https://bugs.chromium.org/p/dawn/issues/detail?id=187
349     DAWN_SKIP_TEST_IF(IsLinux() && IsVulkan() && IsIntel());
350 
351     ViewportParams viewport = {-1.0, -1.0, 2.0, 2.0, 0.0, 0.5};
352     TestInfo info = {viewport, BottomRightTriangleColor, BackgroundColor, 0.25};
353     DoTest(info);
354 }
355 
356 // Shrink the viewport to its half and move toward bottom-right by (3, 3), So point(0, 0) is not
357 // covered by any triangle. Point(3, 3) is tend to be covered by the top-left triangle. However,
358 // depth values of the top-left triangle are >= 0.25. They are greater than the depth values in
359 // depth buffer, so the top-left triangle is not drawn at all. As a result, point(3, 3) is not
360 // covered by any triangle, either.
TEST_P(ViewportTest,ShrinkViewportAndShiftToBottomRightAndApplyDepth)361 TEST_P(ViewportTest, ShrinkViewportAndShiftToBottomRightAndApplyDepth) {
362     ViewportParams viewport = {3.0, 3.0, 2.0, 2.0, 0.0, 0.5};
363     TestInfo info = {viewport, BackgroundColor, BackgroundColor, 0.25};
364     DoTest(info);
365 }
366 
367 DAWN_INSTANTIATE_TEST(ViewportTest, OpenGLBackend, VulkanBackend);
368