Commit 36bce9c5 authored by Laszlo Agocs's avatar Laszlo Agocs

vk, gl, d3d: move readbacks to res.upd. batch

...and fix up the whole res update system for d3d and gl. (make it
go through the (fake) command buffer like everything else)
parent 5969d1b8
......@@ -167,12 +167,14 @@ int main(int argc, char **argv)
cb->setViewport({ 0, 0, 1280, 720 });
cb->setVertexInput(0, { { vbuf, 0 } });
cb->draw(3);
cb->endPass();
u = r->nextResourceUpdateBatch();
QRhiReadbackDescription rb(tex);
QRhiReadbackResult rbResult;
rbResult.completed = [frame] { qDebug(" - readback %d completed", frame); };
cb->readback(rb, &rbResult);
u->readBackTexture(rb, &rbResult);
cb->endPass(u);
qDebug("Submit and wait");
r->endOffscreenFrame();
......
......@@ -180,12 +180,14 @@ int main(int argc, char **argv)
cb->setViewport({ 0, 0, 1280, 720 });
cb->setVertexInput(0, { { vbuf, 0 } });
cb->draw(3);
cb->endPass();
u = r->nextResourceUpdateBatch();
QRhiReadbackDescription rb(tex);
QRhiReadbackResult rbResult;
rbResult.completed = [frame] { qDebug(" - readback %d completed", frame); };
cb->readback(rb, &rbResult);
u->readBackTexture(rb, &rbResult);
cb->endPass(u);
qDebug("Submit and wait");
r->endOffscreenFrame();
......
......@@ -190,12 +190,14 @@ int main(int argc, char **argv)
cb->setViewport({ 0, 0, 1280, 720 });
cb->setVertexInput(0, { { vbuf, 0 } });
cb->draw(3);
cb->endPass();
u = r->nextResourceUpdateBatch();
QRhiReadbackDescription rb(tex);
QRhiReadbackResult rbResult;
rbResult.completed = [frame] { qDebug(" - readback %d completed", frame); };
cb->readback(rb, &rbResult);
u->readBackTexture(rb, &rbResult);
cb->endPass(u);
qDebug("Submit and wait");
r->endOffscreenFrame();
......
......@@ -254,9 +254,10 @@ void ExampleWindow::render()
}
if (!m_onScreenOnly)
m_liveTexCubeRenderer.queueDraw(cb, outputSize);
cb->endPass();
QRhiResourceUpdateBatch *passEndUpdates = nullptr;
#ifdef READBACK_SWAPCHAIN
passEndUpdates = m_r->nextResourceUpdateBatch();
QRhiReadbackDescription rb; // no texture given -> backbuffer
QRhiReadbackResult *rbResult = new QRhiReadbackResult;
int frameNo = m_frameCount;
......@@ -276,9 +277,11 @@ void ExampleWindow::render()
}
delete rbResult;
};
m_r->readback(cb, rb, rbResult);
passEndUpdates->readBackTexture(rb, rbResult);
#endif
cb->endPass(passEndUpdates);
m_r->endFrame(m_sc);
++m_frameCount;
......
......@@ -459,6 +459,11 @@ void QRhiResourceUpdateBatch::copyTexture(QRhiTexture *dst, QRhiTexture *src)
d->textureCopies.append({ dst, src, QRhiTextureCopyDescription() });
}
void QRhiResourceUpdateBatch::readBackTexture(const QRhiReadbackDescription &rb, QRhiReadbackResult *result)
{
d->textureReadbacks.append({ rb, result });
}
void QRhiResourceUpdateBatch::prepareTextureForUse(QRhiTexture *tex, TexturePrepareFlags flags)
{
d->texturePrepares.append({ tex, flags });
......@@ -501,6 +506,7 @@ void QRhiResourceUpdateBatchPrivate::free()
staticBufferUploads.clear();
textureUploads.clear();
textureCopies.clear();
textureReadbacks.clear();
texturePrepares.clear();
rhi->resUpdPoolMap.clearBit(poolIndex);
......@@ -513,15 +519,21 @@ void QRhiResourceUpdateBatchPrivate::merge(QRhiResourceUpdateBatchPrivate *other
staticBufferUploads += other->staticBufferUploads;
textureUploads += other->textureUploads;
textureCopies += other->textureCopies;
textureReadbacks += other->textureReadbacks;
texturePrepares += other->texturePrepares;
}
void QRhiCommandBuffer::resourceUpdate(QRhiResourceUpdateBatch *resourceUpdates)
{
rhi->resourceUpdate(this, resourceUpdates);
}
void QRhiCommandBuffer::beginPass(QRhiRenderTarget *rt,
const QRhiColorClearValue &colorClearValue,
const QRhiDepthStencilClearValue &depthStencilClearValue,
QRhiResourceUpdateBatch *resourceUpdates)
{
rhi->beginPass(rt, this, colorClearValue, depthStencilClearValue, resourceUpdates);
rhi->beginPass(this, rt, colorClearValue, depthStencilClearValue, resourceUpdates);
}
void QRhiCommandBuffer::endPass(QRhiResourceUpdateBatch *resourceUpdates)
......@@ -575,11 +587,6 @@ void QRhiCommandBuffer::drawIndexed(quint32 indexCount,
rhi->drawIndexed(this, indexCount, instanceCount, firstIndex, vertexOffset, firstInstance);
}
bool QRhiCommandBuffer::readback(const QRhiReadbackDescription &rb, QRhiReadbackResult *result)
{
return rhi->readback(this, rb, result);
}
int QRhi::ubufAligned(int v) const
{
const int byteAlign = ubufAlignment();
......
......@@ -319,7 +319,7 @@ Q_DECLARE_TYPEINFO(QRhiTextureCopyDescription, Q_MOVABLE_TYPE);
struct Q_RHI_EXPORT QRhiReadbackDescription
{
QRhiReadbackDescription() { } // source is the current back buffer (if swapchain supports readback)
QRhiReadbackDescription() { } // source is the back buffer of the swapchain of the current frame (if the swapchain supports readback)
QRhiReadbackDescription(QRhiTexture *texture_) : texture(texture_) { } // source is the specified texture
QRhiTexture *texture = nullptr;
int layer = 0;
......@@ -879,14 +879,6 @@ protected:
Q_DECLARE_OPERATORS_FOR_FLAGS(QRhiSwapChain::SurfaceImportFlags)
struct Q_RHI_EXPORT QRhiReadbackResult
{
std::function<void()> completed = nullptr;
QRhiTexture::Format format;
QSize pixelSize;
QByteArray data;
}; // non-movable due to the std::function
class Q_RHI_EXPORT QRhiCommandBuffer : public QRhiResource
{
public:
......@@ -895,6 +887,11 @@ public:
IndexUInt32
};
// Sometimes committing the updates is necessary without starting a render
// pass. Not often needed, updates should typically be passed to beginPass
// (or endPass, in case of readbacks) instead.
void resourceUpdate(QRhiResourceUpdateBatch *resourceUpdates);
void beginPass(QRhiRenderTarget *rt,
const QRhiColorClearValue &colorClearValue, // ignored when rt has PreserveColorContents
const QRhiDepthStencilClearValue &depthStencilClearValue, // ignored when no ds attachment
......@@ -937,9 +934,17 @@ public:
qint32 vertexOffset = 0,
quint32 firstInstance = 0);
protected:
QRhiCommandBuffer(QRhiImplementation *rhi);
void *m_reserved;
};
struct Q_RHI_EXPORT QRhiReadbackResult
{
/*
When used in a begin-endFrame (not offscreen), the data may only be
available in a future frame. Hence the completed callback:
When doing a readback after a pass inside a begin-endFrame (not
offscreen), the data may only be available in a future frame. Hence the
completed callback:
beginFrame(sc);
beginPass
...
......@@ -956,16 +961,15 @@ public:
};
u = nextResourceUpdateBatch();
QRhiReadbackDescription rb; // no texture -> backbuffer
u->readback(rb, rbResult);
u->readBackTexture(rb, rbResult);
endPass(u);
endFrame(sc);
*/
bool readback(const QRhiReadbackDescription &rb, QRhiReadbackResult *result);
protected:
QRhiCommandBuffer(QRhiImplementation *rhi);
void *m_reserved;
};
std::function<void()> completed = nullptr;
QRhiTexture::Format format;
QSize pixelSize;
QByteArray data;
}; // non-movable due to the std::function
class Q_RHI_EXPORT QRhiResourceUpdateBatch // sort of a command buffer for copy type of operations
{
......@@ -986,14 +990,16 @@ public:
// beginPass(). (nb the one we merged from must be release()'d manually)
void merge(QRhiResourceUpdateBatch *other);
// None of these execute anything. Deferred to beginPass. What exactly then
// happens underneath is hidden from the applications.
// None of these execute anything. Deferred to
// beginPass/endPass/resourceUpdate. What exactly then happens underneath
// is hidden from the applications.
void updateDynamicBuffer(QRhiBuffer *buf, int offset, int size, const void *data);
void uploadStaticBuffer(QRhiBuffer *buf, const void *data);
void uploadTexture(QRhiTexture *tex, const QRhiTextureUploadDescription &desc);
void uploadTexture(QRhiTexture *tex, const QImage &image); // shortcut
void copyTexture(QRhiTexture *dst, QRhiTexture *src, const QRhiTextureCopyDescription &desc);
void copyTexture(QRhiTexture *dst, QRhiTexture *src); // shortcut
void readBackTexture(const QRhiReadbackDescription &rb, QRhiReadbackResult *result);
// This is not normally needed, textures that have an upload or are used
// with a TextureRenderTarget will be fine without it. May be more relevant later.
......@@ -1122,7 +1128,7 @@ public:
beginPass
...
u = nextResourceUpdateBatch();
u->readback(rb, &rbResult);
u->readBackTexture(rb, &rbResult);
endPass(u);
endOffscreenFrame();
// image data available in rbResult
......@@ -1131,14 +1137,10 @@ public:
FrameOpResult endOffscreenFrame();
// Waits for any work on the graphics queue (where applicable) to complete,
// then forcibly executes all deferred operations, like completing
// readbacks and resource releases. This should _not_ be used in practice,
// except in infrequent special cases, like when the results of a readback
// are needed asap and no new frames are going to be generated for some
// time. Can be called inside and outside of a frame, but not inside a
// pass. Inside a frame it implies submitting any work on the command
// buffer. Unnecessary in combination with begin/endOffscreenFrame because
// ending an offscreen frame implies waiting for completion.
// then executes all deferred operations, like completing readbacks and
// resource releases. Can be called inside and outside of a frame, but not
// inside a pass. Inside a frame it implies submitting any work on the
// command buffer.
QRhi::FrameOpResult finish();
// Returns an instance to which updates can be queued. Batch instances are
......
......@@ -86,11 +86,12 @@ public:
virtual QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain) = 0;
virtual QRhi::FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb) = 0;
virtual QRhi::FrameOpResult endOffscreenFrame() = 0;
virtual bool readback(QRhiCommandBuffer *cb, const QRhiReadbackDescription &rb, QRhiReadbackResult *result) = 0;
virtual QRhi::FrameOpResult finish() = 0;
virtual void beginPass(QRhiRenderTarget *rt,
QRhiCommandBuffer *cb,
virtual void resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) = 0;
virtual void beginPass(QRhiCommandBuffer *cb,
QRhiRenderTarget *rt,
const QRhiColorClearValue &colorClearValue,
const QRhiDepthStencilClearValue &depthStencilClearValue,
QRhiResourceUpdateBatch *resourceUpdates) = 0;
......@@ -181,6 +182,16 @@ struct QRhiResourceUpdateBatchPrivate
QRhiTextureCopyDescription desc;
};
struct TextureRead {
TextureRead() { }
TextureRead(const QRhiReadbackDescription &rb_, QRhiReadbackResult *result_)
: rb(rb_), result(result_)
{ }
QRhiReadbackDescription rb;
QRhiReadbackResult *result;
};
struct TexturePrepare {
TexturePrepare() { }
TexturePrepare(QRhiTexture *tex_, QRhiResourceUpdateBatch::TexturePrepareFlags flags_)
......@@ -195,6 +206,7 @@ struct QRhiResourceUpdateBatchPrivate
QVector<StaticBufferUpload> staticBufferUploads;
QVector<TextureUpload> textureUploads;
QVector<TextureCopy> textureCopies;
QVector<TextureRead> textureReadbacks;
QVector<TexturePrepare> texturePrepares;
QRhiResourceUpdateBatch *q = nullptr;
......@@ -211,6 +223,7 @@ Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::DynamicBufferUpdate, Q_MOVABL
Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::StaticBufferUpload, Q_MOVABLE_TYPE);
Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::TextureUpload, Q_MOVABLE_TYPE);
Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::TextureCopy, Q_MOVABLE_TYPE);
Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::TextureRead, Q_MOVABLE_TYPE);
Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::TexturePrepare, Q_MOVABLE_TYPE);
template<typename T>
......
......@@ -156,6 +156,8 @@ void QRhiD3D11::create()
void QRhiD3D11::destroy()
{
finishActiveReadbacks();
if (!importedDevice) {
if (context) {
context->Release();
......@@ -166,6 +168,7 @@ void QRhiD3D11::destroy()
dev = nullptr;
}
}
if (dxgiFactory) {
dxgiFactory->Release();
dxgiFactory = nullptr;
......@@ -472,6 +475,8 @@ QRhi::FrameOpResult QRhiD3D11::beginFrame(QRhiSwapChain *swapChain)
swapChainD->msaaRtv[swapChainD->currentFrame] : swapChainD->rtv[swapChainD->currentFrame];
swapChainD->rt.d.dsv = swapChainD->ds ? swapChainD->ds->dsv : nullptr;
finishActiveReadbacks();
return QRhi::FrameOpSuccess;
}
......@@ -521,6 +526,7 @@ QRhi::FrameOpResult QRhiD3D11::endOffscreenFrame()
ofr.active = false;
executeCommandBuffer(&ofr.cbWrapper);
finishActiveReadbacks();
++finishedFrameCount;
return QRhi::FrameOpSuccess;;
......@@ -642,60 +648,6 @@ static inline bool isDepthTextureFormat(QRhiTexture::Format format)
}
}
bool QRhiD3D11::readback(QRhiCommandBuffer *cb, const QRhiReadbackDescription &rb, QRhiReadbackResult *result)
{
Q_ASSERT(inFrame && !inPass);
ID3D11Resource *src;
DXGI_FORMAT dxgiFormat;
QSize pixelSize;
QRhiTexture::Format format;
UINT subres = 0;
QD3D11Texture *texD = QRHI_RES(QD3D11Texture, rb.texture);
QD3D11SwapChain *swapChainD = nullptr;
if (texD) {
if (texD->sampleDesc.Count > 1) {
qWarning("Multisample texture cannot be read back");
return false;
}
src = texD->tex;
dxgiFormat = toD3DTextureFormat(texD->m_format, texD->m_flags);
pixelSize = texD->m_pixelSize;
if (rb.level > 0) {
pixelSize.setWidth(qFloor(float(qMax(1, pixelSize.width() >> rb.level))));
pixelSize.setHeight(qFloor(float(qMax(1, pixelSize.height() >> rb.level))));
}
format = texD->m_format;
subres = D3D11CalcSubresource(rb.level, rb.layer, texD->mipLevelCount);
} else {
Q_ASSERT(contextState.currentSwapChain);
swapChainD = QRHI_RES(QD3D11SwapChain, contextState.currentSwapChain);
src = swapChainD->tex[swapChainD->currentFrame];
dxgiFormat = swapChainD->colorFormat;
pixelSize = swapChainD->pixelSize;
format = colorTextureFormatFromDxgiFormat(dxgiFormat, nullptr);
if (format == QRhiTexture::UnknownFormat)
return false;
}
quint32 bufSize = 0;
textureFormatInfo(format, pixelSize, nullptr, &bufSize);
QD3D11CommandBuffer *cbD = QRHI_RES(QD3D11CommandBuffer, cb);
QD3D11CommandBuffer::Command cmd;
cmd.cmd = QD3D11CommandBuffer::Command::ReadPixels;
cmd.args.readPixels.src = src;
cmd.args.readPixels.dxgiFormat = dxgiFormat;
cmd.args.readPixels.format = format;
cmd.args.readPixels.w = pixelSize.width();
cmd.args.readPixels.h = pixelSize.height();
cmd.args.readPixels.byteSize = bufSize;
cmd.args.readPixels.subres = subres;
cmd.args.readPixels.result = result;
cbD->commands.append(cmd);
return true;
}
QRhi::FrameOpResult QRhiD3D11::finish()
{
Q_ASSERT(!inPass);
......@@ -710,11 +662,13 @@ QRhi::FrameOpResult QRhiD3D11::finish()
contextState.currentSwapChain->cb.resetCommands();
}
}
finishActiveReadbacks();
return QRhi::FrameOpSuccess;
}
void QRhiD3D11::commitResourceUpdates(QRhiResourceUpdateBatch *resourceUpdates)
void QRhiD3D11::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
{
QD3D11CommandBuffer *cbD = QRHI_RES(QD3D11CommandBuffer, cb);
QRhiResourceUpdateBatchPrivate *ud = QRhiResourceUpdateBatchPrivate::get(resourceUpdates);
for (const QRhiResourceUpdateBatchPrivate::DynamicBufferUpdate &u : ud->dynamicBufferUpdates) {
......@@ -728,8 +682,14 @@ void QRhiD3D11::commitResourceUpdates(QRhiResourceUpdateBatch *resourceUpdates)
QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, u.buf);
Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
Q_ASSERT(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.srcRowPitch = 0;
if (!(u.data.size() & 0xFF)) {
context->UpdateSubresource(bufD->buffer, 0, nullptr, u.data.constData(), 0, 0);
cmd.args.updateSubRes.hasDstBox = false;
} else {
// Specify the region since the ID3D11Buffer's size is rounded up to be
// a multiple of 256 while the data we have has the original size.
......@@ -737,8 +697,10 @@ void QRhiD3D11::commitResourceUpdates(QRhiResourceUpdateBatch *resourceUpdates)
box.left = box.top = box.front = 0;
box.back = box.bottom = 1;
box.right = u.data.size(); // no -1: right, bottom, back are exclusive, see D3D11_BOX doc
context->UpdateSubresource(bufD->buffer, 0, &box, u.data.constData(), 0, 0);
cmd.args.updateSubRes.hasDstBox = true;
cmd.args.updateSubRes.dstBox = box;
}
cbD->commands.append(cmd);
}
for (const QRhiResourceUpdateBatchPrivate::TextureUpload &u : ud->textureUploads) {
......@@ -754,12 +716,16 @@ void QRhiD3D11::commitResourceUpdates(QRhiResourceUpdateBatch *resourceUpdates)
box.front = 0;
// back, right, bottom are exclusive
box.back = 1;
QD3D11CommandBuffer::Command cmd;
cmd.cmd = QD3D11CommandBuffer::Command::UpdateSubRes;
cmd.args.updateSubRes.dst = texD->tex;
cmd.args.updateSubRes.dstSubRes = subres;
if (!mipDesc.image.isNull()) {
QImage img = mipDesc.image;
int w = img.width();
int h = img.height();
int bpl = img.bytesPerLine();
const uchar *p = img.constBits();
if (!mipDesc.sourceSize.isEmpty() || !mipDesc.sourceTopLeft.isNull()) {
const int sx = mipDesc.sourceTopLeft.x();
const int sy = mipDesc.sourceTopLeft.y();
......@@ -768,18 +734,23 @@ void QRhiD3D11::commitResourceUpdates(QRhiResourceUpdateBatch *resourceUpdates)
h = mipDesc.sourceSize.height();
}
if (img.depth() == 32) {
p = img.constBits() + sy * img.bytesPerLine() + sx * 4;
const int offset = sy * img.bytesPerLine() + sx * 4;
cmd.args.updateSubRes.src = static_cast<const uchar *>(cbD->retainImage(img)) + offset;
} else {
img = img.copy(sx, sy, w, h);
bpl = img.bytesPerLine();
p = img.constBits();
cmd.args.updateSubRes.src = cbD->retainImage(img);
}
} else {
cmd.args.updateSubRes.src = cbD->retainImage(img);
}
box.left = dx;
box.top = dy;
box.right = dx + w;
box.bottom = dy + h;
context->UpdateSubresource(texD->tex, subres, &box, p, bpl, 0);
cmd.args.updateSubRes.hasDstBox = true;
cmd.args.updateSubRes.dstBox = box;
cmd.args.updateSubRes.srcRowPitch = bpl;
} else if (!mipDesc.compressedData.isEmpty() && isCompressedFormat(texD->m_format)) {
int w, h;
if (mipDesc.sourceSize.isEmpty()) {
......@@ -799,9 +770,12 @@ void QRhiD3D11::commitResourceUpdates(QRhiResourceUpdateBatch *resourceUpdates)
box.top = aligned(dy, blockDim.height());
box.right = aligned(dx + w, blockDim.width());
box.bottom = aligned(dy + h, blockDim.height());
context->UpdateSubresource(texD->tex, subres, &box,
mipDesc.compressedData.constData(), bpl, 0);
cmd.args.updateSubRes.hasDstBox = true;
cmd.args.updateSubRes.dstBox = box;
cmd.args.updateSubRes.src = cbD->retainData(mipDesc.compressedData);
cmd.args.updateSubRes.srcRowPitch = bpl;
}
cbD->commands.append(cmd);
}
}
}
......@@ -823,13 +797,130 @@ void QRhiD3D11::commitResourceUpdates(QRhiResourceUpdateBatch *resourceUpdates)
srcBox.right = srcBox.left + size.width();
srcBox.bottom = srcBox.top + size.height();
srcBox.back = 1;
context->CopySubresourceRegion(dstD->tex, dstSubRes, dx, dy, 0,
srcD->tex, srcSubRes, &srcBox);
QD3D11CommandBuffer::Command cmd;
cmd.cmd = QD3D11CommandBuffer::Command::CopySubRes;
cmd.args.copySubRes.dst = dstD->tex;
cmd.args.copySubRes.dstSubRes = dstSubRes;
cmd.args.copySubRes.dstX = dx;
cmd.args.copySubRes.dstY = dy;
cmd.args.copySubRes.src = srcD->tex;
cmd.args.copySubRes.srcSubRes = srcSubRes;
cmd.args.copySubRes.hasSrcBox = true;
cmd.args.copySubRes.srcBox = srcBox;
cbD->commands.append(cmd);
}
for (const QRhiResourceUpdateBatchPrivate::TextureRead &u : ud->textureReadbacks) {
ActiveReadback aRb;
aRb.desc = u.rb;
aRb.result = u.result;
ID3D11Resource *src;
DXGI_FORMAT dxgiFormat;
QSize pixelSize;
QRhiTexture::Format format;
UINT subres = 0;
QD3D11Texture *texD = QRHI_RES(QD3D11Texture, u.rb.texture);
QD3D11SwapChain *swapChainD = nullptr;
if (texD) {
if (texD->sampleDesc.Count > 1) {
qWarning("Multisample texture cannot be read back");
continue;
}
src = texD->tex;
dxgiFormat = toD3DTextureFormat(texD->m_format, texD->m_flags);
pixelSize = texD->m_pixelSize;
if (u.rb.level > 0) {
pixelSize.setWidth(qFloor(float(qMax(1, pixelSize.width() >> u.rb.level))));
pixelSize.setHeight(qFloor(float(qMax(1, pixelSize.height() >> u.rb.level))));
}
format = texD->m_format;
subres = D3D11CalcSubresource(u.rb.level, u.rb.layer, texD->mipLevelCount);
} else {
Q_ASSERT(contextState.currentSwapChain);
swapChainD = QRHI_RES(QD3D11SwapChain, contextState.currentSwapChain);
src = swapChainD->tex[swapChainD->currentFrame];
dxgiFormat = swapChainD->colorFormat;
pixelSize = swapChainD->pixelSize;
format = colorTextureFormatFromDxgiFormat(dxgiFormat, nullptr);
if (format == QRhiTexture::UnknownFormat)
continue;
}
quint32 bufSize = 0;
textureFormatInfo(format, pixelSize, nullptr, &bufSize);
D3D11_TEXTURE2D_DESC desc;
memset(&desc, 0, sizeof(desc));
desc.Width = pixelSize.width();
desc.Height = pixelSize.height();
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = dxgiFormat;
desc.SampleDesc.Count = 1;
desc.Usage = D3D11_USAGE_STAGING;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
ID3D11Texture2D *stagingTex;
HRESULT hr = dev->CreateTexture2D(&desc, nullptr, &stagingTex);
if (FAILED(hr)) {
qWarning("Failed to create readback staging texture: %s", qPrintable(comErrorMessage(hr)));
return;
}
QD3D11CommandBuffer::Command cmd;
cmd.cmd = QD3D11CommandBuffer::Command::CopySubRes;
cmd.args.copySubRes.dst = stagingTex;
cmd.args.copySubRes.dstSubRes = 0;
cmd.args.copySubRes.dstX = 0;
cmd.args.copySubRes.dstY = 0;
cmd.args.copySubRes.src = src;
cmd.args.copySubRes.srcSubRes = subres;
cmd.args.copySubRes.hasSrcBox = false;
cbD->commands.append(cmd);
aRb.stagingTex = stagingTex;
aRb.bufSize = bufSize;
aRb.pixelSize = pixelSize;
aRb.format = format;
activeReadbacks.append(aRb);
}
ud->free();
}
void QRhiD3D11::finishActiveReadbacks()
{
QVarLengthArray<std::function<void()>, 4> completedCallbacks;
for (int i = activeReadbacks.count() - 1; i >= 0; --i) {
const QRhiD3D11::ActiveReadback &aRb(activeReadbacks[i]);
aRb.result->format = aRb.format;
aRb.result->pixelSize = aRb.pixelSize;
aRb.result->data.resize(aRb.bufSize);
D3D11_MAPPED_SUBRESOURCE mp;
HRESULT hr = context->Map(aRb.stagingTex, 0, D3D11_MAP_READ, 0, &mp);
if (FAILED(hr)) {
qWarning("Failed to map readback staging texture: %s", qPrintable(comErrorMessage(hr)));
aRb.stagingTex->Release();
continue;
}
memcpy(aRb.result->data.data(), mp.pData, aRb.result->data.size());
context->Unmap(aRb.stagingTex, 0);
aRb.stagingTex->Release();
if (aRb.result->completed)
completedCallbacks.append(aRb.result->completed);
activeReadbacks.removeAt(i);
}
for (auto f : completedCallbacks)
f();
}
static inline QD3D11BasicRenderTargetData *basicRtData(QRhiRenderTarget *rt)
{
switch (rt->type()) {
......@@ -843,8 +934,15 @@ static inline QD3D11BasicRenderTargetData *basicRtData(QRhiRenderTarget *rt)
}
}
void QRhiD3D11::beginPass(QRhiRenderTarget *rt,
QRhiCommandBuffer *cb,