1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.1 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 colorbuffer tests.
22 *//*--------------------------------------------------------------------*/
23
24 #include "es31fFboColorbufferTests.hpp"
25 #include "es31fFboTestCase.hpp"
26 #include "es31fFboTestUtil.hpp"
27
28 #include "gluTextureUtil.hpp"
29 #include "gluContextInfo.hpp"
30
31 #include "tcuCommandLine.hpp"
32 #include "tcuImageCompare.hpp"
33 #include "tcuRGBA.hpp"
34 #include "tcuTestLog.hpp"
35 #include "tcuTextureUtil.hpp"
36
37 #include "sglrContextUtil.hpp"
38
39 #include "deRandom.hpp"
40 #include "deString.h"
41
42 #include "glwEnums.hpp"
43
44 namespace deqp
45 {
46 namespace gles31
47 {
48 namespace Functional
49 {
50
51 using std::string;
52 using tcu::Vec2;
53 using tcu::Vec3;
54 using tcu::Vec4;
55 using tcu::IVec2;
56 using tcu::IVec3;
57 using tcu::IVec4;
58 using tcu::UVec4;
59 using tcu::TestLog;
60 using namespace FboTestUtil;
61
62 const tcu::RGBA MIN_THRESHOLD(12, 12, 12, 12);
63
generateRandomColor(de::Random & random)64 static tcu::Vec4 generateRandomColor (de::Random& random)
65 {
66 tcu::Vec4 retVal;
67
68 retVal[0] = random.getFloat();
69 retVal[1] = random.getFloat();
70 retVal[2] = random.getFloat();
71 retVal[3] = 1.0f;
72
73 return retVal;
74 }
75
getCubeFaceFromNdx(int ndx)76 static tcu::CubeFace getCubeFaceFromNdx (int ndx)
77 {
78 switch (ndx)
79 {
80 case 0: return tcu::CUBEFACE_POSITIVE_X;
81 case 1: return tcu::CUBEFACE_NEGATIVE_X;
82 case 2: return tcu::CUBEFACE_POSITIVE_Y;
83 case 3: return tcu::CUBEFACE_NEGATIVE_Y;
84 case 4: return tcu::CUBEFACE_POSITIVE_Z;
85 case 5: return tcu::CUBEFACE_NEGATIVE_Z;
86 default:
87 DE_ASSERT(false);
88 return tcu::CUBEFACE_LAST;
89 }
90 }
91
92 class FboColorbufferCase : public FboTestCase
93 {
94 public:
FboColorbufferCase(Context & context,const char * name,const char * desc,const deUint32 format)95 FboColorbufferCase (Context& context, const char* name, const char* desc, const deUint32 format)
96 : FboTestCase (context, name, desc)
97 , m_format (format)
98 {
99 }
100
compare(const tcu::Surface & reference,const tcu::Surface & result)101 bool compare (const tcu::Surface& reference, const tcu::Surface& result)
102 {
103 const tcu::RGBA threshold (tcu::max(getFormatThreshold(m_format), MIN_THRESHOLD));
104
105 m_testCtx.getLog() << TestLog::Message << "Comparing images, threshold: " << threshold << TestLog::EndMessage;
106
107 return tcu::bilinearCompare(m_testCtx.getLog(), "Result", "Image comparison result", reference.getAccess(), result.getAccess(), threshold, tcu::COMPARE_LOG_RESULT);
108 }
109
110 protected:
111 const deUint32 m_format;
112 };
113
114 class FboColorTex2DCase : public FboColorbufferCase
115 {
116 public:
FboColorTex2DCase(Context & context,const char * name,const char * description,deUint32 texFmt,const IVec2 & texSize)117 FboColorTex2DCase (Context& context, const char* name, const char* description, deUint32 texFmt, const IVec2& texSize)
118 : FboColorbufferCase (context, name, description, texFmt)
119 , m_texFmt (texFmt)
120 , m_texSize (texSize)
121 {
122 }
123
124 protected:
preCheck(void)125 void preCheck (void)
126 {
127 checkFormatSupport(m_texFmt);
128 }
129
render(tcu::Surface & dst)130 void render (tcu::Surface& dst)
131 {
132 tcu::TextureFormat texFmt = glu::mapGLInternalFormat(m_texFmt);
133 tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(texFmt);
134
135 Texture2DShader texToFboShader (DataTypes() << glu::TYPE_SAMPLER_2D, getFragmentOutputType(texFmt), fmtInfo.valueMax-fmtInfo.valueMin, fmtInfo.valueMin);
136 deUint32 texToFboShaderID = getCurrentContext()->createProgram(&texToFboShader);
137 deUint32 fbo;
138 deUint32 tex;
139
140 // Setup shader
141 texToFboShader.setUniforms(*getCurrentContext(), texToFboShaderID);
142
143 // Generate fbo
144 {
145 glu::TransferFormat transferFmt = glu::getTransferFormat(texFmt);
146 deUint32 format = m_texFmt;
147 const IVec2& size = m_texSize;
148
149 glGenFramebuffers(1, &fbo);
150 glGenTextures(1, &tex);
151
152 glBindTexture(GL_TEXTURE_2D, tex);
153 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
154 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
155 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
156 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
157 glTexImage2D(GL_TEXTURE_2D, 0, format, size.x(), size.y(), 0, transferFmt.format, transferFmt.dataType, DE_NULL);
158
159 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
160 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
161 checkError();
162 checkFramebufferStatus(GL_FRAMEBUFFER);
163 }
164
165 // Render texture to fbo
166 {
167 const deUint32 format = GL_RGBA;
168 const deUint32 dataType = GL_UNSIGNED_BYTE;
169 const int texW = 128;
170 const int texH = 128;
171 deUint32 tmpTex = 0;
172 const IVec2& viewport = m_texSize;
173 tcu::TextureLevel data (glu::mapGLTransferFormat(format, dataType), texW, texH, 1);
174
175 tcu::fillWithComponentGradients(data.getAccess(), Vec4(0.0f), Vec4(1.0f));
176
177 glGenTextures(1, &tmpTex);
178 glBindTexture(GL_TEXTURE_2D, tmpTex);
179 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
180 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
181 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
182 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
183 glTexImage2D(GL_TEXTURE_2D, 0, format, texW, texH, 0, format, dataType, data.getAccess().getDataPtr());
184
185 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
186 glViewport(0, 0, viewport.x(), viewport.y());
187 sglr::drawQuad(*getCurrentContext(), texToFboShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
188 }
189
190 readPixels(dst, 0, 0, getWidth(), getHeight(), texFmt, fmtInfo.lookupScale, fmtInfo.lookupBias);
191 checkError();
192 }
193
194 private:
195 deUint32 m_texFmt;
196 IVec2 m_texSize;
197 };
198
199 class FboColorTexCubeArrayCase : public FboColorbufferCase
200 {
201 public:
FboColorTexCubeArrayCase(Context & context,const char * name,const char * description,deUint32 texFmt,const IVec3 & texSize)202 FboColorTexCubeArrayCase (Context& context, const char* name, const char* description, deUint32 texFmt, const IVec3& texSize)
203 : FboColorbufferCase (context, name, description, texFmt)
204 , m_texSize (texSize)
205 {
206 DE_ASSERT(texSize.z() % 6 == 0);
207 }
208
209 protected:
preCheck(void)210 void preCheck (void)
211 {
212 auto ctxType = m_context.getRenderContext().getType();
213 if (!glu::contextSupports(ctxType, glu::ApiType::core(4, 5)) &&
214 !glu::contextSupports(ctxType, glu::ApiType::es(3, 2)) &&
215 !m_context.getContextInfo().isExtensionSupported("GL_EXT_texture_cube_map_array"))
216 TCU_THROW(NotSupportedError, "Test requires extension GL_EXT_texture_cube_map_array or a context version equal or higher than 3.2");
217
218 checkFormatSupport(m_format);
219 }
220
render(tcu::Surface & dst)221 void render (tcu::Surface& dst)
222 {
223 TestLog& log = m_testCtx.getLog();
224 de::Random rnd (deStringHash(getName()) ^ 0xed607a89 ^ m_testCtx.getCommandLine().getBaseSeed());
225 tcu::TextureFormat texFmt = glu::mapGLInternalFormat(m_format);
226 tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(texFmt);
227
228 Texture2DShader texToFboShader (DataTypes() << glu::TYPE_SAMPLER_2D, getFragmentOutputType(texFmt), fmtInfo.valueMax-fmtInfo.valueMin, fmtInfo.valueMin);
229 TextureCubeArrayShader arrayTexShader (glu::getSamplerCubeArrayType(texFmt), glu::TYPE_FLOAT_VEC4, glu::getContextTypeGLSLVersion(m_context.getRenderContext().getType()));
230
231 deUint32 texToFboShaderID = getCurrentContext()->createProgram(&texToFboShader);
232 deUint32 arrayTexShaderID = getCurrentContext()->createProgram(&arrayTexShader);
233
234 // Setup textures
235 texToFboShader.setUniforms(*getCurrentContext(), texToFboShaderID);
236 arrayTexShader.setTexScaleBias(fmtInfo.lookupScale, fmtInfo.lookupBias);
237
238 // Framebuffers.
239 std::vector<deUint32> fbos;
240 deUint32 tex;
241
242 {
243 glu::TransferFormat transferFmt = glu::getTransferFormat(texFmt);
244 bool isFilterable = glu::isGLInternalColorFormatFilterable(m_format);
245 const IVec3& size = m_texSize;
246
247 log << TestLog::Message
248 << "Creating a cube map array texture ("
249 << size.x() << "x" << size.y()
250 << ", depth: "
251 << size.z() << ")"
252 << TestLog::EndMessage;
253
254 glGenTextures(1, &tex);
255
256 glBindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, tex);
257 glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
258 glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
259 glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
260 glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MIN_FILTER, isFilterable ? GL_LINEAR : GL_NEAREST);
261 glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MAG_FILTER, isFilterable ? GL_LINEAR : GL_NEAREST);
262 glTexImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, 0, m_format, size.x(), size.y(), size.z(), 0, transferFmt.format, transferFmt.dataType, DE_NULL);
263
264 log << TestLog::Message << "Creating a framebuffer object for each layer-face" << TestLog::EndMessage;
265
266 // Generate an FBO for each layer-face
267 for (int ndx = 0; ndx < m_texSize.z(); ndx++)
268 {
269 deUint32 layerFbo;
270
271 glGenFramebuffers(1, &layerFbo);
272 glBindFramebuffer(GL_FRAMEBUFFER, layerFbo);
273 glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0, ndx);
274 checkError();
275 checkFramebufferStatus(GL_FRAMEBUFFER);
276
277 fbos.push_back(layerFbo);
278 }
279 }
280
281 log << TestLog::Message << "Rendering test images to layer-faces in randomized order" << TestLog::EndMessage;
282
283 {
284 std::vector<int> order(fbos.size());
285
286 for (size_t n = 0; n < order.size(); n++)
287 order[n] = (int)n;
288 rnd.shuffle(order.begin(), order.end());
289
290 for (size_t ndx = 0; ndx < order.size(); ndx++)
291 {
292 const int layerFace = order[ndx];
293 const deUint32 format = GL_RGBA;
294 const deUint32 dataType = GL_UNSIGNED_BYTE;
295 const int texW = 128;
296 const int texH = 128;
297 deUint32 tmpTex = 0;
298 const deUint32 fbo = fbos[layerFace];
299 const IVec3& viewport = m_texSize;
300 tcu::TextureLevel data (glu::mapGLTransferFormat(format, dataType), texW, texH, 1);
301
302 tcu::fillWithGrid(data.getAccess(), 8, generateRandomColor(rnd), Vec4(0.0f));
303
304 glGenTextures(1, &tmpTex);
305 glBindTexture(GL_TEXTURE_2D, tmpTex);
306 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
307 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
308 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
309 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
310 glTexImage2D(GL_TEXTURE_2D, 0, format, texW, texH, 0, format, dataType, data.getAccess().getDataPtr());
311
312 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
313 glViewport(0, 0, viewport.x(), viewport.y());
314 sglr::drawQuad(*getCurrentContext(), texToFboShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f));
315 checkError();
316
317 // Render to framebuffer
318 {
319 const Vec3 p0 = Vec3(float(ndx % 2) - 1.0f, float(ndx / 2) - 1.0f, 0.0f);
320 const Vec3 p1 = p0 + Vec3(1.0f, 1.0f, 0.0f);
321 const int layer = layerFace / 6;
322 const tcu::CubeFace face = getCubeFaceFromNdx(layerFace % 6);
323
324 glBindFramebuffer(GL_FRAMEBUFFER, 0);
325 glViewport(0, 0, getWidth(), getHeight());
326
327 glActiveTexture(GL_TEXTURE0);
328 glBindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, tex);
329
330 arrayTexShader.setLayer(layer);
331 arrayTexShader.setFace(face);
332 arrayTexShader.setUniforms(*getCurrentContext(), arrayTexShaderID);
333
334 sglr::drawQuad(*getCurrentContext(), arrayTexShaderID, p0, p1);
335 checkError();
336 }
337 }
338 }
339
340 readPixels(dst, 0, 0, getWidth(), getHeight());
341 }
342
343 private:
344 IVec3 m_texSize;
345 };
346
FboColorTests(Context & context)347 FboColorTests::FboColorTests (Context& context)
348 : TestCaseGroup(context, "color", "Colorbuffer tests")
349 {
350 }
351
~FboColorTests(void)352 FboColorTests::~FboColorTests (void)
353 {
354 }
355
init(void)356 void FboColorTests::init (void)
357 {
358 static const deUint32 colorFormats[] =
359 {
360 // RGBA formats
361 GL_RGBA32I,
362 GL_RGBA32UI,
363 GL_RGBA16I,
364 GL_RGBA16UI,
365 GL_RGBA8,
366 GL_RGBA8I,
367 GL_RGBA8UI,
368 GL_SRGB8_ALPHA8,
369 GL_RGB10_A2,
370 GL_RGB10_A2UI,
371 GL_RGBA4,
372 GL_RGB5_A1,
373
374 // RGB formats
375 GL_RGB8,
376 GL_RGB565,
377
378 // RG formats
379 GL_RG32I,
380 GL_RG32UI,
381 GL_RG16I,
382 GL_RG16UI,
383 GL_RG8,
384 GL_RG8I,
385 GL_RG8UI,
386
387 // R formats
388 GL_R32I,
389 GL_R32UI,
390 GL_R16I,
391 GL_R16UI,
392 GL_R8,
393 GL_R8I,
394 GL_R8UI,
395
396 // GL_EXT_color_buffer_float
397 GL_RGBA32F,
398 GL_RGBA16F,
399 GL_R11F_G11F_B10F,
400 GL_RG32F,
401 GL_RG16F,
402 GL_R32F,
403 GL_R16F,
404
405 // GL_EXT_color_buffer_half_float
406 GL_RGB16F
407 };
408
409 static const deUint32 unorm16ColorFormats[] =
410 {
411 GL_R16,
412 GL_RG16,
413 GL_RGBA16
414 };
415
416 // .texcubearray
417 {
418 tcu::TestCaseGroup* texCubeArrayGroup = new tcu::TestCaseGroup(m_testCtx, "texcubearray", "Cube map array texture tests");
419 addChild(texCubeArrayGroup);
420
421 for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(colorFormats); fmtNdx++)
422 texCubeArrayGroup->addChild(new FboColorTexCubeArrayCase(m_context, getFormatName(colorFormats[fmtNdx]), "",
423 colorFormats[fmtNdx], IVec3(128, 128, 12)));
424 }
425
426 // .tex2d
427 {
428 tcu::TestCaseGroup* tex2dGroup = new tcu::TestCaseGroup(m_testCtx, "tex2d", "Render to texture");
429 addChild(tex2dGroup);
430
431 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(unorm16ColorFormats); ndx++)
432 tex2dGroup->addChild(new FboColorTex2DCase(m_context, getFormatName(unorm16ColorFormats[ndx]), "", unorm16ColorFormats[ndx], IVec2(129, 117)));
433 }
434 }
435
436 } // Functional
437 } // gles31
438 } // deqp
439