1 //
2 // Copyright 2015 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 #include "test_utils/ANGLETest.h"
8
9 using namespace angle;
10
11 namespace
12 {
13
14 class ViewportTest : public ANGLETest
15 {
16 protected:
ViewportTest()17 ViewportTest()
18 {
19 setWindowWidth(512);
20 setWindowHeight(512);
21 setConfigRedBits(8);
22 setConfigGreenBits(8);
23 setConfigBlueBits(8);
24 setConfigAlphaBits(8);
25 setConfigDepthBits(24);
26
27 mProgram = 0;
28 }
29
runNonScissoredTest()30 void runNonScissoredTest()
31 {
32 glClearColor(0, 0, 0, 1);
33 glClear(GL_COLOR_BUFFER_BIT);
34
35 runTest();
36 }
37
runScissoredTest()38 void runScissoredTest()
39 {
40 glClearColor(0, 0, 0, 1);
41 glClear(GL_COLOR_BUFFER_BIT);
42
43 glEnable(GL_SCISSOR_TEST);
44 glScissor(0, getWindowHeight() / 2, getWindowWidth(), getWindowHeight() / 2);
45
46 runTest();
47 }
48
runTest()49 void runTest()
50 {
51 // Firstly ensure that no errors have been hit.
52 EXPECT_GL_NO_ERROR();
53
54 GLint viewportSize[4];
55 glGetIntegerv(GL_VIEWPORT, viewportSize);
56
57 // Clear to green. Might be a scissored clear, if scissorSize != window size
58 glClearColor(0, 1, 0, 1);
59 glClear(GL_COLOR_BUFFER_BIT);
60
61 // Draw a red quad centered in the middle of the viewport, with dimensions 25% of the size of the viewport.
62 drawQuad(mProgram, "position", 0.5f, 0.25f);
63
64 GLint centerViewportX = viewportSize[0] + (viewportSize[2] / 2);
65 GLint centerViewportY = viewportSize[1] + (viewportSize[3] / 2);
66
67 GLint redQuadLeftSideX = viewportSize[0] + viewportSize[2] * 3 / 8;
68 GLint redQuadRightSideX = viewportSize[0] + viewportSize[2] * 5 / 8;
69 GLint redQuadTopSideY = viewportSize[1] + viewportSize[3] * 3 / 8;
70 GLint redQuadBottomSideY = viewportSize[1] + viewportSize[3] * 5 / 8;
71
72 // The midpoint of the viewport should be red.
73 checkPixel(centerViewportX, centerViewportY, true);
74
75 // Pixels just inside the red quad should be red.
76 checkPixel(redQuadLeftSideX, redQuadTopSideY, true);
77 checkPixel(redQuadLeftSideX, redQuadBottomSideY - 1, true);
78 checkPixel(redQuadRightSideX - 1, redQuadTopSideY, true);
79 checkPixel(redQuadRightSideX - 1, redQuadBottomSideY - 1, true);
80
81 // Pixels just outside the red quad shouldn't be red.
82 checkPixel(redQuadLeftSideX - 1, redQuadTopSideY - 1, false);
83 checkPixel(redQuadLeftSideX - 1, redQuadBottomSideY, false);
84 checkPixel(redQuadRightSideX, redQuadTopSideY - 1, false);
85 checkPixel(redQuadRightSideX, redQuadBottomSideY, false);
86
87 // Pixels just within the viewport shouldn't be red.
88 checkPixel(viewportSize[0], viewportSize[1], false);
89 checkPixel(viewportSize[0], viewportSize[1] + viewportSize[3] - 1, false);
90 checkPixel(viewportSize[0] + viewportSize[2] - 1, viewportSize[1], false);
91 checkPixel(viewportSize[0] + viewportSize[2] - 1, viewportSize[1] + viewportSize[3] - 1, false);
92 }
93
checkPixel(GLint x,GLint y,GLboolean renderedRed)94 void checkPixel(GLint x, GLint y, GLboolean renderedRed)
95 {
96 // By default, expect the pixel to be black.
97 GLint expectedRedChannel = 0;
98 GLint expectedGreenChannel = 0;
99
100 GLint scissorSize[4];
101 glGetIntegerv(GL_SCISSOR_BOX, scissorSize);
102
103 EXPECT_GL_NO_ERROR();
104
105 if (scissorSize[0] <= x && x < scissorSize[0] + scissorSize[2]
106 && scissorSize[1] <= y && y < scissorSize[1] + scissorSize[3])
107 {
108 // If the pixel lies within the scissor rect, then it should have been cleared to green.
109 // If we rendered a red square on top of it, then the pixel should be red (the green channel will have been reset to 0).
110 expectedRedChannel = renderedRed ? 255 : 0;
111 expectedGreenChannel = renderedRed ? 0 : 255;
112 }
113
114 // If the pixel is within the bounds of the window, then we check it. Otherwise we skip it.
115 if (0 <= x && x < getWindowWidth() && 0 <= y && y < getWindowHeight())
116 {
117 EXPECT_PIXEL_EQ(x, y, expectedRedChannel, expectedGreenChannel, 0, 255);
118 }
119 }
120
SetUp()121 void SetUp() override
122 {
123 ANGLETest::SetUp();
124
125 const std::string testVertexShaderSource = SHADER_SOURCE
126 (
127 attribute highp vec4 position;
128
129 void main(void)
130 {
131 gl_Position = position;
132 }
133 );
134
135 const std::string testFragmentShaderSource = SHADER_SOURCE
136 (
137 void main(void)
138 {
139 gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
140 }
141 );
142
143 mProgram = CompileProgram(testVertexShaderSource, testFragmentShaderSource);
144 if (mProgram == 0)
145 {
146 FAIL() << "shader compilation failed.";
147 }
148
149 glUseProgram(mProgram);
150
151 glClearColor(0, 0, 0, 1);
152 glClearDepthf(0.0);
153 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
154
155 // Call glViewport and glScissor with default parameters.
156 glScissor(0, 0, getWindowWidth(), getWindowHeight());
157 glViewport(0, 0, getWindowWidth(), getWindowHeight());
158
159 glDisable(GL_DEPTH_TEST);
160 }
161
TearDown()162 void TearDown() override
163 {
164 glDeleteProgram(mProgram);
165
166 ANGLETest::TearDown();
167 }
168
169 GLuint mProgram;
170 };
171
TEST_P(ViewportTest,QuarterWindow)172 TEST_P(ViewportTest, QuarterWindow)
173 {
174 glViewport(0, 0, getWindowWidth() / 4, getWindowHeight() / 4);
175
176 runNonScissoredTest();
177
178 runScissoredTest();
179 }
180
TEST_P(ViewportTest,QuarterWindowCentered)181 TEST_P(ViewportTest, QuarterWindowCentered)
182 {
183 glViewport(getWindowWidth() * 3 / 8, getWindowHeight() * 3 / 8, getWindowWidth() / 4, getWindowHeight() / 4);
184
185 runNonScissoredTest();
186
187 runScissoredTest();
188 }
189
TEST_P(ViewportTest,FullWindow)190 TEST_P(ViewportTest, FullWindow)
191 {
192 glViewport(0, 0, getWindowWidth(), getWindowHeight());
193
194 runNonScissoredTest();
195
196 runScissoredTest();
197 }
198
TEST_P(ViewportTest,FullWindowOffCenter)199 TEST_P(ViewportTest, FullWindowOffCenter)
200 {
201 glViewport(-getWindowWidth() / 2, getWindowHeight() / 2, getWindowWidth(), getWindowHeight());
202
203 runNonScissoredTest();
204
205 runScissoredTest();
206 }
207
TEST_P(ViewportTest,DoubleWindow)208 TEST_P(ViewportTest, DoubleWindow)
209 {
210 glViewport(0, 0, getWindowWidth() * 2, getWindowHeight() * 2);
211
212 runNonScissoredTest();
213
214 runScissoredTest();
215 }
216
TEST_P(ViewportTest,DoubleWindowCentered)217 TEST_P(ViewportTest, DoubleWindowCentered)
218 {
219 glViewport(-getWindowWidth() / 2, -getWindowHeight() / 2, getWindowWidth() * 2, getWindowHeight() * 2);
220
221 runNonScissoredTest();
222
223 runScissoredTest();
224 }
225
TEST_P(ViewportTest,DoubleWindowOffCenter)226 TEST_P(ViewportTest, DoubleWindowOffCenter)
227 {
228 glViewport(-getWindowWidth() * 3 / 4, getWindowHeight() * 3 / 4, getWindowWidth(), getWindowHeight());
229
230 runNonScissoredTest();
231
232 runScissoredTest();
233 }
234
TEST_P(ViewportTest,TripleWindow)235 TEST_P(ViewportTest, TripleWindow)
236 {
237 glViewport(0, 0, getWindowWidth() * 3, getWindowHeight() * 3);
238
239 runNonScissoredTest();
240
241 runScissoredTest();
242 }
243
TEST_P(ViewportTest,TripleWindowCentered)244 TEST_P(ViewportTest, TripleWindowCentered)
245 {
246 glViewport(-getWindowWidth(), -getWindowHeight(), getWindowWidth() * 3, getWindowHeight() * 3);
247
248 runNonScissoredTest();
249
250 runScissoredTest();
251 }
252
TEST_P(ViewportTest,TripleWindowOffCenter)253 TEST_P(ViewportTest, TripleWindowOffCenter)
254 {
255 glViewport(-getWindowWidth() * 3 / 2, -getWindowHeight() * 3 / 2, getWindowWidth() * 3, getWindowHeight() * 3);
256
257 runNonScissoredTest();
258
259 runScissoredTest();
260 }
261
262 // Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
263 // D3D11 Feature Level 9 and D3D9 emulate large and negative viewports in the vertex shader. We should test both of these as well as D3D11 Feature Level 10_0+.
264 ANGLE_INSTANTIATE_TEST(ViewportTest,
265 ES2_D3D9(),
266 ES2_D3D11(EGL_EXPERIMENTAL_PRESENT_PATH_COPY_ANGLE),
267 ES2_D3D11(EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE),
268 ES2_D3D11_FL9_3(),
269 ES2_OPENGLES(),
270 ES3_OPENGLES());
271
272 } // namespace
273