1 /*-------------------------------------------------------------------------
2  * OpenGL Conformance Test Suite
3  * -----------------------------
4  *
5  * Copyright (c) 2015-2016 The Khronos Group Inc.
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
22  */ /*-------------------------------------------------------------------*/
23 
24 /*!
25  * \file  esextcDrawBuffersIndexedColorMasks.hpp
26  * \brief Draw Buffers Indexed tests 4. Color masks
27  */ /*-------------------------------------------------------------------*/
28 
29 #include "esextcDrawBuffersIndexedColorMasks.hpp"
30 #include "gluPixelTransfer.hpp"
31 #include "gluShaderProgram.hpp"
32 #include "tcuTestLog.hpp"
33 #include <cmath>
34 
35 namespace glcts
36 {
37 
38 /** Constructor
39  *
40  *  @param context     Test context
41  *  @param name        Test case's name
42  *  @param description Test case's description
43  **/
DrawBuffersIndexedColorMasks(Context & context,const ExtParameters & extParams,const char * name,const char * description)44 DrawBuffersIndexedColorMasks::DrawBuffersIndexedColorMasks(Context &context, const ExtParameters &extParams,
45                                                            const char *name, const char *description)
46     : DrawBuffersIndexedBase(context, extParams, name, description)
47     , m_fbo(0)
48 {
49     /* Left blank on purpose */
50 }
51 
prepareFramebuffer()52 void DrawBuffersIndexedColorMasks::prepareFramebuffer()
53 {
54     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
55 
56     glw::GLint maxDrawBuffers = 0;
57     gl.getIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
58     if (maxDrawBuffers < 4)
59     {
60         throw tcu::ResourceError("Minimum number of draw buffers too low");
61     }
62 
63     gl.genFramebuffers(1, &m_fbo);
64     gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
65 
66     std::vector<glw::GLenum> bufs(maxDrawBuffers);
67     for (int i = 0; i < maxDrawBuffers; ++i)
68     {
69         bufs[i] = GL_COLOR_ATTACHMENT0 + i;
70     }
71     gl.drawBuffers(maxDrawBuffers, &bufs[0]);
72 
73     gl.disable(GL_DITHER);
74 }
75 
releaseFramebuffer()76 void DrawBuffersIndexedColorMasks::releaseFramebuffer()
77 {
78     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
79 
80     glw::GLint maxDrawBuffers = 0;
81     gl.getIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
82     if (maxDrawBuffers < 4)
83     {
84         throw tcu::ResourceError("Minimum number of draw buffers too low");
85     }
86 
87     BlendMaskStateMachine state(m_context, m_testCtx.getLog(), maxDrawBuffers);
88     state.SetDefaults();
89     gl.deleteFramebuffers(1, &m_fbo);
90     gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
91     glw::GLenum bufs[1] = {GL_BACK};
92     gl.drawBuffers(1, bufs);
93     gl.readBuffer(GL_BACK);
94 }
95 
iterate()96 tcu::TestNode::IterateResult DrawBuffersIndexedColorMasks::iterate()
97 {
98     static const glw::GLenum WriteMasksFormats[] = {
99         GL_R8,     GL_RG8,    GL_RGB8,    GL_RGB565,  GL_RGBA4,    GL_RGB5_A1, GL_RGBA8,   GL_R8I,    GL_R8UI,
100         GL_R16I,   GL_R16UI,  GL_R32I,    GL_R32UI,   GL_RG8I,     GL_RG8UI,   GL_RG16I,   GL_RG16UI, GL_RG32I,
101         GL_RG32UI, GL_RGBA8I, GL_RGBA8UI, GL_RGBA16I, GL_RGBA16UI, GL_RGBA32I, GL_RGBA32UI};
102     static const int kSize       = 32;
103     static unsigned int formatId = 0;
104 
105     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
106     glw::GLenum format       = WriteMasksFormats[formatId];
107 
108     prepareFramebuffer();
109 
110     // Check number of available draw buffers
111     glw::GLint maxDrawBuffers = 0;
112     gl.getIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
113     if (maxDrawBuffers < 4)
114     {
115         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Minimum number of draw buffers too low");
116         return STOP;
117     }
118 
119     // Prepare render targets
120     glw::GLuint tex;
121     gl.genTextures(1, &tex);
122     gl.bindTexture(GL_TEXTURE_2D_ARRAY, tex);
123     gl.texStorage3D(GL_TEXTURE_2D_ARRAY, 1, format, kSize, kSize, maxDrawBuffers);
124     for (int i = 0; i < maxDrawBuffers; ++i)
125     {
126         gl.framebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, tex, 0, i);
127     }
128 
129     // Clear all buffers
130     switch (ReadableType(format))
131     {
132     case GL_UNSIGNED_BYTE:
133     {
134         tcu::Vec4 c0(0.15f, 0.3f, 0.45f, 0.6f);
135         for (int i = 0; i < maxDrawBuffers; ++i)
136         {
137             gl.clearBufferfv(GL_COLOR, i, &c0[0]);
138         }
139         break;
140     }
141     case GL_UNSIGNED_INT:
142     {
143         tcu::UVec4 c0(2, 3, 4, 5);
144         for (int i = 0; i < maxDrawBuffers; ++i)
145         {
146             gl.clearBufferuiv(GL_COLOR, i, &c0[0]);
147         }
148         break;
149     }
150     case GL_INT:
151     {
152         tcu::IVec4 c0(2, 3, 4, 5);
153         for (int i = 0; i < maxDrawBuffers; ++i)
154         {
155             gl.clearBufferiv(GL_COLOR, i, &c0[0]);
156         }
157         break;
158     }
159     }
160 
161     // Set color masks for each buffer
162     BlendMaskStateMachine state(m_context, m_testCtx.getLog(), maxDrawBuffers);
163 
164     glw::GLboolean mask[] = {GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE};
165     for (int i = 0; i < maxDrawBuffers; ++i)
166     {
167         mask[i % 4] = GL_TRUE;
168         state.SetColorMaski(i, mask[0], mask[1], mask[2], mask[3]);
169         mask[i % 4] = GL_FALSE;
170     }
171 
172     // Clear all buffers
173     switch (ReadableType(format))
174     {
175     case GL_UNSIGNED_BYTE:
176     {
177         tcu::Vec4 c1(0.85f, 0.85f, 0.85f, 0.85f);
178         for (int i = 0; i < maxDrawBuffers; ++i)
179         {
180             gl.clearBufferfv(GL_COLOR, i, &c1[0]);
181         }
182         break;
183     }
184     case GL_UNSIGNED_INT:
185     {
186         tcu::UVec4 c1(23, 23, 23, 23);
187         for (int i = 0; i < maxDrawBuffers; ++i)
188         {
189             gl.clearBufferuiv(GL_COLOR, i, &c1[0]);
190         }
191         break;
192     }
193     case GL_INT:
194     {
195         tcu::IVec4 c1(23, 23, 23, 23);
196         for (int i = 0; i < maxDrawBuffers; ++i)
197         {
198             gl.clearBufferiv(GL_COLOR, i, &c1[0]);
199         }
200         break;
201     }
202     }
203 
204     // Verify color
205     int numComponents = NumComponents(format);
206     tcu::RGBA epsilon = GetEpsilon();
207     bool success      = true;
208 
209     for (int i = 0; i < maxDrawBuffers; ++i)
210     {
211         gl.readBuffer(GL_COLOR_ATTACHMENT0 + i);
212 
213         switch (ReadableType(format))
214         {
215         case GL_UNSIGNED_BYTE:
216         {
217             tcu::UVec4 e(static_cast<unsigned int>(0.15f * 255), static_cast<unsigned int>(0.30f * 255),
218                          static_cast<unsigned int>(0.45f * 255), static_cast<unsigned int>(0.60f * 255));
219             e[i % 4] = static_cast<unsigned int>(0.85f * 255);
220             e        = tcu::UVec4(e.x(), numComponents >= 2 ? e.y() : 0, numComponents >= 3 ? e.z() : 0,
221                            numComponents == 4 ? e.w() : 255);
222             tcu::RGBA expected(e.x(), e.y(), e.z(), e.w());
223 
224             std::vector<unsigned char> rendered(kSize * kSize * 4, 45);
225 
226             tcu::TextureLevel textureLevel(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8),
227                                            kSize, kSize);
228             glu::readPixels(m_context.getRenderContext(), 0, 0, textureLevel.getAccess());
229 
230             if (!VerifyImg(textureLevel, expected, epsilon))
231             {
232                 m_testCtx.getLog() << tcu::TestLog::Message << "Write mask error in texture format " << format
233                                    << " occurred for buffer #" << i << "\n"
234                                    << tcu::TestLog::EndMessage;
235                 m_testCtx.getLog() << tcu::TestLog::Image("Result", "Rendered result image", textureLevel.getAccess());
236                 success = false;
237             }
238             break;
239         }
240         case GL_UNSIGNED_INT:
241         {
242             tcu::UVec4 e(2, 3, 4, 5);
243             e[i % 4] = 23;
244             e        = tcu::UVec4(e.x(), numComponents >= 2 ? e.y() : 0, numComponents >= 3 ? e.z() : 0,
245                            numComponents == 4 ? e.w() : 1);
246             tcu::RGBA expected(e.x(), e.y(), e.z(), e.w());
247 
248             tcu::TextureLevel textureLevel(
249                 tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNSIGNED_INT32), kSize, kSize);
250             glu::readPixels(m_context.getRenderContext(), 0, 0, textureLevel.getAccess());
251 
252             if (!VerifyImg(textureLevel, expected, epsilon))
253             {
254                 m_testCtx.getLog() << tcu::TestLog::Message << "Write mask error in texture format " << format
255                                    << " occurred for buffer #" << i << "\n"
256                                    << tcu::TestLog::EndMessage;
257                 m_testCtx.getLog() << tcu::TestLog::Image("Result", "Rendered result image", textureLevel.getAccess());
258                 success = false;
259             }
260             break;
261         }
262         case GL_INT:
263         {
264             tcu::UVec4 e(2, 3, 4, 5);
265             e[i % 4] = 23;
266             e        = tcu::UVec4(e.x(), numComponents >= 2 ? e.y() : 0, numComponents >= 3 ? e.z() : 0,
267                            numComponents == 4 ? e.w() : 1);
268             tcu::RGBA expected(e.x(), e.y(), e.z(), e.w());
269 
270             tcu::TextureLevel textureLevel(
271                 tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::SIGNED_INT32), kSize, kSize);
272             glu::readPixels(m_context.getRenderContext(), 0, 0, textureLevel.getAccess());
273 
274             if (!VerifyImg(textureLevel, expected, epsilon))
275             {
276                 m_testCtx.getLog() << tcu::TestLog::Message << "Write mask error in texture format " << format
277                                    << " occurred for buffer #" << i << "\n"
278                                    << tcu::TestLog::EndMessage;
279                 m_testCtx.getLog() << tcu::TestLog::Image("Result", "Rendered result image", textureLevel.getAccess());
280                 success = false;
281             }
282             break;
283         }
284         }
285     }
286 
287     gl.colorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
288     gl.bindTexture(GL_TEXTURE_2D_ARRAY, 0);
289     gl.deleteTextures(1, &tex);
290     releaseFramebuffer();
291 
292     // Check for error
293     glw::GLenum error_code = gl.getError();
294     if (error_code != GL_NO_ERROR)
295     {
296         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Some functions generated error");
297         formatId = 0;
298         return STOP;
299     }
300 
301     if (!success)
302     {
303         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Write mask error occurred");
304         formatId = 0;
305         return STOP;
306     }
307     else
308     {
309         ++formatId;
310         if (formatId < (sizeof(WriteMasksFormats) / sizeof(WriteMasksFormats[0])))
311         {
312             return CONTINUE;
313         }
314         else
315         {
316             m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
317             formatId = 0;
318             return STOP;
319         }
320     }
321 }
322 
NumComponents(glw::GLenum format)323 unsigned int DrawBuffersIndexedColorMasks::NumComponents(glw::GLenum format)
324 {
325     switch (format)
326     {
327     case GL_R8:
328     case GL_R8I:
329     case GL_R8UI:
330     case GL_R16I:
331     case GL_R16UI:
332     case GL_R32I:
333     case GL_R32UI:
334         return 1;
335     case GL_RG8:
336     case GL_RG8I:
337     case GL_RG8UI:
338     case GL_RG16I:
339     case GL_RG16UI:
340     case GL_RG32I:
341     case GL_RG32UI:
342         return 2;
343     case GL_RGB8:
344     case GL_RGB565:
345         return 3;
346     case GL_RGBA4:
347     case GL_RGB5_A1:
348     case GL_RGBA8:
349     case GL_RGB10_A2:
350     case GL_RGBA8I:
351     case GL_RGBA8UI:
352     case GL_RGBA16I:
353     case GL_RGBA16UI:
354     case GL_RGBA32I:
355     case GL_RGBA32UI:
356         return 4;
357     default:
358         return 0;
359     }
360 }
361 
ReadableType(glw::GLenum format)362 glw::GLenum DrawBuffersIndexedColorMasks::ReadableType(glw::GLenum format)
363 {
364     switch (format)
365     {
366     case GL_R8:
367     case GL_RG8:
368     case GL_RGB8:
369     case GL_RGB565:
370     case GL_RGBA4:
371     case GL_RGB5_A1:
372     case GL_RGBA8:
373     case GL_RGB10_A2:
374         return GL_UNSIGNED_BYTE;
375 
376     case GL_R8I:
377     case GL_R16I:
378     case GL_R32I:
379     case GL_RG8I:
380     case GL_RG16I:
381     case GL_RG32I:
382     case GL_RGBA8I:
383     case GL_RGBA16I:
384     case GL_RGBA32I:
385         return GL_INT;
386 
387     case GL_R8UI:
388     case GL_R16UI:
389     case GL_R32UI:
390     case GL_RG8UI:
391     case GL_RG16UI:
392     case GL_RG32UI:
393     case GL_RGB10_A2UI:
394     case GL_RGBA8UI:
395     case GL_RGBA16UI:
396     case GL_RGBA32UI:
397         return GL_UNSIGNED_INT;
398 
399     default:
400         return 0;
401     }
402 }
403 
GetEpsilon()404 tcu::RGBA DrawBuffersIndexedColorMasks::GetEpsilon()
405 {
406     const glw::Functions &gl = m_context.getRenderContext().getFunctions();
407 
408     tcu::IVec4 bits;
409     tcu::UVec4 epsilon;
410 
411     for (int i = 0; i < 4; ++i)
412     {
413         gl.getIntegerv(GL_RED_BITS + i, &bits[i]);
414         epsilon[i] = de::min(
415             255u, static_cast<unsigned int>(ceil(1.0 + 255.0 * (1.0 / pow(2.0, static_cast<double>(bits[i]))))));
416     }
417 
418     return tcu::RGBA(epsilon.x(), epsilon.y(), epsilon.z(), epsilon.w());
419 }
420 
VerifyImg(const tcu::TextureLevel & textureLevel,tcu::RGBA expectedColor,tcu::RGBA epsilon)421 bool DrawBuffersIndexedColorMasks::VerifyImg(const tcu::TextureLevel &textureLevel, tcu::RGBA expectedColor,
422                                              tcu::RGBA epsilon)
423 {
424     for (int y = 0; y < textureLevel.getHeight(); ++y)
425     {
426         for (int x = 0; x < textureLevel.getWidth(); ++x)
427         {
428             tcu::IVec4 color(textureLevel.getAccess().getPixelInt(x, y));
429             tcu::RGBA pixel(color.x(), color.y(), color.z(), color.w());
430 
431             if (!tcu::compareThreshold(pixel, expectedColor, epsilon))
432             {
433                 m_testCtx.getLog() << tcu::TestLog::Message << "Expected value: " << expectedColor << "\n"
434                                    << "Read value:     " << pixel << "\n"
435                                    << "Epsilon:        " << epsilon << tcu::TestLog::EndMessage;
436                 return false;
437             }
438         }
439     }
440     return true;
441 }
442 
443 } // namespace glcts
444