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