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