diff options
Diffstat (limited to 'src/gui/rhi/qrhinull.cpp')
-rw-r--r-- | src/gui/rhi/qrhinull.cpp | 145 |
1 files changed, 133 insertions, 12 deletions
diff --git a/src/gui/rhi/qrhinull.cpp b/src/gui/rhi/qrhinull.cpp index 487afd3ed1..fe606f971f 100644 --- a/src/gui/rhi/qrhinull.cpp +++ b/src/gui/rhi/qrhinull.cpp @@ -36,6 +36,7 @@ #include "qrhinull_p_p.h" #include <qmath.h> +#include <QPainter> QT_BEGIN_NAMESPACE @@ -385,27 +386,125 @@ QRhi::FrameOpResult QRhiNull::finish() return QRhi::FrameOpSuccess; } +void QRhiNull::simulateTextureUpload(const QRhiResourceUpdateBatchPrivate::TextureOp &u) +{ + QNullTexture *texD = QRHI_RES(QNullTexture, u.dst); + for (int layer = 0; layer < QRhi::MAX_LAYERS; ++layer) { + for (int level = 0; level < QRhi::MAX_LEVELS; ++level) { + for (const QRhiTextureSubresourceUploadDescription &subresDesc : qAsConst(u.subresDesc[layer][level])) { + if (!subresDesc.image().isNull()) { + const QImage src = subresDesc.image(); + QPainter painter(&texD->image[layer][level]); + const QSize srcSize = subresDesc.sourceSize().isEmpty() + ? src.size() : subresDesc.sourceSize(); + painter.setCompositionMode(QPainter::CompositionMode_Source); + painter.drawImage(subresDesc.destinationTopLeft(), src, + QRect(subresDesc.sourceTopLeft(), srcSize)); + } else if (!subresDesc.data().isEmpty()) { + const QSize subresSize = q->sizeForMipLevel(level, texD->pixelSize()); + int w = subresSize.width(); + int h = subresSize.height(); + if (!subresDesc.sourceSize().isEmpty()) { + w = subresDesc.sourceSize().width(); + h = subresDesc.sourceSize().height(); + } + // sourceTopLeft is not supported on this path as per QRhi docs + const char *src = subresDesc.data().constData(); + const int srcBpl = w * 4; + const QPoint dstOffset = subresDesc.destinationTopLeft(); + uchar *dst = texD->image[layer][level].bits(); + const int dstBpl = texD->image[layer][level].bytesPerLine(); + for (int y = 0; y < h; ++y) { + memcpy(dst + dstOffset.x() * 4 + (y + dstOffset.y()) * dstBpl, + src + y * srcBpl, + size_t(srcBpl)); + } + } + } + } + } +} + +void QRhiNull::simulateTextureCopy(const QRhiResourceUpdateBatchPrivate::TextureOp &u) +{ + QNullTexture *srcD = QRHI_RES(QNullTexture, u.src); + QNullTexture *dstD = QRHI_RES(QNullTexture, u.dst); + const QImage &srcImage(srcD->image[u.desc.sourceLayer()][u.desc.sourceLevel()]); + QImage &dstImage(dstD->image[u.desc.destinationLayer()][u.desc.destinationLevel()]); + const QPoint dstPos = u.desc.destinationTopLeft(); + const QSize size = u.desc.pixelSize().isEmpty() ? srcD->pixelSize() : u.desc.pixelSize(); + const QPoint srcPos = u.desc.sourceTopLeft(); + + QPainter painter(&dstImage); + painter.setCompositionMode(QPainter::CompositionMode_Source); + painter.drawImage(QRect(dstPos, size), srcImage, QRect(srcPos, size)); +} + +void QRhiNull::simulateTextureGenMips(const QRhiResourceUpdateBatchPrivate::TextureOp &u) +{ + QNullTexture *texD = QRHI_RES(QNullTexture, u.dst); + const QSize baseSize = texD->pixelSize(); + const int levelCount = q->mipLevelsForSize(baseSize); + for (int level = 1; level < levelCount; ++level) + texD->image[0][level] = texD->image[0][0].scaled(q->sizeForMipLevel(level, baseSize)); +} + void QRhiNull::resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) { Q_UNUSED(cb); QRhiResourceUpdateBatchPrivate *ud = QRhiResourceUpdateBatchPrivate::get(resourceUpdates); + for (const QRhiResourceUpdateBatchPrivate::BufferOp &u : ud->bufferOps) { + if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::DynamicUpdate + || u.type == QRhiResourceUpdateBatchPrivate::BufferOp::StaticUpload) + { + QNullBuffer *bufD = QRHI_RES(QNullBuffer, u.buf); + memcpy(bufD->data.data() + u.offset, u.data.constData(), size_t(u.data.size())); + } else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::Read) { + QRhiBufferReadbackResult *result = u.result; + result->data.resize(u.readSize); + QNullBuffer *bufD = QRHI_RES(QNullBuffer, u.buf); + memcpy(result->data.data(), bufD->data.constData() + u.offset, size_t(u.readSize)); + if (result->completed) + result->completed(); + } + } for (const QRhiResourceUpdateBatchPrivate::TextureOp &u : ud->textureOps) { - if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Read) { - QRhiReadbackResult *result = u.read.result; - QRhiTexture *tex = u.read.rb.texture(); - if (tex) { - result->format = tex->format(); - result->pixelSize = q->sizeForMipLevel(u.read.rb.level(), tex->pixelSize()); + if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Upload) { + if (u.dst->format() == QRhiTexture::RGBA8) + simulateTextureUpload(u); + } else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Copy) { + if (u.src->format() == QRhiTexture::RGBA8 && u.dst->format() == QRhiTexture::RGBA8) + simulateTextureCopy(u); + } else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Read) { + QRhiReadbackResult *result = u.result; + QNullTexture *texD = QRHI_RES(QNullTexture, u.rb.texture()); + if (texD) { + result->format = texD->format(); + result->pixelSize = q->sizeForMipLevel(u.rb.level(), texD->pixelSize()); } else { Q_ASSERT(currentSwapChain); result->format = QRhiTexture::RGBA8; result->pixelSize = currentSwapChain->currentPixelSize(); } + quint32 bytesPerLine = 0; quint32 byteSize = 0; - textureFormatInfo(result->format, result->pixelSize, nullptr, &byteSize); - result->data.fill(0, byteSize); + textureFormatInfo(result->format, result->pixelSize, &bytesPerLine, &byteSize); + if (texD && texD->format() == QRhiTexture::RGBA8) { + result->data.resize(int(byteSize)); + const QImage &src(texD->image[u.rb.layer()][u.rb.level()]); + char *dst = result->data.data(); + for (int y = 0, h = src.height(); y < h; ++y) { + memcpy(dst, src.constScanLine(y), bytesPerLine); + dst += bytesPerLine; + } + } else { + result->data.fill(0, int(byteSize)); + } if (result->completed) result->completed(); + } else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::GenMips) { + if (u.dst->format() == QRhiTexture::RGBA8) + simulateTextureGenMips(u); } } ud->free(); @@ -454,14 +553,18 @@ QNullBuffer::~QNullBuffer() void QNullBuffer::release() { + data.clear(); + QRHI_PROF; QRHI_PROF_F(releaseBuffer(this)); } bool QNullBuffer::build() { + data.fill('\0', m_size); + QRHI_PROF; - QRHI_PROF_F(newBuffer(this, m_size, 1, 0)); + QRHI_PROF_F(newBuffer(this, uint(m_size), 1, 0)); return true; } @@ -513,22 +616,36 @@ void QNullTexture::release() bool QNullTexture::build() { + QRHI_RES_RHI(QRhiNull); const bool isCube = m_flags.testFlag(CubeMap); const bool hasMipMaps = m_flags.testFlag(MipMapped); QSize size = m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize; - const int mipLevelCount = hasMipMaps ? qCeil(log2(qMax(size.width(), size.height()))) + 1 : 1; + const int mipLevelCount = hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1; + const int layerCount = isCube ? 6 : 1; + + if (m_format == RGBA8) { + for (int layer = 0; layer < layerCount; ++layer) { + for (int level = 0; level < mipLevelCount; ++level) { + image[layer][level] = QImage(rhiD->q->sizeForMipLevel(level, size), + QImage::Format_RGBA8888_Premultiplied); + image[layer][level].fill(Qt::yellow); + } + } + } + QRHI_PROF; - QRHI_PROF_F(newTexture(this, true, mipLevelCount, isCube ? 6 : 1, 1)); + QRHI_PROF_F(newTexture(this, true, mipLevelCount, layerCount, 1)); return true; } bool QNullTexture::buildFrom(const QRhiNativeHandles *src) { Q_UNUSED(src); + QRHI_RES_RHI(QRhiNull); const bool isCube = m_flags.testFlag(CubeMap); const bool hasMipMaps = m_flags.testFlag(MipMapped); QSize size = m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize; - const int mipLevelCount = hasMipMaps ? qCeil(log2(qMax(size.width(), size.height()))) + 1 : 1; + const int mipLevelCount = hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1; QRHI_PROF; QRHI_PROF_F(newTexture(this, false, mipLevelCount, isCube ? 6 : 1, 1)); return true; @@ -690,6 +807,10 @@ void QNullGraphicsPipeline::release() bool QNullGraphicsPipeline::build() { + QRHI_RES_RHI(QRhiNull); + if (!rhiD->sanityCheckGraphicsPipeline(this)) + return false; + return true; } |