1 /*-------------------------------------------------------------------------
2 * drawElements TestLog Library
3 * ----------------------------
5 * Copyright 2014 The Android Open Source Project
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * \brief Test case result logging
22 *//*--------------------------------------------------------------------*/
24 #include "qpTestLog.h"
25 #include "qpXmlWriter.h"
27 #include "qpDebugOut.h"
35 #if defined(QP_SUPPORT_PNG)
43 #if (DE_OS == DE_OS_WIN32)
50 /* Utils for verifying container (Section, ImageSet, EglConfigSet) usage in debug builds. */
52 typedef enum ContainerType_e
54 CONTAINERTYPE_SECTION = 0,
55 CONTAINERTYPE_IMAGESET,
56 CONTAINERTYPE_EGLCONFIGSET,
57 CONTAINERTYPE_SHADERPROGRAM,
58 CONTAINERTYPE_SAMPLELIST,
59 CONTAINERTYPE_SAMPLEINFO,
65 DE_INLINE deBool childContainersOk (ContainerType type)
67 return type == CONTAINERTYPE_SECTION || type == CONTAINERTYPE_SAMPLELIST;
72 MAX_CONTAINER_STACK_DEPTH = 32
75 typedef struct ContainerStack_s
78 ContainerType elements[MAX_CONTAINER_STACK_DEPTH];
81 DE_INLINE void ContainerStack_reset (ContainerStack* stack)
83 deMemset(stack, 0, sizeof(ContainerStack));
86 DE_INLINE deBool ContainerStack_isEmpty (const ContainerStack* stack)
88 return stack->numElements == 0;
91 DE_INLINE deBool ContainerStack_push (ContainerStack* stack, ContainerType type)
93 if (stack->numElements == MAX_CONTAINER_STACK_DEPTH)
96 if (stack->numElements > 0 && !childContainersOk(stack->elements[stack->numElements-1]))
99 stack->elements[stack->numElements] = type;
100 stack->numElements += 1;
105 DE_INLINE ContainerType ContainerStack_pop (ContainerStack* stack)
107 DE_ASSERT(stack->numElements > 0);
108 stack->numElements -= 1;
109 return stack->elements[stack->numElements];
112 DE_INLINE ContainerType ContainerStack_getTop (const ContainerStack* stack)
114 if (stack->numElements > 0)
115 return stack->elements[stack->numElements-1];
117 return CONTAINERTYPE_LAST;
122 /* qpTestLog instance */
125 deUint32 flags; /*!< Logging flags. */
127 deMutex lock; /*!< Lock for mutable state below. */
129 /* State protected by lock. */
132 deBool isSessionOpen;
135 #if defined(DE_DEBUG)
136 ContainerStack containerStack; /*!< For container usage verification. */
140 /* Maps integer to string. */
141 typedef struct qpKeyStringMap_s
147 static const char* LOG_FORMAT_VERSION = "0.3.4";
149 /* Mapping enum to above strings... */
150 static const qpKeyStringMap s_qpTestTypeMap[] =
152 { QP_TEST_CASE_TYPE_SELF_VALIDATE, "SelfValidate" },
153 { QP_TEST_CASE_TYPE_PERFORMANCE, "Performance" },
154 { QP_TEST_CASE_TYPE_CAPABILITY, "Capability" },
155 { QP_TEST_CASE_TYPE_ACCURACY, "Accuracy" },
157 { QP_TEST_CASE_TYPE_LAST, DE_NULL }
160 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_qpTestTypeMap) == QP_TEST_CASE_TYPE_LAST + 1);
162 static const qpKeyStringMap s_qpTestResultMap[] =
164 { QP_TEST_RESULT_PASS, "Pass" },
165 { QP_TEST_RESULT_FAIL, "Fail" },
166 { QP_TEST_RESULT_QUALITY_WARNING, "QualityWarning" },
167 { QP_TEST_RESULT_COMPATIBILITY_WARNING, "CompatibilityWarning" },
168 { QP_TEST_RESULT_PENDING, "Pending" }, /* should not be needed here */
169 { QP_TEST_RESULT_NOT_SUPPORTED, "NotSupported" },
170 { QP_TEST_RESULT_RESOURCE_ERROR, "ResourceError" },
171 { QP_TEST_RESULT_INTERNAL_ERROR, "InternalError" },
172 { QP_TEST_RESULT_CRASH, "Crash" },
173 { QP_TEST_RESULT_TIMEOUT, "Timeout" },
175 /* Add new values here if needed, remember to update qpTestResult enumeration. */
177 { QP_TEST_RESULT_LAST, DE_NULL }
180 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_qpTestResultMap) == QP_TEST_RESULT_LAST + 1);
182 /* Key tag to string mapping. */
184 static const qpKeyStringMap s_qpTagMap[] =
186 { QP_KEY_TAG_NONE, DE_NULL },
187 { QP_KEY_TAG_PERFORMANCE, "Performance" },
188 { QP_KEY_TAG_QUALITY, "Quality" },
189 { QP_KEY_TAG_PRECISION, "Precision" },
190 { QP_KEY_TAG_TIME, "Time" },
192 { QP_KEY_TAG_LAST, DE_NULL }
195 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_qpTagMap) == QP_KEY_TAG_LAST + 1);
197 /* Sample value tag to string mapping. */
199 static const qpKeyStringMap s_qpSampleValueTagMap[] =
201 { QP_SAMPLE_VALUE_TAG_PREDICTOR, "Predictor" },
202 { QP_SAMPLE_VALUE_TAG_RESPONSE, "Response" },
204 { QP_SAMPLE_VALUE_TAG_LAST, DE_NULL }
207 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_qpSampleValueTagMap) == QP_SAMPLE_VALUE_TAG_LAST + 1);
209 /* Image compression mode to string mapping. */
211 static const qpKeyStringMap s_qpImageCompressionModeMap[] =
213 { QP_IMAGE_COMPRESSION_MODE_NONE, "None" },
214 { QP_IMAGE_COMPRESSION_MODE_PNG, "PNG" },
216 { QP_IMAGE_COMPRESSION_MODE_BEST, DE_NULL }, /* not allowed to be written! */
218 { QP_IMAGE_COMPRESSION_MODE_LAST, DE_NULL }
221 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_qpImageCompressionModeMap) == QP_IMAGE_COMPRESSION_MODE_LAST + 1);
223 /* Image format to string mapping. */
225 static const qpKeyStringMap s_qpImageFormatMap[] =
227 { QP_IMAGE_FORMAT_RGB888, "RGB888" },
228 { QP_IMAGE_FORMAT_RGBA8888, "RGBA8888" },
230 { QP_IMAGE_FORMAT_LAST, DE_NULL }
233 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_qpImageFormatMap) == QP_IMAGE_FORMAT_LAST + 1);
235 /* Shader type to string mapping. */
237 static const qpKeyStringMap s_qpShaderTypeMap[] =
239 { QP_SHADER_TYPE_VERTEX, "VertexShader" },
240 { QP_SHADER_TYPE_FRAGMENT, "FragmentShader" },
241 { QP_SHADER_TYPE_GEOMETRY, "GeometryShader" },
242 { QP_SHADER_TYPE_TESS_CONTROL, "TessControlShader" },
243 { QP_SHADER_TYPE_TESS_EVALUATION, "TessEvaluationShader" },
244 { QP_SHADER_TYPE_COMPUTE, "ComputeShader" },
246 { QP_SHADER_TYPE_LAST, DE_NULL }
249 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_qpShaderTypeMap) == QP_SHADER_TYPE_LAST + 1);
251 static void qpTestLog_flushFile (qpTestLog* log)
253 DE_ASSERT(log && log->outputFile);
254 fflush(log->outputFile);
255 #if (DE_OS == DE_OS_WIN32) && (DE_COMPILER == DE_COMPILER_MSC)
256 /* \todo [petri] Is this really necessary? */
257 FlushFileBuffers((HANDLE)_get_osfhandle(_fileno(log->outputFile)));
261 #define QP_LOOKUP_STRING(KEYMAP, KEY) qpLookupString(KEYMAP, DE_LENGTH_OF_ARRAY(KEYMAP), (int)(KEY))
263 static const char* qpLookupString (const qpKeyStringMap* keyMap, int keyMapSize, int key)
266 DE_ASSERT(deInBounds32(key, 0, keyMapSize));
267 DE_ASSERT(keyMap[key].key == key);
268 DE_UNREF(keyMapSize); /* for asserting only */
269 return keyMap[key].string;
272 DE_INLINE void int32ToString (int val, char buf[32])
274 deSprintf(&buf[0], 32, "%d", val);
277 DE_INLINE void int64ToString (deInt64 val, char buf[32])
279 deSprintf(&buf[0], 32, "%lld", (long long int)val);
282 DE_INLINE void floatToString (float value, char* buf, size_t bufSize)
284 deSprintf(buf, bufSize, "%f", value);
287 DE_INLINE void doubleToString (double value, char* buf, size_t bufSize)
289 deSprintf(buf, bufSize, "%f", value);
292 static deBool beginSession (qpTestLog* log)
294 DE_ASSERT(log && !log->isSessionOpen);
296 /* Write session info. */
297 fprintf(log->outputFile, "#sessionInfo releaseName %s\n", qpGetReleaseName());
298 fprintf(log->outputFile, "#sessionInfo releaseId 0x%08x\n", qpGetReleaseId());
299 fprintf(log->outputFile, "#sessionInfo targetName \"%s\"\n", qpGetTargetName());
301 /* Write out #beginSession. */
302 fprintf(log->outputFile, "#beginSession\n");
303 qpTestLog_flushFile(log);
305 log->isSessionOpen = DE_TRUE;
310 static deBool endSession (qpTestLog* log)
312 DE_ASSERT(log && log->isSessionOpen);
314 /* Make sure xml is flushed. */
315 qpXmlWriter_flush(log->writer);
317 /* Write out #endSession. */
318 fprintf(log->outputFile, "\n#endSession\n");
319 qpTestLog_flushFile(log);
321 log->isSessionOpen = DE_FALSE;
326 /*--------------------------------------------------------------------*//*!
327 * \brief Create a file based logger instance
328 * \param fileName Name of the file where to put logs
329 * \return qpTestLog instance, or DE_NULL if cannot create file
330 *//*--------------------------------------------------------------------*/
331 qpTestLog* qpTestLog_createFileLog (const char* fileName, deUint32 flags)
333 qpTestLog* log = (qpTestLog*)deCalloc(sizeof(qpTestLog));
337 DE_ASSERT(fileName && fileName[0]); /* must have filename. */
339 #if defined(DE_DEBUG)
340 ContainerStack_reset(&log->containerStack);
343 qpPrintf("Writing test log into %s\n", fileName);
345 /* Create output file. */
346 log->outputFile = fopen(fileName, "wb");
347 if (!log->outputFile)
349 qpPrintf("ERROR: Unable to open test log output file '%s'.\n", fileName);
350 qpTestLog_destroy(log);
355 log->writer = qpXmlWriter_createFileWriter(log->outputFile, 0, !(flags & QP_TEST_LOG_NO_FLUSH));
356 log->lock = deMutex_create(DE_NULL);
357 log->isSessionOpen = DE_FALSE;
358 log->isCaseOpen = DE_FALSE;
362 qpPrintf("ERROR: Unable to create output XML writer to file '%s'.\n", fileName);
363 qpTestLog_destroy(log);
369 qpPrintf("ERROR: Unable to create mutex.\n");
370 qpTestLog_destroy(log);
379 /*--------------------------------------------------------------------*//*!
380 * \brief Destroy a logger instance
381 * \param a qpTestLog instance
382 *//*--------------------------------------------------------------------*/
383 void qpTestLog_destroy (qpTestLog* log)
387 if (log->isSessionOpen)
391 qpXmlWriter_destroy(log->writer);
394 fclose(log->outputFile);
397 deMutex_destroy(log->lock);
402 /*--------------------------------------------------------------------*//*!
403 * \brief Log start of test case
404 * \param log qpTestLog instance
405 * \param testCasePath Full test case path (as seen in Candy).
406 * \param testCaseType Test case type
407 * \return true if ok, false otherwise
408 *//*--------------------------------------------------------------------*/
409 deBool qpTestLog_startCase (qpTestLog* log, const char* testCasePath, qpTestCaseType testCaseType)
411 const char* typeStr = QP_LOOKUP_STRING(s_qpTestTypeMap, testCaseType);
412 int numResultAttribs = 0;
413 qpXmlAttribute resultAttribs[8];
415 DE_ASSERT(log && testCasePath && (testCasePath[0] != 0));
416 deMutex_lock(log->lock);
418 DE_ASSERT(!log->isCaseOpen);
419 DE_ASSERT(ContainerStack_isEmpty(&log->containerStack));
421 /* Flush XML and write out #beginTestCaseResult. */
422 qpXmlWriter_flush(log->writer);
423 fprintf(log->outputFile, "\n#beginTestCaseResult %s\n", testCasePath);
424 if (!(log->flags & QP_TEST_LOG_NO_FLUSH))
425 qpTestLog_flushFile(log);
427 log->isCaseOpen = DE_TRUE;
429 /* Fill in attributes. */
430 resultAttribs[numResultAttribs++] = qpSetStringAttrib("Version", LOG_FORMAT_VERSION);
431 resultAttribs[numResultAttribs++] = qpSetStringAttrib("CasePath", testCasePath);
432 resultAttribs[numResultAttribs++] = qpSetStringAttrib("CaseType", typeStr);
434 if (!qpXmlWriter_startDocument(log->writer) ||
435 !qpXmlWriter_startElement(log->writer, "TestCaseResult", numResultAttribs, resultAttribs))
437 qpPrintf("qpTestLog_startCase(): Writing XML failed\n");
438 deMutex_unlock(log->lock);
442 deMutex_unlock(log->lock);
446 /*--------------------------------------------------------------------*//*!
447 * \brief Log end of test case
448 * \param log qpTestLog instance
449 * \param result Test result
450 * \param description Description of a problem in case of error
451 * \return true if ok, false otherwise
452 *//*--------------------------------------------------------------------*/
453 deBool qpTestLog_endCase (qpTestLog* log, qpTestResult result, const char* resultDetails)
455 const char* statusStr = QP_LOOKUP_STRING(s_qpTestResultMap, result);
456 qpXmlAttribute statusAttrib = qpSetStringAttrib("StatusCode", statusStr);
458 deMutex_lock(log->lock);
460 DE_ASSERT(log->isCaseOpen);
461 DE_ASSERT(ContainerStack_isEmpty(&log->containerStack));
463 /* <Result StatusCode="Pass">Result details</Result>
466 if (!qpXmlWriter_startElement(log->writer, "Result", 1, &statusAttrib) ||
467 (resultDetails && !qpXmlWriter_writeString(log->writer, resultDetails)) ||
468 !qpXmlWriter_endElement(log->writer, "Result") ||
469 !qpXmlWriter_endElement(log->writer, "TestCaseResult") ||
470 !qpXmlWriter_endDocument(log->writer)) /* Close any XML elements still open */
472 qpPrintf("qpTestLog_endCase(): Writing XML failed\n");
473 deMutex_unlock(log->lock);
477 /* Flush XML and write #endTestCaseResult. */
478 qpXmlWriter_flush(log->writer);
479 fprintf(log->outputFile, "\n#endTestCaseResult\n");
480 if (!(log->flags & QP_TEST_LOG_NO_FLUSH))
481 qpTestLog_flushFile(log);
483 log->isCaseOpen = DE_FALSE;
485 deMutex_unlock(log->lock);
489 /*--------------------------------------------------------------------*//*!
490 * \brief Abrupt termination of logging.
491 * \param log qpTestLog instance
492 * \param result Result code, only Crash and Timeout are allowed.
493 * \return true if ok, false otherwise
494 *//*--------------------------------------------------------------------*/
495 deBool qpTestLog_terminateCase (qpTestLog* log, qpTestResult result)
497 const char* resultStr = QP_LOOKUP_STRING(s_qpTestResultMap, result);
500 DE_ASSERT(result == QP_TEST_RESULT_CRASH || result == QP_TEST_RESULT_TIMEOUT);
502 deMutex_lock(log->lock);
504 if (!log->isCaseOpen)
506 deMutex_unlock(log->lock);
507 return DE_FALSE; /* Soft error. This is called from error handler. */
510 /* Flush XML and write #terminateTestCaseResult. */
511 qpXmlWriter_flush(log->writer);
512 fprintf(log->outputFile, "\n#terminateTestCaseResult %s\n", resultStr);
513 qpTestLog_flushFile(log);
515 log->isCaseOpen = DE_FALSE;
517 #if defined(DE_DEBUG)
518 ContainerStack_reset(&log->containerStack);
521 deMutex_unlock(log->lock);
525 static deBool qpTestLog_writeKeyValuePair (qpTestLog* log, const char* elementName, const char* name, const char* description, const char* unit, qpKeyValueTag tag, const char* text)
527 const char* tagString = QP_LOOKUP_STRING(s_qpTagMap, tag);
528 qpXmlAttribute attribs[8];
531 DE_ASSERT(log && elementName && text);
532 deMutex_lock(log->lock);
534 /* Fill in attributes. */
535 if (name) attribs[numAttribs++] = qpSetStringAttrib("Name", name);
536 if (description) attribs[numAttribs++] = qpSetStringAttrib("Description", description);
537 if (tagString) attribs[numAttribs++] = qpSetStringAttrib("Tag", tagString);
538 if (unit) attribs[numAttribs++] = qpSetStringAttrib("Unit", unit);
540 if (!qpXmlWriter_startElement(log->writer, elementName, numAttribs, attribs) ||
541 !qpXmlWriter_writeString(log->writer, text) ||
542 !qpXmlWriter_endElement(log->writer, elementName))
544 qpPrintf("qpTestLog_writeKeyValuePair(): Writing XML failed\n");
545 deMutex_unlock(log->lock);
549 deMutex_unlock(log->lock);
553 /*--------------------------------------------------------------------*//*!
554 * \brief Write a message to output log
555 * \param log qpTestLog instance
556 * \param format Format string of message
557 * \param ... Parameters for message
558 * \return true if ok, false otherwise
559 *//*--------------------------------------------------------------------*/
560 deBool qpTestLog_writeMessage (qpTestLog* log, const char* format, ...)
565 /* \todo [petri] Handle buffer overflows! */
567 va_start(args, format);
568 buffer[DE_LENGTH_OF_ARRAY(buffer) - 1] = 0;
569 vsnprintf(buffer, sizeof(buffer), format, args);
572 printf("%s\n", buffer);
574 /* <Text>text</Text> */
575 return qpTestLog_writeKeyValuePair(log, "Text", DE_NULL, DE_NULL, DE_NULL, QP_KEY_TAG_LAST, buffer);
578 /*--------------------------------------------------------------------*//*!
579 * \brief Write key-value-pair into log
580 * \param log qpTestLog instance
581 * \param name Unique identifier for entry
582 * \param description Human readable description
583 * \param tag Optional tag
584 * \param value Value of the key-value-pair
585 * \return true if ok, false otherwise
586 *//*--------------------------------------------------------------------*/
587 deBool qpTestLog_writeText (qpTestLog* log, const char* name, const char* description, qpKeyValueTag tag, const char* text)
589 /* <Text Name="name" Description="description" Tag="tag">text</Text> */
590 return qpTestLog_writeKeyValuePair(log, "Text", name, description, DE_NULL, tag, text);
593 /*--------------------------------------------------------------------*//*!
594 * \brief Write key-value-pair into log
595 * \param log qpTestLog instance
596 * \param name Unique identifier for entry
597 * \param description Human readable description
598 * \param tag Optional tag
599 * \param value Value of the key-value-pair
600 * \return true if ok, false otherwise
601 *//*--------------------------------------------------------------------*/
602 deBool qpTestLog_writeInteger (qpTestLog* log, const char* name, const char* description, const char* unit, qpKeyValueTag tag, deInt64 value)
605 int64ToString(value, tmpString);
607 printf("%s = %lld %s\n", description, (signed long long)value, unit ? unit : "");
609 /* <Number Name="name" Description="description" Tag="Performance">15</Number> */
610 return qpTestLog_writeKeyValuePair(log, "Number", name, description, unit, tag, tmpString);
613 /*--------------------------------------------------------------------*//*!
614 * \brief Write key-value-pair into log
615 * \param log qpTestLog instance
616 * \param name Unique identifier for entry
617 * \param description Human readable description
618 * \param tag Optional tag
619 * \param value Value of the key-value-pair
620 * \return true if ok, false otherwise
621 *//*--------------------------------------------------------------------*/
622 deBool qpTestLog_writeFloat (qpTestLog* log, const char* name, const char* description, const char* unit, qpKeyValueTag tag, float value)
625 floatToString(value, tmpString, sizeof(tmpString));
627 printf("%s = %f %s\n", description, value, unit ? unit : "");
629 /* <Number Name="name" Description="description" Tag="Performance">15</Number> */
630 return qpTestLog_writeKeyValuePair(log, "Number", name, description, unit, tag, tmpString);
633 typedef struct Buffer_s
640 void Buffer_init (Buffer* buffer)
642 buffer->capacity = 0;
644 buffer->data = DE_NULL;
647 void Buffer_deinit (Buffer* buffer)
649 deFree(buffer->data);
653 deBool Buffer_resize (Buffer* buffer, size_t newSize)
655 /* Grow buffer if necessary. */
656 if (newSize > buffer->capacity)
658 size_t newCapacity = (size_t)deAlign32(deMax32(2*(int)buffer->capacity, (int)newSize), 512);
659 deUint8* newData = (deUint8*)deMalloc(newCapacity);
663 memcpy(newData, buffer->data, buffer->size);
664 deFree(buffer->data);
665 buffer->data = newData;
666 buffer->capacity = newCapacity;
669 buffer->size = newSize;
673 deBool Buffer_append (Buffer* buffer, const deUint8* data, size_t numBytes)
675 size_t offset = buffer->size;
677 if (!Buffer_resize(buffer, buffer->size + numBytes))
681 memcpy(&buffer->data[offset], data, numBytes);
685 #if defined(QP_SUPPORT_PNG)
686 void pngWriteData (png_structp png, png_bytep dataPtr, png_size_t numBytes)
688 Buffer* buffer = (Buffer*)png_get_io_ptr(png);
689 if (!Buffer_append(buffer, (const deUint8*)dataPtr, numBytes))
690 png_error(png, "unable to resize PNG write buffer!");
693 void pngFlushData (png_structp png)
699 static deBool writeCompressedPNG (png_structp png, png_infop info, png_byte** rowPointers, int width, int height, int colorFormat)
701 if (setjmp(png_jmpbuf(png)) == 0)
704 png_set_IHDR(png, info, (png_uint_32)width, (png_uint_32)height,
708 PNG_COMPRESSION_TYPE_BASE,
709 PNG_FILTER_TYPE_BASE);
710 png_write_info(png, info);
711 png_write_image(png, rowPointers);
712 png_write_end(png, NULL);
720 static deBool compressImagePNG (Buffer* buffer, qpImageFormat imageFormat, int width, int height, int rowStride, const void* data)
722 deBool compressOk = DE_FALSE;
723 png_structp png = DE_NULL;
724 png_infop info = DE_NULL;
725 png_byte** rowPointers = DE_NULL;
726 deBool hasAlpha = imageFormat == QP_IMAGE_FORMAT_RGBA8888;
730 DE_ASSERT(imageFormat == QP_IMAGE_FORMAT_RGB888 || imageFormat == QP_IMAGE_FORMAT_RGBA8888);
732 /* Allocate & set row pointers. */
733 rowPointers = (png_byte**)deMalloc((size_t)height * sizeof(png_byte*));
737 for (ndx = 0; ndx < height; ndx++)
738 rowPointers[ndx] = (png_byte*)((const deUint8*)data + ndx*rowStride);
740 /* Initialize PNG compressor. */
741 png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
742 info = png ? png_create_info_struct(png) : DE_NULL;
745 /* Set our own write function. */
746 png_set_write_fn(png, buffer, pngWriteData, pngFlushData);
748 compressOk = writeCompressedPNG(png, info, rowPointers, width, height,
749 hasAlpha ? PNG_COLOR_TYPE_RGBA : PNG_COLOR_TYPE_RGB);
752 /* Cleanup & return. */
755 png_destroy_info_struct(png, &info);
756 png_destroy_write_struct(&png, DE_NULL);
759 png_destroy_write_struct(&png, &info);
764 #endif /* QP_SUPPORT_PNG */
766 /*--------------------------------------------------------------------*//*!
767 * \brief Start image set
768 * \param log qpTestLog instance
769 * \param name Unique identifier for the set
770 * \param description Human readable description
771 * \return true if ok, false otherwise
772 *//*--------------------------------------------------------------------*/
773 deBool qpTestLog_startImageSet (qpTestLog* log, const char* name, const char* description)
775 qpXmlAttribute attribs[4];
778 DE_ASSERT(log && name);
779 deMutex_lock(log->lock);
781 attribs[numAttribs++] = qpSetStringAttrib("Name", name);
783 attribs[numAttribs++] = qpSetStringAttrib("Description", description);
785 /* <ImageSet Name="<name>"> */
786 if (!qpXmlWriter_startElement(log->writer, "ImageSet", numAttribs, attribs))
788 qpPrintf("qpTestLog_startImageSet(): Writing XML failed\n");
789 deMutex_unlock(log->lock);
793 DE_ASSERT(ContainerStack_push(&log->containerStack, CONTAINERTYPE_IMAGESET));
795 deMutex_unlock(log->lock);
799 /*--------------------------------------------------------------------*//*!
800 * \brief End image set
801 * \param log qpTestLog instance
802 * \return true if ok, false otherwise
803 *//*--------------------------------------------------------------------*/
804 deBool qpTestLog_endImageSet (qpTestLog* log)
807 deMutex_lock(log->lock);
809 /* <ImageSet Name="<name>"> */
810 if (!qpXmlWriter_endElement(log->writer, "ImageSet"))
812 qpPrintf("qpTestLog_endImageSet(): Writing XML failed\n");
813 deMutex_unlock(log->lock);
817 DE_ASSERT(ContainerStack_pop(&log->containerStack) == CONTAINERTYPE_IMAGESET);
819 deMutex_unlock(log->lock);
823 /*--------------------------------------------------------------------*//*!
824 * \brief Write base64 encoded raw image data into log
825 * \param log qpTestLog instance
826 * \param name Unique name (matching names can be compared across BatchResults).
827 * \param description Textual description (shown in Candy).
828 * \param compressionMode Compression mode
829 * \param imageFormat Color format
830 * \param width Width in pixels
831 * \param height Height in pixels
832 * \param stride Data stride (offset between rows)
833 * \param data Pointer to pixel data
834 * \return 0 if OK, otherwise <0
835 *//*--------------------------------------------------------------------*/
836 deBool qpTestLog_writeImage (
839 const char* description,
840 qpImageCompressionMode compressionMode,
841 qpImageFormat imageFormat,
849 qpXmlAttribute attribs[8];
851 Buffer compressedBuffer;
852 const void* writeDataPtr = DE_NULL;
853 size_t writeDataBytes = ~(size_t)0;
855 DE_ASSERT(log && name);
856 DE_ASSERT(deInRange32(width, 1, 16384));
857 DE_ASSERT(deInRange32(height, 1, 16384));
860 if (log->flags & QP_TEST_LOG_EXCLUDE_IMAGES)
861 return DE_TRUE; /* Image not logged. */
863 Buffer_init(&compressedBuffer);
865 /* BEST compression mode defaults to PNG. */
866 if (compressionMode == QP_IMAGE_COMPRESSION_MODE_BEST)
868 #if defined(QP_SUPPORT_PNG)
869 compressionMode = QP_IMAGE_COMPRESSION_MODE_PNG;
871 compressionMode = QP_IMAGE_COMPRESSION_MODE_NONE;
875 #if defined(QP_SUPPORT_PNG)
876 /* Try storing with PNG compression. */
877 if (compressionMode == QP_IMAGE_COMPRESSION_MODE_PNG)
879 deBool compressOk = compressImagePNG(&compressedBuffer, imageFormat, width, height, stride, data);
882 writeDataPtr = compressedBuffer.data;
883 writeDataBytes = compressedBuffer.size;
887 /* Fall-back to default compression. */
888 qpPrintf("WARNING: PNG compression failed -- storing image uncompressed.\n");
889 compressionMode = QP_IMAGE_COMPRESSION_MODE_NONE;
894 /* Handle image compression. */
895 switch (compressionMode)
897 case QP_IMAGE_COMPRESSION_MODE_NONE:
899 int pixelSize = imageFormat == QP_IMAGE_FORMAT_RGB888 ? 3 : 4;
900 int packedStride = pixelSize*width;
902 if (packedStride == stride)
906 /* Need to re-pack pixels. */
907 if (Buffer_resize(&compressedBuffer, (size_t)(packedStride*height)))
910 for (row = 0; row < height; row++)
911 memcpy(&compressedBuffer.data[packedStride*row], &((const deUint8*)data)[row*stride], (size_t)(pixelSize*width));
915 qpPrintf("ERROR: Failed to pack pixels for writing.\n");
916 Buffer_deinit(&compressedBuffer);
921 writeDataBytes = (size_t)(packedStride*height);
925 #if defined(QP_SUPPORT_PNG)
926 case QP_IMAGE_COMPRESSION_MODE_PNG:
927 DE_ASSERT(writeDataPtr); /* Already handled. */
932 qpPrintf("qpTestLog_writeImage(): Unknown compression mode: %s\n", QP_LOOKUP_STRING(s_qpImageCompressionModeMap, compressionMode));
933 Buffer_deinit(&compressedBuffer);
937 /* Fill in attributes. */
938 int32ToString(width, widthStr);
939 int32ToString(height, heightStr);
940 attribs[numAttribs++] = qpSetStringAttrib("Name", name);
941 attribs[numAttribs++] = qpSetStringAttrib("Width", widthStr);
942 attribs[numAttribs++] = qpSetStringAttrib("Height", heightStr);
943 attribs[numAttribs++] = qpSetStringAttrib("Format", QP_LOOKUP_STRING(s_qpImageFormatMap, imageFormat));
944 attribs[numAttribs++] = qpSetStringAttrib("CompressionMode", QP_LOOKUP_STRING(s_qpImageCompressionModeMap, compressionMode));
945 if (description) attribs[numAttribs++] = qpSetStringAttrib("Description", description);
947 /* \note Log lock is acquired after compression! */
948 deMutex_lock(log->lock);
950 /* <Image ID="result" Name="Foobar" Width="640" Height="480" Format="RGB888" CompressionMode="None">base64 data</Image> */
951 if (!qpXmlWriter_startElement(log->writer, "Image", numAttribs, attribs) ||
952 !qpXmlWriter_writeBase64(log->writer, (const deUint8*)writeDataPtr, writeDataBytes) ||
953 !qpXmlWriter_endElement(log->writer, "Image"))
955 qpPrintf("qpTestLog_writeImage(): Writing XML failed\n");
956 deMutex_unlock(log->lock);
957 Buffer_deinit(&compressedBuffer);
961 deMutex_unlock(log->lock);
963 /* Free compressed data if allocated. */
964 Buffer_deinit(&compressedBuffer);
969 /*--------------------------------------------------------------------*//*!
970 * \brief Write a OpenGL ES shader program into the log.
971 * \param linkOk Shader program link result, false on failure
972 * \param linkInfoLog Implementation provided linkage log
973 *//*--------------------------------------------------------------------*/
974 deBool qpTestLog_startShaderProgram (qpTestLog* log, deBool linkOk, const char* linkInfoLog)
976 qpXmlAttribute programAttribs[4];
977 int numProgramAttribs = 0;
980 deMutex_lock(log->lock);
982 programAttribs[numProgramAttribs++] = qpSetStringAttrib("LinkStatus", linkOk ? "OK" : "Fail");
984 if (!qpXmlWriter_startElement(log->writer, "ShaderProgram", numProgramAttribs, programAttribs) ||
985 !qpXmlWriter_writeStringElement(log->writer, "InfoLog", linkInfoLog))
987 qpPrintf("qpTestLog_startShaderProgram(): Writing XML failed\n");
988 deMutex_unlock(log->lock);
992 DE_ASSERT(ContainerStack_push(&log->containerStack, CONTAINERTYPE_SHADERPROGRAM));
994 deMutex_unlock(log->lock);
998 /*--------------------------------------------------------------------*//*!
999 * \brief End shader program
1000 * \param log qpTestLog instance
1001 * \return true if ok, false otherwise
1002 *//*--------------------------------------------------------------------*/
1003 deBool qpTestLog_endShaderProgram (qpTestLog* log)
1006 deMutex_lock(log->lock);
1008 /* </ShaderProgram> */
1009 if (!qpXmlWriter_endElement(log->writer, "ShaderProgram"))
1011 qpPrintf("qpTestLog_endShaderProgram(): Writing XML failed\n");
1012 deMutex_unlock(log->lock);
1016 DE_ASSERT(ContainerStack_pop(&log->containerStack) == CONTAINERTYPE_SHADERPROGRAM);
1018 deMutex_unlock(log->lock);
1022 /*--------------------------------------------------------------------*//*!
1023 * \brief Write a OpenGL ES shader into the log.
1024 * \param type Shader type
1025 * \param source Shader source
1026 * \param compileOk Shader compilation result, false on failure
1027 * \param infoLog Implementation provided shader compilation log
1028 *//*--------------------------------------------------------------------*/
1029 deBool qpTestLog_writeShader (qpTestLog* log, qpShaderType type, const char* source, deBool compileOk, const char* infoLog)
1031 const char* tagName = QP_LOOKUP_STRING(s_qpShaderTypeMap, type);
1032 const char* sourceStr = ((log->flags & QP_TEST_LOG_EXCLUDE_SHADER_SOURCES) == 0 || !compileOk) ? source : "";
1033 int numShaderAttribs = 0;
1034 qpXmlAttribute shaderAttribs[4];
1036 deMutex_lock(log->lock);
1039 DE_ASSERT(ContainerStack_getTop(&log->containerStack) == CONTAINERTYPE_SHADERPROGRAM);
1041 shaderAttribs[numShaderAttribs++] = qpSetStringAttrib("CompileStatus", compileOk ? "OK" : "Fail");
1043 if (!qpXmlWriter_startElement(log->writer, tagName, numShaderAttribs, shaderAttribs) ||
1044 !qpXmlWriter_writeStringElement(log->writer, "ShaderSource", sourceStr) ||
1045 !qpXmlWriter_writeStringElement(log->writer, "InfoLog", infoLog) ||
1046 !qpXmlWriter_endElement(log->writer, tagName))
1048 qpPrintf("qpTestLog_writeShader(): Writing XML failed\n");
1049 deMutex_unlock(log->lock);
1053 deMutex_unlock(log->lock);
1057 /*--------------------------------------------------------------------*//*!
1058 * \brief Start writing a set of EGL configurations into the log.
1059 *//*--------------------------------------------------------------------*/
1060 deBool qpTestLog_startEglConfigSet (qpTestLog* log, const char* name, const char* description)
1062 qpXmlAttribute attribs[4];
1065 DE_ASSERT(log && name);
1066 deMutex_lock(log->lock);
1068 attribs[numAttribs++] = qpSetStringAttrib("Name", name);
1070 attribs[numAttribs++] = qpSetStringAttrib("Description", description);
1072 /* <EglConfigSet Name="<name>"> */
1073 if (!qpXmlWriter_startElement(log->writer, "EglConfigSet", numAttribs, attribs))
1075 qpPrintf("qpTestLog_startEglImageSet(): Writing XML failed\n");
1076 deMutex_unlock(log->lock);
1080 DE_ASSERT(ContainerStack_push(&log->containerStack, CONTAINERTYPE_EGLCONFIGSET));
1082 deMutex_unlock(log->lock);
1086 /*--------------------------------------------------------------------*//*!
1087 * \brief End an EGL config set
1088 *//*--------------------------------------------------------------------*/
1089 deBool qpTestLog_endEglConfigSet (qpTestLog* log)
1092 deMutex_lock(log->lock);
1094 /* <EglConfigSet Name="<name>"> */
1095 if (!qpXmlWriter_endElement(log->writer, "EglConfigSet"))
1097 qpPrintf("qpTestLog_endEglImageSet(): Writing XML failed\n");
1098 deMutex_unlock(log->lock);
1102 DE_ASSERT(ContainerStack_pop(&log->containerStack) == CONTAINERTYPE_EGLCONFIGSET);
1104 deMutex_unlock(log->lock);
1108 /*--------------------------------------------------------------------*//*!
1109 * \brief Write an EGL config inside an EGL config set
1110 * \see qpElgConfigInfo for details
1111 *//*--------------------------------------------------------------------*/
1112 deBool qpTestLog_writeEglConfig (qpTestLog* log, const qpEglConfigInfo* config)
1114 qpXmlAttribute attribs[64];
1117 DE_ASSERT(log && config);
1118 deMutex_lock(log->lock);
1120 attribs[numAttribs++] = qpSetIntAttrib ("BufferSize", config->bufferSize);
1121 attribs[numAttribs++] = qpSetIntAttrib ("RedSize", config->redSize);
1122 attribs[numAttribs++] = qpSetIntAttrib ("GreenSize", config->greenSize);
1123 attribs[numAttribs++] = qpSetIntAttrib ("BlueSize", config->blueSize);
1124 attribs[numAttribs++] = qpSetIntAttrib ("LuminanceSize", config->luminanceSize);
1125 attribs[numAttribs++] = qpSetIntAttrib ("AlphaSize", config->alphaSize);
1126 attribs[numAttribs++] = qpSetIntAttrib ("AlphaMaskSize", config->alphaMaskSize);
1127 attribs[numAttribs++] = qpSetBoolAttrib ("BindToTextureRGB", config->bindToTextureRGB);
1128 attribs[numAttribs++] = qpSetBoolAttrib ("BindToTextureRGBA", config->bindToTextureRGBA);
1129 attribs[numAttribs++] = qpSetStringAttrib ("ColorBufferType", config->colorBufferType);
1130 attribs[numAttribs++] = qpSetStringAttrib ("ConfigCaveat", config->configCaveat);
1131 attribs[numAttribs++] = qpSetIntAttrib ("ConfigID", config->configID);
1132 attribs[numAttribs++] = qpSetStringAttrib ("Conformant", config->conformant);
1133 attribs[numAttribs++] = qpSetIntAttrib ("DepthSize", config->depthSize);
1134 attribs[numAttribs++] = qpSetIntAttrib ("Level", config->level);
1135 attribs[numAttribs++] = qpSetIntAttrib ("MaxPBufferWidth", config->maxPBufferWidth);
1136 attribs[numAttribs++] = qpSetIntAttrib ("MaxPBufferHeight", config->maxPBufferHeight);
1137 attribs[numAttribs++] = qpSetIntAttrib ("MaxPBufferPixels", config->maxPBufferPixels);
1138 attribs[numAttribs++] = qpSetIntAttrib ("MaxSwapInterval", config->maxSwapInterval);
1139 attribs[numAttribs++] = qpSetIntAttrib ("MinSwapInterval", config->minSwapInterval);
1140 attribs[numAttribs++] = qpSetBoolAttrib ("NativeRenderable", config->nativeRenderable);
1141 attribs[numAttribs++] = qpSetStringAttrib ("RenderableType", config->renderableType);
1142 attribs[numAttribs++] = qpSetIntAttrib ("SampleBuffers", config->sampleBuffers);
1143 attribs[numAttribs++] = qpSetIntAttrib ("Samples", config->samples);
1144 attribs[numAttribs++] = qpSetIntAttrib ("StencilSize", config->stencilSize);
1145 attribs[numAttribs++] = qpSetStringAttrib ("SurfaceTypes", config->surfaceTypes);
1146 attribs[numAttribs++] = qpSetStringAttrib ("TransparentType", config->transparentType);
1147 attribs[numAttribs++] = qpSetIntAttrib ("TransparentRedValue", config->transparentRedValue);
1148 attribs[numAttribs++] = qpSetIntAttrib ("TransparentGreenValue", config->transparentGreenValue);
1149 attribs[numAttribs++] = qpSetIntAttrib ("TransparentBlueValue", config->transparentBlueValue);
1150 DE_ASSERT(numAttribs <= DE_LENGTH_OF_ARRAY(attribs));
1152 if (!qpXmlWriter_startElement(log->writer, "EglConfig", numAttribs, attribs) ||
1153 !qpXmlWriter_endElement(log->writer, "EglConfig"))
1155 qpPrintf("qpTestLog_writeEglConfig(): Writing XML failed\n");
1156 deMutex_unlock(log->lock);
1160 deMutex_unlock(log->lock);
1164 /*--------------------------------------------------------------------*//*!
1165 * \brief Start section in log.
1166 * \param log qpTestLog instance
1167 * \param name Section name
1168 * \param description Human readable description
1169 * \return true if ok, false otherwise
1170 *//*--------------------------------------------------------------------*/
1171 deBool qpTestLog_startSection (qpTestLog* log, const char* name, const char* description)
1173 qpXmlAttribute attribs[2];
1176 DE_ASSERT(log && name);
1177 deMutex_lock(log->lock);
1179 attribs[numAttribs++] = qpSetStringAttrib("Name", name);
1181 attribs[numAttribs++] = qpSetStringAttrib("Description", description);
1183 /* <Section Name="<name>" Description="<description>"> */
1184 if (!qpXmlWriter_startElement(log->writer, "Section", numAttribs, attribs))
1186 qpPrintf("qpTestLog_startSection(): Writing XML failed\n");
1187 deMutex_unlock(log->lock);
1191 DE_ASSERT(ContainerStack_push(&log->containerStack, CONTAINERTYPE_SECTION));
1193 deMutex_unlock(log->lock);
1197 /*--------------------------------------------------------------------*//*!
1198 * \brief End section in log.
1199 * \param log qpTestLog instance
1200 * \return true if ok, false otherwise
1201 *//*--------------------------------------------------------------------*/
1202 deBool qpTestLog_endSection (qpTestLog* log)
1205 deMutex_lock(log->lock);
1208 if (!qpXmlWriter_endElement(log->writer, "Section"))
1210 qpPrintf("qpTestLog_endSection(): Writing XML failed\n");
1211 deMutex_unlock(log->lock);
1215 DE_ASSERT(ContainerStack_pop(&log->containerStack) == CONTAINERTYPE_SECTION);
1217 deMutex_unlock(log->lock);
1221 /*--------------------------------------------------------------------*//*!
1222 * \brief Write OpenCL compute kernel source into the log.
1223 *//*--------------------------------------------------------------------*/
1224 deBool qpTestLog_writeKernelSource (qpTestLog* log, const char* source)
1226 const char* sourceStr = (log->flags & QP_TEST_LOG_EXCLUDE_SHADER_SOURCES) != 0 ? "" : source;
1229 deMutex_lock(log->lock);
1231 if (!qpXmlWriter_writeStringElement(log->writer, "KernelSource", sourceStr))
1233 qpPrintf("qpTestLog_writeKernelSource(): Writing XML failed\n");
1234 deMutex_unlock(log->lock);
1238 deMutex_unlock(log->lock);
1242 /*--------------------------------------------------------------------*//*!
1243 * \brief Write a SPIR-V module assembly source into the log.
1244 *//*--------------------------------------------------------------------*/
1245 deBool qpTestLog_writeSpirVAssemblySource (qpTestLog* log, const char* source)
1247 const char* const sourceStr = (log->flags & QP_TEST_LOG_EXCLUDE_SHADER_SOURCES) != 0 ? "" : source;
1249 deMutex_lock(log->lock);
1251 DE_ASSERT(ContainerStack_getTop(&log->containerStack) == CONTAINERTYPE_SHADERPROGRAM);
1253 if (!qpXmlWriter_writeStringElement(log->writer, "SpirVAssemblySource", sourceStr))
1255 qpPrintf("qpTestLog_writeSpirVAssemblySource(): Writing XML failed\n");
1256 deMutex_unlock(log->lock);
1260 deMutex_unlock(log->lock);
1264 /*--------------------------------------------------------------------*//*!
1265 * \brief Write OpenCL kernel compilation results into the log
1266 *//*--------------------------------------------------------------------*/
1267 deBool qpTestLog_writeCompileInfo (qpTestLog* log, const char* name, const char* description, deBool compileOk, const char* infoLog)
1270 qpXmlAttribute attribs[3];
1272 DE_ASSERT(log && name && description && infoLog);
1273 deMutex_lock(log->lock);
1275 attribs[numAttribs++] = qpSetStringAttrib("Name", name);
1276 attribs[numAttribs++] = qpSetStringAttrib("Description", description);
1277 attribs[numAttribs++] = qpSetStringAttrib("CompileStatus", compileOk ? "OK" : "Fail");
1279 if (!qpXmlWriter_startElement(log->writer, "CompileInfo", numAttribs, attribs) ||
1280 !qpXmlWriter_writeStringElement(log->writer, "InfoLog", infoLog) ||
1281 !qpXmlWriter_endElement(log->writer, "CompileInfo"))
1283 qpPrintf("qpTestLog_writeCompileInfo(): Writing XML failed\n");
1284 deMutex_unlock(log->lock);
1288 deMutex_unlock(log->lock);
1292 deBool qpTestLog_startSampleList (qpTestLog* log, const char* name, const char* description)
1295 qpXmlAttribute attribs[2];
1297 DE_ASSERT(log && name && description);
1298 deMutex_lock(log->lock);
1300 attribs[numAttribs++] = qpSetStringAttrib("Name", name);
1301 attribs[numAttribs++] = qpSetStringAttrib("Description", description);
1303 if (!qpXmlWriter_startElement(log->writer, "SampleList", numAttribs, attribs))
1305 qpPrintf("qpTestLog_startSampleList(): Writing XML failed\n");
1306 deMutex_unlock(log->lock);
1310 DE_ASSERT(ContainerStack_push(&log->containerStack, CONTAINERTYPE_SAMPLELIST));
1312 deMutex_unlock(log->lock);
1316 deBool qpTestLog_startSampleInfo (qpTestLog* log)
1319 deMutex_lock(log->lock);
1321 if (!qpXmlWriter_startElement(log->writer, "SampleInfo", 0, DE_NULL))
1323 qpPrintf("qpTestLog_startSampleInfo(): Writing XML failed\n");
1324 deMutex_unlock(log->lock);
1328 DE_ASSERT(ContainerStack_push(&log->containerStack, CONTAINERTYPE_SAMPLEINFO));
1330 deMutex_unlock(log->lock);
1334 deBool qpTestLog_writeValueInfo (qpTestLog* log, const char* name, const char* description, const char* unit, qpSampleValueTag tag)
1336 const char* tagName = QP_LOOKUP_STRING(s_qpSampleValueTagMap, tag);
1338 qpXmlAttribute attribs[4];
1340 DE_ASSERT(log && name && description && tagName);
1341 deMutex_lock(log->lock);
1343 DE_ASSERT(ContainerStack_getTop(&log->containerStack) == CONTAINERTYPE_SAMPLEINFO);
1345 attribs[numAttribs++] = qpSetStringAttrib("Name", name);
1346 attribs[numAttribs++] = qpSetStringAttrib("Description", description);
1347 attribs[numAttribs++] = qpSetStringAttrib("Tag", tagName);
1350 attribs[numAttribs++] = qpSetStringAttrib("Unit", unit);
1352 if (!qpXmlWriter_startElement(log->writer, "ValueInfo", numAttribs, attribs) ||
1353 !qpXmlWriter_endElement(log->writer, "ValueInfo"))
1355 qpPrintf("qpTestLog_writeValueInfo(): Writing XML failed\n");
1356 deMutex_unlock(log->lock);
1360 deMutex_unlock(log->lock);
1364 deBool qpTestLog_endSampleInfo (qpTestLog* log)
1367 deMutex_lock(log->lock);
1369 if (!qpXmlWriter_endElement(log->writer, "SampleInfo"))
1371 qpPrintf("qpTestLog_endSampleInfo(): Writing XML failed\n");
1372 deMutex_unlock(log->lock);
1376 DE_ASSERT(ContainerStack_pop(&log->containerStack) == CONTAINERTYPE_SAMPLEINFO);
1378 deMutex_unlock(log->lock);
1382 deBool qpTestLog_startSample (qpTestLog* log)
1385 deMutex_lock(log->lock);
1387 DE_ASSERT(ContainerStack_getTop(&log->containerStack) == CONTAINERTYPE_SAMPLELIST);
1389 if (!qpXmlWriter_startElement(log->writer, "Sample", 0, DE_NULL))
1391 qpPrintf("qpTestLog_startSample(): Writing XML failed\n");
1392 deMutex_unlock(log->lock);
1396 DE_ASSERT(ContainerStack_push(&log->containerStack, CONTAINERTYPE_SAMPLE));
1398 deMutex_unlock(log->lock);
1402 deBool qpTestLog_writeValueFloat (qpTestLog* log, double value)
1404 char tmpString[512];
1405 doubleToString(value, tmpString, (int)sizeof(tmpString));
1407 deMutex_lock(log->lock);
1409 DE_ASSERT(ContainerStack_getTop(&log->containerStack) == CONTAINERTYPE_SAMPLE);
1411 if (!qpXmlWriter_writeStringElement(log->writer, "Value", &tmpString[0]))
1413 qpPrintf("qpTestLog_writeSampleValue(): Writing XML failed\n");
1414 deMutex_unlock(log->lock);
1418 deMutex_unlock(log->lock);
1422 deBool qpTestLog_writeValueInteger (qpTestLog* log, deInt64 value)
1425 int64ToString(value, tmpString);
1427 deMutex_lock(log->lock);
1429 DE_ASSERT(ContainerStack_getTop(&log->containerStack) == CONTAINERTYPE_SAMPLE);
1431 if (!qpXmlWriter_writeStringElement(log->writer, "Value", &tmpString[0]))
1433 qpPrintf("qpTestLog_writeSampleValue(): Writing XML failed\n");
1434 deMutex_unlock(log->lock);
1438 deMutex_unlock(log->lock);
1442 deBool qpTestLog_endSample (qpTestLog* log)
1445 deMutex_lock(log->lock);
1447 if (!qpXmlWriter_endElement(log->writer, "Sample"))
1449 qpPrintf("qpTestLog_endSample(): Writing XML failed\n");
1450 deMutex_unlock(log->lock);
1454 DE_ASSERT(ContainerStack_pop(&log->containerStack) == CONTAINERTYPE_SAMPLE);
1456 deMutex_unlock(log->lock);
1460 deBool qpTestLog_endSampleList (qpTestLog* log)
1463 deMutex_lock(log->lock);
1465 if (!qpXmlWriter_endElement(log->writer, "SampleList"))
1467 qpPrintf("qpTestLog_endSampleList(): Writing XML failed\n");
1468 deMutex_unlock(log->lock);
1472 DE_ASSERT(ContainerStack_pop(&log->containerStack) == CONTAINERTYPE_SAMPLELIST);
1474 deMutex_unlock(log->lock);
1478 deUint32 qpTestLog_getLogFlags (const qpTestLog* log)
1484 const char* qpGetTestResultName (qpTestResult result)
1486 return QP_LOOKUP_STRING(s_qpTestResultMap, result);