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:
LogWriteFailedError(void)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
LogImage(const std::string & name,const std::string & description,const Surface & surface,qpImageCompressionMode compression)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
LogImage(const std::string & name,const std::string & description,const ConstPixelBufferAccess & access,qpImageCompressionMode compression)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 computePixelScaleBias(access, m_scale, m_bias);
67 }
68
69 // MessageBuilder
70
MessageBuilder(const MessageBuilder & other)71 MessageBuilder::MessageBuilder (const MessageBuilder& other)
72 : m_log(other.m_log)
73 {
74 m_str.str(other.m_str.str());
75 }
76
operator =(const MessageBuilder & other)77 MessageBuilder& MessageBuilder::operator= (const MessageBuilder& other)
78 {
79 m_log = other.m_log;
80 m_str.str(other.m_str.str());
81 return *this;
82 }
83
operator <<(const TestLog::EndMessageToken &)84 TestLog& MessageBuilder::operator<< (const TestLog::EndMessageToken&)
85 {
86 m_log->writeMessage(m_str.str().c_str());
87 return *m_log;
88 }
89
90 // SampleBuilder
91
operator <<(const TestLog::EndSampleToken &)92 TestLog& SampleBuilder::operator<< (const TestLog::EndSampleToken&)
93 {
94 m_log->startSample();
95
96 for (std::vector<Value>::const_iterator val = m_values.begin(); val != m_values.end(); ++val)
97 {
98 if (val->type == Value::TYPE_FLOAT64)
99 m_log->writeSampleValue(val->value.float64);
100 else if (val->type == Value::TYPE_INT64)
101 m_log->writeSampleValue(val->value.int64);
102 else
103 DE_ASSERT(false);
104 }
105
106 m_log->endSample();
107
108 return *m_log;
109 }
110
111 // TestLog
112
TestLog(const char * fileName,deUint32 flags)113 TestLog::TestLog (const char* fileName, deUint32 flags)
114 : m_log(qpTestLog_createFileLog(fileName, flags))
115 {
116 if (!m_log)
117 throw ResourceError(std::string("Failed to open test log file '") + fileName + "'");
118 }
119
~TestLog(void)120 TestLog::~TestLog (void)
121 {
122 qpTestLog_destroy(m_log);
123 }
124
writeMessage(const char * msgStr)125 void TestLog::writeMessage (const char* msgStr)
126 {
127 if (qpTestLog_writeText(m_log, DE_NULL, DE_NULL, QP_KEY_TAG_LAST, msgStr) == DE_FALSE)
128 throw LogWriteFailedError();
129 }
130
startImageSet(const char * name,const char * description)131 void TestLog::startImageSet (const char* name, const char* description)
132 {
133 if (qpTestLog_startImageSet(m_log, name, description) == DE_FALSE)
134 throw LogWriteFailedError();
135 }
136
endImageSet(void)137 void TestLog::endImageSet (void)
138 {
139 if (qpTestLog_endImageSet(m_log) == DE_FALSE)
140 throw LogWriteFailedError();
141 }
142
143 template <int Size>
computeScaledSize(const Vector<int,Size> & imageSize,int maxSize)144 static Vector<int, Size> computeScaledSize (const Vector<int, Size>& imageSize, int maxSize)
145 {
146 bool allInRange = true;
147 for (int i = 0; i < Size; i++)
148 allInRange = allInRange && (imageSize[i] <= maxSize);
149
150 if (allInRange)
151 return imageSize;
152 else
153 {
154 float d = 1.0f;
155 for (int i = 0; i < Size; i++)
156 d = de::max(d, (float)imageSize[i] / (float)maxSize);
157
158 Vector<int, Size> res;
159 for (int i = 0; i < Size; i++)
160 res[i] = deRoundFloatToInt32((float)imageSize[i] / d);
161
162 return res;
163 }
164 }
165
writeImage(const char * name,const char * description,const ConstPixelBufferAccess & access,const Vec4 & pixelScale,const Vec4 & pixelBias,qpImageCompressionMode compressionMode)166 void TestLog::writeImage (const char* name, const char* description, const ConstPixelBufferAccess& access, const Vec4& pixelScale, const Vec4& pixelBias, qpImageCompressionMode compressionMode)
167 {
168 const TextureFormat& format = access.getFormat();
169 int width = access.getWidth();
170 int height = access.getHeight();
171 int depth = access.getDepth();
172
173 if (depth == 1 && format.type == TextureFormat::UNORM_INT8 &&
174 width <= MAX_IMAGE_SIZE_2D && height <= MAX_IMAGE_SIZE_2D &&
175 (format.order == TextureFormat::RGB || format.order == TextureFormat::RGBA)
176 && pixelBias[0] == 0.0f && pixelBias[1] == 0.0f && pixelBias[2] == 0.0f && pixelBias[3] == 0.0f
177 && pixelScale[0] == 1.0f && pixelScale[1] == 1.0f && pixelScale[2] == 1.0f && pixelScale[3] == 1.0f)
178 {
179 // Fast-path.
180 bool isRGBA = format.order == TextureFormat::RGBA;
181
182 writeImage(name, description, compressionMode,
183 isRGBA ? QP_IMAGE_FORMAT_RGBA8888 : QP_IMAGE_FORMAT_RGB888,
184 width, height, access.getRowPitch(), access.getDataPtr());
185 }
186 else if (depth == 1)
187 {
188 Sampler sampler (Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE, Sampler::LINEAR, Sampler::NEAREST);
189 IVec2 logImageSize = computeScaledSize(IVec2(width, height), MAX_IMAGE_SIZE_2D);
190 tcu::TextureLevel logImage (TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8), logImageSize.x(), logImageSize.y(), 1);
191 PixelBufferAccess logImageAccess = logImage.getAccess();
192 std::ostringstream longDesc;
193
194 longDesc << description << " (p' = p * " << pixelScale << " + " << pixelBias << ")";
195
196 for (int y = 0; y < logImage.getHeight(); y++)
197 {
198 for (int x = 0; x < logImage.getWidth(); x++)
199 {
200 float yf = ((float)y + 0.5f) / (float)logImage.getHeight();
201 float xf = ((float)x + 0.5f) / (float)logImage.getWidth();
202 Vec4 s = access.sample2D(sampler, sampler.minFilter, xf, yf, 0)*pixelScale + pixelBias;
203
204 logImageAccess.setPixel(s, x, y);
205 }
206 }
207
208 writeImage(name, longDesc.str().c_str(), compressionMode, QP_IMAGE_FORMAT_RGBA8888,
209 logImageAccess.getWidth(), logImageAccess.getHeight(), logImageAccess.getRowPitch(),
210 logImageAccess.getDataPtr());
211 }
212 else
213 {
214 // Isometric splat volume rendering.
215 const float blendFactor = 0.85f;
216 IVec3 scaledSize = computeScaledSize(IVec3(width, height, depth), MAX_IMAGE_SIZE_3D);
217 int w = scaledSize.x();
218 int h = scaledSize.y();
219 int d = scaledSize.z();
220 int logImageW = w+d - 1;
221 int logImageH = w+d+h;
222 std::vector<float> blendImage (logImageW*logImageH*4, 0.0f);
223 PixelBufferAccess blendImageAccess (TextureFormat(TextureFormat::RGBA, TextureFormat::FLOAT), logImageW, logImageH, 1, &blendImage[0]);
224 tcu::TextureLevel logImage (TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8), logImageW, logImageH, 1);
225 PixelBufferAccess logImageAccess = logImage.getAccess();
226 Sampler sampler (Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE, Sampler::NEAREST, Sampler::NEAREST);
227 std::ostringstream longDesc;
228
229 // \note Back-to-front.
230 for (int z = d-1; z >= 0; z--)
231 {
232 for (int y = 0; y < h; y++)
233 {
234 for (int x = 0; x < w; x++)
235 {
236 int px = w - (x + 1) + z;
237 int py = (w + d + h) - (x + y + z + 1);
238
239 float xf = ((float)x + 0.5f) / (float)w;
240 float yf = ((float)y + 0.5f) / (float)h;
241 float zf = ((float)z + 0.5f) / (float)d;
242
243 Vec4 p = blendImageAccess.getPixel(px, py);
244 Vec4 s = access.sample3D(sampler, sampler.minFilter, xf, yf, zf);
245 Vec4 b = s + p*blendFactor;
246
247 blendImageAccess.setPixel(b, px, py);
248 }
249 }
250 }
251
252 // Scale blend image nicely.
253 longDesc << description << " (p' = p * " << pixelScale << " + " << pixelBias << ")";
254
255 // Write to final image.
256 tcu::clear(logImageAccess, tcu::IVec4(0x33, 0x66, 0x99, 0xff));
257
258 for (int z = 0; z < d; z++)
259 {
260 for (int y = 0; y < h; y++)
261 {
262 for (int x = 0; x < w; x++)
263 {
264 if (z != 0 && !(x == 0 || y == h-1 || y == h-2))
265 continue;
266
267 int px = w - (x + 1) + z;
268 int py = (w + d + h) - (x + y + z + 1);
269 Vec4 s = blendImageAccess.getPixel(px, py)*pixelScale + pixelBias;
270
271 logImageAccess.setPixel(s, px, py);
272 }
273 }
274 }
275
276 writeImage(name, longDesc.str().c_str(), compressionMode, QP_IMAGE_FORMAT_RGBA8888,
277 logImageAccess.getWidth(), logImageAccess.getHeight(), logImageAccess.getRowPitch(),
278 logImageAccess.getDataPtr());
279 }
280 }
281
writeImage(const char * name,const char * description,qpImageCompressionMode compressionMode,qpImageFormat format,int width,int height,int stride,const void * data)282 void TestLog::writeImage (const char* name, const char* description, qpImageCompressionMode compressionMode, qpImageFormat format, int width, int height, int stride, const void* data)
283 {
284 if (qpTestLog_writeImage(m_log, name, description, compressionMode, format, width, height, stride, data) == DE_FALSE)
285 throw LogWriteFailedError();
286 }
287
startSection(const char * name,const char * description)288 void TestLog::startSection (const char* name, const char* description)
289 {
290 if (qpTestLog_startSection(m_log, name, description) == DE_FALSE)
291 throw LogWriteFailedError();
292 }
293
endSection(void)294 void TestLog::endSection (void)
295 {
296 if (qpTestLog_endSection(m_log) == DE_FALSE)
297 throw LogWriteFailedError();
298 }
299
startShaderProgram(bool linkOk,const char * linkInfoLog)300 void TestLog::startShaderProgram (bool linkOk, const char* linkInfoLog)
301 {
302 if (qpTestLog_startShaderProgram(m_log, linkOk?DE_TRUE:DE_FALSE, linkInfoLog) == DE_FALSE)
303 throw LogWriteFailedError();
304 }
305
endShaderProgram(void)306 void TestLog::endShaderProgram (void)
307 {
308 if (qpTestLog_endShaderProgram(m_log) == DE_FALSE)
309 throw LogWriteFailedError();
310 }
311
writeShader(qpShaderType type,const char * source,bool compileOk,const char * infoLog)312 void TestLog::writeShader (qpShaderType type, const char* source, bool compileOk, const char* infoLog)
313 {
314 if (qpTestLog_writeShader(m_log, type, source, compileOk?DE_TRUE:DE_FALSE, infoLog) == DE_FALSE)
315 throw LogWriteFailedError();
316 }
317
writeKernelSource(const char * source)318 void TestLog::writeKernelSource (const char* source)
319 {
320 if (qpTestLog_writeKernelSource(m_log, source) == DE_FALSE)
321 throw LogWriteFailedError();
322 }
323
writeCompileInfo(const char * name,const char * description,bool compileOk,const char * infoLog)324 void TestLog::writeCompileInfo (const char* name, const char* description, bool compileOk, const char* infoLog)
325 {
326 if (qpTestLog_writeCompileInfo(m_log, name, description, compileOk ? DE_TRUE : DE_FALSE, infoLog) == DE_FALSE)
327 throw LogWriteFailedError();
328 }
329
writeFloat(const char * name,const char * description,const char * unit,qpKeyValueTag tag,float value)330 void TestLog::writeFloat (const char* name, const char* description, const char* unit, qpKeyValueTag tag, float value)
331 {
332 if (qpTestLog_writeFloat(m_log, name, description, unit, tag, value) == DE_FALSE)
333 throw LogWriteFailedError();
334 }
335
writeInteger(const char * name,const char * description,const char * unit,qpKeyValueTag tag,deInt64 value)336 void TestLog::writeInteger (const char* name, const char* description, const char* unit, qpKeyValueTag tag, deInt64 value)
337 {
338 if (qpTestLog_writeInteger(m_log, name, description, unit, tag, value) == DE_FALSE)
339 throw LogWriteFailedError();
340 }
341
startEglConfigSet(const char * name,const char * description)342 void TestLog::startEglConfigSet (const char* name, const char* description)
343 {
344 if (qpTestLog_startEglConfigSet(m_log, name, description) == DE_FALSE)
345 throw LogWriteFailedError();
346 }
347
writeEglConfig(const qpEglConfigInfo * config)348 void TestLog::writeEglConfig (const qpEglConfigInfo* config)
349 {
350 if (qpTestLog_writeEglConfig(m_log, config) == DE_FALSE)
351 throw LogWriteFailedError();
352 }
353
endEglConfigSet(void)354 void TestLog::endEglConfigSet (void)
355 {
356 if (qpTestLog_endEglConfigSet(m_log) == DE_FALSE)
357 throw LogWriteFailedError();
358 }
359
startCase(const char * testCasePath,qpTestCaseType testCaseType)360 void TestLog::startCase (const char* testCasePath, qpTestCaseType testCaseType)
361 {
362 if (qpTestLog_startCase(m_log, testCasePath, testCaseType) == DE_FALSE)
363 throw LogWriteFailedError();
364 }
365
endCase(qpTestResult result,const char * description)366 void TestLog::endCase (qpTestResult result, const char* description)
367 {
368 if (qpTestLog_endCase(m_log, result, description) == DE_FALSE)
369 throw LogWriteFailedError();
370 }
371
terminateCase(qpTestResult result)372 void TestLog::terminateCase (qpTestResult result)
373 {
374 if (qpTestLog_terminateCase(m_log, result) == DE_FALSE)
375 throw LogWriteFailedError();
376 }
377
startSampleList(const std::string & name,const std::string & description)378 void TestLog::startSampleList (const std::string& name, const std::string& description)
379 {
380 if (qpTestLog_startSampleList(m_log, name.c_str(), description.c_str()) == DE_FALSE)
381 throw LogWriteFailedError();
382 }
383
startSampleInfo(void)384 void TestLog::startSampleInfo (void)
385 {
386 if (qpTestLog_startSampleInfo(m_log) == DE_FALSE)
387 throw LogWriteFailedError();
388 }
389
writeValueInfo(const std::string & name,const std::string & description,const std::string & unit,qpSampleValueTag tag)390 void TestLog::writeValueInfo (const std::string& name, const std::string& description, const std::string& unit, qpSampleValueTag tag)
391 {
392 if (qpTestLog_writeValueInfo(m_log, name.c_str(), description.c_str(), unit.empty() ? DE_NULL : unit.c_str(), tag) == DE_FALSE)
393 throw LogWriteFailedError();
394 }
395
endSampleInfo(void)396 void TestLog::endSampleInfo (void)
397 {
398 if (qpTestLog_endSampleInfo(m_log) == DE_FALSE)
399 throw LogWriteFailedError();
400 }
401
startSample(void)402 void TestLog::startSample (void)
403 {
404 if (qpTestLog_startSample(m_log) == DE_FALSE)
405 throw LogWriteFailedError();
406 }
407
writeSampleValue(double value)408 void TestLog::writeSampleValue (double value)
409 {
410 if (qpTestLog_writeValueFloat(m_log, value) == DE_FALSE)
411 throw LogWriteFailedError();
412 }
413
writeSampleValue(deInt64 value)414 void TestLog::writeSampleValue (deInt64 value)
415 {
416 if (qpTestLog_writeValueInteger(m_log, value) == DE_FALSE)
417 throw LogWriteFailedError();
418 }
419
endSample(void)420 void TestLog::endSample (void)
421 {
422 if (qpTestLog_endSample(m_log) == DE_FALSE)
423 throw LogWriteFailedError();
424 }
425
endSampleList(void)426 void TestLog::endSampleList (void)
427 {
428 if (qpTestLog_endSampleList(m_log) == DE_FALSE)
429 throw LogWriteFailedError();
430 }
431
432 const TestLog::BeginMessageToken TestLog::Message = TestLog::BeginMessageToken();
433 const TestLog::EndMessageToken TestLog::EndMessage = TestLog::EndMessageToken();
434 const TestLog::EndImageSetToken TestLog::EndImageSet = TestLog::EndImageSetToken();
435 const TestLog::EndSectionToken TestLog::EndSection = TestLog::EndSectionToken();
436 const TestLog::EndShaderProgramToken TestLog::EndShaderProgram = TestLog::EndShaderProgramToken();
437 const TestLog::SampleInfoToken TestLog::SampleInfo = TestLog::SampleInfoToken();
438 const TestLog::EndSampleInfoToken TestLog::EndSampleInfo = TestLog::EndSampleInfoToken();
439 const TestLog::BeginSampleToken TestLog::Sample = TestLog::BeginSampleToken();
440 const TestLog::EndSampleToken TestLog::EndSample = TestLog::EndSampleToken();
441 const TestLog::EndSampleListToken TestLog::EndSampleList = TestLog::EndSampleListToken();
442
443 } // tcu
444