Use glReadnPixels only if KHR_robustness is supported am: d99ba132d9 am: 875d3c2990...
[platform/upstream/VK-GL-CTS.git] / framework / common / tcuTestLog.cpp
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program Tester Core
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 Test Log C++ Wrapper.
22  *//*--------------------------------------------------------------------*/
23
24 #include "tcuTestLog.hpp"
25 #include "tcuTextureUtil.hpp"
26 #include "tcuSurface.hpp"
27 #include "deMath.h"
28
29 #include <limits>
30
31 namespace tcu
32 {
33
34 class LogWriteFailedError : public ResourceError
35 {
36 public:
37         LogWriteFailedError (void) : ResourceError("Writing to test log failed") {}
38 };
39
40 enum
41 {
42         MAX_IMAGE_SIZE_2D               = 4096,
43         MAX_IMAGE_SIZE_3D               = 128
44 };
45
46 // LogImage
47
48 LogImage::LogImage (const std::string& name, const std::string& description, const Surface& surface, qpImageCompressionMode compression)
49         : m_name                (name)
50         , m_description (description)
51         , m_access              (surface.getAccess())
52         , m_scale               (1.0f, 1.0f, 1.0f, 1.0f)
53         , m_bias                (0.0f, 0.0f, 0.0f, 0.0f)
54         , m_compression (compression)
55 {
56 }
57
58 LogImage::LogImage (const std::string& name, const std::string& description, const ConstPixelBufferAccess& access, qpImageCompressionMode compression)
59         : m_name                (name)
60         , m_description (description)
61         , m_access              (access)
62         , m_scale               (1.0f, 1.0f, 1.0f, 1.0f)
63         , m_bias                (0.0f, 0.0f, 0.0f, 0.0f)
64         , m_compression (compression)
65 {
66         // Simplify combined formats that only use a single channel
67         if (tcu::isCombinedDepthStencilType(m_access.getFormat().type))
68         {
69                 if (m_access.getFormat().order == tcu::TextureFormat::D)
70                         m_access = tcu::getEffectiveDepthStencilAccess(m_access, tcu::Sampler::MODE_DEPTH);
71                 else if (m_access.getFormat().order == tcu::TextureFormat::S)
72                         m_access = tcu::getEffectiveDepthStencilAccess(m_access, tcu::Sampler::MODE_STENCIL);
73         }
74
75         // Implicit scale and bias
76         if (m_access.getFormat().order != tcu::TextureFormat::DS)
77                 computePixelScaleBias(m_access, m_scale, m_bias);
78         else
79         {
80                 // Pack D and S bias and scale to R and G
81                 const ConstPixelBufferAccess    depthAccess             = tcu::getEffectiveDepthStencilAccess(m_access, tcu::Sampler::MODE_DEPTH);
82                 const ConstPixelBufferAccess    stencilAccess   = tcu::getEffectiveDepthStencilAccess(m_access, tcu::Sampler::MODE_STENCIL);
83                 tcu::Vec4                                               depthScale;
84                 tcu::Vec4                                               depthBias;
85                 tcu::Vec4                                               stencilScale;
86                 tcu::Vec4                                               stencilBias;
87
88                 computePixelScaleBias(depthAccess, depthScale, depthBias);
89                 computePixelScaleBias(stencilAccess, stencilScale, stencilBias);
90
91                 m_scale = tcu::Vec4(depthScale.x(), stencilScale.x(), 0.0f, 0.0f);
92                 m_bias = tcu::Vec4(depthBias.x(), stencilBias.x(), 0.0f, 0.0f);
93         }
94 }
95
96 LogImage::LogImage (const std::string& name, const std::string& description, const ConstPixelBufferAccess& access, const Vec4& scale, const Vec4& bias, qpImageCompressionMode compression)
97         : m_name                (name)
98         , m_description (description)
99         , m_access              (access)
100         , m_scale               (scale)
101         , m_bias                (bias)
102         , m_compression (compression)
103 {
104         // Cannot set scale and bias of combined formats
105         DE_ASSERT(access.getFormat().order != tcu::TextureFormat::DS);
106
107         // Simplify access
108         if (tcu::isCombinedDepthStencilType(access.getFormat().type))
109         {
110                 if (access.getFormat().order == tcu::TextureFormat::D)
111                         m_access = tcu::getEffectiveDepthStencilAccess(access, tcu::Sampler::MODE_DEPTH);
112                 if (access.getFormat().order == tcu::TextureFormat::S)
113                         m_access = tcu::getEffectiveDepthStencilAccess(access, tcu::Sampler::MODE_STENCIL);
114                 else
115                 {
116                         // Cannot log a DS format
117                         DE_ASSERT(false);
118                         return;
119                 }
120         }
121 }
122
123 void LogImage::write (TestLog& log) const
124 {
125         if (m_access.getFormat().order != tcu::TextureFormat::DS)
126                 log.writeImage(m_name.c_str(), m_description.c_str(), m_access, m_scale, m_bias, m_compression);
127         else
128         {
129                 const ConstPixelBufferAccess    depthAccess             = tcu::getEffectiveDepthStencilAccess(m_access, tcu::Sampler::MODE_DEPTH);
130                 const ConstPixelBufferAccess    stencilAccess   = tcu::getEffectiveDepthStencilAccess(m_access, tcu::Sampler::MODE_STENCIL);
131
132                 log.startImageSet(m_name.c_str(), m_description.c_str());
133                 log.writeImage("Depth", "Depth channel", depthAccess, m_scale.swizzle(0, 0, 0, 0), m_bias.swizzle(0, 0, 0, 0), m_compression);
134                 log.writeImage("Stencil", "Stencil channel", stencilAccess, m_scale.swizzle(1, 1, 1, 1), m_bias.swizzle(1, 1, 1, 1), m_compression);
135                 log.endImageSet();
136         }
137 }
138
139 // MessageBuilder
140
141 MessageBuilder::MessageBuilder (const MessageBuilder& other)
142         : m_log(other.m_log)
143 {
144         m_str.str(other.m_str.str());
145 }
146
147 MessageBuilder& MessageBuilder::operator= (const MessageBuilder& other)
148 {
149         m_log = other.m_log;
150         m_str.str(other.m_str.str());
151         return *this;
152 }
153
154 TestLog& MessageBuilder::operator<< (const TestLog::EndMessageToken&)
155 {
156         m_log->writeMessage(m_str.str().c_str());
157         return *m_log;
158 }
159
160 // SampleBuilder
161
162 TestLog& SampleBuilder::operator<< (const TestLog::EndSampleToken&)
163 {
164         m_log->startSample();
165
166         for (std::vector<Value>::const_iterator val = m_values.begin(); val != m_values.end(); ++val)
167         {
168                 if (val->type == Value::TYPE_FLOAT64)
169                         m_log->writeSampleValue(val->value.float64);
170                 else if (val->type == Value::TYPE_INT64)
171                         m_log->writeSampleValue(val->value.int64);
172                 else
173                         DE_ASSERT(false);
174         }
175
176         m_log->endSample();
177
178         return *m_log;
179 }
180
181 // TestLog
182
183 TestLog::TestLog (const char* fileName, deUint32 flags)
184         : m_log(qpTestLog_createFileLog(fileName, flags))
185 {
186         if (!m_log)
187                 throw ResourceError(std::string("Failed to open test log file '") + fileName + "'");
188 }
189
190 TestLog::~TestLog (void)
191 {
192         qpTestLog_destroy(m_log);
193 }
194
195 void TestLog::writeMessage (const char* msgStr)
196 {
197         if (qpTestLog_writeText(m_log, DE_NULL, DE_NULL, QP_KEY_TAG_LAST, msgStr) == DE_FALSE)
198                 throw LogWriteFailedError();
199 }
200
201 void TestLog::startImageSet (const char* name, const char* description)
202 {
203         if (qpTestLog_startImageSet(m_log, name, description) == DE_FALSE)
204                 throw LogWriteFailedError();
205 }
206
207 void TestLog::endImageSet (void)
208 {
209         if (qpTestLog_endImageSet(m_log) == DE_FALSE)
210                 throw LogWriteFailedError();
211 }
212
213 template <int Size>
214 static Vector<int, Size> computeScaledSize (const Vector<int, Size>& imageSize, int maxSize)
215 {
216         bool allInRange = true;
217         for (int i = 0; i < Size; i++)
218                 allInRange = allInRange && (imageSize[i] <= maxSize);
219
220         if (allInRange)
221                 return imageSize;
222         else
223         {
224                 float d = 1.0f;
225                 for (int i = 0; i < Size; i++)
226                         d = de::max(d, (float)imageSize[i] / (float)maxSize);
227
228                 Vector<int, Size> res;
229                 for (int i = 0; i < Size; i++)
230                         res[i] = de::max(1, deRoundFloatToInt32((float)imageSize[i] / d));
231
232                 return res;
233         }
234 }
235
236 void TestLog::writeImage (const char* name, const char* description, const ConstPixelBufferAccess& access, const Vec4& pixelScale, const Vec4& pixelBias, qpImageCompressionMode compressionMode)
237 {
238         const TextureFormat&    format          = access.getFormat();
239         int                                             width           = access.getWidth();
240         int                                             height          = access.getHeight();
241         int                                             depth           = access.getDepth();
242
243         // Writing a combined image does not make sense
244         DE_ASSERT(!tcu::isCombinedDepthStencilType(access.getFormat().type));
245
246         // Do not bother with preprocessing if images are not stored
247         if ((qpTestLog_getLogFlags(m_log) & QP_TEST_LOG_EXCLUDE_IMAGES) != 0)
248                 return;
249
250         if (depth == 1 && format.type == TextureFormat::UNORM_INT8
251                 && width <= MAX_IMAGE_SIZE_2D && height <= MAX_IMAGE_SIZE_2D
252                 && (format.order == TextureFormat::RGB || format.order == TextureFormat::RGBA)
253                 && access.getPixelPitch() == access.getFormat().getPixelSize()
254                 && pixelBias[0] == 0.0f && pixelBias[1] == 0.0f && pixelBias[2] == 0.0f && pixelBias[3] == 0.0f
255                 && pixelScale[0] == 1.0f && pixelScale[1] == 1.0f && pixelScale[2] == 1.0f && pixelScale[3] == 1.0f)
256         {
257                 // Fast-path.
258                 bool isRGBA = format.order == TextureFormat::RGBA;
259
260                 writeImage(name, description, compressionMode,
261                                    isRGBA ? QP_IMAGE_FORMAT_RGBA8888 : QP_IMAGE_FORMAT_RGB888,
262                                    width, height, access.getRowPitch(), access.getDataPtr());
263         }
264         else if (depth == 1)
265         {
266                 Sampler                         sampler                 (Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE, Sampler::LINEAR, Sampler::NEAREST);
267                 IVec2                           logImageSize    = computeScaledSize(IVec2(width, height), MAX_IMAGE_SIZE_2D);
268                 tcu::TextureLevel       logImage                (TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8), logImageSize.x(), logImageSize.y(), 1);
269                 PixelBufferAccess       logImageAccess  = logImage.getAccess();
270                 std::ostringstream      longDesc;
271
272                 longDesc << description << " (p' = p * " << pixelScale << " + " << pixelBias << ")";
273
274                 for (int y = 0; y < logImage.getHeight(); y++)
275                 {
276                         for (int x = 0; x < logImage.getWidth(); x++)
277                         {
278                                 float   yf      = ((float)y + 0.5f) / (float)logImage.getHeight();
279                                 float   xf      = ((float)x + 0.5f) / (float)logImage.getWidth();
280                                 Vec4    s       = access.sample2D(sampler, sampler.minFilter, xf, yf, 0)*pixelScale + pixelBias;
281
282                                 logImageAccess.setPixel(s, x, y);
283                         }
284                 }
285
286                 writeImage(name, longDesc.str().c_str(), compressionMode, QP_IMAGE_FORMAT_RGBA8888,
287                                    logImageAccess.getWidth(), logImageAccess.getHeight(), logImageAccess.getRowPitch(),
288                                    logImageAccess.getDataPtr());
289         }
290         else
291         {
292                 // Isometric splat volume rendering.
293                 const float                     blendFactor                     = 0.85f;
294                 IVec3                           scaledSize                      = computeScaledSize(IVec3(width, height, depth), MAX_IMAGE_SIZE_3D);
295                 int                                     w                                       = scaledSize.x();
296                 int                                     h                                       = scaledSize.y();
297                 int                                     d                                       = scaledSize.z();
298                 int                                     logImageW                       = w+d - 1;
299                 int                                     logImageH                       = w+d+h;
300                 std::vector<float>      blendImage                      (logImageW*logImageH*4, 0.0f);
301                 PixelBufferAccess       blendImageAccess        (TextureFormat(TextureFormat::RGBA, TextureFormat::FLOAT), logImageW, logImageH, 1, &blendImage[0]);
302                 tcu::TextureLevel       logImage                        (TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8), logImageW, logImageH, 1);
303                 PixelBufferAccess       logImageAccess          = logImage.getAccess();
304                 Sampler                         sampler                         (Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE, Sampler::NEAREST, Sampler::NEAREST);
305                 std::ostringstream      longDesc;
306
307                 // \note Back-to-front.
308                 for (int z = d-1; z >= 0; z--)
309                 {
310                         for (int y = 0; y < h; y++)
311                         {
312                                 for (int x = 0; x < w; x++)
313                                 {
314                                         int             px      = w - (x + 1) + z;
315                                         int             py      = (w + d + h) - (x + y + z + 1);
316
317                                         float   xf      = ((float)x + 0.5f) / (float)w;
318                                         float   yf      = ((float)y + 0.5f) / (float)h;
319                                         float   zf      = ((float)z + 0.5f) / (float)d;
320
321                                         Vec4    p       = blendImageAccess.getPixel(px, py);
322                                         Vec4    s       = access.sample3D(sampler, sampler.minFilter, xf, yf, zf);
323                                         Vec4    b       = s + p*blendFactor;
324
325                                         blendImageAccess.setPixel(b, px, py);
326                                 }
327                         }
328                 }
329
330                 // Scale blend image nicely.
331                 longDesc << description << " (p' = p * " << pixelScale << " + " << pixelBias << ")";
332
333                 // Write to final image.
334                 tcu::clear(logImageAccess, tcu::IVec4(0x33, 0x66, 0x99, 0xff));
335
336                 for (int z = 0; z < d; z++)
337                 {
338                         for (int y = 0; y < h; y++)
339                         {
340                                 for (int x = 0; x < w; x++)
341                                 {
342                                         if (z != 0 && !(x == 0 || y == h-1 || y == h-2))
343                                                 continue;
344
345                                         int             px      = w - (x + 1) + z;
346                                         int             py      = (w + d + h) - (x + y + z + 1);
347                                         Vec4    s       = blendImageAccess.getPixel(px, py)*pixelScale + pixelBias;
348
349                                         logImageAccess.setPixel(s, px, py);
350                                 }
351                         }
352                 }
353
354                 writeImage(name, longDesc.str().c_str(), compressionMode, QP_IMAGE_FORMAT_RGBA8888,
355                                    logImageAccess.getWidth(), logImageAccess.getHeight(), logImageAccess.getRowPitch(),
356                                    logImageAccess.getDataPtr());
357         }
358 }
359
360 void TestLog::writeImage (const char* name, const char* description, qpImageCompressionMode compressionMode, qpImageFormat format, int width, int height, int stride, const void* data)
361 {
362         if (qpTestLog_writeImage(m_log, name, description, compressionMode, format, width, height, stride, data) == DE_FALSE)
363                 throw LogWriteFailedError();
364 }
365
366 void TestLog::startSection (const char* name, const char* description)
367 {
368         if (qpTestLog_startSection(m_log, name, description) == DE_FALSE)
369                 throw LogWriteFailedError();
370 }
371
372 void TestLog::endSection (void)
373 {
374         if (qpTestLog_endSection(m_log) == DE_FALSE)
375                 throw LogWriteFailedError();
376 }
377
378 void TestLog::startShaderProgram (bool linkOk, const char* linkInfoLog)
379 {
380         if (qpTestLog_startShaderProgram(m_log, linkOk?DE_TRUE:DE_FALSE, linkInfoLog) == DE_FALSE)
381                 throw LogWriteFailedError();
382 }
383
384 void TestLog::endShaderProgram (void)
385 {
386         if (qpTestLog_endShaderProgram(m_log) == DE_FALSE)
387                 throw LogWriteFailedError();
388 }
389
390 void TestLog::writeShader (qpShaderType type, const char* source, bool compileOk, const char* infoLog)
391 {
392         if (qpTestLog_writeShader(m_log, type, source, compileOk?DE_TRUE:DE_FALSE, infoLog) == DE_FALSE)
393                 throw LogWriteFailedError();
394 }
395
396 void TestLog::writeSpirVAssemblySource (const char* source)
397 {
398         if (qpTestLog_writeSpirVAssemblySource(m_log, source) == DE_FALSE)
399                 throw LogWriteFailedError();
400 }
401
402 void TestLog::writeKernelSource (const char* source)
403 {
404         if (qpTestLog_writeKernelSource(m_log, source) == DE_FALSE)
405                 throw LogWriteFailedError();
406 }
407
408 void TestLog::writeCompileInfo (const char* name, const char* description, bool compileOk, const char* infoLog)
409 {
410         if (qpTestLog_writeCompileInfo(m_log, name, description, compileOk ? DE_TRUE : DE_FALSE, infoLog) == DE_FALSE)
411                 throw LogWriteFailedError();
412 }
413
414 void TestLog::writeFloat (const char* name, const char* description, const char* unit, qpKeyValueTag tag, float value)
415 {
416         if (qpTestLog_writeFloat(m_log, name, description, unit, tag, value) == DE_FALSE)
417                 throw LogWriteFailedError();
418 }
419
420 void TestLog::writeInteger (const char* name, const char* description, const char* unit, qpKeyValueTag tag, deInt64 value)
421 {
422         if (qpTestLog_writeInteger(m_log, name, description, unit, tag, value) == DE_FALSE)
423                 throw LogWriteFailedError();
424 }
425
426 void TestLog::startEglConfigSet (const char* name, const char* description)
427 {
428         if (qpTestLog_startEglConfigSet(m_log, name, description) == DE_FALSE)
429                 throw LogWriteFailedError();
430 }
431
432 void TestLog::writeEglConfig (const qpEglConfigInfo* config)
433 {
434         if (qpTestLog_writeEglConfig(m_log, config) == DE_FALSE)
435                 throw LogWriteFailedError();
436 }
437
438 void TestLog::endEglConfigSet (void)
439 {
440         if (qpTestLog_endEglConfigSet(m_log) == DE_FALSE)
441                 throw LogWriteFailedError();
442 }
443
444 void TestLog::startCase (const char* testCasePath, qpTestCaseType testCaseType)
445 {
446         if (qpTestLog_startCase(m_log, testCasePath, testCaseType) == DE_FALSE)
447                 throw LogWriteFailedError();
448 }
449
450 void TestLog::endCase (qpTestResult result, const char* description)
451 {
452         if (qpTestLog_endCase(m_log, result, description) == DE_FALSE)
453                 throw LogWriteFailedError();
454 }
455
456 void TestLog::terminateCase (qpTestResult result)
457 {
458         if (qpTestLog_terminateCase(m_log, result) == DE_FALSE)
459                 throw LogWriteFailedError();
460 }
461
462 void TestLog::startSampleList (const std::string& name, const std::string& description)
463 {
464         if (qpTestLog_startSampleList(m_log, name.c_str(), description.c_str()) == DE_FALSE)
465                 throw LogWriteFailedError();
466 }
467
468 void TestLog::startSampleInfo (void)
469 {
470         if (qpTestLog_startSampleInfo(m_log) == DE_FALSE)
471                 throw LogWriteFailedError();
472 }
473
474 void TestLog::writeValueInfo (const std::string& name, const std::string& description, const std::string& unit, qpSampleValueTag tag)
475 {
476         if (qpTestLog_writeValueInfo(m_log, name.c_str(), description.c_str(), unit.empty() ? DE_NULL : unit.c_str(), tag) == DE_FALSE)
477                 throw LogWriteFailedError();
478 }
479
480 void TestLog::endSampleInfo (void)
481 {
482         if (qpTestLog_endSampleInfo(m_log) == DE_FALSE)
483                 throw LogWriteFailedError();
484 }
485
486 void TestLog::startSample (void)
487 {
488         if (qpTestLog_startSample(m_log) == DE_FALSE)
489                 throw LogWriteFailedError();
490 }
491
492 void TestLog::writeSampleValue (double value)
493 {
494         if (qpTestLog_writeValueFloat(m_log, value) == DE_FALSE)
495                 throw LogWriteFailedError();
496 }
497
498 void TestLog::writeSampleValue (deInt64 value)
499 {
500         if (qpTestLog_writeValueInteger(m_log, value) == DE_FALSE)
501                 throw LogWriteFailedError();
502 }
503
504 void TestLog::endSample (void)
505 {
506         if (qpTestLog_endSample(m_log) == DE_FALSE)
507                 throw LogWriteFailedError();
508 }
509
510 void TestLog::endSampleList (void)
511 {
512         if (qpTestLog_endSampleList(m_log) == DE_FALSE)
513                 throw LogWriteFailedError();
514 }
515
516 const TestLog::BeginMessageToken                TestLog::Message                        = TestLog::BeginMessageToken();
517 const TestLog::EndMessageToken                  TestLog::EndMessage                     = TestLog::EndMessageToken();
518 const TestLog::EndImageSetToken                 TestLog::EndImageSet            = TestLog::EndImageSetToken();
519 const TestLog::EndSectionToken                  TestLog::EndSection                     = TestLog::EndSectionToken();
520 const TestLog::EndShaderProgramToken    TestLog::EndShaderProgram       = TestLog::EndShaderProgramToken();
521 const TestLog::SampleInfoToken                  TestLog::SampleInfo                     = TestLog::SampleInfoToken();
522 const TestLog::EndSampleInfoToken               TestLog::EndSampleInfo          = TestLog::EndSampleInfoToken();
523 const TestLog::BeginSampleToken                 TestLog::Sample                         = TestLog::BeginSampleToken();
524 const TestLog::EndSampleToken                   TestLog::EndSample                      = TestLog::EndSampleToken();
525 const TestLog::EndSampleListToken               TestLog::EndSampleList          = TestLog::EndSampleListToken();
526
527 } // tcu