• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2016 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 // CHROMIUMFramebufferMixedSamplesTest
7 //   Test CHROMIUM subset of NV_framebuffer_mixed_samples.
8 //   This extension allows rendering to a framebuffer that has different
9 //   sample counts for different render buffers (stencil, depth, color)
10 
11 #include "test_utils/ANGLETest.h"
12 
13 using namespace angle;
14 
15 namespace
16 {
17 
18 const GLuint kWidth  = 100;
19 const GLuint kHeight = 100;
20 
21 class CHROMIUMFramebufferMixedSamplesTest : public ANGLETest<>
22 {
23   protected:
24     enum SetupFBOType
25     {
26         MixedSampleFBO,   // 1 color sample, N stencil samples.
27         SingleSampleFBO,  // 1 color sample, 1 stencil sample.
28     };
29 
isApplicable() const30     bool isApplicable() const
31     {
32         return IsGLExtensionEnabled("GL_CHROMIUM_framebuffer_mixed_samples") &&
33                IsGLExtensionEnabled("GL_OES_rgb8_rgba8");
34     }
35 
testSetUp()36     void testSetUp() override
37     {
38         mProgram = CompileProgram(essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
39 
40         GLuint position_loc = glGetAttribLocation(mProgram, essl1_shaders::PositionAttrib());
41         mColorLoc           = glGetUniformLocation(mProgram, essl1_shaders::ColorUniform());
42 
43         glGenBuffers(1, &mVBO);
44         glBindBuffer(GL_ARRAY_BUFFER, mVBO);
45 
46         static float vertices[] = {
47             1.0f,  1.0f, -1.0f, 1.0f,  -1.0f, -1.0f, -1.0f, 1.0f, -1.0f,
48             -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, 1.0f,  -1.0f, 1.0f, 1.0f,
49         };
50         glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
51         glEnableVertexAttribArray(position_loc);
52         glVertexAttribPointer(position_loc, 2, GL_FLOAT, GL_FALSE, 0, 0);
53 
54         ASSERT_GL_NO_ERROR();
55     }
56 
testTearDown()57     void testTearDown() override
58     {
59         glDeleteBuffers(1, &mVBO);
60         glDeleteProgram(mProgram);
61 
62         ASSERT_GL_NO_ERROR();
63     }
64 
prepareForDraw(SetupFBOType fbo_type)65     void prepareForDraw(SetupFBOType fbo_type)
66     {
67         glActiveTexture(GL_TEXTURE0);
68         glGenTextures(1, &mTexture);
69         glBindTexture(GL_TEXTURE_2D, mTexture);
70         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
71         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
72         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
73         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
74         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
75                      nullptr);
76         glBindTexture(GL_TEXTURE_2D, 0);
77 
78         glGenRenderbuffers(1, &mStencilRB);
79         glBindRenderbuffer(GL_RENDERBUFFER, mStencilRB);
80 
81         if (fbo_type == MixedSampleFBO)
82         {
83             // Create a sample buffer.
84             GLsizei num_samples = 8, max_samples = 0;
85             glGetIntegerv(GL_MAX_SAMPLES, &max_samples);
86             num_samples = std::min(num_samples, max_samples);
87             glRenderbufferStorageMultisampleANGLE(GL_RENDERBUFFER, num_samples, GL_STENCIL_INDEX8,
88                                                   kWidth, kHeight);
89             GLint param = 0;
90             glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, &param);
91             EXPECT_GT(param, 1);
92         }
93         else
94         {
95             glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, kWidth, kHeight);
96         }
97         glBindRenderbuffer(GL_RENDERBUFFER, 0);
98 
99         glGenFramebuffers(1, &mSampleFBO);
100         glBindFramebuffer(GL_FRAMEBUFFER, mSampleFBO);
101         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTexture, 0);
102         glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
103                                   mStencilRB);
104         EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
105                   glCheckFramebufferStatus(GL_FRAMEBUFFER));
106 
107         glUseProgram(mProgram);
108         glBindBuffer(GL_ARRAY_BUFFER, 0);
109         glViewport(0, 0, kWidth, kHeight);
110         glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
111         glClearStencil(1);
112         glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
113         glEnable(GL_STENCIL_TEST);
114         glEnable(GL_BLEND);
115         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
116         glStencilMask(0xffffffff);
117         glStencilFunc(GL_EQUAL, 1, 0xffffffff);
118         glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO);
119 
120         ASSERT_GL_NO_ERROR();
121     }
122 
cleanup()123     void cleanup()
124     {
125         glBindFramebuffer(GL_FRAMEBUFFER, 0);
126         glDeleteFramebuffers(1, &mSampleFBO);
127         glDeleteTextures(1, &mTexture);
128         glDeleteRenderbuffers(1, &mStencilRB);
129 
130         ASSERT_GL_NO_ERROR();
131     }
132 
133     GLuint mSampleFBO;
134     GLuint mStencilRB;
135     GLuint mTexture;
136 
137     GLuint mProgram;
138     GLuint mVBO;
139     GLint mColorLoc;
140 };
141 
142 }  // namespace
143 
TEST_P(CHROMIUMFramebufferMixedSamplesTest,StateSettingTest)144 TEST_P(CHROMIUMFramebufferMixedSamplesTest, StateSettingTest)
145 {
146     if (!isApplicable())
147     {
148         return;
149     }
150 
151     GLint value = -1;
152     glGetIntegerv(GL_COVERAGE_MODULATION_CHROMIUM, &value);
153     EXPECT_EQ(GL_NONE, value);
154     GLenum kValues[] = {GL_NONE, GL_RGB, GL_RGBA, GL_ALPHA};
155     for (auto expect : kValues)
156     {
157         glCoverageModulationCHROMIUM(expect);
158         value = -1;
159         glGetIntegerv(GL_COVERAGE_MODULATION_CHROMIUM, &value);
160         EXPECT_EQ(expect, static_cast<GLenum>(value));
161         EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
162     }
163 
164     glCoverageModulationCHROMIUM(GL_BYTE);
165     EXPECT_EQ(static_cast<GLenum>(GL_INVALID_ENUM), glGetError());
166     value = -1;
167     glGetIntegerv(GL_COVERAGE_MODULATION_CHROMIUM, &value);
168     EXPECT_EQ(static_cast<GLenum>(GL_ALPHA), static_cast<GLenum>(value));
169     EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
170 }
171 
172 // The test pattern is as follows:
173 // A green triangle (bottom left, top right, top left).
174 // A blue triangle (top left, bottom right, bottom left).
175 // The triangles will overlap but overlap only contains green pixels,
176 // due to each draw erasing its area from stencil.
177 // The blue triangle will fill only the area (bottom left, center,
178 // bottom right).
179 
180 // The test tests that CoverageModulation call works.
181 // The fractional pixels of both triangles end up being modulated
182 // by the coverage of the fragment. Test that drawing with and without
183 // CoverageModulation causes the result to be different.
TEST_P(CHROMIUMFramebufferMixedSamplesTest,CoverageModulation)184 TEST_P(CHROMIUMFramebufferMixedSamplesTest, CoverageModulation)
185 {
186     if (!isApplicable())
187     {
188         return;
189     }
190     static const float kBlue[]  = {0.0f, 0.0f, 1.0f, 1.0f};
191     static const float kGreen[] = {0.0f, 1.0f, 0.0f, 1.0f};
192     std::unique_ptr<uint8_t[]> results[3];
193     const GLint kResultSize = kWidth * kHeight * 4;
194 
195     for (int pass = 0; pass < 3; ++pass)
196     {
197         prepareForDraw(MixedSampleFBO);
198         if (pass == 1)
199         {
200             glCoverageModulationCHROMIUM(GL_RGBA);
201         }
202         glUniform4fv(mColorLoc, 1, kGreen);
203         glDrawArrays(GL_TRIANGLES, 0, 3);
204 
205         glUniform4fv(mColorLoc, 1, kBlue);
206         glDrawArrays(GL_TRIANGLES, 3, 3);
207         if (pass == 1)
208         {
209             glCoverageModulationCHROMIUM(GL_NONE);
210         }
211         results[pass].reset(new uint8_t[kResultSize]);
212         memset(results[pass].get(), 123u, kResultSize);
213         glReadPixels(0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, results[pass].get());
214 
215         cleanup();
216     }
217 
218     EXPECT_NE(0, memcmp(results[0].get(), results[1].get(), kResultSize));
219     // Verify that rendering is deterministic, so that the pass above does not
220     // come from non-deterministic rendering.
221     EXPECT_EQ(0, memcmp(results[0].get(), results[2].get(), kResultSize));
222 }
223 
224 // The test tests that the stencil buffer can be multisampled, even though the
225 // color buffer is single-sampled. Draws the same pattern with single-sample
226 // stencil buffer and with multisample stencil buffer. The images should differ.
TEST_P(CHROMIUMFramebufferMixedSamplesTest,MultisampleStencilEffective)227 TEST_P(CHROMIUMFramebufferMixedSamplesTest, MultisampleStencilEffective)
228 {
229     if (!isApplicable())
230     {
231         return;
232     }
233 
234     static const float kBlue[]  = {0.0f, 0.0f, 1.0f, 1.0f};
235     static const float kGreen[] = {0.0f, 1.0f, 0.0f, 1.0f};
236 
237     std::unique_ptr<uint8_t[]> results[3];
238     const GLint kResultSize = kWidth * kHeight * 4;
239 
240     for (int pass = 0; pass < 3; ++pass)
241     {
242         if (pass == 1)
243         {
244             prepareForDraw(MixedSampleFBO);
245         }
246         else
247         {
248             prepareForDraw(SingleSampleFBO);
249         }
250         glUniform4fv(mColorLoc, 1, kGreen);
251         glDrawArrays(GL_TRIANGLES, 0, 3);
252 
253         glUniform4fv(mColorLoc, 1, kBlue);
254         glDrawArrays(GL_TRIANGLES, 3, 3);
255 
256         results[pass].reset(new uint8_t[kResultSize]);
257         memset(results[pass].get(), 12u, kResultSize);
258         glReadPixels(0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, results[pass].get());
259 
260         cleanup();
261     }
262 
263     EXPECT_NE(0, memcmp(results[0].get(), results[1].get(), kResultSize));
264     // Verify that rendering is deterministic, so that the pass above does not
265     // come from non-deterministic rendering.
266     EXPECT_EQ(0, memcmp(results[0].get(), results[2].get(), kResultSize));
267 }
268 
269 ANGLE_INSTANTIATE_TEST_ES2(CHROMIUMFramebufferMixedSamplesTest);
270