C
Monitor: Verifying the Rendering Output
// Copyright (C) 2025 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
// This file is part of the Qt Safe Renderer module
#include "goldencrccalculator.h"
#include <QtSafeRenderer/qsafelayoutresourcereader.h>
#include <QtSafeRenderer/qsaferenderer.h>
#include <QtSafeRenderer/qsafelayout.h>
#include <QtSafeRenderer/qsafewindow.h>
#include <QtSafeRenderer/qsafesize.h>
#include <QtSafeRenderer/qsafepoint.h>
#include <QtSafeRenderer/qsafestring.h>
#include <QtSafeRenderer/qsafeexceptionhandler.h>
#include <QtSafeRenderer/qsafeexceptionhandlerinterface.h>
#include "offscreensurface.h"
#include <QtSafePlatformAdaptation/outputverifier.h>
#include <QtSafePlatformAdaptation/verifyregion.h>
#include <QtSafeOutputVerifierAdaptation/calcmisr.h>
#include <cstring>
#include <new>
#include <cstdio>
#include <cstdlib>
class GoldenCrcCalculatorImpl {
public:
GoldenCrcCalculatorImpl(SafeRenderer::QSafeLayout *layoutPtr)
: m_layout(layoutPtr)
, m_surface(m_layout->size())
, m_renderer(&m_surface, m_layout)
, m_misrCalculator(*m_surface.framebuffer(), m_layout->size())
{
SafeRenderer::QSafeExceptionHandler::installExceptionHandler(&m_exceptionHandler);
}
qint32 calculateItemCRCById(quint32 itemId, quint32 stateId, quint32* crcOut)
{
qint32 returnValue = -1;
if (crcOut != NULL) {
/* Clear then render the item; custom exception handler will abort on errors */
(void)m_renderer.clearBitmap(itemId, false);
SafeRenderer::QSafeRect dirtyRect = m_renderer.drawBitmap(itemId);
SafeRenderer::VerifyRegion verifyRegion(itemId, stateId, dirtyRect);
m_misrCalculator.getCRC(verifyRegion);
*crcOut = verifyRegion.crc();
returnValue = 0;
}
return returnValue;
}
private:
SafeRenderer::QSafeLayout* m_layout;
OffscreenSurface m_surface;
SafeRenderer::QSafeRenderer m_renderer;
SafeRenderer::MISRCalculator m_misrCalculator;
class ExceptionHandler : public SafeRenderer::QSafeExceptionHandlerInterface {
public:
virtual bool onException(const SafeRenderer::QSafeException &exception) {
std::fprintf(stderr, "GoldenCrcCalculator fatal error: %s\n", exception.what());
std::abort();
}
};
ExceptionHandler m_exceptionHandler;
};
// C API Implementation
extern "C" {
SafeLayoutHandle qsrCreateLayoutFromResource(const qchar* resourcePath)
{
SafeLayoutHandle layoutHandle = NULL;
if (resourcePath != NULL) {
// Use QSafeRenderer allocator to allocate the memory from the memory pool.
SafeRenderer::quint8 *implMem = SafeRenderer::allocAlignedFromMemoryPool(sizeof(SafeRenderer::QSafeLayoutResourceReader));
SafeRenderer::QSafeLayoutResourceReader *layoutReader = new (implMem) SafeRenderer::QSafeLayoutResourceReader(resourcePath);
layoutHandle = layoutReader;
}
return layoutHandle;
}
void qsrDestroyLayout(SafeLayoutHandle layoutHandle)
{
if (layoutHandle != NULL) {
SafeRenderer::QSafeLayoutResourceReader *layoutReader = static_cast<SafeRenderer::QSafeLayoutResourceReader *>(layoutHandle);
layoutReader->~QSafeLayoutResourceReader();
// The default allocator in QSR does not support dealloc, but this is
// used here in case the allocator is customized.
SafeRenderer::deallocFromMemoryPool(reinterpret_cast<SafeRenderer::quint8*>(layoutReader));
}
}
qint32 qsrSetTextForItem(quint32 itemId, const qchar *text, SafeLayoutHandle layoutHandle)
{
qint32 returnValue = -1;
if (layoutHandle != NULL) {
SafeRenderer::QSafeLayout *layoutPtr = static_cast<SafeRenderer::QSafeLayout *>(layoutHandle);
layoutPtr->setTextForItem(itemId, text);
returnValue = 0;
}
return returnValue;
}
GoldenCrcCalculatorHandle qsrGoldenCrcCalculatorCreate(SafeLayoutHandle layoutHandle)
{
GoldenCrcCalculatorHandle crcCalc = NULL;
if (layoutHandle != NULL) {
// Use QSafeRenderer allocator to allocate the memory from the memory pool.
SafeRenderer::QSafeLayout *layoutPtr = static_cast<SafeRenderer::QSafeLayout *>(layoutHandle);
SafeRenderer::quint8* implMem = SafeRenderer::allocAlignedFromMemoryPool(sizeof(GoldenCrcCalculatorImpl));
crcCalc = new (implMem) GoldenCrcCalculatorImpl(layoutPtr);
}
return crcCalc;
}
void qsrGoldenCrcCalculatorDestroy(GoldenCrcCalculatorHandle handle)
{
if (handle) {
GoldenCrcCalculatorImpl* impl = static_cast<GoldenCrcCalculatorImpl*>(handle);
impl->~GoldenCrcCalculatorImpl();
// The default allocator in QSR does not support dealloc, but this is
// used here in case the allocator is customized.
SafeRenderer::deallocFromMemoryPool(reinterpret_cast<SafeRenderer::quint8*>(impl));
}
}
qint32 qsrCalculateItemCrc(GoldenCrcCalculatorHandle handle,
const quint32 itemId,
const quint32 stateId,
quint32* crcOut) {
qint32 returnValue = -1;
if (handle != NULL) {
GoldenCrcCalculatorImpl* impl = static_cast<GoldenCrcCalculatorImpl*>(handle);
returnValue = impl->calculateItemCRCById(itemId, stateId, crcOut);
}
return returnValue;
}
} // extern "C"