summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@qt.io>2020-09-29 17:38:26 +0200
committerLaszlo Agocs <laszlo.agocs@qt.io>2020-09-30 10:39:59 +0200
commit2f879062a5ce9e78c1e257924bcdc5ac95cba465 (patch)
tree34222dd886c8608d4ea7190763a67827f598e321 /src
parent0836db2330c0542d91fe61935e97d3369db93156 (diff)
rhi: Manage buffer data without QBA
Use a simple and straightforward container that only does what we need here. Change-Id: I1a81b53a58bc91d533e3d7df5471a1362046825d Reviewed-by: Andy Nichols <andy.nichols@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/gui/rhi/qrhi_p_p.h115
-rw-r--r--src/gui/rhi/qrhid3d11.cpp8
-rw-r--r--src/gui/rhi/qrhid3d11_p_p.h6
-rw-r--r--src/gui/rhi/qrhigles2.cpp14
-rw-r--r--src/gui/rhi/qrhigles2_p_p.h6
-rw-r--r--src/gui/rhi/qrhimetal.mm10
-rw-r--r--src/gui/rhi/qrhinull.cpp2
-rw-r--r--src/gui/rhi/qrhivulkan.cpp16
-rw-r--r--src/gui/rhi/qrhivulkan_p_p.h5
9 files changed, 119 insertions, 63 deletions
diff --git a/src/gui/rhi/qrhi_p_p.h b/src/gui/rhi/qrhi_p_p.h
index 3b68b5d078..1316321694 100644
--- a/src/gui/rhi/qrhi_p_p.h
+++ b/src/gui/rhi/qrhi_p_p.h
@@ -277,6 +277,80 @@ bool qrhi_toTopLeftRenderTargetRect(const QSize &outputSize, const std::array<T,
return true;
}
+struct QRhiBufferDataPrivate
+{
+ Q_DISABLE_COPY_MOVE(QRhiBufferDataPrivate)
+ QRhiBufferDataPrivate() { }
+ ~QRhiBufferDataPrivate() { delete[] largeData; }
+ int ref = 1;
+ int size = 0;
+ int largeAlloc = 0;
+ char *largeData = nullptr;
+ static constexpr int SMALL_DATA_SIZE = 1024;
+ char data[SMALL_DATA_SIZE];
+};
+
+// no detach-with-contents, no atomic refcount, no shrink
+class QRhiBufferData
+{
+public:
+ QRhiBufferData() = default;
+ ~QRhiBufferData()
+ {
+ if (d && !--d->ref)
+ delete d;
+ }
+ QRhiBufferData(const QRhiBufferData &other)
+ : d(other.d)
+ {
+ if (d)
+ d->ref += 1;
+ }
+ QRhiBufferData &operator=(const QRhiBufferData &other)
+ {
+ if (d == other.d)
+ return *this;
+ if (other.d)
+ other.d->ref += 1;
+ if (d && !--d->ref)
+ delete d;
+ d = other.d;
+ return *this;
+ }
+ const char *constData() const
+ {
+ return d->size <= QRhiBufferDataPrivate::SMALL_DATA_SIZE ? d->data : d->largeData;
+ }
+ int size() const
+ {
+ return d->size;
+ }
+ void assign(const char *s, int size)
+ {
+ if (!d) {
+ d = new QRhiBufferDataPrivate;
+ } else if (d->ref != 1) {
+ d->ref -= 1;
+ d = new QRhiBufferDataPrivate;
+ }
+ d->size = size;
+ if (size <= QRhiBufferDataPrivate::SMALL_DATA_SIZE) {
+ memcpy(d->data, s, size);
+ } else {
+ if (d->largeAlloc < size) {
+ delete[] d->largeData;
+ d->largeAlloc = size;
+ d->largeData = new char[size];
+ }
+ memcpy(d->largeData, s, size);
+ }
+ }
+private:
+ QRhiBufferDataPrivate *d = nullptr;
+};
+
+Q_DECLARE_TYPEINFO(QRhiBufferData, Q_MOVABLE_TYPE);
+
class QRhiResourceUpdateBatchPrivate
{
public:
@@ -289,8 +363,7 @@ public:
Type type;
QRhiBuffer *buf;
int offset;
- QByteArray data;
- int dataSize; // the real number of currently used bytes in data, not the same as data.size()
+ QRhiBufferData data;
int readSize;
QRhiBufferReadbackResult *result;
@@ -301,8 +374,7 @@ public:
op.buf = buf;
op.offset = offset;
const int effectiveSize = size ? size : buf->size();
- op.data = QByteArray(reinterpret_cast<const char *>(data), effectiveSize);
- op.dataSize = effectiveSize;
+ op.data.assign(reinterpret_cast<const char *>(data), effectiveSize);
return op;
}
@@ -312,28 +384,7 @@ public:
op->buf = buf;
op->offset = offset;
const int effectiveSize = size ? size : buf->size();
-
- // Why the isDetached check? Simply because the cost of detaching
- // with a larger allocation may be a lot higher than creating a new
- // deep copy bytearray with our (potentially lot smaller) data.
- // This reduces the benefits with certain backends (e.g. Vulkan)
- // that hold on to the data (implicit sharing!) of host visible
- // buffers for the current and next frame (assuming 2 frames in
- // flight), but it is still an improvement (enabled by
- // nextResourceUpdateBatch's shuffling when choosing a free batch
- // from the pool). For other backends (e.g. D3D11) this can reduce
- // mallocs (caused by creating new deep copy bytearrays) almost
- // completely after a few frames (assuming of course that no
- // dynamic elements with larger buffer data appear).
-
- if (op->data.isDetached()) {
- if (op->data.size() < effectiveSize)
- op->data.resize(effectiveSize);
- memcpy(op->data.data(), data, effectiveSize);
- } else {
- op->data = QByteArray(reinterpret_cast<const char *>(data), effectiveSize);
- }
- op->dataSize = effectiveSize;
+ op->data.assign(reinterpret_cast<const char *>(data), effectiveSize);
}
static BufferOp staticUpload(QRhiBuffer *buf, int offset, int size, const void *data)
@@ -343,8 +394,7 @@ public:
op.buf = buf;
op.offset = offset;
const int effectiveSize = size ? size : buf->size();
- op.data = QByteArray(reinterpret_cast<const char *>(data), effectiveSize);
- op.dataSize = effectiveSize;
+ op.data.assign(reinterpret_cast<const char *>(data), effectiveSize);
return op;
}
@@ -354,14 +404,7 @@ public:
op->buf = buf;
op->offset = offset;
const int effectiveSize = size ? size : buf->size();
- if (op->data.isDetached()) {
- if (op->data.size() < effectiveSize)
- op->data.resize(effectiveSize);
- memcpy(op->data.data(), data, effectiveSize);
- } else {
- op->data = QByteArray(reinterpret_cast<const char *>(data), effectiveSize);
- }
- op->dataSize = effectiveSize;
+ op->data.assign(reinterpret_cast<const char *>(data), effectiveSize);
}
static BufferOp read(QRhiBuffer *buf, int offset, int size, QRhiBufferReadbackResult *result)
diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp
index 1c7f3cd17a..2fe138dd55 100644
--- a/src/gui/rhi/qrhid3d11.cpp
+++ b/src/gui/rhi/qrhid3d11.cpp
@@ -1418,17 +1418,17 @@ void QRhiD3D11::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::DynamicUpdate) {
QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, u.buf);
Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
- memcpy(bufD->dynBuf + u.offset, u.data.constData(), size_t(u.dataSize));
+ memcpy(bufD->dynBuf + u.offset, u.data.constData(), size_t(u.data.size()));
bufD->hasPendingDynamicUpdates = true;
} else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::StaticUpload) {
QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, u.buf);
Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
- Q_ASSERT(u.offset + u.dataSize <= bufD->m_size);
+ Q_ASSERT(u.offset + u.data.size() <= bufD->m_size);
QD3D11CommandBuffer::Command cmd;
cmd.cmd = QD3D11CommandBuffer::Command::UpdateSubRes;
cmd.args.updateSubRes.dst = bufD->buffer;
cmd.args.updateSubRes.dstSubRes = 0;
- cmd.args.updateSubRes.src = cbD->retainData(u.data);
+ cmd.args.updateSubRes.src = cbD->retainBufferData(u.data);
cmd.args.updateSubRes.srcRowPitch = 0;
// Specify the region (even when offset is 0 and all data is provided)
// since the ID3D11Buffer's size is rounded up to be a multiple of 256
@@ -1437,7 +1437,7 @@ void QRhiD3D11::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
box.left = UINT(u.offset);
box.top = box.front = 0;
box.back = box.bottom = 1;
- box.right = UINT(u.offset + u.dataSize); // no -1: right, bottom, back are exclusive, see D3D11_BOX doc
+ box.right = UINT(u.offset + u.data.size()); // no -1: right, bottom, back are exclusive, see D3D11_BOX doc
cmd.args.updateSubRes.hasDstBox = true;
cmd.args.updateSubRes.dstBox = box;
cbD->commands.append(cmd);
diff --git a/src/gui/rhi/qrhid3d11_p_p.h b/src/gui/rhi/qrhid3d11_p_p.h
index 7c13544276..b89b6f5124 100644
--- a/src/gui/rhi/qrhid3d11_p_p.h
+++ b/src/gui/rhi/qrhid3d11_p_p.h
@@ -473,6 +473,7 @@ struct QD3D11CommandBuffer : public QRhiCommandBuffer
quint32 currentVertexOffsets[D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT];
QVarLengthArray<QByteArray, 4> dataRetainPool;
+ QVarLengthArray<QRhiBufferData, 4> bufferDataRetainPool;
QVarLengthArray<QImage, 4> imageRetainPool;
// relies heavily on implicit sharing (no copies of the actual data will be made)
@@ -480,6 +481,10 @@ struct QD3D11CommandBuffer : public QRhiCommandBuffer
dataRetainPool.append(data);
return reinterpret_cast<const uchar *>(dataRetainPool.last().constData());
}
+ const uchar *retainBufferData(const QRhiBufferData &data) {
+ bufferDataRetainPool.append(data);
+ return reinterpret_cast<const uchar *>(bufferDataRetainPool.last().constData());
+ }
const uchar *retainImage(const QImage &image) {
imageRetainPool.append(image);
return imageRetainPool.last().constBits();
@@ -487,6 +492,7 @@ struct QD3D11CommandBuffer : public QRhiCommandBuffer
void resetCommands() {
commands.clear();
dataRetainPool.clear();
+ bufferDataRetainPool.clear();
imageRetainPool.clear();
}
void resetState() {
diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp
index 372bf39c3e..c1ea444c50 100644
--- a/src/gui/rhi/qrhigles2.cpp
+++ b/src/gui/rhi/qrhigles2.cpp
@@ -1697,7 +1697,7 @@ void QRhiGles2::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
QGles2Buffer *bufD = QRHI_RES(QGles2Buffer, u.buf);
Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
if (bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer)) {
- memcpy(bufD->ubuf + u.offset, u.data.constData(), size_t(u.dataSize));
+ memcpy(bufD->ubuf + u.offset, u.data.constData(), size_t(u.data.size()));
} else {
trackedBufferBarrier(cbD, bufD, QGles2Buffer::AccessUpdate);
QGles2CommandBuffer::Command cmd;
@@ -1705,16 +1705,16 @@ void QRhiGles2::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
cmd.args.bufferSubData.target = bufD->targetForDataOps;
cmd.args.bufferSubData.buffer = bufD->buffer;
cmd.args.bufferSubData.offset = u.offset;
- cmd.args.bufferSubData.size = u.dataSize;
- cmd.args.bufferSubData.data = cbD->retainData(u.data);
+ cmd.args.bufferSubData.size = u.data.size();
+ cmd.args.bufferSubData.data = cbD->retainBufferData(u.data);
cbD->commands.append(cmd);
}
} else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::StaticUpload) {
QGles2Buffer *bufD = QRHI_RES(QGles2Buffer, u.buf);
Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
- Q_ASSERT(u.offset + u.dataSize <= bufD->m_size);
+ Q_ASSERT(u.offset + u.data.size() <= bufD->m_size);
if (bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer)) {
- memcpy(bufD->ubuf + u.offset, u.data.constData(), size_t(u.dataSize));
+ memcpy(bufD->ubuf + u.offset, u.data.constData(), size_t(u.data.size()));
} else {
trackedBufferBarrier(cbD, bufD, QGles2Buffer::AccessUpdate);
QGles2CommandBuffer::Command cmd;
@@ -1722,8 +1722,8 @@ void QRhiGles2::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
cmd.args.bufferSubData.target = bufD->targetForDataOps;
cmd.args.bufferSubData.buffer = bufD->buffer;
cmd.args.bufferSubData.offset = u.offset;
- cmd.args.bufferSubData.size = u.dataSize;
- cmd.args.bufferSubData.data = cbD->retainData(u.data);
+ cmd.args.bufferSubData.size = u.data.size();
+ cmd.args.bufferSubData.data = cbD->retainBufferData(u.data);
cbD->commands.append(cmd);
}
} else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::Read) {
diff --git a/src/gui/rhi/qrhigles2_p_p.h b/src/gui/rhi/qrhigles2_p_p.h
index 5940633151..65fb820a36 100644
--- a/src/gui/rhi/qrhigles2_p_p.h
+++ b/src/gui/rhi/qrhigles2_p_p.h
@@ -578,6 +578,7 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer
} computePassState;
QVarLengthArray<QByteArray, 4> dataRetainPool;
+ QVarLengthArray<QRhiBufferData, 4> bufferDataRetainPool;
QVarLengthArray<QImage, 4> imageRetainPool;
// relies heavily on implicit sharing (no copies of the actual data will be made)
@@ -585,6 +586,10 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer
dataRetainPool.append(data);
return dataRetainPool.last().constData();
}
+ const uchar *retainBufferData(const QRhiBufferData &data) {
+ bufferDataRetainPool.append(data);
+ return reinterpret_cast<const uchar *>(bufferDataRetainPool.last().constData());
+ }
const void *retainImage(const QImage &image) {
imageRetainPool.append(image);
return imageRetainPool.last().constBits();
@@ -592,6 +597,7 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer
void resetCommands() {
commands.clear();
dataRetainPool.clear();
+ bufferDataRetainPool.clear();
imageRetainPool.clear();
passResTrackers.clear();
diff --git a/src/gui/rhi/qrhimetal.mm b/src/gui/rhi/qrhimetal.mm
index 9058a7556a..a31d37c01a 100644
--- a/src/gui/rhi/qrhimetal.mm
+++ b/src/gui/rhi/qrhimetal.mm
@@ -1703,10 +1703,10 @@ void QRhiMetal::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
// basically the same. So go through the same pendingUpdates machinery.
QMetalBuffer *bufD = QRHI_RES(QMetalBuffer, u.buf);
Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
- Q_ASSERT(u.offset + u.dataSize <= bufD->m_size);
+ Q_ASSERT(u.offset + u.data.size() <= bufD->m_size);
for (int i = 0, ie = bufD->d->slotted ? QMTL_FRAMES_IN_FLIGHT : 1; i != ie; ++i)
bufD->d->pendingUpdates[i].append(
- QRhiResourceUpdateBatchPrivate::BufferOp::dynamicUpdate(u.buf, u.offset, u.dataSize, u.data.constData()));
+ QRhiResourceUpdateBatchPrivate::BufferOp::dynamicUpdate(u.buf, u.offset, u.data.size(), u.data.constData()));
} else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::Read) {
QMetalBuffer *bufD = QRHI_RES(QMetalBuffer, u.buf);
executeBufferHostWritesForCurrentFrame(bufD);
@@ -1868,11 +1868,11 @@ void QRhiMetal::executeBufferHostWritesForSlot(QMetalBuffer *bufD, int slot)
int changeEnd = -1;
for (const QRhiResourceUpdateBatchPrivate::BufferOp &u : qAsConst(bufD->d->pendingUpdates[slot])) {
Q_ASSERT(bufD == QRHI_RES(QMetalBuffer, u.buf));
- memcpy(static_cast<char *>(p) + u.offset, u.data.constData(), size_t(u.dataSize));
+ memcpy(static_cast<char *>(p) + u.offset, u.data.constData(), size_t(u.data.size()));
if (changeBegin == -1 || u.offset < changeBegin)
changeBegin = u.offset;
- if (changeEnd == -1 || u.offset + u.dataSize > changeEnd)
- changeEnd = u.offset + u.dataSize;
+ if (changeEnd == -1 || u.offset + u.data.size() > changeEnd)
+ changeEnd = u.offset + u.data.size();
}
#ifdef Q_OS_MACOS
if (changeBegin >= 0 && bufD->d->managed)
diff --git a/src/gui/rhi/qrhinull.cpp b/src/gui/rhi/qrhinull.cpp
index e0eb110c0d..4c650e68a0 100644
--- a/src/gui/rhi/qrhinull.cpp
+++ b/src/gui/rhi/qrhinull.cpp
@@ -465,7 +465,7 @@ void QRhiNull::resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *re
|| u.type == QRhiResourceUpdateBatchPrivate::BufferOp::StaticUpload)
{
QNullBuffer *bufD = QRHI_RES(QNullBuffer, u.buf);
- memcpy(bufD->data.data() + u.offset, u.data.constData(), size_t(u.dataSize));
+ 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);
diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp
index 5146a2ccc3..c0162820b6 100644
--- a/src/gui/rhi/qrhivulkan.cpp
+++ b/src/gui/rhi/qrhivulkan.cpp
@@ -2929,11 +2929,11 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat
QVkBuffer *bufD = QRHI_RES(QVkBuffer, u.buf);
Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
for (int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
- bufD->pendingDynamicUpdates[i].append({ u.offset, u.dataSize, u.data });
+ bufD->pendingDynamicUpdates[i].append({ u.offset, u.data });
} else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::StaticUpload) {
QVkBuffer *bufD = QRHI_RES(QVkBuffer, u.buf);
Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
- Q_ASSERT(u.offset + u.dataSize <= bufD->m_size);
+ Q_ASSERT(u.offset + u.data.size() <= bufD->m_size);
if (!bufD->stagingBuffers[currentFrameSlot]) {
VkBufferCreateInfo bufferInfo;
@@ -2967,9 +2967,9 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat
qWarning("Failed to map buffer: %d", err);
continue;
}
- memcpy(static_cast<uchar *>(p) + u.offset, u.data.constData(), size_t(u.dataSize));
+ memcpy(static_cast<uchar *>(p) + u.offset, u.data.constData(), size_t(u.data.size()));
vmaUnmapMemory(toVmaAllocator(allocator), a);
- vmaFlushAllocation(toVmaAllocator(allocator), a, VkDeviceSize(u.offset), VkDeviceSize(u.dataSize));
+ vmaFlushAllocation(toVmaAllocator(allocator), a, VkDeviceSize(u.offset), VkDeviceSize(u.data.size()));
trackedBufferBarrier(cbD, bufD, 0,
VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
@@ -2978,7 +2978,7 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat
memset(&copyInfo, 0, sizeof(copyInfo));
copyInfo.srcOffset = VkDeviceSize(u.offset);
copyInfo.dstOffset = VkDeviceSize(u.offset);
- copyInfo.size = VkDeviceSize(u.dataSize);
+ copyInfo.size = VkDeviceSize(u.data.size());
QVkCommandBuffer::Command cmd;
cmd.cmd = QVkCommandBuffer::Command::CopyBuffer;
@@ -3429,11 +3429,11 @@ void QRhiVulkan::executeBufferHostWritesForSlot(QVkBuffer *bufD, int slot)
int changeBegin = -1;
int changeEnd = -1;
for (const QVkBuffer::DynamicUpdate &u : qAsConst(bufD->pendingDynamicUpdates[slot])) {
- memcpy(static_cast<char *>(p) + u.offset, u.data.constData(), size_t(u.size));
+ memcpy(static_cast<char *>(p) + u.offset, u.data.constData(), size_t(u.data.size()));
if (changeBegin == -1 || u.offset < changeBegin)
changeBegin = u.offset;
- if (changeEnd == -1 || u.offset + u.size > changeEnd)
- changeEnd = u.offset + u.size;
+ if (changeEnd == -1 || u.offset + u.data.size() > changeEnd)
+ changeEnd = u.offset + u.data.size();
}
vmaUnmapMemory(toVmaAllocator(allocator), a);
if (changeBegin >= 0)
diff --git a/src/gui/rhi/qrhivulkan_p_p.h b/src/gui/rhi/qrhivulkan_p_p.h
index f3157c9112..c590039bc1 100644
--- a/src/gui/rhi/qrhivulkan_p_p.h
+++ b/src/gui/rhi/qrhivulkan_p_p.h
@@ -82,8 +82,7 @@ struct QVkBuffer : public QRhiBuffer
QVkAlloc allocations[QVK_FRAMES_IN_FLIGHT];
struct DynamicUpdate {
int offset;
- int size;
- QByteArray data;
+ QRhiBufferData data;
};
QVarLengthArray<DynamicUpdate, 16> pendingDynamicUpdates[QVK_FRAMES_IN_FLIGHT];
VkBuffer stagingBuffers[QVK_FRAMES_IN_FLIGHT];
@@ -98,6 +97,8 @@ struct QVkBuffer : public QRhiBuffer
friend class QRhiVulkan;
};
+Q_DECLARE_TYPEINFO(QVkBuffer::DynamicUpdate, Q_MOVABLE_TYPE);
+
struct QVkTexture;
struct QVkRenderBuffer : public QRhiRenderBuffer