xref: /aosp_15_r20/external/deqp/modules/gles31/functional/es31fFboColorbufferTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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