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 class BlendMinMaxTest : public ANGLETest
12 {
13   protected:
BlendMinMaxTest()14     BlendMinMaxTest()
15     {
16         setWindowWidth(128);
17         setWindowHeight(128);
18         setConfigRedBits(8);
19         setConfigGreenBits(8);
20         setConfigBlueBits(8);
21         setConfigAlphaBits(8);
22         setConfigDepthBits(24);
23 
24         mProgram = 0;
25         mColorLocation = -1;
26         mFramebuffer = 0;
27         mColorRenderbuffer = 0;
28     }
29 
30     struct Color
31     {
32         float values[4];
33     };
34 
getExpected(bool blendMin,float curColor,float prevColor)35     static float getExpected(bool blendMin, float curColor, float prevColor)
36     {
37         return blendMin ? std::min(curColor, prevColor) : std::max(curColor, prevColor);
38     }
39 
runTest(GLenum colorFormat,GLenum type)40     void runTest(GLenum colorFormat, GLenum type)
41     {
42         if (getClientMajorVersion() < 3 && !extensionEnabled("GL_EXT_blend_minmax"))
43         {
44             std::cout << "Test skipped because ES3 or GL_EXT_blend_minmax is not available." << std::endl;
45             return;
46         }
47 
48         // TODO(geofflang): figure out why this fails
49         if (IsIntel() && GetParam() == ES2_OPENGL())
50         {
51             std::cout << "Test skipped on OpenGL Intel due to flakyness." << std::endl;
52             return;
53         }
54 
55         SetUpFramebuffer(colorFormat);
56 
57         int minValue = 0;
58         int maxValue = 1;
59         if (type == GL_FLOAT)
60         {
61             minValue = -1024;
62             maxValue = 1024;
63         }
64 
65         const size_t colorCount = 128;
66         Color colors[colorCount];
67         for (size_t i = 0; i < colorCount; i++)
68         {
69             for (size_t j = 0; j < 4; j++)
70             {
71                 colors[i].values[j] =
72                     static_cast<float>(minValue + (rand() % (maxValue - minValue)));
73             }
74         }
75 
76         float prevColor[4];
77         for (size_t i = 0; i < colorCount; i++)
78         {
79             const Color &color = colors[i];
80             glUseProgram(mProgram);
81             glUniform4f(mColorLocation, color.values[0], color.values[1], color.values[2], color.values[3]);
82 
83             bool blendMin = (rand() % 2 == 0);
84             glBlendEquation(blendMin ? GL_MIN : GL_MAX);
85 
86             drawQuad(mProgram, "aPosition", 0.5f);
87 
88             float pixel[4];
89             if (type == GL_UNSIGNED_BYTE)
90             {
91                 GLubyte ubytePixel[4];
92                 glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, ubytePixel);
93                 for (size_t componentIdx = 0; componentIdx < ArraySize(pixel); componentIdx++)
94                 {
95                     pixel[componentIdx] = ubytePixel[componentIdx] / 255.0f;
96                 }
97             }
98             else if (type == GL_FLOAT)
99             {
100                 glReadPixels(0, 0, 1, 1, GL_RGBA, GL_FLOAT, pixel);
101             }
102             else
103             {
104                 FAIL() << "Unexpected pixel type";
105             }
106 
107             if (i > 0)
108             {
109                 const float errorRange = 1.0f / 255.0f;
110                 for (size_t componentIdx = 0; componentIdx < ArraySize(pixel); componentIdx++)
111                 {
112                     EXPECT_NEAR(
113                         getExpected(blendMin, color.values[componentIdx], prevColor[componentIdx]),
114                         pixel[componentIdx], errorRange);
115                 }
116             }
117 
118             memcpy(prevColor, pixel, sizeof(pixel));
119         }
120     }
121 
SetUp()122     virtual void SetUp()
123     {
124         ANGLETest::SetUp();
125 
126         const std::string testVertexShaderSource = SHADER_SOURCE
127         (
128             attribute highp vec4 aPosition;
129 
130             void main(void)
131             {
132                 gl_Position = aPosition;
133             }
134         );
135 
136         const std::string testFragmentShaderSource = SHADER_SOURCE
137         (
138             uniform highp vec4 color;
139             void main(void)
140             {
141                 gl_FragColor = color;
142             }
143         );
144 
145         mProgram = CompileProgram(testVertexShaderSource, testFragmentShaderSource);
146         if (mProgram == 0)
147         {
148             FAIL() << "shader compilation failed.";
149         }
150 
151         mColorLocation = glGetUniformLocation(mProgram, "color");
152 
153         glUseProgram(mProgram);
154 
155         glClearColor(0, 0, 0, 0);
156         glClearDepthf(0.0);
157         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
158 
159         glEnable(GL_BLEND);
160         glDisable(GL_DEPTH_TEST);
161     }
162 
SetUpFramebuffer(GLenum colorFormat)163     void SetUpFramebuffer(GLenum colorFormat)
164     {
165         glGenFramebuffers(1, &mFramebuffer);
166         glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mFramebuffer);
167         glBindFramebuffer(GL_READ_FRAMEBUFFER, mFramebuffer);
168 
169         glGenRenderbuffers(1, &mColorRenderbuffer);
170         glBindRenderbuffer(GL_RENDERBUFFER, mColorRenderbuffer);
171         glRenderbufferStorage(GL_RENDERBUFFER, colorFormat, getWindowWidth(), getWindowHeight());
172         glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, mColorRenderbuffer);
173 
174         glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
175         glClear(GL_COLOR_BUFFER_BIT);
176 
177         ASSERT_GL_NO_ERROR();
178     }
179 
TearDown()180     virtual void TearDown()
181     {
182         glDeleteProgram(mProgram);
183         glDeleteFramebuffers(1, &mFramebuffer);
184         glDeleteRenderbuffers(1, &mColorRenderbuffer);
185 
186         ANGLETest::TearDown();
187     }
188 
189     GLuint mProgram;
190     GLint mColorLocation;
191 
192     GLuint mFramebuffer;
193     GLuint mColorRenderbuffer;
194 };
195 
TEST_P(BlendMinMaxTest,RGBA8)196 TEST_P(BlendMinMaxTest, RGBA8)
197 {
198     runTest(GL_RGBA8, GL_UNSIGNED_BYTE);
199 }
200 
TEST_P(BlendMinMaxTest,RGBA32F)201 TEST_P(BlendMinMaxTest, RGBA32F)
202 {
203     if (getClientMajorVersion() < 3 || !extensionEnabled("GL_EXT_color_buffer_float"))
204     {
205         std::cout << "Test skipped because ES3 and GL_EXT_color_buffer_float are not available."
206                   << std::endl;
207         return;
208     }
209 
210     // TODO(jmadill): Figure out why this is broken on Intel
211     if (IsIntel() && (GetParam() == ES2_D3D11() || GetParam() == ES2_D3D9()))
212     {
213         std::cout << "Test skipped on Intel OpenGL." << std::endl;
214         return;
215     }
216 
217     // TODO (bug 1284): Investigate RGBA32f D3D SDK Layers messages on D3D11_FL9_3
218     if (IsD3D11_FL93())
219     {
220         std::cout << "Test skipped on Feature Level 9_3." << std::endl;
221         return;
222     }
223 
224     runTest(GL_RGBA32F, GL_FLOAT);
225 }
226 
TEST_P(BlendMinMaxTest,RGBA16F)227 TEST_P(BlendMinMaxTest, RGBA16F)
228 {
229     if (getClientMajorVersion() < 3 && !extensionEnabled("GL_EXT_color_buffer_half_float"))
230     {
231         std::cout << "Test skipped because ES3 or GL_EXT_color_buffer_half_float is not available."
232                   << std::endl;
233         return;
234     }
235 
236     // TODO(jmadill): figure out why this fails
237     if (IsIntel() && (GetParam() == ES2_D3D11() || GetParam() == ES2_D3D9()))
238     {
239         std::cout << "Test skipped on Intel due to failures." << std::endl;
240         return;
241     }
242 
243     runTest(GL_RGBA16F, GL_FLOAT);
244 }
245 
246 // Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
247 ANGLE_INSTANTIATE_TEST(BlendMinMaxTest,
248                        ES2_D3D9(),
249                        ES2_D3D11(),
250                        ES3_D3D11(),
251                        ES2_D3D11_FL9_3(),
252                        ES2_OPENGL(),
253                        ES3_OPENGL(),
254                        ES2_OPENGLES(),
255                        ES3_OPENGLES());
256