1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.0 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 Fragment shader output tests.
22 *
23 * \todo [2012-04-10 pyry] Missing:
24 * + non-contiguous attachments in framebuffer
25 *//*--------------------------------------------------------------------*/
26
27 #include "es3fFragmentOutputTests.hpp"
28 #include "gluShaderUtil.hpp"
29 #include "gluShaderProgram.hpp"
30 #include "gluTextureUtil.hpp"
31 #include "gluStrUtil.hpp"
32 #include "tcuTestLog.hpp"
33 #include "tcuTexture.hpp"
34 #include "tcuTextureUtil.hpp"
35 #include "tcuVector.hpp"
36 #include "tcuVectorUtil.hpp"
37 #include "tcuImageCompare.hpp"
38 #include "deRandom.hpp"
39 #include "deStringUtil.hpp"
40 #include "deMath.h"
41
42 // For getFormatName() \todo [pyry] Move to glu?
43 #include "es3fFboTestUtil.hpp"
44
45 #include "glwEnums.hpp"
46 #include "glwFunctions.hpp"
47
48 namespace deqp
49 {
50 namespace gles3
51 {
52 namespace Functional
53 {
54
55 using std::vector;
56 using std::string;
57 using tcu::IVec2;
58 using tcu::IVec4;
59 using tcu::UVec2;
60 using tcu::UVec4;
61 using tcu::Vec2;
62 using tcu::Vec3;
63 using tcu::Vec4;
64 using tcu::BVec4;
65 using tcu::TestLog;
66 using FboTestUtil::getFormatName;
67 using FboTestUtil::getFramebufferReadFormat;
68
69 struct BufferSpec
70 {
BufferSpecdeqp::gles3::Functional::BufferSpec71 BufferSpec (void)
72 : format (GL_NONE)
73 , width (0)
74 , height (0)
75 , samples (0)
76 {
77 }
78
BufferSpecdeqp::gles3::Functional::BufferSpec79 BufferSpec (deUint32 format_, int width_, int height_, int samples_)
80 : format (format_)
81 , width (width_)
82 , height (height_)
83 , samples (samples_)
84 {
85 }
86
87 deUint32 format;
88 int width;
89 int height;
90 int samples;
91 };
92
93 struct FragmentOutput
94 {
FragmentOutputdeqp::gles3::Functional::FragmentOutput95 FragmentOutput (void)
96 : type (glu::TYPE_LAST)
97 , precision (glu::PRECISION_LAST)
98 , location (0)
99 , arrayLength (0)
100 {
101 }
102
FragmentOutputdeqp::gles3::Functional::FragmentOutput103 FragmentOutput (glu::DataType type_, glu::Precision precision_, int location_, int arrayLength_ = 0)
104 : type (type_)
105 , precision (precision_)
106 , location (location_)
107 , arrayLength (arrayLength_)
108 {
109 }
110
111 glu::DataType type;
112 glu::Precision precision;
113 int location;
114 int arrayLength; //!< 0 if not an array.
115 };
116
117 struct OutputVec
118 {
119 vector<FragmentOutput> outputs;
120
operator <<deqp::gles3::Functional::OutputVec121 OutputVec& operator<< (const FragmentOutput& output)
122 {
123 outputs.push_back(output);
124 return *this;
125 }
126
toVecdeqp::gles3::Functional::OutputVec127 vector<FragmentOutput> toVec (void) const
128 {
129 return outputs;
130 }
131 };
132
133 class FragmentOutputCase : public TestCase
134 {
135 public:
136 FragmentOutputCase (Context& context, const char* name, const char* desc, const vector<BufferSpec>& fboSpec, const vector<FragmentOutput>& outputs);
137 ~FragmentOutputCase (void);
138
139 void init (void);
140 void deinit (void);
141 IterateResult iterate (void);
142
143 private:
144 FragmentOutputCase (const FragmentOutputCase& other);
145 FragmentOutputCase& operator= (const FragmentOutputCase& other);
146
147 vector<BufferSpec> m_fboSpec;
148 vector<FragmentOutput> m_outputs;
149
150 glu::ShaderProgram* m_program;
151 deUint32 m_framebuffer;
152 vector<deUint32> m_renderbuffers;
153 };
154
FragmentOutputCase(Context & context,const char * name,const char * desc,const vector<BufferSpec> & fboSpec,const vector<FragmentOutput> & outputs)155 FragmentOutputCase::FragmentOutputCase (Context& context, const char* name, const char* desc, const vector<BufferSpec>& fboSpec, const vector<FragmentOutput>& outputs)
156 : TestCase (context, name, desc)
157 , m_fboSpec (fboSpec)
158 , m_outputs (outputs)
159 , m_program (DE_NULL)
160 , m_framebuffer (0)
161 {
162 }
163
~FragmentOutputCase(void)164 FragmentOutputCase::~FragmentOutputCase (void)
165 {
166 deinit();
167 }
168
createProgram(const glu::RenderContext & context,const vector<FragmentOutput> & outputs)169 static glu::ShaderProgram* createProgram (const glu::RenderContext& context, const vector<FragmentOutput>& outputs)
170 {
171 std::ostringstream vtx;
172 std::ostringstream frag;
173
174 vtx << "#version 300 es\n"
175 << "in highp vec4 a_position;\n";
176 frag << "#version 300 es\n";
177
178 // Input-output declarations.
179 for (int outNdx = 0; outNdx < (int)outputs.size(); outNdx++)
180 {
181 const FragmentOutput& output = outputs[outNdx];
182 bool isArray = output.arrayLength > 0;
183 const char* typeName = glu::getDataTypeName(output.type);
184 const char* precName = glu::getPrecisionName(output.precision);
185 bool isFloat = glu::isDataTypeFloatOrVec(output.type);
186 const char* interp = isFloat ? "smooth" : "flat";
187
188 if (isArray)
189 {
190 for (int elemNdx = 0; elemNdx < output.arrayLength; elemNdx++)
191 {
192 vtx << "in " << precName << " " << typeName << " in" << outNdx << "_" << elemNdx << ";\n"
193 << interp << " out " << precName << " " << typeName << " var" << outNdx << "_" << elemNdx << ";\n";
194 frag << interp << " in " << precName << " " << typeName << " var" << outNdx << "_" << elemNdx << ";\n";
195 }
196 frag << "layout(location = " << output.location << ") out " << precName << " " << typeName << " out" << outNdx << "[" << output.arrayLength << "];\n";
197 }
198 else
199 {
200 vtx << "in " << precName << " " << typeName << " in" << outNdx << ";\n"
201 << interp << " out " << precName << " " << typeName << " var" << outNdx << ";\n";
202 frag << interp << " in " << precName << " " << typeName << " var" << outNdx << ";\n"
203 << "layout(location = " << output.location << ") out " << precName << " " << typeName << " out" << outNdx << ";\n";
204 }
205 }
206
207 vtx << "\nvoid main()\n{\n";
208 frag << "\nvoid main()\n{\n";
209
210 vtx << " gl_Position = a_position;\n";
211
212 // Copy body
213 for (int outNdx = 0; outNdx < (int)outputs.size(); outNdx++)
214 {
215 const FragmentOutput& output = outputs[outNdx];
216 bool isArray = output.arrayLength > 0;
217
218 if (isArray)
219 {
220 for (int elemNdx = 0; elemNdx < output.arrayLength; elemNdx++)
221 {
222 vtx << "\tvar" << outNdx << "_" << elemNdx << " = in" << outNdx << "_" << elemNdx << ";\n";
223 frag << "\tout" << outNdx << "[" << elemNdx << "] = var" << outNdx << "_" << elemNdx << ";\n";
224 }
225 }
226 else
227 {
228 vtx << "\tvar" << outNdx << " = in" << outNdx << ";\n";
229 frag << "\tout" << outNdx << " = var" << outNdx << ";\n";
230 }
231 }
232
233 vtx << "}\n";
234 frag << "}\n";
235
236 return new glu::ShaderProgram(context, glu::makeVtxFragSources(vtx.str(), frag.str()));
237 }
238
init(void)239 void FragmentOutputCase::init (void)
240 {
241 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
242 TestLog& log = m_testCtx.getLog();
243
244 // Check that all attachments are supported
245 for (std::vector<BufferSpec>::const_iterator bufIter = m_fboSpec.begin(); bufIter != m_fboSpec.end(); ++bufIter)
246 {
247 if (!glu::isSizedFormatColorRenderable(m_context.getRenderContext(), m_context.getContextInfo(), bufIter->format))
248 throw tcu::NotSupportedError("Unsupported attachment format");
249 }
250
251 DE_ASSERT(!m_program);
252 m_program = createProgram(m_context.getRenderContext(), m_outputs);
253
254 log << *m_program;
255 if (!m_program->isOk())
256 TCU_FAIL("Compile failed");
257
258 // Print render target info to log.
259 log << TestLog::Section("Framebuffer", "Framebuffer configuration");
260
261 for (int ndx = 0; ndx < (int)m_fboSpec.size(); ndx++)
262 log << TestLog::Message << "COLOR_ATTACHMENT" << ndx << ": "
263 << glu::getPixelFormatStr(m_fboSpec[ndx].format) << ", "
264 << m_fboSpec[ndx].width << "x" << m_fboSpec[ndx].height << ", "
265 << m_fboSpec[ndx].samples << " samples"
266 << TestLog::EndMessage;
267
268 log << TestLog::EndSection;
269
270 // Create framebuffer.
271 m_renderbuffers.resize(m_fboSpec.size(), 0);
272 gl.genFramebuffers(1, &m_framebuffer);
273 gl.genRenderbuffers((int)m_renderbuffers.size(), &m_renderbuffers[0]);
274
275 gl.bindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
276
277 for (int bufNdx = 0; bufNdx < (int)m_renderbuffers.size(); bufNdx++)
278 {
279 deUint32 rbo = m_renderbuffers[bufNdx];
280 const BufferSpec& bufSpec = m_fboSpec[bufNdx];
281 deUint32 attachment = GL_COLOR_ATTACHMENT0+bufNdx;
282
283 gl.bindRenderbuffer(GL_RENDERBUFFER, rbo);
284 gl.renderbufferStorageMultisample(GL_RENDERBUFFER, bufSpec.samples, bufSpec.format, bufSpec.width, bufSpec.height);
285 gl.framebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, rbo);
286 }
287 GLU_EXPECT_NO_ERROR(gl.getError(), "After framebuffer setup");
288
289 deUint32 fboStatus = gl.checkFramebufferStatus(GL_FRAMEBUFFER);
290 if (fboStatus == GL_FRAMEBUFFER_UNSUPPORTED)
291 throw tcu::NotSupportedError("Framebuffer not supported", "", __FILE__, __LINE__);
292 else if (fboStatus != GL_FRAMEBUFFER_COMPLETE)
293 throw tcu::TestError((string("Incomplete framebuffer: ") + glu::getFramebufferStatusStr(fboStatus).toString()).c_str(), "", __FILE__, __LINE__);
294
295 gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
296 GLU_EXPECT_NO_ERROR(gl.getError(), "After init");
297 }
298
deinit(void)299 void FragmentOutputCase::deinit (void)
300 {
301 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
302
303 if (m_framebuffer)
304 {
305 gl.deleteFramebuffers(1, &m_framebuffer);
306 m_framebuffer = 0;
307 }
308
309 if (!m_renderbuffers.empty())
310 {
311 gl.deleteRenderbuffers((int)m_renderbuffers.size(), &m_renderbuffers[0]);
312 m_renderbuffers.clear();
313 }
314
315 delete m_program;
316 m_program = DE_NULL;
317 }
318
getMinSize(const vector<BufferSpec> & fboSpec)319 static IVec2 getMinSize (const vector<BufferSpec>& fboSpec)
320 {
321 IVec2 minSize(0x7fffffff, 0x7fffffff);
322 for (vector<BufferSpec>::const_iterator i = fboSpec.begin(); i != fboSpec.end(); i++)
323 {
324 minSize.x() = de::min(minSize.x(), i->width);
325 minSize.y() = de::min(minSize.y(), i->height);
326 }
327 return minSize;
328 }
329
getNumInputVectors(const vector<FragmentOutput> & outputs)330 static int getNumInputVectors (const vector<FragmentOutput>& outputs)
331 {
332 int numVecs = 0;
333 for (vector<FragmentOutput>::const_iterator i = outputs.begin(); i != outputs.end(); i++)
334 numVecs += (i->arrayLength > 0 ? i->arrayLength : 1);
335 return numVecs;
336 }
337
getFloatRange(glu::Precision precision)338 static Vec2 getFloatRange (glu::Precision precision)
339 {
340 // \todo [2012-04-09 pyry] Not quite the full ranges.
341 static const Vec2 ranges[] =
342 {
343 Vec2(-2.0f, 2.0f),
344 Vec2(-16000.0f, 16000.0f),
345 Vec2(-1e35f, 1e35f)
346 };
347 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(ranges) == glu::PRECISION_LAST);
348 DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(ranges)));
349 return ranges[precision];
350 }
351
getIntRange(glu::Precision precision)352 static IVec2 getIntRange (glu::Precision precision)
353 {
354 static const IVec2 ranges[] =
355 {
356 IVec2(-(1<< 7), (1<< 7)-1),
357 IVec2(-(1<<15), (1<<15)-1),
358 IVec2(0x80000000, 0x7fffffff)
359 };
360 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(ranges) == glu::PRECISION_LAST);
361 DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(ranges)));
362 return ranges[precision];
363 }
364
getUintRange(glu::Precision precision)365 static UVec2 getUintRange (glu::Precision precision)
366 {
367 static const UVec2 ranges[] =
368 {
369 UVec2(0, (1<< 8)-1),
370 UVec2(0, (1<<16)-1),
371 UVec2(0, 0xffffffffu)
372 };
373 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(ranges) == glu::PRECISION_LAST);
374 DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(ranges)));
375 return ranges[precision];
376 }
377
readVec4(const float * ptr,int numComponents)378 static inline Vec4 readVec4 (const float* ptr, int numComponents)
379 {
380 DE_ASSERT(numComponents >= 1);
381 return Vec4(ptr[0],
382 numComponents >= 2 ? ptr[1] : 0.0f,
383 numComponents >= 3 ? ptr[2] : 0.0f,
384 numComponents >= 4 ? ptr[3] : 0.0f);
385 }
386
readIVec4(const int * ptr,int numComponents)387 static inline IVec4 readIVec4 (const int* ptr, int numComponents)
388 {
389 DE_ASSERT(numComponents >= 1);
390 return IVec4(ptr[0],
391 numComponents >= 2 ? ptr[1] : 0,
392 numComponents >= 3 ? ptr[2] : 0,
393 numComponents >= 4 ? ptr[3] : 0);
394 }
395
renderFloatReference(const tcu::PixelBufferAccess & dst,int gridWidth,int gridHeight,int numComponents,const float * vertices)396 static void renderFloatReference (const tcu::PixelBufferAccess& dst, int gridWidth, int gridHeight, int numComponents, const float* vertices)
397 {
398 const bool isSRGB = dst.getFormat().order == tcu::TextureFormat::sRGB ||dst.getFormat().order == tcu::TextureFormat::sRGBA;
399 const float cellW = (float)dst.getWidth() / (float)(gridWidth-1);
400 const float cellH = (float)dst.getHeight() / (float)(gridHeight-1);
401
402 for (int y = 0; y < dst.getHeight(); y++)
403 {
404 for (int x = 0; x < dst.getWidth(); x++)
405 {
406 const int cellX = de::clamp(deFloorFloatToInt32((float)x / cellW), 0, gridWidth-2);
407 const int cellY = de::clamp(deFloorFloatToInt32((float)y / cellH), 0, gridHeight-2);
408 const float xf = ((float)x - (float)cellX*cellW + 0.5f) / cellW;
409 const float yf = ((float)y - (float)cellY*cellH + 0.5f) / cellH;
410 const Vec4 v00 = readVec4(vertices + ((cellY+0)*gridWidth + cellX+0)*numComponents, numComponents);
411 const Vec4 v01 = readVec4(vertices + ((cellY+1)*gridWidth + cellX+0)*numComponents, numComponents);
412 const Vec4 v10 = readVec4(vertices + ((cellY+0)*gridWidth + cellX+1)*numComponents, numComponents);
413 const Vec4 v11 = readVec4(vertices + ((cellY+1)*gridWidth + cellX+1)*numComponents, numComponents);
414 const bool tri = xf + yf >= 1.0f;
415 const Vec4& v0 = tri ? v11 : v00;
416 const Vec4& v1 = tri ? v01 : v10;
417 const Vec4& v2 = tri ? v10 : v01;
418 const float s = tri ? 1.0f-xf : xf;
419 const float t = tri ? 1.0f-yf : yf;
420 const Vec4 color = v0 + (v1-v0)*s + (v2-v0)*t;
421
422 dst.setPixel(isSRGB ? tcu::linearToSRGB(color) : color, x, y);
423 }
424 }
425 }
426
renderIntReference(const tcu::PixelBufferAccess & dst,int gridWidth,int gridHeight,int numComponents,const int * vertices)427 static void renderIntReference (const tcu::PixelBufferAccess& dst, int gridWidth, int gridHeight, int numComponents, const int* vertices)
428 {
429 float cellW = (float)dst.getWidth() / (float)(gridWidth-1);
430 float cellH = (float)dst.getHeight() / (float)(gridHeight-1);
431
432 for (int y = 0; y < dst.getHeight(); y++)
433 {
434 for (int x = 0; x < dst.getWidth(); x++)
435 {
436 int cellX = de::clamp(deFloorFloatToInt32((float)x / cellW), 0, gridWidth-2);
437 int cellY = de::clamp(deFloorFloatToInt32((float)y / cellH), 0, gridHeight-2);
438 IVec4 c = readIVec4(vertices + (cellY*gridWidth + cellX+1)*numComponents, numComponents);
439
440 dst.setPixel(c, x, y);
441 }
442 }
443 }
444
445 static const IVec4 s_swizzles[] =
446 {
447 IVec4(0,1,2,3),
448 IVec4(1,2,3,0),
449 IVec4(2,3,0,1),
450 IVec4(3,0,1,2),
451 IVec4(3,2,1,0),
452 IVec4(2,1,0,3),
453 IVec4(1,0,3,2),
454 IVec4(0,3,2,1)
455 };
456
457 template <typename T>
swizzleVec(const tcu::Vector<T,4> & vec,int swzNdx)458 inline tcu::Vector<T, 4> swizzleVec (const tcu::Vector<T, 4>& vec, int swzNdx)
459 {
460 const IVec4& swz = s_swizzles[swzNdx % DE_LENGTH_OF_ARRAY(s_swizzles)];
461 return vec.swizzle(swz[0], swz[1], swz[2], swz[3]);
462 }
463
464 namespace
465 {
466
467 struct AttachmentData
468 {
469 tcu::TextureFormat format; //!< Actual format of attachment.
470 tcu::TextureFormat referenceFormat; //!< Used for reference rendering.
471 tcu::TextureFormat readFormat;
472 int numWrittenChannels;
473 glu::Precision outPrecision;
474 vector<deUint8> renderedData;
475 vector<deUint8> referenceData;
476 };
477
478 } // anonymous
479
iterate(void)480 FragmentOutputCase::IterateResult FragmentOutputCase::iterate (void)
481 {
482 TestLog& log = m_testCtx.getLog();
483 const glw::Functions& gl = m_context.getRenderContext().getFunctions();
484
485 // Compute grid size & index list.
486 const int minCellSize = 8;
487 const IVec2 minBufSize = getMinSize(m_fboSpec);
488 const int gridWidth = de::clamp(minBufSize.x()/minCellSize, 1, 255)+1;
489 const int gridHeight = de::clamp(minBufSize.y()/minCellSize, 1, 255)+1;
490 const int numVertices = gridWidth*gridHeight;
491 const int numQuads = (gridWidth-1)*(gridHeight-1);
492 const int numIndices = numQuads*6;
493
494 const int numInputVecs = getNumInputVectors(m_outputs);
495 vector<vector<deUint32> > inputs (numInputVecs);
496 vector<float> positions (numVertices*4);
497 vector<deUint16> indices (numIndices);
498
499 const int readAlignment = 4;
500 const int viewportW = minBufSize.x();
501 const int viewportH = minBufSize.y();
502 const int numAttachments = (int)m_fboSpec.size();
503
504 vector<deUint32> drawBuffers (numAttachments);
505 vector<AttachmentData> attachments (numAttachments);
506
507 // Initialize attachment data.
508 for (int ndx = 0; ndx < numAttachments; ndx++)
509 {
510 const tcu::TextureFormat texFmt = glu::mapGLInternalFormat(m_fboSpec[ndx].format);
511 const tcu::TextureChannelClass chnClass = tcu::getTextureChannelClass(texFmt.type);
512 const bool isFixedPoint = chnClass == tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT ||
513 chnClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT;
514
515 // \note Fixed-point formats use float reference to enable more accurate result verification.
516 const tcu::TextureFormat refFmt = isFixedPoint ? tcu::TextureFormat(texFmt.order, tcu::TextureFormat::FLOAT) : texFmt;
517 const tcu::TextureFormat readFmt = getFramebufferReadFormat(texFmt);
518 const int attachmentW = m_fboSpec[ndx].width;
519 const int attachmentH = m_fboSpec[ndx].height;
520
521 drawBuffers[ndx] = GL_COLOR_ATTACHMENT0+ndx;
522 attachments[ndx].format = texFmt;
523 attachments[ndx].readFormat = readFmt;
524 attachments[ndx].referenceFormat = refFmt;
525 attachments[ndx].renderedData.resize(readFmt.getPixelSize()*attachmentW*attachmentH);
526 attachments[ndx].referenceData.resize(refFmt.getPixelSize()*attachmentW*attachmentH);
527 }
528
529 // Initialize indices.
530 for (int quadNdx = 0; quadNdx < numQuads; quadNdx++)
531 {
532 int quadY = quadNdx / (gridWidth-1);
533 int quadX = quadNdx - quadY*(gridWidth-1);
534
535 indices[quadNdx*6+0] = quadX + quadY*gridWidth;
536 indices[quadNdx*6+1] = quadX + (quadY+1)*gridWidth;
537 indices[quadNdx*6+2] = quadX + quadY*gridWidth + 1;
538 indices[quadNdx*6+3] = indices[quadNdx*6+1];
539 indices[quadNdx*6+4] = quadX + (quadY+1)*gridWidth + 1;
540 indices[quadNdx*6+5] = indices[quadNdx*6+2];
541 }
542
543 for (int y = 0; y < gridHeight; y++)
544 {
545 for (int x = 0; x < gridWidth; x++)
546 {
547 float xf = (float)x / (float)(gridWidth-1);
548 float yf = (float)y / (float)(gridHeight-1);
549
550 positions[(y*gridWidth + x)*4 + 0] = 2.0f*xf - 1.0f;
551 positions[(y*gridWidth + x)*4 + 1] = 2.0f*yf - 1.0f;
552 positions[(y*gridWidth + x)*4 + 2] = 0.0f;
553 positions[(y*gridWidth + x)*4 + 3] = 1.0f;
554 }
555 }
556
557 // Initialize input vectors.
558 {
559 int curInVec = 0;
560 for (int outputNdx = 0; outputNdx < (int)m_outputs.size(); outputNdx++)
561 {
562 const FragmentOutput& output = m_outputs[outputNdx];
563 bool isFloat = glu::isDataTypeFloatOrVec(output.type);
564 bool isInt = glu::isDataTypeIntOrIVec(output.type);
565 bool isUint = glu::isDataTypeUintOrUVec(output.type);
566 int numVecs = output.arrayLength > 0 ? output.arrayLength : 1;
567 int numScalars = glu::getDataTypeScalarSize(output.type);
568
569 for (int vecNdx = 0; vecNdx < numVecs; vecNdx++)
570 {
571 inputs[curInVec].resize(numVertices*numScalars);
572
573 // Record how many outputs are written in attachment.
574 DE_ASSERT(output.location+vecNdx < (int)attachments.size());
575 attachments[output.location+vecNdx].numWrittenChannels = numScalars;
576 attachments[output.location+vecNdx].outPrecision = output.precision;
577
578 if (isFloat)
579 {
580 Vec2 range = getFloatRange(output.precision);
581 Vec4 minVal (range.x());
582 Vec4 maxVal (range.y());
583 float* dst = (float*)&inputs[curInVec][0];
584
585 if (de::inBounds(output.location+vecNdx, 0, (int)attachments.size()))
586 {
587 // \note Floating-point precision conversion is not well-defined. For that reason we must
588 // limit value range to intersection of both data type and render target value ranges.
589 const tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(attachments[output.location+vecNdx].format);
590 minVal = tcu::max(minVal, fmtInfo.valueMin);
591 maxVal = tcu::min(maxVal, fmtInfo.valueMax);
592 }
593
594 m_testCtx.getLog() << TestLog::Message << "out" << curInVec << " value range: " << minVal << " -> " << maxVal << TestLog::EndMessage;
595
596 for (int y = 0; y < gridHeight; y++)
597 {
598 for (int x = 0; x < gridWidth; x++)
599 {
600 float xf = (float)x / (float)(gridWidth-1);
601 float yf = (float)y / (float)(gridHeight-1);
602
603 float f0 = (xf + yf) * 0.5f;
604 float f1 = 0.5f + (xf - yf) * 0.5f;
605 Vec4 f = swizzleVec(Vec4(f0, f1, 1.0f-f0, 1.0f-f1), curInVec);
606 Vec4 c = minVal + (maxVal-minVal)*f;
607 float* v = dst + (y*gridWidth + x)*numScalars;
608
609 for (int ndx = 0; ndx < numScalars; ndx++)
610 v[ndx] = c[ndx];
611 }
612 }
613 }
614 else if (isInt)
615 {
616 const IVec2 range = getIntRange(output.precision);
617 IVec4 minVal (range.x());
618 IVec4 maxVal (range.y());
619
620 if (de::inBounds(output.location+vecNdx, 0, (int)attachments.size()))
621 {
622 // Limit to range of output format as conversion mode is not specified.
623 const IVec4 fmtBits = tcu::getTextureFormatBitDepth(attachments[output.location+vecNdx].format);
624 const BVec4 isZero = lessThanEqual(fmtBits, IVec4(0));
625 const IVec4 fmtMinVal = (-(tcu::Vector<deInt64, 4>(1) << (fmtBits-1).cast<deInt64>())).asInt();
626 const IVec4 fmtMaxVal = ((tcu::Vector<deInt64, 4>(1) << (fmtBits-1).cast<deInt64>())-deInt64(1)).asInt();
627
628 minVal = select(minVal, tcu::max(minVal, fmtMinVal), isZero);
629 maxVal = select(maxVal, tcu::min(maxVal, fmtMaxVal), isZero);
630 }
631
632 m_testCtx.getLog() << TestLog::Message << "out" << curInVec << " value range: " << minVal << " -> " << maxVal << TestLog::EndMessage;
633
634 const IVec4 rangeDiv = swizzleVec((IVec4(gridWidth, gridHeight, gridWidth, gridHeight)-1), curInVec);
635 const IVec4 step = ((maxVal.cast<deInt64>() - minVal.cast<deInt64>()) / (rangeDiv.cast<deInt64>())).asInt();
636 deInt32* dst = (deInt32*)&inputs[curInVec][0];
637
638 for (int y = 0; y < gridHeight; y++)
639 {
640 for (int x = 0; x < gridWidth; x++)
641 {
642 int ix = gridWidth - x - 1;
643 int iy = gridHeight - y - 1;
644 IVec4 c = minVal + step*swizzleVec(IVec4(x, y, ix, iy), curInVec);
645 deInt32* v = dst + (y*gridWidth + x)*numScalars;
646
647 DE_ASSERT(boolAll(logicalAnd(greaterThanEqual(c, minVal), lessThanEqual(c, maxVal))));
648
649 for (int ndx = 0; ndx < numScalars; ndx++)
650 v[ndx] = c[ndx];
651 }
652 }
653 }
654 else if (isUint)
655 {
656 const UVec2 range = getUintRange(output.precision);
657 UVec4 maxVal (range.y());
658
659 if (de::inBounds(output.location+vecNdx, 0, (int)attachments.size()))
660 {
661 // Limit to range of output format as conversion mode is not specified.
662 const IVec4 fmtBits = tcu::getTextureFormatBitDepth(attachments[output.location+vecNdx].format);
663 const UVec4 fmtMaxVal = ((tcu::Vector<deUint64, 4>(1) << fmtBits.cast<deUint64>())-deUint64(1)).asUint();
664
665 maxVal = tcu::min(maxVal, fmtMaxVal);
666 }
667
668 m_testCtx.getLog() << TestLog::Message << "out" << curInVec << " value range: " << UVec4(0) << " -> " << maxVal << TestLog::EndMessage;
669
670 const IVec4 rangeDiv = swizzleVec((IVec4(gridWidth, gridHeight, gridWidth, gridHeight)-1), curInVec);
671 const UVec4 step = maxVal / rangeDiv.asUint();
672 deUint32* dst = &inputs[curInVec][0];
673
674 DE_ASSERT(range.x() == 0);
675
676 for (int y = 0; y < gridHeight; y++)
677 {
678 for (int x = 0; x < gridWidth; x++)
679 {
680 int ix = gridWidth - x - 1;
681 int iy = gridHeight - y - 1;
682 UVec4 c = step*swizzleVec(IVec4(x, y, ix, iy).asUint(), curInVec);
683 deUint32* v = dst + (y*gridWidth + x)*numScalars;
684
685 DE_ASSERT(boolAll(lessThanEqual(c, maxVal)));
686
687 for (int ndx = 0; ndx < numScalars; ndx++)
688 v[ndx] = c[ndx];
689 }
690 }
691 }
692 else
693 DE_ASSERT(false);
694
695 curInVec += 1;
696 }
697 }
698 }
699
700 // Render using gl.
701 gl.useProgram(m_program->getProgram());
702 gl.bindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
703 gl.viewport(0, 0, viewportW, viewportH);
704 gl.drawBuffers((int)drawBuffers.size(), &drawBuffers[0]);
705 gl.disable(GL_DITHER); // Dithering causes issues with unorm formats. Those issues could be worked around in threshold, but it makes validation less accurate.
706 GLU_EXPECT_NO_ERROR(gl.getError(), "After program setup");
707
708 {
709 int curInVec = 0;
710 for (int outputNdx = 0; outputNdx < (int)m_outputs.size(); outputNdx++)
711 {
712 const FragmentOutput& output = m_outputs[outputNdx];
713 bool isArray = output.arrayLength > 0;
714 bool isFloat = glu::isDataTypeFloatOrVec(output.type);
715 bool isInt = glu::isDataTypeIntOrIVec(output.type);
716 bool isUint = glu::isDataTypeUintOrUVec(output.type);
717 int scalarSize = glu::getDataTypeScalarSize(output.type);
718 deUint32 glScalarType = isFloat ? GL_FLOAT :
719 isInt ? GL_INT :
720 isUint ? GL_UNSIGNED_INT : GL_NONE;
721 int numVecs = isArray ? output.arrayLength : 1;
722
723 for (int vecNdx = 0; vecNdx < numVecs; vecNdx++)
724 {
725 string name = string("in") + de::toString(outputNdx) + (isArray ? string("_") + de::toString(vecNdx) : string());
726 int loc = gl.getAttribLocation(m_program->getProgram(), name.c_str());
727
728 if (loc >= 0)
729 {
730 gl.enableVertexAttribArray(loc);
731 if (isFloat)
732 gl.vertexAttribPointer(loc, scalarSize, glScalarType, GL_FALSE, 0, &inputs[curInVec][0]);
733 else
734 gl.vertexAttribIPointer(loc, scalarSize, glScalarType, 0, &inputs[curInVec][0]);
735 }
736 else
737 log << TestLog::Message << "Warning: No location for attribute '" << name << "' found." << TestLog::EndMessage;
738
739 curInVec += 1;
740 }
741 }
742 }
743 {
744 int posLoc = gl.getAttribLocation(m_program->getProgram(), "a_position");
745 TCU_CHECK(posLoc >= 0);
746 gl.enableVertexAttribArray(posLoc);
747 gl.vertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &positions[0]);
748 }
749 GLU_EXPECT_NO_ERROR(gl.getError(), "After attribute setup");
750
751 gl.drawElements(GL_TRIANGLES, numIndices, GL_UNSIGNED_SHORT, &indices[0]);
752 GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawElements");
753
754 // Read all attachment points.
755 for (int ndx = 0; ndx < numAttachments; ndx++)
756 {
757 const glu::TransferFormat transferFmt = glu::getTransferFormat(attachments[ndx].readFormat);
758 void* dst = &attachments[ndx].renderedData[0];
759
760 gl.readBuffer(GL_COLOR_ATTACHMENT0+ndx);
761 gl.readPixels(0, 0, minBufSize.x(), minBufSize.y(), transferFmt.format, transferFmt.dataType, dst);
762 }
763
764 // Render reference images.
765 {
766 int curInNdx = 0;
767 for (int outputNdx = 0; outputNdx < (int)m_outputs.size(); outputNdx++)
768 {
769 const FragmentOutput& output = m_outputs[outputNdx];
770 const bool isArray = output.arrayLength > 0;
771 const bool isFloat = glu::isDataTypeFloatOrVec(output.type);
772 const bool isInt = glu::isDataTypeIntOrIVec(output.type);
773 const bool isUint = glu::isDataTypeUintOrUVec(output.type);
774 const int scalarSize = glu::getDataTypeScalarSize(output.type);
775 const int numVecs = isArray ? output.arrayLength : 1;
776
777 for (int vecNdx = 0; vecNdx < numVecs; vecNdx++)
778 {
779 const int location = output.location+vecNdx;
780 const void* inputData = &inputs[curInNdx][0];
781
782 DE_ASSERT(de::inBounds(location, 0, (int)m_fboSpec.size()));
783
784 const int bufW = m_fboSpec[location].width;
785 const int bufH = m_fboSpec[location].height;
786 const tcu::PixelBufferAccess buf (attachments[location].referenceFormat, bufW, bufH, 1, &attachments[location].referenceData[0]);
787 const tcu::PixelBufferAccess viewportBuf = getSubregion(buf, 0, 0, 0, viewportW, viewportH, 1);
788
789 if (isInt || isUint)
790 renderIntReference(viewportBuf, gridWidth, gridHeight, scalarSize, (const int*)inputData);
791 else if (isFloat)
792 renderFloatReference(viewportBuf, gridWidth, gridHeight, scalarSize, (const float*)inputData);
793 else
794 DE_ASSERT(false);
795
796 curInNdx += 1;
797 }
798 }
799 }
800
801 // Compare all images.
802 bool allLevelsOk = true;
803 for (int attachNdx = 0; attachNdx < numAttachments; attachNdx++)
804 {
805 const int attachmentW = m_fboSpec[attachNdx].width;
806 const int attachmentH = m_fboSpec[attachNdx].height;
807 const int numValidChannels = attachments[attachNdx].numWrittenChannels;
808 const tcu::BVec4 cmpMask (numValidChannels >= 1, numValidChannels >= 2, numValidChannels >= 3, numValidChannels >= 4);
809 const glu::Precision outPrecision = attachments[attachNdx].outPrecision;
810 const tcu::TextureFormat& format = attachments[attachNdx].format;
811 tcu::ConstPixelBufferAccess rendered (attachments[attachNdx].readFormat, attachmentW, attachmentH, 1, deAlign32(attachments[attachNdx].readFormat.getPixelSize()*attachmentW, readAlignment), 0, &attachments[attachNdx].renderedData[0]);
812 tcu::ConstPixelBufferAccess reference (attachments[attachNdx].referenceFormat, attachmentW, attachmentH, 1, &attachments[attachNdx].referenceData[0]);
813 tcu::TextureChannelClass texClass = tcu::getTextureChannelClass(format.type);
814 bool isOk = true;
815 const string name = string("Attachment") + de::toString(attachNdx);
816 const string desc = string("Color attachment ") + de::toString(attachNdx);
817
818 log << TestLog::Message << "Attachment " << attachNdx << ": " << numValidChannels << " channels have defined values and used for comparison" << TestLog::EndMessage;
819
820 switch (texClass)
821 {
822 case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
823 {
824 UVec4 formatThreshold; //!< Threshold computed based on format.
825 deUint32 precThreshold = 0; //!< Threshold computed based on output type precision
826 UVec4 finalThreshold;
827
828 switch (format.type)
829 {
830 case tcu::TextureFormat::FLOAT: formatThreshold = UVec4(4); break;
831 case tcu::TextureFormat::HALF_FLOAT: formatThreshold = UVec4((1<<13) + 4); break;
832 case tcu::TextureFormat::UNSIGNED_INT_11F_11F_10F_REV: formatThreshold = UVec4((1<<17) + 4, (1<<17)+4, (1<<18)+4, 4); break;
833 default:
834 DE_ASSERT(false);
835 break;
836 }
837
838 switch (outPrecision)
839 {
840 case glu::PRECISION_LOWP: precThreshold = (1<<21); break;
841 case glu::PRECISION_MEDIUMP: precThreshold = (1<<13); break;
842 case glu::PRECISION_HIGHP: precThreshold = 0; break;
843 default:
844 DE_ASSERT(false);
845 }
846
847 finalThreshold = select(max(formatThreshold, UVec4(precThreshold)), UVec4(~0u), cmpMask);
848
849 isOk = tcu::floatUlpThresholdCompare(log, name.c_str(), desc.c_str(), reference, rendered, finalThreshold, tcu::COMPARE_LOG_RESULT);
850 break;
851 }
852
853 case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
854 {
855 // \note glReadPixels() allows only 8 bits to be read. This means that RGB10_A2 will loose some
856 // bits in the process and it must be taken into account when computing threshold.
857 const IVec4 bits = min(IVec4(8), tcu::getTextureFormatBitDepth(format));
858 const Vec4 baseThreshold = 1.0f / ((IVec4(1) << bits)-1).asFloat();
859 const Vec4 threshold = select(baseThreshold, Vec4(2.0f), cmpMask);
860
861 isOk = tcu::floatThresholdCompare(log, name.c_str(), desc.c_str(), reference, rendered, threshold, tcu::COMPARE_LOG_RESULT);
862 break;
863 }
864
865 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
866 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
867 {
868 const tcu::UVec4 threshold = select(UVec4(0u), UVec4(~0u), cmpMask);
869 isOk = tcu::intThresholdCompare(log, name.c_str(), desc.c_str(), reference, rendered, threshold, tcu::COMPARE_LOG_RESULT);
870 break;
871 }
872
873 default:
874 TCU_FAIL("Unsupported comparison");
875 break;
876 }
877
878 if (!isOk)
879 allLevelsOk = false;
880 }
881
882 m_testCtx.setTestResult(allLevelsOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
883 allLevelsOk ? "Pass" : "Image comparison failed");
884 return STOP;
885 }
886
FragmentOutputTests(Context & context)887 FragmentOutputTests::FragmentOutputTests (Context& context)
888 : TestCaseGroup(context, "fragment_out", "Fragment output tests")
889 {
890 }
891
~FragmentOutputTests(void)892 FragmentOutputTests::~FragmentOutputTests (void)
893 {
894 }
895
createRandomCase(Context & context,int minRenderTargets,int maxRenderTargets,deUint32 seed)896 static FragmentOutputCase* createRandomCase (Context& context, int minRenderTargets, int maxRenderTargets, deUint32 seed)
897 {
898 static const glu::DataType outputTypes[] =
899 {
900 glu::TYPE_FLOAT,
901 glu::TYPE_FLOAT_VEC2,
902 glu::TYPE_FLOAT_VEC3,
903 glu::TYPE_FLOAT_VEC4,
904 glu::TYPE_INT,
905 glu::TYPE_INT_VEC2,
906 glu::TYPE_INT_VEC3,
907 glu::TYPE_INT_VEC4,
908 glu::TYPE_UINT,
909 glu::TYPE_UINT_VEC2,
910 glu::TYPE_UINT_VEC3,
911 glu::TYPE_UINT_VEC4
912 };
913 static const glu::Precision precisions[] =
914 {
915 glu::PRECISION_LOWP,
916 glu::PRECISION_MEDIUMP,
917 glu::PRECISION_HIGHP
918 };
919 static const deUint32 floatFormats[] =
920 {
921 GL_RGBA32F,
922 GL_RGBA16F,
923 GL_R11F_G11F_B10F,
924 GL_RG32F,
925 GL_RG16F,
926 GL_R32F,
927 GL_R16F,
928 GL_RGBA8,
929 GL_SRGB8_ALPHA8,
930 GL_RGB10_A2,
931 GL_RGBA4,
932 GL_RGB5_A1,
933 GL_RGB8,
934 GL_RGB565,
935 GL_RG8,
936 GL_R8
937 };
938 static const deUint32 intFormats[] =
939 {
940 GL_RGBA32I,
941 GL_RGBA16I,
942 GL_RGBA8I,
943 GL_RG32I,
944 GL_RG16I,
945 GL_RG8I,
946 GL_R32I,
947 GL_R16I,
948 GL_R8I
949 };
950 static const deUint32 uintFormats[] =
951 {
952 GL_RGBA32UI,
953 GL_RGBA16UI,
954 GL_RGBA8UI,
955 GL_RGB10_A2UI,
956 GL_RG32UI,
957 GL_RG16UI,
958 GL_RG8UI,
959 GL_R32UI,
960 GL_R16UI,
961 GL_R8UI
962 };
963
964 de::Random rnd (seed);
965 vector<FragmentOutput> outputs;
966 vector<BufferSpec> targets;
967 vector<glu::DataType> outTypes;
968
969 int numTargets = rnd.getInt(minRenderTargets, maxRenderTargets);
970 const int width = 128; // \todo [2012-04-10 pyry] Separate randomized sizes per target?
971 const int height = 64;
972 const int samples = 0;
973
974 // Compute outputs.
975 int curLoc = 0;
976 while (curLoc < numTargets)
977 {
978 bool useArray = rnd.getFloat() < 0.3f;
979 int maxArrayLen = numTargets-curLoc;
980 int arrayLen = useArray ? rnd.getInt(1, maxArrayLen) : 0;
981 glu::DataType basicType = rnd.choose<glu::DataType>(&outputTypes[0], &outputTypes[0] + DE_LENGTH_OF_ARRAY(outputTypes));
982 glu::Precision precision = rnd.choose<glu::Precision>(&precisions[0], &precisions[0] + DE_LENGTH_OF_ARRAY(precisions));
983 int numLocations = useArray ? arrayLen : 1;
984
985 outputs.push_back(FragmentOutput(basicType, precision, curLoc, arrayLen));
986
987 for (int ndx = 0; ndx < numLocations; ndx++)
988 outTypes.push_back(basicType);
989
990 curLoc += numLocations;
991 }
992 DE_ASSERT(curLoc == numTargets);
993 DE_ASSERT((int)outTypes.size() == numTargets);
994
995 // Compute buffers.
996 while ((int)targets.size() < numTargets)
997 {
998 glu::DataType outType = outTypes[targets.size()];
999 bool isFloat = glu::isDataTypeFloatOrVec(outType);
1000 bool isInt = glu::isDataTypeIntOrIVec(outType);
1001 bool isUint = glu::isDataTypeUintOrUVec(outType);
1002 deUint32 format = 0;
1003
1004 if (isFloat)
1005 format = rnd.choose<deUint32>(&floatFormats[0], &floatFormats[0] + DE_LENGTH_OF_ARRAY(floatFormats));
1006 else if (isInt)
1007 format = rnd.choose<deUint32>(&intFormats[0], &intFormats[0] + DE_LENGTH_OF_ARRAY(intFormats));
1008 else if (isUint)
1009 format = rnd.choose<deUint32>(&uintFormats[0], &uintFormats[0] + DE_LENGTH_OF_ARRAY(uintFormats));
1010 else
1011 DE_ASSERT(false);
1012
1013 targets.push_back(BufferSpec(format, width, height, samples));
1014 }
1015
1016 return new FragmentOutputCase(context, de::toString(seed).c_str(), "", targets, outputs);
1017 }
1018
init(void)1019 void FragmentOutputTests::init (void)
1020 {
1021 static const deUint32 requiredFloatFormats[] =
1022 {
1023 GL_RGBA32F,
1024 GL_RGBA16F,
1025 GL_R11F_G11F_B10F,
1026 GL_RG32F,
1027 GL_RG16F,
1028 GL_R32F,
1029 GL_R16F
1030 };
1031 static const deUint32 requiredFixedFormats[] =
1032 {
1033 GL_RGBA8,
1034 GL_SRGB8_ALPHA8,
1035 GL_RGB10_A2,
1036 GL_RGBA4,
1037 GL_RGB5_A1,
1038 GL_RGB8,
1039 GL_RGB565,
1040 GL_RG8,
1041 GL_R8
1042 };
1043 static const deUint32 requiredIntFormats[] =
1044 {
1045 GL_RGBA32I,
1046 GL_RGBA16I,
1047 GL_RGBA8I,
1048 GL_RG32I,
1049 GL_RG16I,
1050 GL_RG8I,
1051 GL_R32I,
1052 GL_R16I,
1053 GL_R8I
1054 };
1055 static const deUint32 requiredUintFormats[] =
1056 {
1057 GL_RGBA32UI,
1058 GL_RGBA16UI,
1059 GL_RGBA8UI,
1060 GL_RGB10_A2UI,
1061 GL_RG32UI,
1062 GL_RG16UI,
1063 GL_RG8UI,
1064 GL_R32UI,
1065 GL_R16UI,
1066 GL_R8UI
1067 };
1068
1069 static const glu::Precision precisions[] =
1070 {
1071 glu::PRECISION_LOWP,
1072 glu::PRECISION_MEDIUMP,
1073 glu::PRECISION_HIGHP
1074 };
1075
1076 // .basic.
1077 {
1078 tcu::TestCaseGroup* basicGroup = new tcu::TestCaseGroup(m_testCtx, "basic", "Basic fragment output tests");
1079 addChild(basicGroup);
1080
1081 const int width = 64;
1082 const int height = 64;
1083 const int samples = 0;
1084
1085 // .float
1086 tcu::TestCaseGroup* floatGroup = new tcu::TestCaseGroup(m_testCtx, "float", "Floating-point output tests");
1087 basicGroup->addChild(floatGroup);
1088 for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(requiredFloatFormats); fmtNdx++)
1089 {
1090 deUint32 format = requiredFloatFormats[fmtNdx];
1091 string fmtName = getFormatName(format);
1092 vector<BufferSpec> fboSpec;
1093
1094 fboSpec.push_back(BufferSpec(format, width, height, samples));
1095
1096 for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisions); precNdx++)
1097 {
1098 glu::Precision prec = precisions[precNdx];
1099 string precName = glu::getPrecisionName(prec);
1100
1101 floatGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_float").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_FLOAT, prec, 0)).toVec()));
1102 floatGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_vec2").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_FLOAT_VEC2, prec, 0)).toVec()));
1103 floatGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_vec3").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_FLOAT_VEC3, prec, 0)).toVec()));
1104 floatGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_vec4").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_FLOAT_VEC4, prec, 0)).toVec()));
1105 }
1106 }
1107
1108 // .fixed
1109 tcu::TestCaseGroup* fixedGroup = new tcu::TestCaseGroup(m_testCtx, "fixed", "Fixed-point output tests");
1110 basicGroup->addChild(fixedGroup);
1111 for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(requiredFixedFormats); fmtNdx++)
1112 {
1113 deUint32 format = requiredFixedFormats[fmtNdx];
1114 string fmtName = getFormatName(format);
1115 vector<BufferSpec> fboSpec;
1116
1117 fboSpec.push_back(BufferSpec(format, width, height, samples));
1118
1119 for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisions); precNdx++)
1120 {
1121 glu::Precision prec = precisions[precNdx];
1122 string precName = glu::getPrecisionName(prec);
1123
1124 fixedGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_float").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_FLOAT, prec, 0)).toVec()));
1125 fixedGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_vec2").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_FLOAT_VEC2, prec, 0)).toVec()));
1126 fixedGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_vec3").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_FLOAT_VEC3, prec, 0)).toVec()));
1127 fixedGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_vec4").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_FLOAT_VEC4, prec, 0)).toVec()));
1128 }
1129 }
1130
1131 // .int
1132 tcu::TestCaseGroup* intGroup = new tcu::TestCaseGroup(m_testCtx, "int", "Integer output tests");
1133 basicGroup->addChild(intGroup);
1134 for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(requiredIntFormats); fmtNdx++)
1135 {
1136 deUint32 format = requiredIntFormats[fmtNdx];
1137 string fmtName = getFormatName(format);
1138 vector<BufferSpec> fboSpec;
1139
1140 fboSpec.push_back(BufferSpec(format, width, height, samples));
1141
1142 for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisions); precNdx++)
1143 {
1144 glu::Precision prec = precisions[precNdx];
1145 string precName = glu::getPrecisionName(prec);
1146
1147 intGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_int").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_INT, prec, 0)).toVec()));
1148 intGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_ivec2").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_INT_VEC2, prec, 0)).toVec()));
1149 intGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_ivec3").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_INT_VEC3, prec, 0)).toVec()));
1150 intGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_ivec4").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_INT_VEC4, prec, 0)).toVec()));
1151 }
1152 }
1153
1154 // .uint
1155 tcu::TestCaseGroup* uintGroup = new tcu::TestCaseGroup(m_testCtx, "uint", "Usigned integer output tests");
1156 basicGroup->addChild(uintGroup);
1157 for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(requiredUintFormats); fmtNdx++)
1158 {
1159 deUint32 format = requiredUintFormats[fmtNdx];
1160 string fmtName = getFormatName(format);
1161 vector<BufferSpec> fboSpec;
1162
1163 fboSpec.push_back(BufferSpec(format, width, height, samples));
1164
1165 for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisions); precNdx++)
1166 {
1167 glu::Precision prec = precisions[precNdx];
1168 string precName = glu::getPrecisionName(prec);
1169
1170 uintGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_uint").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_UINT, prec, 0)).toVec()));
1171 uintGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_uvec2").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_UINT_VEC2, prec, 0)).toVec()));
1172 uintGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_uvec3").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_UINT_VEC3, prec, 0)).toVec()));
1173 uintGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_uvec4").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_UINT_VEC4, prec, 0)).toVec()));
1174 }
1175 }
1176 }
1177
1178 // .array
1179 {
1180 tcu::TestCaseGroup* arrayGroup = new tcu::TestCaseGroup(m_testCtx, "array", "Array outputs");
1181 addChild(arrayGroup);
1182
1183 const int width = 64;
1184 const int height = 64;
1185 const int samples = 0;
1186 const int numTargets = 3;
1187
1188 // .float
1189 tcu::TestCaseGroup* floatGroup = new tcu::TestCaseGroup(m_testCtx, "float", "Floating-point output tests");
1190 arrayGroup->addChild(floatGroup);
1191 for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(requiredFloatFormats); fmtNdx++)
1192 {
1193 deUint32 format = requiredFloatFormats[fmtNdx];
1194 string fmtName = getFormatName(format);
1195 vector<BufferSpec> fboSpec;
1196
1197 for (int ndx = 0; ndx < numTargets; ndx++)
1198 fboSpec.push_back(BufferSpec(format, width, height, samples));
1199
1200 for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisions); precNdx++)
1201 {
1202 glu::Precision prec = precisions[precNdx];
1203 string precName = glu::getPrecisionName(prec);
1204
1205 floatGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_float").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_FLOAT, prec, 0, numTargets)).toVec()));
1206 floatGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_vec2").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_FLOAT_VEC2, prec, 0, numTargets)).toVec()));
1207 floatGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_vec3").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_FLOAT_VEC3, prec, 0, numTargets)).toVec()));
1208 floatGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_vec4").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_FLOAT_VEC4, prec, 0, numTargets)).toVec()));
1209 }
1210 }
1211
1212 // .fixed
1213 tcu::TestCaseGroup* fixedGroup = new tcu::TestCaseGroup(m_testCtx, "fixed", "Fixed-point output tests");
1214 arrayGroup->addChild(fixedGroup);
1215 for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(requiredFixedFormats); fmtNdx++)
1216 {
1217 deUint32 format = requiredFixedFormats[fmtNdx];
1218 string fmtName = getFormatName(format);
1219 vector<BufferSpec> fboSpec;
1220
1221 for (int ndx = 0; ndx < numTargets; ndx++)
1222 fboSpec.push_back(BufferSpec(format, width, height, samples));
1223
1224 for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisions); precNdx++)
1225 {
1226 glu::Precision prec = precisions[precNdx];
1227 string precName = glu::getPrecisionName(prec);
1228
1229 fixedGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_float").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_FLOAT, prec, 0, numTargets)).toVec()));
1230 fixedGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_vec2").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_FLOAT_VEC2, prec, 0, numTargets)).toVec()));
1231 fixedGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_vec3").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_FLOAT_VEC3, prec, 0, numTargets)).toVec()));
1232 fixedGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_vec4").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_FLOAT_VEC4, prec, 0, numTargets)).toVec()));
1233 }
1234 }
1235
1236 // .int
1237 tcu::TestCaseGroup* intGroup = new tcu::TestCaseGroup(m_testCtx, "int", "Integer output tests");
1238 arrayGroup->addChild(intGroup);
1239 for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(requiredIntFormats); fmtNdx++)
1240 {
1241 deUint32 format = requiredIntFormats[fmtNdx];
1242 string fmtName = getFormatName(format);
1243 vector<BufferSpec> fboSpec;
1244
1245 for (int ndx = 0; ndx < numTargets; ndx++)
1246 fboSpec.push_back(BufferSpec(format, width, height, samples));
1247
1248 for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisions); precNdx++)
1249 {
1250 glu::Precision prec = precisions[precNdx];
1251 string precName = glu::getPrecisionName(prec);
1252
1253 intGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_int").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_INT, prec, 0, numTargets)).toVec()));
1254 intGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_ivec2").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_INT_VEC2, prec, 0, numTargets)).toVec()));
1255 intGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_ivec3").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_INT_VEC3, prec, 0, numTargets)).toVec()));
1256 intGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_ivec4").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_INT_VEC4, prec, 0, numTargets)).toVec()));
1257 }
1258 }
1259
1260 // .uint
1261 tcu::TestCaseGroup* uintGroup = new tcu::TestCaseGroup(m_testCtx, "uint", "Usigned integer output tests");
1262 arrayGroup->addChild(uintGroup);
1263 for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(requiredUintFormats); fmtNdx++)
1264 {
1265 deUint32 format = requiredUintFormats[fmtNdx];
1266 string fmtName = getFormatName(format);
1267 vector<BufferSpec> fboSpec;
1268
1269 for (int ndx = 0; ndx < numTargets; ndx++)
1270 fboSpec.push_back(BufferSpec(format, width, height, samples));
1271
1272 for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisions); precNdx++)
1273 {
1274 glu::Precision prec = precisions[precNdx];
1275 string precName = glu::getPrecisionName(prec);
1276
1277 uintGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_uint").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_UINT, prec, 0, numTargets)).toVec()));
1278 uintGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_uvec2").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_UINT_VEC2, prec, 0, numTargets)).toVec()));
1279 uintGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_uvec3").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_UINT_VEC3, prec, 0, numTargets)).toVec()));
1280 uintGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_uvec4").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_UINT_VEC4, prec, 0, numTargets)).toVec()));
1281 }
1282 }
1283 }
1284
1285 // .random
1286 {
1287 tcu::TestCaseGroup* randomGroup = new tcu::TestCaseGroup(m_testCtx, "random", "Random fragment output cases");
1288 addChild(randomGroup);
1289
1290 for (deUint32 seed = 0; seed < 100; seed++)
1291 randomGroup->addChild(createRandomCase(m_context, 2, 4, seed));
1292 }
1293 }
1294
1295 } // Functional
1296 } // gles3
1297 } // deqp
1298