rhi: Reuse buffer/texture op entries in res.update batches

More of an enabler for reusing the data in the individual entries since
not clearing the QVLA does not give us much on its own.

Change-Id: Ief9761f75382c3373cc2bc7b866eb59fdd8b3277
Reviewed-by: Andy Nichols <andy.nichols@qt.io>
This commit is contained in:
Laszlo Agocs 2020-09-22 19:21:19 +02:00
parent 230be3c4d1
commit 6b52ba4286
7 changed files with 125 additions and 36 deletions

View File

@ -4694,8 +4694,9 @@ void QRhiResourceUpdateBatch::release()
/*!
Copies all queued operations from the \a other batch into this one.
\note \a other is not changed in any way, typically it will still need a
destroy()
\note \a other may no longer contain valid data after the merge operation,
and must not be submitted, but it will still need to be released by calling
release().
This allows for a convenient pattern where resource updates that are
already known during the initialization step are collected into a batch
@ -4718,7 +4719,7 @@ void QRhiResourceUpdateBatch::release()
QRhiResourceUpdateBatch *resUpdates = rhi->nextResourceUpdateBatch();
if (initialUpdates) {
resUpdates->merge(initialUpdates);
initialUpdates->destroy();
initialUpdates->release();
initialUpdates = nullptr;
}
resUpdates->updateDynamicBuffer(...);
@ -4771,8 +4772,14 @@ bool QRhiResourceUpdateBatch::hasOptimalCapacity() const
*/
void QRhiResourceUpdateBatch::updateDynamicBuffer(QRhiBuffer *buf, int offset, int size, const void *data)
{
if (size > 0)
d->bufferOps.append(QRhiResourceUpdateBatchPrivate::BufferOp::dynamicUpdate(buf, offset, size, data));
if (size > 0) {
const int idx = d->activeBufferOpCount++;
const int opListSize = d->bufferOps.size();
if (idx < opListSize)
QRhiResourceUpdateBatchPrivate::BufferOp::changeToDynamicUpdate(&d->bufferOps[idx], buf, offset, size, data);
else
d->bufferOps.append(QRhiResourceUpdateBatchPrivate::BufferOp::dynamicUpdate(buf, offset, size, data));
}
}
/*!
@ -4785,8 +4792,13 @@ void QRhiResourceUpdateBatch::updateDynamicBuffer(QRhiBuffer *buf, int offset, i
*/
void QRhiResourceUpdateBatch::uploadStaticBuffer(QRhiBuffer *buf, int offset, int size, const void *data)
{
if (size > 0)
d->bufferOps.append(QRhiResourceUpdateBatchPrivate::BufferOp::staticUpload(buf, offset, size, data));
if (size > 0) {
const int idx = d->activeBufferOpCount++;
if (idx < d->bufferOps.size())
QRhiResourceUpdateBatchPrivate::BufferOp::changeToStaticUpload(&d->bufferOps[idx], buf, offset, size, data);
else
d->bufferOps.append(QRhiResourceUpdateBatchPrivate::BufferOp::staticUpload(buf, offset, size, data));
}
}
/*!
@ -4795,8 +4807,13 @@ void QRhiResourceUpdateBatch::uploadStaticBuffer(QRhiBuffer *buf, int offset, in
*/
void QRhiResourceUpdateBatch::uploadStaticBuffer(QRhiBuffer *buf, const void *data)
{
if (buf->size() > 0)
d->bufferOps.append(QRhiResourceUpdateBatchPrivate::BufferOp::staticUpload(buf, 0, 0, data));
if (buf->size() > 0) {
const int idx = d->activeBufferOpCount++;
if (idx < d->bufferOps.size())
QRhiResourceUpdateBatchPrivate::BufferOp::changeToStaticUpload(&d->bufferOps[idx], buf, 0, 0, data);
else
d->bufferOps.append(QRhiResourceUpdateBatchPrivate::BufferOp::staticUpload(buf, 0, 0, data));
}
}
/*!
@ -4825,7 +4842,11 @@ void QRhiResourceUpdateBatch::uploadStaticBuffer(QRhiBuffer *buf, const void *da
*/
void QRhiResourceUpdateBatch::readBackBuffer(QRhiBuffer *buf, int offset, int size, QRhiBufferReadbackResult *result)
{
d->bufferOps.append(QRhiResourceUpdateBatchPrivate::BufferOp::read(buf, offset, size, result));
const int idx = d->activeBufferOpCount++;
if (idx < d->bufferOps.size())
d->bufferOps[idx] = QRhiResourceUpdateBatchPrivate::BufferOp::read(buf, offset, size, result);
else
d->bufferOps.append(QRhiResourceUpdateBatchPrivate::BufferOp::read(buf, offset, size, result));
}
/*!
@ -4837,8 +4858,13 @@ void QRhiResourceUpdateBatch::readBackBuffer(QRhiBuffer *buf, int offset, int si
*/
void QRhiResourceUpdateBatch::uploadTexture(QRhiTexture *tex, const QRhiTextureUploadDescription &desc)
{
if (desc.cbeginEntries() != desc.cendEntries())
d->textureOps.append(QRhiResourceUpdateBatchPrivate::TextureOp::upload(tex, desc));
if (desc.cbeginEntries() != desc.cendEntries()) {
const int idx = d->activeTextureOpCount++;
if (idx < d->textureOps.size())
d->textureOps[idx] = QRhiResourceUpdateBatchPrivate::TextureOp::upload(tex, desc);
else
d->textureOps.append(QRhiResourceUpdateBatchPrivate::TextureOp::upload(tex, desc));
}
}
/*!
@ -4863,7 +4889,11 @@ void QRhiResourceUpdateBatch::uploadTexture(QRhiTexture *tex, const QImage &imag
*/
void QRhiResourceUpdateBatch::copyTexture(QRhiTexture *dst, QRhiTexture *src, const QRhiTextureCopyDescription &desc)
{
d->textureOps.append(QRhiResourceUpdateBatchPrivate::TextureOp::copy(dst, src, desc));
const int idx = d->activeTextureOpCount++;
if (idx < d->textureOps.size())
d->textureOps[idx] = QRhiResourceUpdateBatchPrivate::TextureOp::copy(dst, src, desc);
else
d->textureOps.append(QRhiResourceUpdateBatchPrivate::TextureOp::copy(dst, src, desc));
}
/*!
@ -4925,7 +4955,11 @@ void QRhiResourceUpdateBatch::copyTexture(QRhiTexture *dst, QRhiTexture *src, co
*/
void QRhiResourceUpdateBatch::readBackTexture(const QRhiReadbackDescription &rb, QRhiReadbackResult *result)
{
d->textureOps.append(QRhiResourceUpdateBatchPrivate::TextureOp::read(rb, result));
const int idx = d->activeTextureOpCount++;
if (idx < d->textureOps.size())
d->textureOps[idx] = QRhiResourceUpdateBatchPrivate::TextureOp::read(rb, result);
else
d->textureOps.append(QRhiResourceUpdateBatchPrivate::TextureOp::read(rb, result));
}
/*!
@ -4937,7 +4971,11 @@ void QRhiResourceUpdateBatch::readBackTexture(const QRhiReadbackDescription &rb,
*/
void QRhiResourceUpdateBatch::generateMips(QRhiTexture *tex, int layer)
{
d->textureOps.append(QRhiResourceUpdateBatchPrivate::TextureOp::genMips(tex, layer));
const int idx = d->activeTextureOpCount++;
if (idx < d->textureOps.size())
d->textureOps[idx] = QRhiResourceUpdateBatchPrivate::TextureOp::genMips(tex, layer);
else
d->textureOps.append(QRhiResourceUpdateBatchPrivate::TextureOp::genMips(tex, layer));
}
/*!
@ -4997,8 +5035,8 @@ void QRhiResourceUpdateBatchPrivate::free()
{
Q_ASSERT(poolIndex >= 0 && rhi->resUpdPool[poolIndex] == q);
bufferOps.clear();
textureOps.clear();
activeBufferOpCount = 0;
activeTextureOpCount = 0;
rhi->resUpdPoolMap.clearBit(poolIndex);
poolIndex = -1;
@ -5006,19 +5044,36 @@ void QRhiResourceUpdateBatchPrivate::free()
void QRhiResourceUpdateBatchPrivate::merge(QRhiResourceUpdateBatchPrivate *other)
{
bufferOps.reserve(bufferOps.size() + other->bufferOps.size());
for (const BufferOp &op : qAsConst(other->bufferOps))
bufferOps.append(op);
int combinedSize = activeBufferOpCount + other->activeBufferOpCount;
if (bufferOps.size() < combinedSize)
bufferOps.resize(combinedSize);
for (int i = activeBufferOpCount; i < combinedSize; ++i)
bufferOps[i] = std::move(other->bufferOps[i - activeBufferOpCount]);
activeBufferOpCount += other->activeBufferOpCount;
textureOps.reserve(textureOps.size() + other->textureOps.size());
for (const TextureOp &op : qAsConst(other->textureOps))
textureOps.append(op);
combinedSize = activeTextureOpCount + other->activeTextureOpCount;
if (textureOps.size() < combinedSize)
textureOps.resize(combinedSize);
for (int i = activeTextureOpCount; i < combinedSize; ++i)
textureOps[i] = std::move(other->textureOps[i - activeTextureOpCount]);
activeTextureOpCount += other->activeTextureOpCount;
}
bool QRhiResourceUpdateBatchPrivate::hasOptimalCapacity() const
{
return bufferOps.count() < BUFFER_OPS_STATIC_ALLOC - 16
&& textureOps.count() < TEXTURE_OPS_STATIC_ALLOC - 16;
return activeBufferOpCount < BUFFER_OPS_STATIC_ALLOC - 16
&& activeTextureOpCount < TEXTURE_OPS_STATIC_ALLOC - 16;
}
void QRhiResourceUpdateBatchPrivate::trimOpLists()
{
Q_ASSERT(poolIndex == -1); // must not be in use
activeBufferOpCount = 0;
bufferOps.clear();
activeTextureOpCount = 0;
textureOps.clear();
}
/*!
@ -5723,6 +5778,11 @@ QRhiProfiler *QRhi::profiler()
void QRhi::releaseCachedResources()
{
d->releaseCachedResources();
for (QRhiResourceUpdateBatch *u : d->resUpdPool) {
if (u->d->poolIndex < 0)
u->d->trimOpLists();
}
}
/*!

View File

@ -302,6 +302,14 @@ public:
return op;
}
static void changeToDynamicUpdate(BufferOp *op, QRhiBuffer *buf, int offset, int size, const void *data)
{
op->type = DynamicUpdate;
op->buf = buf;
op->offset = offset;
op->data = QByteArray(reinterpret_cast<const char *>(data), size ? size : buf->size());
}
static BufferOp staticUpload(QRhiBuffer *buf, int offset, int size, const void *data)
{
BufferOp op = {};
@ -312,6 +320,14 @@ public:
return op;
}
static void changeToStaticUpload(BufferOp *op, QRhiBuffer *buf, int offset, int size, const void *data)
{
op->type = StaticUpload;
op->buf = buf;
op->offset = offset;
op->data = QByteArray(reinterpret_cast<const char *>(data), size ? size : buf->size());
}
static BufferOp read(QRhiBuffer *buf, int offset, int size, QRhiBufferReadbackResult *result)
{
BufferOp op = {};
@ -383,8 +399,11 @@ public:
}
};
int activeBufferOpCount = 0; // this is the real number of used elements in bufferOps, not bufferOps.count()
static const int BUFFER_OPS_STATIC_ALLOC = 1024;
QVarLengthArray<BufferOp, BUFFER_OPS_STATIC_ALLOC> bufferOps;
int activeTextureOpCount = 0; // this is the real number of used elements in textureOps, not textureOps.count()
static const int TEXTURE_OPS_STATIC_ALLOC = 256;
QVarLengthArray<TextureOp, TEXTURE_OPS_STATIC_ALLOC> textureOps;
@ -395,6 +414,7 @@ public:
void free();
void merge(QRhiResourceUpdateBatchPrivate *other);
bool hasOptimalCapacity() const;
void trimOpLists();
static QRhiResourceUpdateBatchPrivate *get(QRhiResourceUpdateBatch *b) { return b->d; }
};

View File

@ -1413,7 +1413,8 @@ void QRhiD3D11::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
QRhiResourceUpdateBatchPrivate *ud = QRhiResourceUpdateBatchPrivate::get(resourceUpdates);
QRhiProfilerPrivate *rhiP = profilerPrivateOrNull();
for (const QRhiResourceUpdateBatchPrivate::BufferOp &u : ud->bufferOps) {
for (int opIdx = 0; opIdx < ud->activeBufferOpCount; ++opIdx) {
const QRhiResourceUpdateBatchPrivate::BufferOp &u(ud->bufferOps[opIdx]);
if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::DynamicUpdate) {
QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, u.buf);
Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
@ -1485,8 +1486,8 @@ void QRhiD3D11::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
u.result->completed();
}
}
for (const QRhiResourceUpdateBatchPrivate::TextureOp &u : ud->textureOps) {
for (int opIdx = 0; opIdx < ud->activeTextureOpCount; ++opIdx) {
const QRhiResourceUpdateBatchPrivate::TextureOp &u(ud->textureOps[opIdx]);
if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Upload) {
QD3D11Texture *texD = QRHI_RES(QD3D11Texture, u.dst);
for (int layer = 0; layer < QRhi::MAX_LAYERS; ++layer) {

View File

@ -1681,7 +1681,8 @@ void QRhiGles2::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
QGles2CommandBuffer *cbD = QRHI_RES(QGles2CommandBuffer, cb);
QRhiResourceUpdateBatchPrivate *ud = QRhiResourceUpdateBatchPrivate::get(resourceUpdates);
for (const QRhiResourceUpdateBatchPrivate::BufferOp &u : ud->bufferOps) {
for (int opIdx = 0; opIdx < ud->activeBufferOpCount; ++opIdx) {
const QRhiResourceUpdateBatchPrivate::BufferOp &u(ud->bufferOps[opIdx]);
if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::DynamicUpdate) {
QGles2Buffer *bufD = QRHI_RES(QGles2Buffer, u.buf);
Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
@ -1735,7 +1736,8 @@ void QRhiGles2::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
}
}
for (const QRhiResourceUpdateBatchPrivate::TextureOp &u : ud->textureOps) {
for (int opIdx = 0; opIdx < ud->activeTextureOpCount; ++opIdx) {
const QRhiResourceUpdateBatchPrivate::TextureOp &u(ud->textureOps[opIdx]);
if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Upload) {
QGles2Texture *texD = QRHI_RES(QGles2Texture, u.dst);
for (int layer = 0; layer < QRhi::MAX_LAYERS; ++layer) {

View File

@ -1691,7 +1691,8 @@ void QRhiMetal::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
QRhiResourceUpdateBatchPrivate *ud = QRhiResourceUpdateBatchPrivate::get(resourceUpdates);
QRhiProfilerPrivate *rhiP = profilerPrivateOrNull();
for (const QRhiResourceUpdateBatchPrivate::BufferOp &u : ud->bufferOps) {
for (int opIdx = 0; opIdx < ud->activeBufferOpCount; ++opIdx) {
const QRhiResourceUpdateBatchPrivate::BufferOp &u(ud->bufferOps[opIdx]);
if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::DynamicUpdate) {
QMetalBuffer *bufD = QRHI_RES(QMetalBuffer, u.buf);
Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
@ -1729,7 +1730,8 @@ void QRhiMetal::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
}
};
for (const QRhiResourceUpdateBatchPrivate::TextureOp &u : ud->textureOps) {
for (int opIdx = 0; opIdx < ud->activeTextureOpCount; ++opIdx) {
const QRhiResourceUpdateBatchPrivate::TextureOp &u(ud->textureOps[opIdx]);
if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Upload) {
QMetalTexture *utexD = QRHI_RES(QMetalTexture, u.dst);
qsizetype stagingSize = 0;

View File

@ -459,7 +459,8 @@ void QRhiNull::resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *re
{
Q_UNUSED(cb);
QRhiResourceUpdateBatchPrivate *ud = QRhiResourceUpdateBatchPrivate::get(resourceUpdates);
for (const QRhiResourceUpdateBatchPrivate::BufferOp &u : ud->bufferOps) {
for (int opIdx = 0; opIdx < ud->activeBufferOpCount; ++opIdx) {
const QRhiResourceUpdateBatchPrivate::BufferOp &u(ud->bufferOps[opIdx]);
if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::DynamicUpdate
|| u.type == QRhiResourceUpdateBatchPrivate::BufferOp::StaticUpload)
{
@ -474,7 +475,8 @@ void QRhiNull::resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *re
result->completed();
}
}
for (const QRhiResourceUpdateBatchPrivate::TextureOp &u : ud->textureOps) {
for (int opIdx = 0; opIdx < ud->activeTextureOpCount; ++opIdx) {
const QRhiResourceUpdateBatchPrivate::TextureOp &u(ud->textureOps[opIdx]);
if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Upload) {
if (u.dst->format() == QRhiTexture::RGBA8)
simulateTextureUpload(u);

View File

@ -2923,7 +2923,8 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat
QRhiResourceUpdateBatchPrivate *ud = QRhiResourceUpdateBatchPrivate::get(resourceUpdates);
QRhiProfilerPrivate *rhiP = profilerPrivateOrNull();
for (const QRhiResourceUpdateBatchPrivate::BufferOp &u : ud->bufferOps) {
for (int opIdx = 0; opIdx < ud->activeBufferOpCount; ++opIdx) {
const QRhiResourceUpdateBatchPrivate::BufferOp &u(ud->bufferOps[opIdx]);
if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::DynamicUpdate) {
QVkBuffer *bufD = QRHI_RES(QVkBuffer, u.buf);
Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
@ -3073,7 +3074,8 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat
}
}
for (const QRhiResourceUpdateBatchPrivate::TextureOp &u : ud->textureOps) {
for (int opIdx = 0; opIdx < ud->activeTextureOpCount; ++opIdx) {
const QRhiResourceUpdateBatchPrivate::TextureOp &u(ud->textureOps[opIdx]);
if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Upload) {
QVkTexture *utexD = QRHI_RES(QVkTexture, u.dst);
// batch into a single staging buffer and a single CopyBufferToImage with multiple copyInfos