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