1#ifndef _TCUTESTLOG_HPP
2#define _TCUTESTLOG_HPP
3/*-------------------------------------------------------------------------
4 * drawElements Quality Program Tester Core
5 * ----------------------------------------
6 *
7 * Copyright 2014 The Android Open Source Project
8 *
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 *      http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 *
21 *//*!
22 * \file
23 * \brief Test Log C++ Wrapper.
24 *//*--------------------------------------------------------------------*/
25
26#include "tcuDefs.hpp"
27#include "qpTestLog.h"
28#include "tcuTexture.hpp"
29
30#include <sstream>
31
32namespace tcu
33{
34
35class Surface;
36class MessageBuilder;
37class LogImageSet;
38class LogImage;
39class LogSection;
40class LogShaderProgram;
41class LogShader;
42class LogSpirVAssemblySource;
43class LogKernelSource;
44class LogSampleList;
45class LogValueInfo;
46class SampleBuilder;
47template<typename T> class LogNumber;
48
49/*--------------------------------------------------------------------*//*!
50 * \brief Test log
51 *
52 * TestLog provides convinient C++ API for logging. The API has been designed
53 * around stream operators much like STL iostream library. The following
54 * examples demonstrate how to use TestLog.
55 *
56 * \code
57 * TestLog& log = m_testCtx.getLog();
58 *
59 * // Write message to log.
60 * log << TestLog::Message << "Hello, World!" << TestLog::EndMessage;
61 * int myNumber = 3;
62 * log << TestLog::Message << "Diff is " << myNumber << TestLog::EndMessage;
63 *
64 * // Write image
65 * Surface myImage(256, 256);
66 * log << TestLog::Image("TestImage", "My test image", myImage);
67 *
68 * // Multiple commands can be combined:
69 * log << TestLog::Section("Details", "Test case details")
70 *     << TestLog::Message << "Here be dragons" << TestLog::EndMessage
71 *     << TestLog::ImageSet("Result", "Result images")
72 *     << TestLog::Image("ImageA", "Image A", imageA)
73 *     << TestLog::Image("ImageB", "Image B", imageB)
74 *     << TestLog::EndImageSet << TestLog::EndSection;
75 * \endcode
76 *//*--------------------------------------------------------------------*/
77class TestLog
78{
79public:
80	// Tokens
81	static const class BeginMessageToken {}			Message;
82	static const class EndMessageToken {}			EndMessage;
83	static const class EndImageSetToken {}			EndImageSet;
84	static const class EndSectionToken {}			EndSection;
85	static const class EndShaderProgramToken {}		EndShaderProgram;
86	static const class SampleInfoToken {}			SampleInfo;
87	static const class EndSampleInfoToken {}		EndSampleInfo;
88	static const class BeginSampleToken {}			Sample;
89	static const class EndSampleToken {}			EndSample;
90	static const class EndSampleListToken {}		EndSampleList;
91
92	// Typedefs.
93	typedef LogImageSet				ImageSet;
94	typedef LogImage				Image;
95	typedef LogSection				Section;
96	typedef LogShaderProgram		ShaderProgram;
97	typedef LogShader				Shader;
98	typedef LogSpirVAssemblySource	SpirVAssemblySource;
99	typedef LogKernelSource			KernelSource;
100	typedef LogSampleList			SampleList;
101	typedef LogValueInfo			ValueInfo;
102	typedef LogNumber<float>		Float;
103	typedef LogNumber<deInt64>		Integer;
104
105	explicit			TestLog					(const char* fileName, deUint32 flags = 0);
106						~TestLog				(void);
107
108	MessageBuilder		operator<<				(const BeginMessageToken&);
109	MessageBuilder		message					(void);
110
111	TestLog&			operator<<				(const ImageSet& imageSet);
112	TestLog&			operator<<				(const Image& image);
113	TestLog&			operator<<				(const EndImageSetToken&);
114
115	TestLog&			operator<<				(const Section& section);
116	TestLog&			operator<<				(const EndSectionToken&);
117
118	TestLog&			operator<<				(const ShaderProgram& shaderProgram);
119	TestLog&			operator<<				(const EndShaderProgramToken&);
120	TestLog&			operator<<				(const Shader& shader);
121	TestLog&			operator<<				(const SpirVAssemblySource& module);
122
123	TestLog&			operator<<				(const KernelSource& kernelSrc);
124
125	template<typename T>
126	TestLog&			operator<<				(const LogNumber<T>& number);
127
128	TestLog&			operator<<				(const SampleList& sampleList);
129	TestLog&			operator<<				(const SampleInfoToken&);
130	TestLog&			operator<<				(const ValueInfo& valueInfo);
131	TestLog&			operator<<				(const EndSampleInfoToken&);
132	SampleBuilder		operator<<				(const BeginSampleToken&);
133	TestLog&			operator<<				(const EndSampleListToken&);
134
135	// Raw api
136	void				writeMessage			(const char* message);
137
138	void				startImageSet			(const char* name, const char* description);
139	void				endImageSet				(void);
140	void				writeImage				(const char* name, const char* description, const ConstPixelBufferAccess& surface, const Vec4& scale, const Vec4& bias, qpImageCompressionMode compressionMode = QP_IMAGE_COMPRESSION_MODE_BEST);
141	void				writeImage				(const char* name, const char* description, qpImageCompressionMode compressionMode, qpImageFormat format, int width, int height, int stride, const void* data);
142
143	void				startSection			(const char* name, const char* description);
144	void				endSection				(void);
145
146	void				startShaderProgram		(bool linkOk, const char* linkInfoLog);
147	void				endShaderProgram		(void);
148	void				writeShader				(qpShaderType type, const char* source, bool compileOk, const char* infoLog);
149	void				writeSpirVAssemblySource(const char* source);
150	void				writeKernelSource		(const char* source);
151	void				writeCompileInfo		(const char* name, const char* description, bool compileOk, const char* infoLog);
152
153	void				writeFloat				(const char* name, const char* description, const char* unit, qpKeyValueTag tag, float value);
154	void				writeInteger			(const char* name, const char* description, const char* unit, qpKeyValueTag tag, deInt64 value);
155
156	void				startEglConfigSet		(const char* name, const char* description);
157	void				writeEglConfig			(const qpEglConfigInfo* config);
158	void				endEglConfigSet			(void);
159
160	void				startCase				(const char* testCasePath, qpTestCaseType testCaseType);
161	void				endCase					(qpTestResult result, const char* description);
162	void				terminateCase			(qpTestResult result);
163
164	void				startSampleList			(const std::string& name, const std::string& description);
165	void				startSampleInfo			(void);
166	void				writeValueInfo			(const std::string& name, const std::string& description, const std::string& unit, qpSampleValueTag tag);
167	void				endSampleInfo			(void);
168	void				startSample				(void);
169	void				writeSampleValue		(double value);
170	void				writeSampleValue		(deInt64 value);
171	void				endSample				(void);
172	void				endSampleList			(void);
173
174private:
175						TestLog					(const TestLog& other); // Not allowed!
176	TestLog&			operator=				(const TestLog& other); // Not allowed!
177
178	qpTestLog*			m_log;
179};
180
181class MessageBuilder
182{
183public:
184	explicit				MessageBuilder		(TestLog* log) : m_log(log) {}
185							~MessageBuilder		(void) {}
186
187	std::string				toString			(void) const { return m_str.str(); }
188
189	TestLog&				operator<<			(const TestLog::EndMessageToken&);
190
191	template <typename T>
192	MessageBuilder&			operator<<			(const T& value);
193
194							MessageBuilder		(const MessageBuilder& other);
195	MessageBuilder&			operator=			(const MessageBuilder& other);
196
197private:
198	TestLog*				m_log;
199	std::ostringstream		m_str;
200};
201
202class SampleBuilder
203{
204public:
205							SampleBuilder		(TestLog* log) : m_log(log) {}
206
207	SampleBuilder&			operator<<			(int v)		{ m_values.push_back(Value((deInt64)v));	return *this; }
208	SampleBuilder&			operator<<			(deInt64 v)	{ m_values.push_back(Value(v));				return *this; }
209	SampleBuilder&			operator<<			(float v)	{ m_values.push_back(Value((double)v));		return *this; }
210	SampleBuilder&			operator<<			(double v)	{ m_values.push_back(Value(v));				return *this; }
211
212	TestLog&				operator<<			(const TestLog::EndSampleToken&);
213
214private:
215	struct Value
216	{
217		enum Type { TYPE_INT64 = 0, TYPE_FLOAT64, TYPE_LAST };
218
219		Type	type;
220		union
221		{
222			deInt64		int64;
223			double		float64;
224		} value;
225
226		Value (void)		: type(TYPE_LAST)		{ value.int64 = 0;		}
227		Value (double v)	: type(TYPE_FLOAT64)	{ value.float64 = v;	}
228		Value (deInt64 v)	: type(TYPE_INT64)		{ value.int64 = v;		}
229	};
230
231	TestLog*				m_log;
232	std::vector<Value>		m_values;
233};
234
235class LogImageSet
236{
237public:
238	LogImageSet (const std::string& name, const std::string& description)
239		: m_name		(name)
240		, m_description	(description)
241	{
242	}
243
244	void write (TestLog& log) const;
245
246private:
247	std::string		m_name;
248	std::string		m_description;
249};
250
251// \note Doesn't take copy of surface contents
252class LogImage
253{
254public:
255	LogImage (const std::string& name, const std::string& description, const Surface& surface, qpImageCompressionMode compression = QP_IMAGE_COMPRESSION_MODE_BEST);
256
257	LogImage (const std::string& name, const std::string& description, const ConstPixelBufferAccess& access, qpImageCompressionMode compression = QP_IMAGE_COMPRESSION_MODE_BEST);
258
259	LogImage (const std::string& name, const std::string& description, const ConstPixelBufferAccess& access, const Vec4& scale, const Vec4& bias, qpImageCompressionMode compression = QP_IMAGE_COMPRESSION_MODE_BEST);
260
261	void write (TestLog& log) const;
262
263private:
264	std::string				m_name;
265	std::string				m_description;
266	ConstPixelBufferAccess	m_access;
267	Vec4					m_scale;
268	Vec4					m_bias;
269	qpImageCompressionMode	m_compression;
270};
271
272class LogSection
273{
274public:
275	LogSection (const std::string& name, const std::string& description)
276		: m_name		(name)
277		, m_description	(description)
278	{
279	}
280
281	void write (TestLog& log) const;
282
283private:
284	std::string		m_name;
285	std::string		m_description;
286};
287
288class LogShaderProgram
289{
290public:
291	LogShaderProgram (bool linkOk, const std::string& linkInfoLog)
292		: m_linkOk		(linkOk)
293		, m_linkInfoLog	(linkInfoLog)
294	{
295	}
296
297	void write (TestLog& log) const;
298
299private:
300	bool			m_linkOk;
301	std::string		m_linkInfoLog;
302};
303
304class LogShader
305{
306public:
307	LogShader (qpShaderType type, const std::string& source, bool compileOk, const std::string& infoLog)
308		: m_type		(type)
309		, m_source		(source)
310		, m_compileOk	(compileOk)
311		, m_infoLog		(infoLog)
312	{
313	}
314
315	void write (TestLog& log) const;
316
317private:
318	qpShaderType	m_type;
319	std::string		m_source;
320	bool			m_compileOk;
321	std::string		m_infoLog;
322};
323
324class LogSpirVAssemblySource
325{
326public:
327	LogSpirVAssemblySource (const std::string& source)
328		: m_source		(source)
329	{
330	}
331
332	void write (TestLog& log) const;
333
334private:
335	std::string		m_source;
336};
337
338class LogKernelSource
339{
340public:
341	explicit LogKernelSource (const std::string& source)
342		: m_source(source)
343	{
344	}
345
346	void write (TestLog& log) const;
347
348private:
349	std::string	m_source;
350};
351
352class LogSampleList
353{
354public:
355	LogSampleList (const std::string& name, const std::string& description)
356		: m_name		(name)
357		, m_description	(description)
358	{
359	}
360
361	void write (TestLog& log) const;
362
363private:
364	std::string		m_name;
365	std::string		m_description;
366};
367
368class LogValueInfo
369{
370public:
371	LogValueInfo (const std::string& name, const std::string& description, const std::string& unit, qpSampleValueTag tag)
372		: m_name		(name)
373		, m_description	(description)
374		, m_unit		(unit)
375		, m_tag			(tag)
376	{
377	}
378
379	void write (TestLog& log) const;
380
381private:
382	std::string			m_name;
383	std::string			m_description;
384	std::string			m_unit;
385	qpSampleValueTag	m_tag;
386};
387
388template<typename T>
389class LogNumber
390{
391public:
392	LogNumber (const std::string& name, const std::string& desc, const std::string& unit, qpKeyValueTag tag, T value)
393		: m_name	(name)
394		, m_desc	(desc)
395		, m_unit	(unit)
396		, m_tag		(tag)
397		, m_value	(value)
398	{
399	}
400
401	void write (TestLog& log) const;
402
403private:
404	std::string		m_name;
405	std::string		m_desc;
406	std::string		m_unit;
407	qpKeyValueTag	m_tag;
408	T				m_value;
409};
410
411// Section helper that closes section when leaving scope.
412class ScopedLogSection
413{
414public:
415	ScopedLogSection (TestLog& log, const std::string& name, const std::string& description)
416		: m_log(log)
417	{
418		m_log << TestLog::Section(name, description);
419	}
420
421	~ScopedLogSection (void)
422	{
423		m_log << TestLog::EndSection;
424	}
425
426private:
427	TestLog& m_log;
428};
429
430// TestLog stream operators.
431
432inline TestLog& TestLog::operator<< (const ImageSet& imageSet)			{ imageSet.write(*this);	return *this;	}
433inline TestLog& TestLog::operator<< (const Image& image)				{ image.write(*this);		return *this;	}
434inline TestLog& TestLog::operator<< (const EndImageSetToken&)			{ endImageSet();			return *this;	}
435inline TestLog& TestLog::operator<< (const Section& section)			{ section.write(*this);		return *this;	}
436inline TestLog& TestLog::operator<< (const EndSectionToken&)			{ endSection();				return *this;	}
437inline TestLog& TestLog::operator<< (const ShaderProgram& shaderProg)	{ shaderProg.write(*this);	return *this;	}
438inline TestLog& TestLog::operator<< (const EndShaderProgramToken&)		{ endShaderProgram();		return *this;	}
439inline TestLog& TestLog::operator<< (const Shader& shader)				{ shader.write(*this);		return *this;	}
440inline TestLog& TestLog::operator<< (const SpirVAssemblySource& module)	{ module.write(*this);		return *this;	}
441inline TestLog& TestLog::operator<< (const KernelSource& kernelSrc)		{ kernelSrc.write(*this);	return *this;	}
442inline TestLog&	TestLog::operator<<	(const SampleList& sampleList)		{ sampleList.write(*this);	return *this;	}
443inline TestLog&	TestLog::operator<<	(const SampleInfoToken&)			{ startSampleInfo();		return *this;	}
444inline TestLog&	TestLog::operator<<	(const ValueInfo& valueInfo)		{ valueInfo.write(*this);	return *this;	}
445inline TestLog&	TestLog::operator<<	(const EndSampleInfoToken&)			{ endSampleInfo();			return *this;	}
446inline TestLog&	TestLog::operator<<	(const EndSampleListToken&)			{ endSampleList();			return *this;	}
447
448template<typename T>
449inline TestLog& TestLog::operator<< (const LogNumber<T>& number)
450{
451	number.write(*this);
452	return *this;
453}
454
455inline TestLog& operator<< (TestLog& log, const std::exception& e)
456{
457	// \todo [2012-10-18 pyry] Print type info?
458	return log << TestLog::Message << e.what() << TestLog::EndMessage;
459}
460
461// Utility class inline implementations.
462
463template <typename T>
464inline MessageBuilder& MessageBuilder::operator<< (const T& value)
465{
466	// Overload stream operator to implement custom format
467	m_str << value;
468	return *this;
469}
470
471inline MessageBuilder TestLog::operator<< (const BeginMessageToken&)
472{
473	return MessageBuilder(this);
474}
475
476inline MessageBuilder TestLog::message (void)
477{
478	return MessageBuilder(this);
479}
480
481inline SampleBuilder TestLog::operator<< (const BeginSampleToken&)
482{
483	return SampleBuilder(this);
484}
485
486inline void LogImageSet::write (TestLog& log) const
487{
488	log.startImageSet(m_name.c_str(), m_description.c_str());
489}
490
491inline void LogSection::write (TestLog& log) const
492{
493	log.startSection(m_name.c_str(), m_description.c_str());
494}
495
496inline void LogShaderProgram::write (TestLog& log) const
497{
498	log.startShaderProgram(m_linkOk, m_linkInfoLog.c_str());
499}
500
501inline void LogShader::write (TestLog& log) const
502{
503	log.writeShader(m_type, m_source.c_str(), m_compileOk, m_infoLog.c_str());
504}
505
506inline void LogSpirVAssemblySource::write (TestLog& log) const
507{
508	log.writeSpirVAssemblySource(m_source.c_str());
509}
510
511inline void LogKernelSource::write (TestLog& log) const
512{
513	log.writeKernelSource(m_source.c_str());
514}
515
516inline void LogSampleList::write (TestLog& log) const
517{
518	log.startSampleList(m_name, m_description);
519}
520
521inline void LogValueInfo::write (TestLog& log) const
522{
523	log.writeValueInfo(m_name, m_description, m_unit, m_tag);
524}
525
526template<>
527inline void LogNumber<float>::write (TestLog& log) const
528{
529	log.writeFloat(m_name.c_str(), m_desc.c_str(), m_unit.c_str(), m_tag, m_value);
530}
531
532template<>
533inline void LogNumber<deInt64>::write (TestLog& log) const
534{
535	log.writeInteger(m_name.c_str(), m_desc.c_str(), m_unit.c_str(), m_tag, m_value);
536}
537
538} // tcu
539
540#endif // _TCUTESTLOG_HPP
541