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