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 	// Do not bother with preprocessing if images are not stored
174 	if ((qpTestLog_getLogFlags(m_log) & QP_TEST_LOG_EXCLUDE_IMAGES) != 0)
175 		return;
176 
177 	if (depth == 1 && format.type == TextureFormat::UNORM_INT8
178 		&& width <= MAX_IMAGE_SIZE_2D && height <= MAX_IMAGE_SIZE_2D
179 		&& (format.order == TextureFormat::RGB || format.order == TextureFormat::RGBA)
180 		&& access.getPixelPitch() == access.getFormat().getPixelSize()
181 		&& pixelBias[0] == 0.0f && pixelBias[1] == 0.0f && pixelBias[2] == 0.0f && pixelBias[3] == 0.0f
182 		&& pixelScale[0] == 1.0f && pixelScale[1] == 1.0f && pixelScale[2] == 1.0f && pixelScale[3] == 1.0f)
183 	{
184 		// Fast-path.
185 		bool isRGBA = format.order == TextureFormat::RGBA;
186 
187 		writeImage(name, description, compressionMode,
188 				   isRGBA ? QP_IMAGE_FORMAT_RGBA8888 : QP_IMAGE_FORMAT_RGB888,
189 				   width, height, access.getRowPitch(), access.getDataPtr());
190 	}
191 	else if (depth == 1)
192 	{
193 		Sampler				sampler			(Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE, Sampler::LINEAR, Sampler::NEAREST);
194 		IVec2				logImageSize	= computeScaledSize(IVec2(width, height), MAX_IMAGE_SIZE_2D);
195 		tcu::TextureLevel	logImage		(TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8), logImageSize.x(), logImageSize.y(), 1);
196 		PixelBufferAccess	logImageAccess	= logImage.getAccess();
197 		std::ostringstream	longDesc;
198 
199 		longDesc << description << " (p' = p * " << pixelScale << " + " << pixelBias << ")";
200 
201 		for (int y = 0; y < logImage.getHeight(); y++)
202 		{
203 			for (int x = 0; x < logImage.getWidth(); x++)
204 			{
205 				float	yf	= ((float)y + 0.5f) / (float)logImage.getHeight();
206 				float	xf	= ((float)x + 0.5f) / (float)logImage.getWidth();
207 				Vec4	s	= access.sample2D(sampler, sampler.minFilter, xf, yf, 0)*pixelScale + pixelBias;
208 
209 				logImageAccess.setPixel(s, x, y);
210 			}
211 		}
212 
213 		writeImage(name, longDesc.str().c_str(), compressionMode, QP_IMAGE_FORMAT_RGBA8888,
214 				   logImageAccess.getWidth(), logImageAccess.getHeight(), logImageAccess.getRowPitch(),
215 				   logImageAccess.getDataPtr());
216 	}
217 	else
218 	{
219 		// Isometric splat volume rendering.
220 		const float			blendFactor			= 0.85f;
221 		IVec3				scaledSize			= computeScaledSize(IVec3(width, height, depth), MAX_IMAGE_SIZE_3D);
222 		int					w					= scaledSize.x();
223 		int					h					= scaledSize.y();
224 		int					d					= scaledSize.z();
225 		int					logImageW			= w+d - 1;
226 		int					logImageH			= w+d+h;
227 		std::vector<float>	blendImage			(logImageW*logImageH*4, 0.0f);
228 		PixelBufferAccess	blendImageAccess	(TextureFormat(TextureFormat::RGBA, TextureFormat::FLOAT), logImageW, logImageH, 1, &blendImage[0]);
229 		tcu::TextureLevel	logImage			(TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8), logImageW, logImageH, 1);
230 		PixelBufferAccess	logImageAccess		= logImage.getAccess();
231 		Sampler				sampler				(Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE, Sampler::CLAMP_TO_EDGE, Sampler::NEAREST, Sampler::NEAREST);
232 		std::ostringstream	longDesc;
233 
234 		// \note Back-to-front.
235 		for (int z = d-1; z >= 0; z--)
236 		{
237 			for (int y = 0; y < h; y++)
238 			{
239 				for (int x = 0; x < w; x++)
240 				{
241 					int		px	= w - (x + 1) + z;
242 					int		py	= (w + d + h) - (x + y + z + 1);
243 
244 					float	xf	= ((float)x + 0.5f) / (float)w;
245 					float	yf	= ((float)y + 0.5f) / (float)h;
246 					float	zf	= ((float)z + 0.5f) / (float)d;
247 
248 					Vec4	p	= blendImageAccess.getPixel(px, py);
249 					Vec4	s	= access.sample3D(sampler, sampler.minFilter, xf, yf, zf);
250 					Vec4	b	= s + p*blendFactor;
251 
252 					blendImageAccess.setPixel(b, px, py);
253 				}
254 			}
255 		}
256 
257 		// Scale blend image nicely.
258 		longDesc << description << " (p' = p * " << pixelScale << " + " << pixelBias << ")";
259 
260 		// Write to final image.
261 		tcu::clear(logImageAccess, tcu::IVec4(0x33, 0x66, 0x99, 0xff));
262 
263 		for (int z = 0; z < d; z++)
264 		{
265 			for (int y = 0; y < h; y++)
266 			{
267 				for (int x = 0; x < w; x++)
268 				{
269 					if (z != 0 && !(x == 0 || y == h-1 || y == h-2))
270 						continue;
271 
272 					int		px	= w - (x + 1) + z;
273 					int		py	= (w + d + h) - (x + y + z + 1);
274 					Vec4	s	= blendImageAccess.getPixel(px, py)*pixelScale + pixelBias;
275 
276 					logImageAccess.setPixel(s, px, py);
277 				}
278 			}
279 		}
280 
281 		writeImage(name, longDesc.str().c_str(), compressionMode, QP_IMAGE_FORMAT_RGBA8888,
282 				   logImageAccess.getWidth(), logImageAccess.getHeight(), logImageAccess.getRowPitch(),
283 				   logImageAccess.getDataPtr());
284 	}
285 }
286 
writeImage(const char * name,const char * description,qpImageCompressionMode compressionMode,qpImageFormat format,int width,int height,int stride,const void * data)287 void TestLog::writeImage (const char* name, const char* description, qpImageCompressionMode compressionMode, qpImageFormat format, int width, int height, int stride, const void* data)
288 {
289 	if (qpTestLog_writeImage(m_log, name, description, compressionMode, format, width, height, stride, data) == DE_FALSE)
290 		throw LogWriteFailedError();
291 }
292 
startSection(const char * name,const char * description)293 void TestLog::startSection (const char* name, const char* description)
294 {
295 	if (qpTestLog_startSection(m_log, name, description) == DE_FALSE)
296 		throw LogWriteFailedError();
297 }
298 
endSection(void)299 void TestLog::endSection (void)
300 {
301 	if (qpTestLog_endSection(m_log) == DE_FALSE)
302 		throw LogWriteFailedError();
303 }
304 
startShaderProgram(bool linkOk,const char * linkInfoLog)305 void TestLog::startShaderProgram (bool linkOk, const char* linkInfoLog)
306 {
307 	if (qpTestLog_startShaderProgram(m_log, linkOk?DE_TRUE:DE_FALSE, linkInfoLog) == DE_FALSE)
308 		throw LogWriteFailedError();
309 }
310 
endShaderProgram(void)311 void TestLog::endShaderProgram (void)
312 {
313 	if (qpTestLog_endShaderProgram(m_log) == DE_FALSE)
314 		throw LogWriteFailedError();
315 }
316 
writeShader(qpShaderType type,const char * source,bool compileOk,const char * infoLog)317 void TestLog::writeShader (qpShaderType type, const char* source, bool compileOk, const char* infoLog)
318 {
319 	if (qpTestLog_writeShader(m_log, type, source, compileOk?DE_TRUE:DE_FALSE, infoLog) == DE_FALSE)
320 		throw LogWriteFailedError();
321 }
322 
writeKernelSource(const char * source)323 void TestLog::writeKernelSource (const char* source)
324 {
325 	if (qpTestLog_writeKernelSource(m_log, source) == DE_FALSE)
326 		throw LogWriteFailedError();
327 }
328 
writeCompileInfo(const char * name,const char * description,bool compileOk,const char * infoLog)329 void TestLog::writeCompileInfo (const char* name, const char* description, bool compileOk, const char* infoLog)
330 {
331 	if (qpTestLog_writeCompileInfo(m_log, name, description, compileOk ? DE_TRUE : DE_FALSE, infoLog) == DE_FALSE)
332 		throw LogWriteFailedError();
333 }
334 
writeFloat(const char * name,const char * description,const char * unit,qpKeyValueTag tag,float value)335 void TestLog::writeFloat (const char* name, const char* description, const char* unit, qpKeyValueTag tag, float value)
336 {
337 	if (qpTestLog_writeFloat(m_log, name, description, unit, tag, value) == DE_FALSE)
338 		throw LogWriteFailedError();
339 }
340 
writeInteger(const char * name,const char * description,const char * unit,qpKeyValueTag tag,deInt64 value)341 void TestLog::writeInteger (const char* name, const char* description, const char* unit, qpKeyValueTag tag, deInt64 value)
342 {
343 	if (qpTestLog_writeInteger(m_log, name, description, unit, tag, value) == DE_FALSE)
344 		throw LogWriteFailedError();
345 }
346 
startEglConfigSet(const char * name,const char * description)347 void TestLog::startEglConfigSet (const char* name, const char* description)
348 {
349 	if (qpTestLog_startEglConfigSet(m_log, name, description) == DE_FALSE)
350 		throw LogWriteFailedError();
351 }
352 
writeEglConfig(const qpEglConfigInfo * config)353 void TestLog::writeEglConfig (const qpEglConfigInfo* config)
354 {
355 	if (qpTestLog_writeEglConfig(m_log, config) == DE_FALSE)
356 		throw LogWriteFailedError();
357 }
358 
endEglConfigSet(void)359 void TestLog::endEglConfigSet (void)
360 {
361 	if (qpTestLog_endEglConfigSet(m_log) == DE_FALSE)
362 		throw LogWriteFailedError();
363 }
364 
startCase(const char * testCasePath,qpTestCaseType testCaseType)365 void TestLog::startCase (const char* testCasePath, qpTestCaseType testCaseType)
366 {
367 	if (qpTestLog_startCase(m_log, testCasePath, testCaseType) == DE_FALSE)
368 		throw LogWriteFailedError();
369 }
370 
endCase(qpTestResult result,const char * description)371 void TestLog::endCase (qpTestResult result, const char* description)
372 {
373 	if (qpTestLog_endCase(m_log, result, description) == DE_FALSE)
374 		throw LogWriteFailedError();
375 }
376 
terminateCase(qpTestResult result)377 void TestLog::terminateCase (qpTestResult result)
378 {
379 	if (qpTestLog_terminateCase(m_log, result) == DE_FALSE)
380 		throw LogWriteFailedError();
381 }
382 
startSampleList(const std::string & name,const std::string & description)383 void TestLog::startSampleList (const std::string& name, const std::string& description)
384 {
385 	if (qpTestLog_startSampleList(m_log, name.c_str(), description.c_str()) == DE_FALSE)
386 		throw LogWriteFailedError();
387 }
388 
startSampleInfo(void)389 void TestLog::startSampleInfo (void)
390 {
391 	if (qpTestLog_startSampleInfo(m_log) == DE_FALSE)
392 		throw LogWriteFailedError();
393 }
394 
writeValueInfo(const std::string & name,const std::string & description,const std::string & unit,qpSampleValueTag tag)395 void TestLog::writeValueInfo (const std::string& name, const std::string& description, const std::string& unit, qpSampleValueTag tag)
396 {
397 	if (qpTestLog_writeValueInfo(m_log, name.c_str(), description.c_str(), unit.empty() ? DE_NULL : unit.c_str(), tag) == DE_FALSE)
398 		throw LogWriteFailedError();
399 }
400 
endSampleInfo(void)401 void TestLog::endSampleInfo (void)
402 {
403 	if (qpTestLog_endSampleInfo(m_log) == DE_FALSE)
404 		throw LogWriteFailedError();
405 }
406 
startSample(void)407 void TestLog::startSample (void)
408 {
409 	if (qpTestLog_startSample(m_log) == DE_FALSE)
410 		throw LogWriteFailedError();
411 }
412 
writeSampleValue(double value)413 void TestLog::writeSampleValue (double value)
414 {
415 	if (qpTestLog_writeValueFloat(m_log, value) == DE_FALSE)
416 		throw LogWriteFailedError();
417 }
418 
writeSampleValue(deInt64 value)419 void TestLog::writeSampleValue (deInt64 value)
420 {
421 	if (qpTestLog_writeValueInteger(m_log, value) == DE_FALSE)
422 		throw LogWriteFailedError();
423 }
424 
endSample(void)425 void TestLog::endSample (void)
426 {
427 	if (qpTestLog_endSample(m_log) == DE_FALSE)
428 		throw LogWriteFailedError();
429 }
430 
endSampleList(void)431 void TestLog::endSampleList (void)
432 {
433 	if (qpTestLog_endSampleList(m_log) == DE_FALSE)
434 		throw LogWriteFailedError();
435 }
436 
437 const TestLog::BeginMessageToken		TestLog::Message			= TestLog::BeginMessageToken();
438 const TestLog::EndMessageToken			TestLog::EndMessage			= TestLog::EndMessageToken();
439 const TestLog::EndImageSetToken			TestLog::EndImageSet		= TestLog::EndImageSetToken();
440 const TestLog::EndSectionToken			TestLog::EndSection			= TestLog::EndSectionToken();
441 const TestLog::EndShaderProgramToken	TestLog::EndShaderProgram	= TestLog::EndShaderProgramToken();
442 const TestLog::SampleInfoToken			TestLog::SampleInfo			= TestLog::SampleInfoToken();
443 const TestLog::EndSampleInfoToken		TestLog::EndSampleInfo		= TestLog::EndSampleInfoToken();
444 const TestLog::BeginSampleToken			TestLog::Sample				= TestLog::BeginSampleToken();
445 const TestLog::EndSampleToken			TestLog::EndSample			= TestLog::EndSampleToken();
446 const TestLog::EndSampleListToken		TestLog::EndSampleList		= TestLog::EndSampleListToken();
447 
448 } // tcu
449