Home | History | Annotate | Download | only in common
      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
    528