Commit 969214c6 authored by Laszlo Agocs's avatar Laszlo Agocs

Start getting the readback api into shape

parent 75bda640
......@@ -103,8 +103,15 @@ int main(int argc, char **argv)
r->beginPass(rt, cb, { 0, 1, 0, 1 }, { 1, 0 }, nullptr);
r->endPass(cb);
QRhiReadbackDescription rb(tex);
QRhiReadbackResult rbResult;
r->readback(cb, rb, &rbResult);
qDebug("Submit and wait");
r->endAndWaitOffscreenFrame();
// here it's simple, no need to bother with the completed callback of rbResult
qDebug() << rbResult.data.size();
}
rt->releaseAndDestroy();
......
......@@ -487,9 +487,9 @@ void QRhi::drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
d->drawIndexed(cb, indexCount, instanceCount, firstIndex, vertexOffset, firstInstance);
}
void QRhi::readback(QRhiCommandBuffer *cb, QRhiReadback *rb)
void QRhi::readback(QRhiCommandBuffer *cb, const QRhiReadbackDescription &rb, QRhiReadbackResult *result)
{
d->readback(cb, rb);
d->readback(cb, rb, result);
}
QVector<int> QRhi::supportedSampleCounts() const
......
......@@ -45,6 +45,7 @@
#include <QVector>
#include <QImage>
#include <QtShaderTools/QBakedShader>
#include <functional>
QT_BEGIN_NAMESPACE
......@@ -280,12 +281,22 @@ Q_DECLARE_TYPEINFO(QRhiTextureUploadDescription::Layer::MipLevel, Q_MOVABLE_TYPE
Q_DECLARE_TYPEINFO(QRhiTextureUploadDescription::Layer, Q_MOVABLE_TYPE);
Q_DECLARE_TYPEINFO(QRhiTextureUploadDescription, Q_MOVABLE_TYPE);
struct Q_RHI_EXPORT QRhiReadback
struct Q_RHI_EXPORT QRhiReadbackDescription
{
// ###
QRhiReadbackDescription() { }
QRhiReadbackDescription(QRhiTexture *texture_) : texture(texture_) { }
QRhiTexture *texture = nullptr;
int layer = 0;
int level = 0;
};
Q_DECLARE_TYPEINFO(QRhiReadback, Q_MOVABLE_TYPE);
Q_DECLARE_TYPEINFO(QRhiReadbackDescription, Q_MOVABLE_TYPE);
struct Q_RHI_EXPORT QRhiReadbackResult
{
std::function<void()> completed = nullptr;
QByteArray data;
}; // non-movable due to the std::function
class Q_RHI_EXPORT QRhiResource
{
......@@ -980,12 +991,13 @@ public:
The typical use case is to use it in completely offscreen applications,
e.g. to generate image sequences by rendering and reading back without
ever showing a window.
QRhiReadbackResult rbResult;
QRhiCommandBuffer *cb; // not owned
beginOffscreenFrame(&cb);
// ... the usual, set up a QRhiTextureRenderTarget, beginPass-endPass, etc.
readback(cb, someTexture, rb);
readback(cb, rb, &rbResult);
endAndWaitOffscreenFrame();
// the results are available in rb
// image data available in rbResult
*/
FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb);
FrameOpResult endAndWaitOffscreenFrame();
......@@ -1037,8 +1049,8 @@ public:
quint32 instanceCount = 1, quint32 firstIndex = 0,
qint32 vertexOffset = 0, quint32 firstInstance = 0);
// Must only be called outside a begin-endPass section.
void readback(QRhiCommandBuffer *cb, QRhiReadback *rb);
// Cannot be mixed with beginPass-endPass.
void readback(QRhiCommandBuffer *cb, const QRhiReadbackDescription &rb, QRhiReadbackResult *result);
QVector<int> supportedSampleCounts() const;
......
......@@ -113,7 +113,7 @@ public:
quint32 instanceCount, quint32 firstIndex,
qint32 vertexOffset, quint32 firstInstance) = 0;
virtual void readback(QRhiCommandBuffer *cb, QRhiReadback *rb) = 0;
virtual void readback(QRhiCommandBuffer *cb, const QRhiReadbackDescription &rb, QRhiReadbackResult *result) = 0;
virtual QVector<int> supportedSampleCounts() const = 0;
virtual int ubufAlignment() const = 0;
......
......@@ -453,10 +453,11 @@ void QRhiD3D11::drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
cbD->commands.append(cmd);
}
void QRhiD3D11::readback(QRhiCommandBuffer *cb, QRhiReadback *rb)
void QRhiD3D11::readback(QRhiCommandBuffer *cb, const QRhiReadbackDescription &rb, QRhiReadbackResult *result)
{
Q_UNUSED(cb);
Q_UNUSED(rb);
Q_UNUSED(result);
}
QRhi::FrameOpResult QRhiD3D11::beginFrame(QRhiSwapChain *swapChain)
......
......@@ -405,7 +405,7 @@ public:
quint32 instanceCount, quint32 firstIndex,
qint32 vertexOffset, quint32 firstInstance) override;
void readback(QRhiCommandBuffer *cb, QRhiReadback *rb) override;
void readback(QRhiCommandBuffer *cb, const QRhiReadbackDescription &rb, QRhiReadbackResult *result) override;
QVector<int> supportedSampleCounts() const override;
int ubufAlignment() const override;
......
......@@ -366,10 +366,11 @@ void QRhiGles2::drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
cbD->commands.append(cmd);
}
void QRhiGles2::readback(QRhiCommandBuffer *cb, QRhiReadback *rb)
void QRhiGles2::readback(QRhiCommandBuffer *cb, const QRhiReadbackDescription &rb, QRhiReadbackResult *result)
{
Q_UNUSED(cb);
Q_UNUSED(rb);
Q_UNUSED(result);
}
QRhi::FrameOpResult QRhiGles2::beginFrame(QRhiSwapChain *swapChain)
......
......@@ -363,7 +363,7 @@ public:
quint32 instanceCount, quint32 firstIndex,
qint32 vertexOffset, quint32 firstInstance) override;
void readback(QRhiCommandBuffer *cb, QRhiReadback *rb) override;
void readback(QRhiCommandBuffer *cb, const QRhiReadbackDescription &rb, QRhiReadbackResult *result) override;
QVector<int> supportedSampleCounts() const override;
int ubufAlignment() const override;
......
......@@ -496,10 +496,11 @@ void QRhiMetal::drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
baseInstance: firstInstance];
}
void QRhiMetal::readback(QRhiCommandBuffer *cb, QRhiReadback *rb)
void QRhiMetal::readback(QRhiCommandBuffer *cb, const QRhiReadbackDescription &rb, QRhiReadbackResult *result)
{
Q_UNUSED(cb);
Q_UNUSED(rb);
Q_UNUSED(result);
}
QRhi::FrameOpResult QRhiMetal::beginFrame(QRhiSwapChain *swapChain)
......
......@@ -294,7 +294,7 @@ public:
quint32 instanceCount, quint32 firstIndex,
qint32 vertexOffset, quint32 firstInstance) override;
void readback(QRhiCommandBuffer *cb, QRhiReadback *rb) override;
void readback(QRhiCommandBuffer *cb, const QRhiReadbackDescription &rb, QRhiReadbackResult *result) override;
QVector<int> supportedSampleCounts() const override;
int ubufAlignment() const override;
......
......@@ -1384,11 +1384,7 @@ QRhi::FrameOpResult QRhiVulkan::endAndWaitOffscreenFrame()
submitInfo.pWaitDstStageMask = &psf;
err = df->vkQueueSubmit(gfxQueue, 1, &submitInfo, ofr.cmdFence);
if (err == VK_SUCCESS) {
// wait for completion
df->vkWaitForFences(dev, 1, &ofr.cmdFence, VK_TRUE, UINT64_MAX);
df->vkResetFences(dev, 1, &ofr.cmdFence);
} else {
if (err != VK_SUCCESS) {
if (checkDeviceLost(err))
return QRhi::FrameOpDeviceLost;
else
......@@ -1396,6 +1392,14 @@ QRhi::FrameOpResult QRhiVulkan::endAndWaitOffscreenFrame()
return QRhi::FrameOpError;
}
// wait for completion
df->vkWaitForFences(dev, 1, &ofr.cmdFence, VK_TRUE, UINT64_MAX);
df->vkResetFences(dev, 1, &ofr.cmdFence);
// Here we know that executing the host-side reads for this (or any
// previous) frame is safe since we waited for completion above.
finishActiveReadbacks(true);
return QRhi::FrameOpSuccess;
}
......@@ -1426,6 +1430,15 @@ void QRhiVulkan::prepareNewFrame(QRhiCommandBuffer *cb)
Q_ASSERT(!inFrame);
inFrame = true;
// Now is the time to do things for frame N-F, where N is the current one,
// F is QVK_FRAMES_IN_FLIGHT, because only here it is guaranteed that that
// frame has completed on the GPU (due to the fence wait in beginFrame). To
// decide if something is safe to handle now a simple "lastActiveFrameSlot
// == currentFrameSlot" is sufficient (remember that e.g. with F==2
// currentFrameSlot goes 0, 1, 0, 1, 0, ...)
finishActiveReadbacks();
executeDeferredReleases();
QRHI_RES(QVkCommandBuffer, cb)->resetState();
......@@ -1972,6 +1985,27 @@ void QRhiVulkan::executeDeferredReleases(bool forced)
}
}
void QRhiVulkan::finishActiveReadbacks(bool forced)
{
QVarLengthArray<std::function<void()>, 4> completedCallbacks;
for (int i = activeReadbacks.count() - 1; i >= 0; --i) {
const QRhiVulkan::ActiveReadback &aRb(activeReadbacks[i]);
if (forced || currentFrameSlot == aRb.activeFrameSlot || aRb.activeFrameSlot < 0) {
// map and memcpy
// destroy temp buffer
if (aRb.result->completed)
completedCallbacks.append(aRb.result->completed);
activeReadbacks.removeAt(i);
}
}
for (auto f : completedCallbacks)
f();
}
static struct {
VkSampleCountFlagBits mask;
int count;
......@@ -2315,10 +2349,20 @@ void QRhiVulkan::drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
df->vkCmdDrawIndexed(QRHI_RES(QVkCommandBuffer, cb)->cb, indexCount, instanceCount, firstIndex, vertexOffset, firstInstance);
}
void QRhiVulkan::readback(QRhiCommandBuffer *cb, QRhiReadback *rb)
void QRhiVulkan::readback(QRhiCommandBuffer *cb, const QRhiReadbackDescription &rb, QRhiReadbackResult *result)
{
Q_UNUSED(cb);
Q_UNUSED(rb);
Q_ASSERT(inFrame && !inPass);
// create a host visible buffer
// add a vkCmdCopyImageToBuffer
ActiveReadback aRb;
aRb.activeFrameSlot = currentFrameSlot;
aRb.desc = rb;
aRb.result = result;
activeReadbacks.append(aRb);
}
static inline VkBufferUsageFlagBits toVkBufferUsage(QRhiBuffer::UsageFlags usage)
......
......@@ -356,7 +356,7 @@ public:
quint32 instanceCount, quint32 firstIndex,
qint32 vertexOffset, quint32 firstInstance) override;
void readback(QRhiCommandBuffer *cb, QRhiReadback *rb) override;
void readback(QRhiCommandBuffer *cb, const QRhiReadbackDescription &rb, QRhiReadbackResult *result) override;
QVector<int> supportedSampleCounts() const override;
int ubufAlignment() const override;
......@@ -403,6 +403,7 @@ public:
void activateTextureRenderTarget(QRhiCommandBuffer *cb, QRhiTextureRenderTarget *rt);
void deactivateTextureRenderTarget(QRhiCommandBuffer *cb, QRhiTextureRenderTarget *rt);
void executeDeferredReleases(bool forced = false);
void finishActiveReadbacks(bool forced = false);
void bufferBarrier(QRhiCommandBuffer *cb, QRhiBuffer *buf);
void imageBarrier(QRhiCommandBuffer *cb, QRhiTexture *tex,
......@@ -415,7 +416,6 @@ public:
// in case they changed in the meantime.
void updateShaderResourceBindings(QRhiShaderResourceBindings *srb, int descSetIdx = -1);
QRhi *q;
QVulkanInstance *inst = nullptr;
QWindow *maybeWindow = nullptr;
bool importedDevPoolQueue = false;
......@@ -464,6 +464,13 @@ public:
VkFence cmdFence = VK_NULL_HANDLE;
} ofr;
struct ActiveReadback {
int activeFrameSlot = -1;
QRhiReadbackDescription desc;
QRhiReadbackResult *result;
};
QVector<ActiveReadback> activeReadbacks;
struct DeferredReleaseEntry {
enum Type {
Pipeline,
......@@ -526,6 +533,7 @@ public:
Q_DECLARE_TYPEINFO(QRhiVulkan::DescriptorPoolData, Q_MOVABLE_TYPE);
Q_DECLARE_TYPEINFO(QRhiVulkan::DeferredReleaseEntry, Q_MOVABLE_TYPE);
Q_DECLARE_TYPEINFO(QRhiVulkan::ActiveReadback, Q_MOVABLE_TYPE);
QT_END_NAMESPACE
......
......@@ -2,6 +2,7 @@ gl, mtl: compressed textures
gl, mtl: srgb (tex, swapchain buf)
rhi without a window, fully offscreen
readbacks
some wait-gpu stuff for waiting for readback results inside a begin-endFrame f.ex.?
multi window? (multi swapchain) -> trouble
vk: rendering hangs sometimes when minimize and back on some systems?
mtl: cubemaps
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment