#ifndef _TCUTESTLOG_HPP #define _TCUTESTLOG_HPP /*------------------------------------------------------------------------- * drawElements Quality Program Tester Core * ---------------------------------------- * * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *//*! * \file * \brief Test Log C++ Wrapper. *//*--------------------------------------------------------------------*/ #include "tcuDefs.hpp" #include "qpTestLog.h" #include "tcuTexture.hpp" #include namespace tcu { class Surface; class MessageBuilder; class LogImageSet; class LogImage; class LogSection; class LogShaderProgram; class LogShader; class LogSpirVAssemblySource; class LogKernelSource; class LogSampleList; class LogValueInfo; class SampleBuilder; template class LogNumber; /*--------------------------------------------------------------------*//*! * \brief Test log * * TestLog provides convinient C++ API for logging. The API has been designed * around stream operators much like STL iostream library. The following * examples demonstrate how to use TestLog. * * \code * TestLog& log = m_testCtx.getLog(); * * // Write message to log. * log << TestLog::Message << "Hello, World!" << TestLog::EndMessage; * int myNumber = 3; * log << TestLog::Message << "Diff is " << myNumber << TestLog::EndMessage; * * // Write image * Surface myImage(256, 256); * log << TestLog::Image("TestImage", "My test image", myImage); * * // Multiple commands can be combined: * log << TestLog::Section("Details", "Test case details") * << TestLog::Message << "Here be dragons" << TestLog::EndMessage * << TestLog::ImageSet("Result", "Result images") * << TestLog::Image("ImageA", "Image A", imageA) * << TestLog::Image("ImageB", "Image B", imageB) * << TestLog::EndImageSet << TestLog::EndSection; * \endcode *//*--------------------------------------------------------------------*/ class TestLog { public: // Tokens static const class BeginMessageToken { } Message; static const class EndMessageToken { } EndMessage; static const class EndImageSetToken { } EndImageSet; static const class EndSectionToken { } EndSection; static const class EndShaderProgramToken { } EndShaderProgram; static const class SampleInfoToken { } SampleInfo; static const class EndSampleInfoToken { } EndSampleInfo; static const class BeginSampleToken { } Sample; static const class EndSampleToken { } EndSample; static const class EndSampleListToken { } EndSampleList; // Typedefs. typedef LogImageSet ImageSet; typedef LogImage Image; typedef LogSection Section; typedef LogShaderProgram ShaderProgram; typedef LogShader Shader; typedef LogSpirVAssemblySource SpirVAssemblySource; typedef LogKernelSource KernelSource; typedef LogSampleList SampleList; typedef LogValueInfo ValueInfo; typedef LogNumber Float; typedef LogNumber Integer; explicit TestLog(const char *fileName, uint32_t flags = 0); ~TestLog(void); void writeSessionInfo(std::string additionalInfo = ""); MessageBuilder operator<<(const BeginMessageToken &); MessageBuilder message(void); TestLog &operator<<(const ImageSet &imageSet); TestLog &operator<<(const Image &image); TestLog &operator<<(const EndImageSetToken &); TestLog &operator<<(const Section §ion); TestLog &operator<<(const EndSectionToken &); TestLog &operator<<(const ShaderProgram &shaderProgram); TestLog &operator<<(const EndShaderProgramToken &); TestLog &operator<<(const Shader &shader); TestLog &operator<<(const SpirVAssemblySource &module); TestLog &operator<<(const KernelSource &kernelSrc); template TestLog &operator<<(const LogNumber &number); TestLog &operator<<(const SampleList &sampleList); TestLog &operator<<(const SampleInfoToken &); TestLog &operator<<(const ValueInfo &valueInfo); TestLog &operator<<(const EndSampleInfoToken &); SampleBuilder operator<<(const BeginSampleToken &); TestLog &operator<<(const EndSampleListToken &); // Raw api void writeMessage(const char *message); void startImageSet(const char *name, const char *description); void endImageSet(void); void writeImage(const char *name, const char *description, const ConstPixelBufferAccess &surface, const Vec4 &scale, const Vec4 &bias, qpImageCompressionMode compressionMode = QP_IMAGE_COMPRESSION_MODE_BEST); void writeImage(const char *name, const char *description, qpImageCompressionMode compressionMode, qpImageFormat format, int width, int height, int stride, const void *data); void startSection(const char *name, const char *description); void endSection(void); void startShaderProgram(bool linkOk, const char *linkInfoLog); void endShaderProgram(void); void writeShader(qpShaderType type, const char *source, bool compileOk, const char *infoLog); void writeSpirVAssemblySource(const char *source); void writeKernelSource(const char *source); void writeCompileInfo(const char *name, const char *description, bool compileOk, const char *infoLog); void writeFloat(const char *name, const char *description, const char *unit, qpKeyValueTag tag, float value); void writeInteger(const char *name, const char *description, const char *unit, qpKeyValueTag tag, int64_t value); void startEglConfigSet(const char *name, const char *description); void writeEglConfig(const qpEglConfigInfo *config); void endEglConfigSet(void); void startCase(const char *testCasePath, qpTestCaseType testCaseType); void endCase(qpTestResult result, const char *description); void terminateCase(qpTestResult result); void startTestsCasesTime(void); void endTestsCasesTime(void); void startSampleList(const std::string &name, const std::string &description); void startSampleInfo(void); void writeValueInfo(const std::string &name, const std::string &description, const std::string &unit, qpSampleValueTag tag); void endSampleInfo(void); void startSample(void); void writeSampleValue(double value); void writeSampleValue(int64_t value); void endSample(void); void endSampleList(void); void writeRaw(const char *rawContents); bool isShaderLoggingEnabled(void); void supressLogging(bool value); bool isSupressLogging(void); private: TestLog(const TestLog &other); // Not allowed! TestLog &operator=(const TestLog &other); // Not allowed! qpTestLog *m_log; bool m_logSupressed; bool m_skipAdditionalDataInLog; }; class MessageBuilder { public: explicit MessageBuilder(TestLog *log) : m_log(log) { } ~MessageBuilder(void) { } std::string toString(void) const { return m_str.str(); } TestLog &operator<<(const TestLog::EndMessageToken &); template MessageBuilder &operator<<(const T &value); MessageBuilder(const MessageBuilder &other); MessageBuilder &operator=(const MessageBuilder &other); private: TestLog *m_log; std::ostringstream m_str; }; class SampleBuilder { public: SampleBuilder(TestLog *log) : m_log(log) { } SampleBuilder &operator<<(int v) { m_values.push_back(Value((int64_t)v)); return *this; } SampleBuilder &operator<<(int64_t v) { m_values.push_back(Value(v)); return *this; } SampleBuilder &operator<<(float v) { m_values.push_back(Value((double)v)); return *this; } SampleBuilder &operator<<(double v) { m_values.push_back(Value(v)); return *this; } TestLog &operator<<(const TestLog::EndSampleToken &); private: struct Value { enum Type { TYPE_INT64 = 0, TYPE_FLOAT64, TYPE_LAST }; Type type; union { int64_t int64; double float64; } value; Value(void) : type(TYPE_LAST) { value.int64 = 0; } Value(double v) : type(TYPE_FLOAT64) { value.float64 = v; } Value(int64_t v) : type(TYPE_INT64) { value.int64 = v; } }; TestLog *m_log; std::vector m_values; }; class LogImageSet { public: LogImageSet(const std::string &name, const std::string &description) : m_name(name), m_description(description) { } void write(TestLog &log) const; private: std::string m_name; std::string m_description; }; // \note Doesn't take copy of surface contents class LogImage { public: LogImage(const std::string &name, const std::string &description, const Surface &surface, qpImageCompressionMode compression = QP_IMAGE_COMPRESSION_MODE_BEST); LogImage(const std::string &name, const std::string &description, const ConstPixelBufferAccess &access, qpImageCompressionMode compression = QP_IMAGE_COMPRESSION_MODE_BEST); 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); void write(TestLog &log) const; private: std::string m_name; std::string m_description; ConstPixelBufferAccess m_access; Vec4 m_scale; Vec4 m_bias; qpImageCompressionMode m_compression; }; class LogSection { public: LogSection(const std::string &name, const std::string &description) : m_name(name), m_description(description) { } void write(TestLog &log) const; private: std::string m_name; std::string m_description; }; class LogShaderProgram { public: LogShaderProgram(bool linkOk, const std::string &linkInfoLog) : m_linkOk(linkOk), m_linkInfoLog(linkInfoLog) { } void write(TestLog &log) const; private: bool m_linkOk; std::string m_linkInfoLog; }; class LogShader { public: LogShader(qpShaderType type, const std::string &source, bool compileOk, const std::string &infoLog) : m_type(type) , m_source(source) , m_compileOk(compileOk) , m_infoLog(infoLog) { } void write(TestLog &log) const; private: qpShaderType m_type; std::string m_source; bool m_compileOk; std::string m_infoLog; }; class LogSpirVAssemblySource { public: LogSpirVAssemblySource(const std::string &source) : m_source(source) { } void write(TestLog &log) const; private: std::string m_source; }; class LogKernelSource { public: explicit LogKernelSource(const std::string &source) : m_source(source) { } void write(TestLog &log) const; private: std::string m_source; }; class LogSampleList { public: LogSampleList(const std::string &name, const std::string &description) : m_name(name), m_description(description) { } void write(TestLog &log) const; private: std::string m_name; std::string m_description; }; class LogValueInfo { public: LogValueInfo(const std::string &name, const std::string &description, const std::string &unit, qpSampleValueTag tag) : m_name(name) , m_description(description) , m_unit(unit) , m_tag(tag) { } void write(TestLog &log) const; private: std::string m_name; std::string m_description; std::string m_unit; qpSampleValueTag m_tag; }; template class LogNumber { public: LogNumber(const std::string &name, const std::string &desc, const std::string &unit, qpKeyValueTag tag, T value) : m_name(name) , m_desc(desc) , m_unit(unit) , m_tag(tag) , m_value(value) { } void write(TestLog &log) const; private: std::string m_name; std::string m_desc; std::string m_unit; qpKeyValueTag m_tag; T m_value; }; // Section helper that closes section when leaving scope. class ScopedLogSection { public: ScopedLogSection(TestLog &log, const std::string &name, const std::string &description) : m_log(log) { m_log << TestLog::Section(name, description); } ~ScopedLogSection(void) { m_log << TestLog::EndSection; } private: TestLog &m_log; }; // TestLog stream operators. inline TestLog &TestLog::operator<<(const ImageSet &imageSet) { imageSet.write(*this); return *this; } inline TestLog &TestLog::operator<<(const Image &image) { image.write(*this); return *this; } inline TestLog &TestLog::operator<<(const EndImageSetToken &) { endImageSet(); return *this; } inline TestLog &TestLog::operator<<(const Section §ion) { section.write(*this); return *this; } inline TestLog &TestLog::operator<<(const EndSectionToken &) { endSection(); return *this; } inline TestLog &TestLog::operator<<(const ShaderProgram &shaderProg) { shaderProg.write(*this); return *this; } inline TestLog &TestLog::operator<<(const EndShaderProgramToken &) { endShaderProgram(); return *this; } inline TestLog &TestLog::operator<<(const Shader &shader) { shader.write(*this); return *this; } inline TestLog &TestLog::operator<<(const SpirVAssemblySource &module) { module.write(*this); return *this; } inline TestLog &TestLog::operator<<(const KernelSource &kernelSrc) { kernelSrc.write(*this); return *this; } inline TestLog &TestLog::operator<<(const SampleList &sampleList) { sampleList.write(*this); return *this; } inline TestLog &TestLog::operator<<(const SampleInfoToken &) { startSampleInfo(); return *this; } inline TestLog &TestLog::operator<<(const ValueInfo &valueInfo) { valueInfo.write(*this); return *this; } inline TestLog &TestLog::operator<<(const EndSampleInfoToken &) { endSampleInfo(); return *this; } inline TestLog &TestLog::operator<<(const EndSampleListToken &) { endSampleList(); return *this; } template inline TestLog &TestLog::operator<<(const LogNumber &number) { number.write(*this); return *this; } inline TestLog &operator<<(TestLog &log, const std::exception &e) { // \todo [2012-10-18 pyry] Print type info? return log << TestLog::Message << e.what() << TestLog::EndMessage; } // Utility class inline implementations. template inline MessageBuilder &MessageBuilder::operator<<(const T &value) { // Overload stream operator to implement custom format m_str << value; return *this; } inline MessageBuilder TestLog::operator<<(const BeginMessageToken &) { return MessageBuilder(this); } inline MessageBuilder TestLog::message(void) { return MessageBuilder(this); } inline SampleBuilder TestLog::operator<<(const BeginSampleToken &) { return SampleBuilder(this); } inline void LogImageSet::write(TestLog &log) const { log.startImageSet(m_name.c_str(), m_description.c_str()); } inline void LogSection::write(TestLog &log) const { log.startSection(m_name.c_str(), m_description.c_str()); } inline void LogShaderProgram::write(TestLog &log) const { log.startShaderProgram(m_linkOk, m_linkInfoLog.c_str()); } inline void LogShader::write(TestLog &log) const { log.writeShader(m_type, m_source.c_str(), m_compileOk, m_infoLog.c_str()); } inline void LogSpirVAssemblySource::write(TestLog &log) const { log.writeSpirVAssemblySource(m_source.c_str()); } inline void LogKernelSource::write(TestLog &log) const { log.writeKernelSource(m_source.c_str()); } inline void LogSampleList::write(TestLog &log) const { log.startSampleList(m_name, m_description); } inline void LogValueInfo::write(TestLog &log) const { log.writeValueInfo(m_name, m_description, m_unit, m_tag); } template <> inline void LogNumber::write(TestLog &log) const { log.writeFloat(m_name.c_str(), m_desc.c_str(), m_unit.c_str(), m_tag, m_value); } template <> inline void LogNumber::write(TestLog &log) const { log.writeInteger(m_name.c_str(), m_desc.c_str(), m_unit.c_str(), m_tag, m_value); } } // namespace tcu #endif // _TCUTESTLOG_HPP