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