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 computePixelScaleBias(access, m_scale, m_bias); 67 } 68 69 // MessageBuilder 70 71 MessageBuilder::MessageBuilder (const MessageBuilder& other) 72 : m_log(other.m_log) 73 { 74 m_str.str(other.m_str.str()); 75 } 76 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 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 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 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 120 TestLog::~TestLog (void) 121 { 122 qpTestLog_destroy(m_log); 123 } 124 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 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 137 void TestLog::endImageSet (void) 138 { 139 if (qpTestLog_endImageSet(m_log) == DE_FALSE) 140 throw LogWriteFailedError(); 141 } 142 143 template <int Size> 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 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 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 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 294 void TestLog::endSection (void) 295 { 296 if (qpTestLog_endSection(m_log) == DE_FALSE) 297 throw LogWriteFailedError(); 298 } 299 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 306 void TestLog::endShaderProgram (void) 307 { 308 if (qpTestLog_endShaderProgram(m_log) == DE_FALSE) 309 throw LogWriteFailedError(); 310 } 311 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 318 void TestLog::writeKernelSource (const char* source) 319 { 320 if (qpTestLog_writeKernelSource(m_log, source) == DE_FALSE) 321 throw LogWriteFailedError(); 322 } 323 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 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 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 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 348 void TestLog::writeEglConfig (const qpEglConfigInfo* config) 349 { 350 if (qpTestLog_writeEglConfig(m_log, config) == DE_FALSE) 351 throw LogWriteFailedError(); 352 } 353 354 void TestLog::endEglConfigSet (void) 355 { 356 if (qpTestLog_endEglConfigSet(m_log) == DE_FALSE) 357 throw LogWriteFailedError(); 358 } 359 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 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 372 void TestLog::terminateCase (qpTestResult result) 373 { 374 if (qpTestLog_terminateCase(m_log, result) == DE_FALSE) 375 throw LogWriteFailedError(); 376 } 377 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 384 void TestLog::startSampleInfo (void) 385 { 386 if (qpTestLog_startSampleInfo(m_log) == DE_FALSE) 387 throw LogWriteFailedError(); 388 } 389 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 396 void TestLog::endSampleInfo (void) 397 { 398 if (qpTestLog_endSampleInfo(m_log) == DE_FALSE) 399 throw LogWriteFailedError(); 400 } 401 402 void TestLog::startSample (void) 403 { 404 if (qpTestLog_startSample(m_log) == DE_FALSE) 405 throw LogWriteFailedError(); 406 } 407 408 void TestLog::writeSampleValue (double value) 409 { 410 if (qpTestLog_writeValueFloat(m_log, value) == DE_FALSE) 411 throw LogWriteFailedError(); 412 } 413 414 void TestLog::writeSampleValue (deInt64 value) 415 { 416 if (qpTestLog_writeValueInteger(m_log, value) == DE_FALSE) 417 throw LogWriteFailedError(); 418 } 419 420 void TestLog::endSample (void) 421 { 422 if (qpTestLog_endSample(m_log) == DE_FALSE) 423 throw LogWriteFailedError(); 424 } 425 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