Commit e0f7c08a authored by Laszlo Agocs's avatar Laszlo Agocs

Add begin/endFrame flags to allow specifying SkipPresent

beginFrame() has no applicable flags as of now but the flags parameter is
there for future use.
parent 7f26cab6
......@@ -65,6 +65,7 @@
#include <QRhiProfiler>
#define PROFILE_TO_FILE
//#define SKIP_PRESENT
//#define USE_MSAA
//#define USE_SRGB_SWAPCHAIN
//#define READBACK_SWAPCHAIN
......@@ -92,6 +93,10 @@ void preInit()
d.profOut.open(QIODevice::WriteOnly);
#endif
#ifdef SKIP_PRESENT
endFrameFlags |= QRhi::SkipPresent;
#endif
#ifdef USE_MSAA
sampleCount = 4; // enable 4x MSAA (except for the render-to-texture pass)
#endif
......
......@@ -333,6 +333,23 @@ QT_BEGIN_NAMESPACE
\l{QRhiGraphicsPipeline::TriangleStrip}{TriangleStrip}.
*/
/*!
\enum QRhi::BeginFrameFlag
Flag values for QRhi::beginFrame()
*/
/*!
\enum QRhi::EndFrameFlag
Flag values for QRhi::endFrame()
\value SkipPresent Specifies that no present command is to be queued or no
swapBuffers call is to be made. This way no image is presented. Generating
multiple frames with all having this flag set is not recommended (except,
for example, for benchmarking purposes - but keep in mind that backends may
behave differently when it comes to waiting for command completion without
presenting so the results are not comparable between them)
*/
/*!
\enum QRhi::ResourceSizeLimit
Describes the resource limit to query.
......@@ -3659,11 +3676,13 @@ QRhiSwapChain *QRhi::newSwapChain()
\endlist
\a flags is currently unused.
\sa endFrame()
*/
QRhi::FrameOpResult QRhi::beginFrame(QRhiSwapChain *swapChain)
QRhi::FrameOpResult QRhi::beginFrame(QRhiSwapChain *swapChain, BeginFrameFlags flags)
{
return d->beginFrame(swapChain);
return d->beginFrame(swapChain, flags);
}
/*!
......@@ -3673,11 +3692,15 @@ QRhi::FrameOpResult QRhi::beginFrame(QRhiSwapChain *swapChain)
Double (or triple) buffering is managed internally by the QRhiSwapChain and
QRhi.
\a flags can optionally be used to change the behavior in certain ways.
Passing QRhi::SkipPresent skips queuing the Present command or calling
swapBuffers.
\sa beginFrame()
*/
QRhi::FrameOpResult QRhi::endFrame(QRhiSwapChain *swapChain)
QRhi::FrameOpResult QRhi::endFrame(QRhiSwapChain *swapChain, EndFrameFlags flags)
{
return d->endFrame(swapChain);
return d->endFrame(swapChain, flags);
}
/*!
......
......@@ -1157,6 +1157,15 @@ public:
PrimitiveRestart
};
enum BeginFrameFlag {
};
Q_DECLARE_FLAGS(BeginFrameFlags, BeginFrameFlag)
enum EndFrameFlag {
SkipPresent = 1 << 0
};
Q_DECLARE_FLAGS(EndFrameFlags, EndFrameFlag)
enum ResourceSizeLimit {
TextureSizeMin = 1,
TextureSizeMax
......@@ -1194,8 +1203,8 @@ public:
QRhiTextureRenderTarget::Flags flags = QRhiTextureRenderTarget::Flags());
QRhiSwapChain *newSwapChain();
FrameOpResult beginFrame(QRhiSwapChain *swapChain);
FrameOpResult endFrame(QRhiSwapChain *swapChain);
FrameOpResult beginFrame(QRhiSwapChain *swapChain, BeginFrameFlags flags = BeginFrameFlags());
FrameOpResult endFrame(QRhiSwapChain *swapChain, EndFrameFlags flags = EndFrameFlags());
FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb);
FrameOpResult endOffscreenFrame();
......@@ -1233,6 +1242,8 @@ private:
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QRhi::Flags)
Q_DECLARE_OPERATORS_FOR_FLAGS(QRhi::BeginFrameFlags)
Q_DECLARE_OPERATORS_FOR_FLAGS(QRhi::EndFrameFlags)
QT_END_NAMESPACE
......
......@@ -89,8 +89,8 @@ public:
QRhiTextureRenderTarget::Flags flags) = 0;
virtual QRhiSwapChain *createSwapChain() = 0;
virtual QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain) = 0;
virtual QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain) = 0;
virtual QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags) = 0;
virtual QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags) = 0;
virtual QRhi::FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb) = 0;
virtual QRhi::FrameOpResult endOffscreenFrame() = 0;
virtual QRhi::FrameOpResult finish() = 0;
......
......@@ -702,8 +702,9 @@ void QRhiD3D11::debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg)
cbD->commands.append(cmd);
}
QRhi::FrameOpResult QRhiD3D11::beginFrame(QRhiSwapChain *swapChain)
QRhi::FrameOpResult QRhiD3D11::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags)
{
Q_UNUSED(flags);
QMutexLocker lock(rsh ? &rsh->mtx : nullptr);
Q_ASSERT(!inFrame);
......@@ -753,7 +754,7 @@ QRhi::FrameOpResult QRhiD3D11::beginFrame(QRhiSwapChain *swapChain)
return QRhi::FrameOpSuccess;
}
QRhi::FrameOpResult QRhiD3D11::endFrame(QRhiSwapChain *swapChain)
QRhi::FrameOpResult QRhiD3D11::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags)
{
QMutexLocker lock(rsh ? &rsh->mtx : nullptr);
......@@ -793,16 +794,20 @@ QRhi::FrameOpResult QRhiD3D11::endFrame(QRhiSwapChain *swapChain)
// this must be done before the Present
QRHI_PROF_F(endSwapChainFrame(swapChain, swapChainD->frameCount + 1));
const UINT presentFlags = 0;
HRESULT hr = swapChainD->swapChain->Present(swapChainD->swapInterval, presentFlags);
if (FAILED(hr))
qWarning("Failed to present: %s", qPrintable(comErrorMessage(hr)));
if (!flags.testFlag(QRhi::SkipPresent)) {
const UINT presentFlags = 0;
HRESULT hr = swapChainD->swapChain->Present(swapChainD->swapInterval, presentFlags);
if (FAILED(hr))
qWarning("Failed to present: %s", qPrintable(comErrorMessage(hr)));
swapChainD->currentFrameSlot = (swapChainD->currentFrameSlot + 1) % QD3D11SwapChain::BUFFER_COUNT;
swapChainD->frameCount += 1;
// move on to the next buffer
swapChainD->currentFrameSlot = (swapChainD->currentFrameSlot + 1) % QD3D11SwapChain::BUFFER_COUNT;
} else {
context->Flush();
}
swapChainD->frameCount += 1;
contextState.currentSwapChain = nullptr;
return QRhi::FrameOpSuccess;
}
......
......@@ -477,8 +477,8 @@ public:
QRhiTextureRenderTarget::Flags flags) override;
QRhiSwapChain *createSwapChain() override;
QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain) override;
QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain) override;
QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags) override;
QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags) override;
QRhi::FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb) override;
QRhi::FrameOpResult endOffscreenFrame() override;
QRhi::FrameOpResult finish() override;
......
......@@ -218,8 +218,8 @@ bool QRhiGles2::ensureContext(QSurface *surface) const
if (!surface)
surface = fallbackSurface;
if (buffersSwapped)
buffersSwapped = false;
if (needsMakeCurrent)
needsMakeCurrent = false;
else if (!nativeWindowGone && QOpenGLContext::currentContext() == ctx && (surface == fallbackSurface || ctx->surface() == surface))
return true;
......@@ -727,8 +727,9 @@ void QRhiGles2::debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg)
Q_UNUSED(msg);
}
QRhi::FrameOpResult QRhiGles2::beginFrame(QRhiSwapChain *swapChain)
QRhi::FrameOpResult QRhiGles2::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags)
{
Q_UNUSED(flags);
Q_ASSERT(!inFrame);
QGles2SwapChain *swapChainD = QRHI_RES(QGles2SwapChain, swapChain);
......@@ -747,7 +748,7 @@ QRhi::FrameOpResult QRhiGles2::beginFrame(QRhiSwapChain *swapChain)
return QRhi::FrameOpSuccess;
}
QRhi::FrameOpResult QRhiGles2::endFrame(QRhiSwapChain *swapChain)
QRhi::FrameOpResult QRhiGles2::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags)
{
Q_ASSERT(inFrame);
inFrame = false;
......@@ -764,15 +765,15 @@ QRhi::FrameOpResult QRhiGles2::endFrame(QRhiSwapChain *swapChain)
// this must be done before the swap
QRHI_PROF_F(endSwapChainFrame(swapChain, swapChainD->frameCount + 1));
if (swapChainD->surface) {
if (swapChainD->surface && !flags.testFlag(QRhi::SkipPresent)) {
ctx->swapBuffers(swapChainD->surface);
buffersSwapped = true;
needsMakeCurrent = true;
} else {
f->glFlush();
}
swapChainD->frameCount += 1;
currentSwapChain = nullptr;
return QRhi::FrameOpSuccess;
}
......
......@@ -471,8 +471,8 @@ public:
QRhiTextureRenderTarget::Flags flags) override;
QRhiSwapChain *createSwapChain() override;
QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain) override;
QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain) override;
QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags) override;
QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags) override;
QRhi::FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb) override;
QRhi::FrameOpResult endOffscreenFrame() override;
QRhi::FrameOpResult finish() override;
......@@ -531,7 +531,7 @@ public:
bool importedContext = false;
QWindow *maybeWindow = nullptr;
QSurface *fallbackSurface = nullptr;
mutable bool buffersSwapped = false;
mutable bool needsMakeCurrent = false;
QOpenGLExtensions *f = nullptr;
struct {
// Multisample fb and blit are supported (GLES 3.0 or OpenGL 3.x). Not
......
......@@ -303,8 +303,8 @@ public:
QRhiTextureRenderTarget::Flags flags) override;
QRhiSwapChain *createSwapChain() override;
QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain) override;
QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain) override;
QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags) override;
QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags) override;
QRhi::FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb) override;
QRhi::FrameOpResult endOffscreenFrame() override;
QRhi::FrameOpResult finish() override;
......
......@@ -261,15 +261,17 @@ void QRhiNull::debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg)
Q_UNUSED(msg);
}
QRhi::FrameOpResult QRhiNull::beginFrame(QRhiSwapChain *swapChain)
QRhi::FrameOpResult QRhiNull::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags)
{
Q_UNUSED(flags);
QRhiProfilerPrivate *rhiP = profilerPrivateOrNull();
QRHI_PROF_F(beginSwapChainFrame(swapChain));
return QRhi::FrameOpSuccess;
}
QRhi::FrameOpResult QRhiNull::endFrame(QRhiSwapChain *swapChain)
QRhi::FrameOpResult QRhiNull::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags)
{
Q_UNUSED(flags);
QNullSwapChain *swapChainD = QRHI_RES(QNullSwapChain, swapChain);
QRhiProfilerPrivate *rhiP = profilerPrivateOrNull();
QRHI_PROF_F(endSwapChainFrame(swapChain, swapChainD->frameCount + 1));
......
......@@ -190,8 +190,8 @@ public:
QRhiTextureRenderTarget::Flags flags) override;
QRhiSwapChain *createSwapChain() override;
QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain) override;
QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain) override;
QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags) override;
QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags) override;
QRhi::FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb) override;
QRhi::FrameOpResult endOffscreenFrame() override;
QRhi::FrameOpResult finish() override;
......
......@@ -1420,20 +1420,21 @@ static inline bool checkDeviceLost(VkResult err)
return false;
}
QRhi::FrameOpResult QRhiVulkan::beginFrame(QRhiSwapChain *swapChain)
QRhi::FrameOpResult QRhiVulkan::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags)
{
Q_UNUSED(flags);
if (QRHI_RES(QVkSwapChain, swapChain)->wrapWindow)
return beginWrapperFrame(swapChain);
else
return beginNonWrapperFrame(swapChain);
}
QRhi::FrameOpResult QRhiVulkan::endFrame(QRhiSwapChain *swapChain)
QRhi::FrameOpResult QRhiVulkan::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags)
{
if (QRHI_RES(QVkSwapChain, swapChain)->wrapWindow)
return endWrapperFrame(swapChain);
else
return endNonWrapperFrame(swapChain);
return endNonWrapperFrame(swapChain, flags);
}
QRhi::FrameOpResult QRhiVulkan::beginWrapperFrame(QRhiSwapChain *swapChain)
......@@ -1682,7 +1683,7 @@ QRhi::FrameOpResult QRhiVulkan::beginNonWrapperFrame(QRhiSwapChain *swapChain)
return QRhi::FrameOpSuccess;
}
QRhi::FrameOpResult QRhiVulkan::endNonWrapperFrame(QRhiSwapChain *swapChain)
QRhi::FrameOpResult QRhiVulkan::endNonWrapperFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags)
{
QMutexLocker lock(rsh ? &rsh->mtx : nullptr);
......@@ -1722,10 +1723,11 @@ QRhi::FrameOpResult QRhiVulkan::endNonWrapperFrame(QRhiSwapChain *swapChain)
// stop recording and submit to the queue
Q_ASSERT(!image.cmdFenceWaitable);
const bool needsPresent = !flags.testFlag(QRhi::SkipPresent);
QRhi::FrameOpResult submitres = endAndSubmitCommandBuffer(image.cmdBuf,
image.cmdFence,
frame.imageSemWaitable ? &frame.imageSem : nullptr,
&frame.drawSem);
needsPresent ? &frame.drawSem : nullptr);
if (submitres != QRhi::FrameOpSuccess)
return submitres;
......@@ -1736,36 +1738,38 @@ QRhi::FrameOpResult QRhiVulkan::endNonWrapperFrame(QRhiSwapChain *swapChain)
// this must be done before the Present
QRHI_PROF_F(endSwapChainFrame(swapChain, swapChainD->frameCount + 1));
// add the Present to the queue
VkPresentInfoKHR presInfo;
memset(&presInfo, 0, sizeof(presInfo));
presInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
presInfo.swapchainCount = 1;
presInfo.pSwapchains = &swapChainD->sc;
presInfo.pImageIndices = &swapChainD->currentImageIndex;
presInfo.waitSemaphoreCount = 1;
presInfo.pWaitSemaphores = &frame.drawSem; // gfxQueueFamilyIdx == presQueueFamilyIdx ? &frame.drawSem : &frame.presTransSem;
VkResult err = vkQueuePresentKHR(gfxQueue, &presInfo);
if (err != VK_SUCCESS) {
if (err == VK_ERROR_OUT_OF_DATE_KHR) {
return QRhi::FrameOpSwapChainOutOfDate;
} else if (err != VK_SUBOPTIMAL_KHR) {
if (checkDeviceLost(err))
return QRhi::FrameOpDeviceLost;
else
qWarning("Failed to present: %d", err);
return QRhi::FrameOpError;
if (needsPresent) {
// add the Present to the queue
VkPresentInfoKHR presInfo;
memset(&presInfo, 0, sizeof(presInfo));
presInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
presInfo.swapchainCount = 1;
presInfo.pSwapchains = &swapChainD->sc;
presInfo.pImageIndices = &swapChainD->currentImageIndex;
presInfo.waitSemaphoreCount = 1;
presInfo.pWaitSemaphores = &frame.drawSem; // gfxQueueFamilyIdx == presQueueFamilyIdx ? &frame.drawSem : &frame.presTransSem;
VkResult err = vkQueuePresentKHR(gfxQueue, &presInfo);
if (err != VK_SUCCESS) {
if (err == VK_ERROR_OUT_OF_DATE_KHR) {
return QRhi::FrameOpSwapChainOutOfDate;
} else if (err != VK_SUBOPTIMAL_KHR) {
if (checkDeviceLost(err))
return QRhi::FrameOpDeviceLost;
else
qWarning("Failed to present: %d", err);
return QRhi::FrameOpError;
}
}
}
frame.imageAcquired = false;
// mark the current swapchain buffer as unused from our side
frame.imageAcquired = false;
// and move on to the next buffer
swapChainD->currentFrameSlot = (swapChainD->currentFrameSlot + 1) % QVK_FRAMES_IN_FLIGHT;
}
swapChainD->currentFrameSlot = (swapChainD->currentFrameSlot + 1) % QVK_FRAMES_IN_FLIGHT;
swapChainD->frameCount += 1;
currentSwapChain = nullptr;
return QRhi::FrameOpSuccess;
}
......
......@@ -375,8 +375,8 @@ public:
QRhiTextureRenderTarget::Flags flags) override;
QRhiSwapChain *createSwapChain() override;
QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain) override;
QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain) override;
QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags) override;
QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags) override;
QRhi::FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb) override;
QRhi::FrameOpResult endOffscreenFrame() override;
QRhi::FrameOpResult finish() override;
......@@ -457,7 +457,7 @@ public:
VkSemaphore *waitSem, VkSemaphore *signalSem);
void waitCommandCompletion(int frameSlot);
QRhi::FrameOpResult beginNonWrapperFrame(QRhiSwapChain *swapChain);
QRhi::FrameOpResult endNonWrapperFrame(QRhiSwapChain *swapChain);
QRhi::FrameOpResult endNonWrapperFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags);
void prepareNewFrame(QRhiCommandBuffer *cb);
void prepareForTransferDest(QRhiCommandBuffer *cb, QVkTexture *texD);
void prepareForTransferSrc(QRhiCommandBuffer *cb, QVkTexture *texD);
......
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