1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.0 Module
3 * -------------------------------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief FBO multisample tests.
22 *//*--------------------------------------------------------------------*/
23
24 #include "es3fFboMultisampleTests.hpp"
25 #include "es3fFboTestCase.hpp"
26 #include "es3fFboTestUtil.hpp"
27 #include "gluTextureUtil.hpp"
28 #include "tcuImageCompare.hpp"
29 #include "tcuTextureUtil.hpp"
30 #include "tcuTestLog.hpp"
31 #include "deStringUtil.hpp"
32 #include "deRandom.hpp"
33 #include "sglrContextUtil.hpp"
34 #include "glwEnums.hpp"
35
36 namespace deqp
37 {
38 namespace gles3
39 {
40 namespace Functional
41 {
42
43 using std::string;
44 using tcu::TestLog;
45 using tcu::Vec2;
46 using tcu::Vec3;
47 using tcu::Vec4;
48 using tcu::IVec2;
49 using tcu::IVec3;
50 using tcu::IVec4;
51 using tcu::UVec4;
52 using namespace FboTestUtil;
53
54 class BasicFboMultisampleCase : public FboTestCase
55 {
56 public:
BasicFboMultisampleCase(Context & context,const char * name,const char * desc,deUint32 colorFormat,deUint32 depthStencilFormat,const IVec2 & size,int numSamples)57 BasicFboMultisampleCase (Context& context, const char* name, const char* desc, deUint32 colorFormat, deUint32 depthStencilFormat, const IVec2& size, int numSamples)
58 : FboTestCase (context, name, desc)
59 , m_colorFormat (colorFormat)
60 , m_depthStencilFormat (depthStencilFormat)
61 , m_size (size)
62 , m_numSamples (numSamples)
63 {
64 }
65
66 protected:
preCheck(void)67 void preCheck (void)
68 {
69 checkFormatSupport (m_colorFormat);
70 checkSampleCount (m_colorFormat, m_numSamples);
71
72 if (m_depthStencilFormat != GL_NONE)
73 {
74 checkFormatSupport (m_depthStencilFormat);
75 checkSampleCount (m_depthStencilFormat, m_numSamples);
76 }
77 }
78
render(tcu::Surface & dst)79 void render (tcu::Surface& dst)
80 {
81 tcu::TextureFormat colorFmt = glu::mapGLInternalFormat(m_colorFormat);
82 tcu::TextureFormat depthStencilFmt = m_depthStencilFormat != GL_NONE ? glu::mapGLInternalFormat(m_depthStencilFormat) : tcu::TextureFormat();
83 tcu::TextureFormatInfo colorFmtInfo = tcu::getTextureFormatInfo(colorFmt);
84 bool depth = depthStencilFmt.order == tcu::TextureFormat::D || depthStencilFmt.order == tcu::TextureFormat::DS;
85 bool stencil = depthStencilFmt.order == tcu::TextureFormat::S || depthStencilFmt.order == tcu::TextureFormat::DS;
86 GradientShader gradShader (getFragmentOutputType(colorFmt));
87 FlatColorShader flatShader (getFragmentOutputType(colorFmt));
88 deUint32 gradShaderID = getCurrentContext()->createProgram(&gradShader);
89 deUint32 flatShaderID = getCurrentContext()->createProgram(&flatShader);
90 deUint32 msaaFbo = 0;
91 deUint32 resolveFbo = 0;
92 deUint32 msaaColorRbo = 0;
93 deUint32 resolveColorRbo = 0;
94 deUint32 msaaDepthStencilRbo = 0;
95 deUint32 resolveDepthStencilRbo = 0;
96
97 // Create framebuffers.
98 for (int ndx = 0; ndx < 2; ndx++)
99 {
100 deUint32& fbo = ndx ? resolveFbo : msaaFbo;
101 deUint32& colorRbo = ndx ? resolveColorRbo : msaaColorRbo;
102 deUint32& depthStencilRbo = ndx ? resolveDepthStencilRbo : msaaDepthStencilRbo;
103 int samples = ndx ? 0 : m_numSamples;
104
105 glGenRenderbuffers(1, &colorRbo);
106 glBindRenderbuffer(GL_RENDERBUFFER, colorRbo);
107 glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, m_colorFormat, m_size.x(), m_size.y());
108
109 if (depth || stencil)
110 {
111 glGenRenderbuffers(1, &depthStencilRbo);
112 glBindRenderbuffer(GL_RENDERBUFFER, depthStencilRbo);
113 glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, m_depthStencilFormat, m_size.x(), m_size.y());
114 }
115
116 glGenFramebuffers(1, &fbo);
117 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
118 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRbo);
119 if (depth)
120 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthStencilRbo);
121 if (stencil)
122 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthStencilRbo);
123
124 checkError();
125 checkFramebufferStatus(GL_FRAMEBUFFER);
126 }
127
128 glBindFramebuffer(GL_FRAMEBUFFER, msaaFbo);
129 glViewport(0, 0, m_size.x(), m_size.y());
130
131 // Clear depth and stencil buffers.
132 glClearBufferfi(GL_DEPTH_STENCIL, 0, 1.0f, 0);
133
134 // Fill MSAA fbo with gradient, depth = [-1..1]
135 glEnable(GL_DEPTH_TEST);
136 gradShader.setGradient(*getCurrentContext(), gradShaderID, colorFmtInfo.valueMin, colorFmtInfo.valueMax);
137 sglr::drawQuad(*getCurrentContext(), gradShaderID, Vec3(-1.0f, -1.0f, -1.0f), Vec3(1.0f, 1.0f, 1.0f));
138
139 // Render random-colored quads.
140 {
141 const int numQuads = 8;
142 de::Random rnd (9);
143
144 glDepthFunc(GL_ALWAYS);
145 glEnable(GL_STENCIL_TEST);
146 glStencilFunc(GL_ALWAYS, 0, 0xffu);
147 glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
148
149 for (int ndx = 0; ndx < numQuads; ndx++)
150 {
151 float r = rnd.getFloat();
152 float g = rnd.getFloat();
153 float b = rnd.getFloat();
154 float a = rnd.getFloat();
155 float x0 = rnd.getFloat(-1.0f, 1.0f);
156 float y0 = rnd.getFloat(-1.0f, 1.0f);
157 float z0 = rnd.getFloat(-1.0f, 1.0f);
158 float x1 = rnd.getFloat(-1.0f, 1.0f);
159 float y1 = rnd.getFloat(-1.0f, 1.0f);
160 float z1 = rnd.getFloat(-1.0f, 1.0f);
161
162 flatShader.setColor(*getCurrentContext(), flatShaderID, Vec4(r,g,b,a) * (colorFmtInfo.valueMax-colorFmtInfo.valueMin) + colorFmtInfo.valueMin);
163 sglr::drawQuad(*getCurrentContext(), flatShaderID, Vec3(x0, y0, z0), Vec3(x1, y1, z1));
164 }
165 }
166
167 glDisable(GL_DEPTH_TEST);
168 glDisable(GL_STENCIL_TEST);
169 checkError();
170
171 // Resolve using glBlitFramebuffer().
172 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolveFbo);
173 glBlitFramebuffer(0, 0, m_size.x(), m_size.y(), 0, 0, m_size.x(), m_size.y(), GL_COLOR_BUFFER_BIT | (depth ? GL_DEPTH_BUFFER_BIT : 0) | (stencil ? GL_STENCIL_BUFFER_BIT : 0), GL_NEAREST);
174
175 glBindFramebuffer(GL_READ_FRAMEBUFFER, resolveFbo);
176
177 if (depth)
178 {
179 // Visualize depth.
180 const int numSteps = 8;
181 const float step = 2.0f / (float)numSteps;
182
183 glEnable(GL_DEPTH_TEST);
184 glDepthFunc(GL_LESS);
185 glDepthMask(GL_FALSE);
186 glColorMask(GL_FALSE, GL_FALSE, GL_TRUE, GL_FALSE);
187
188 for (int ndx = 0; ndx < numSteps; ndx++)
189 {
190 float d = -1.0f + step*(float)ndx;
191 float c = (float)ndx / (float)(numSteps-1);
192
193 flatShader.setColor(*getCurrentContext(), flatShaderID, Vec4(0.0f, 0.0f, c, 1.0f) * (colorFmtInfo.valueMax-colorFmtInfo.valueMin) + colorFmtInfo.valueMin);
194 sglr::drawQuad(*getCurrentContext(), flatShaderID, Vec3(-1.0f, -1.0f, d), Vec3(1.0f, 1.0f, d));
195 }
196
197 glDisable(GL_DEPTH_TEST);
198 }
199
200 if (stencil)
201 {
202 // Visualize stencil.
203 const int numSteps = 4;
204 const int step = 1;
205
206 glEnable(GL_STENCIL_TEST);
207 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
208 glColorMask(GL_FALSE, GL_TRUE, GL_FALSE, GL_FALSE);
209
210 for (int ndx = 0; ndx < numSteps; ndx++)
211 {
212 int s = step*ndx;
213 float c = (float)ndx / (float)(numSteps-1);
214
215 glStencilFunc(GL_EQUAL, s, 0xffu);
216
217 flatShader.setColor(*getCurrentContext(), flatShaderID, Vec4(0.0f, c, 0.0f, 1.0f) * (colorFmtInfo.valueMax-colorFmtInfo.valueMin) + colorFmtInfo.valueMin);
218 sglr::drawQuad(*getCurrentContext(), flatShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
219 }
220
221 glDisable(GL_STENCIL_TEST);
222 }
223
224 readPixels(dst, 0, 0, m_size.x(), m_size.y(), colorFmt, colorFmtInfo.lookupScale, colorFmtInfo.lookupBias);
225 }
226
colorCompare(const tcu::Surface & reference,const tcu::Surface & result)227 bool colorCompare (const tcu::Surface& reference, const tcu::Surface& result)
228 {
229 const tcu::RGBA threshold (tcu::max(getFormatThreshold(m_colorFormat), tcu::RGBA(12, 12, 12, 12)));
230
231 return tcu::bilinearCompare(m_testCtx.getLog(), "Result", "Image comparison result", reference.getAccess(), result.getAccess(), threshold, tcu::COMPARE_LOG_RESULT);
232 }
233
compare(const tcu::Surface & reference,const tcu::Surface & result)234 bool compare (const tcu::Surface& reference, const tcu::Surface& result)
235 {
236 if (m_depthStencilFormat != GL_NONE)
237 return FboTestCase::compare(reference, result);
238 else
239 return colorCompare(reference, result);
240 }
241
242 private:
243 deUint32 m_colorFormat;
244 deUint32 m_depthStencilFormat;
245 IVec2 m_size;
246 int m_numSamples;
247 };
248
FboMultisampleTests(Context & context)249 FboMultisampleTests::FboMultisampleTests (Context& context)
250 : TestCaseGroup(context, "msaa", "Multisample FBO tests")
251 {
252 }
253
~FboMultisampleTests(void)254 FboMultisampleTests::~FboMultisampleTests (void)
255 {
256 }
257
init(void)258 void FboMultisampleTests::init (void)
259 {
260 static const deUint32 colorFormats[] =
261 {
262 // RGBA formats
263 GL_RGBA8,
264 GL_SRGB8_ALPHA8,
265 GL_RGB10_A2,
266 GL_RGBA4,
267 GL_RGB5_A1,
268
269 // RGB formats
270 GL_RGB8,
271 GL_RGB565,
272
273 // RG formats
274 GL_RG8,
275
276 // R formats
277 GL_R8,
278
279 // GL_EXT_color_buffer_float
280 GL_RGBA32F,
281 GL_RGBA16F,
282 GL_R11F_G11F_B10F,
283 GL_RG32F,
284 GL_RG16F,
285 GL_R32F,
286 GL_R16F
287 };
288
289 static const deUint32 depthStencilFormats[] =
290 {
291 GL_DEPTH_COMPONENT32F,
292 GL_DEPTH_COMPONENT24,
293 GL_DEPTH_COMPONENT16,
294 GL_DEPTH32F_STENCIL8,
295 GL_DEPTH24_STENCIL8,
296 GL_STENCIL_INDEX8
297 };
298
299 static const int sampleCounts[] = { 2, 4, 8 };
300
301 for (int sampleCntNdx = 0; sampleCntNdx < DE_LENGTH_OF_ARRAY(sampleCounts); sampleCntNdx++)
302 {
303 int samples = sampleCounts[sampleCntNdx];
304 tcu::TestCaseGroup* sampleCountGroup = new tcu::TestCaseGroup(m_testCtx, (de::toString(samples) + "_samples").c_str(), "");
305 addChild(sampleCountGroup);
306
307 // Color formats.
308 for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(colorFormats); fmtNdx++)
309 sampleCountGroup->addChild(new BasicFboMultisampleCase(m_context, getFormatName(colorFormats[fmtNdx]), "", colorFormats[fmtNdx], GL_NONE, IVec2(119, 131), samples));
310
311 // Depth/stencil formats.
312 for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(depthStencilFormats); fmtNdx++)
313 sampleCountGroup->addChild(new BasicFboMultisampleCase(m_context, getFormatName(depthStencilFormats[fmtNdx]), "", GL_RGBA8, depthStencilFormats[fmtNdx], IVec2(119, 131), samples));
314 }
315 }
316
317 } // Functional
318 } // gles3
319 } // deqp
320