Commit 92c6904d authored by Laszlo Agocs's avatar Laszlo Agocs

Revise the rsh strategy a bit

The threaded case cannot be supported on all backends for now.
Revert parts of the previous d3d patch.

Some day we may consider exploring the possibility of doing something
with deferred contexts on d3d11 but that's not an option for now.
parent ea79bca0
......@@ -88,6 +88,8 @@
#include "../shared/cube.h"
//#define USE_RSH
static QBakedShader getShader(const QString &name)
{
QFile f(name);
......@@ -335,6 +337,8 @@ Renderer::~Renderer()
#endif
}
QRhiResourceSharingHost *rsh = nullptr;
void Renderer::createRhi()
{
if (r)
......@@ -342,9 +346,18 @@ void Renderer::createRhi()
qDebug() << "renderer" << this << "creating rhi";
#ifdef USE_RSH
qDebug("Using QRhiResourceSharingHost");
if (!rsh)
rsh = new QRhiResourceSharingHost;
#endif
#ifndef QT_NO_OPENGL
if (graphicsApi == OpenGL) {
QRhiGles2InitParams params;
#ifdef USE_RSH
params.resourceSharingHost = rsh;
#endif
params.fallbackSurface = fallbackSurface;
params.window = window;
r = QRhi::create(QRhi::OpenGLES2, &params);
......@@ -354,6 +367,9 @@ void Renderer::createRhi()
#if QT_CONFIG(vulkan)
if (graphicsApi == Vulkan) {
QRhiVulkanInitParams params;
#ifdef USE_RSH
params.resourceSharingHost = rsh;
#endif
params.inst = instance;
params.window = window;
r = QRhi::create(QRhi::Vulkan, &params);
......@@ -363,6 +379,9 @@ void Renderer::createRhi()
#ifdef Q_OS_WIN
if (graphicsApi == D3D11) {
QRhiD3D11InitParams params;
#ifdef USE_RSH
params.resourceSharingHost = rsh;
#endif
r = QRhi::create(QRhi::D3D11, &params);
}
#endif
......@@ -370,6 +389,9 @@ void Renderer::createRhi()
#ifdef Q_OS_DARWIN
if (graphicsApi == Metal) {
QRhiMetalInitParams params;
#ifdef USE_RSH
params.resourceSharingHost = rsh;
#endif
r = QRhi::create(QRhi::Metal, &params);
}
#endif
......@@ -761,7 +783,7 @@ int main(int argc, char **argv)
QPlainTextEdit *info = new QPlainTextEdit(
QLatin1String("This application tests rendering on a separate thread per window, with dedicated QRhi instances. "
"No resources are shared across windows here. (QRhiResourceSharingHost is not used) "
"No resources are shared across windows here. "
"\n\nThis is the same concept as the Qt Quick Scenegraph's threaded render loop. This should allow rendering to the different windows "
"without unintentionally throttling each other's threads."
"\n\nUsing API: ") + graphicsApiName());
......@@ -794,6 +816,10 @@ int main(int argc, char **argv)
delete wr.window;
}
#ifdef USE_RSH
delete rsh;
#endif
#if QT_CONFIG(vulkan)
delete instance;
#endif
......
......@@ -313,6 +313,18 @@ QT_BEGIN_NAMESPACE
identically across backends, as long as this feature is reported as
supported, are \l{QRhiGraphicsPipeline::LineStrip}{LineStrip} and
\l{QRhiGraphicsPipeline::TriangleStrip}{TriangleStrip}.
\value CrossThreadResourceSharing Indicates that creating QRhi instances on
different threads with QRhiResourceSharingHost set is allowed. Backends
where the underlying graphics API cannot safely support using the same
device or context from multiple threads will report this feature as
unsupported. In that case creating a QRhi with a QRhiResourceSharingHost
set will behave as if the QRhiResourceSharingHost was not provided at all.
Application and framework design may need to take support for this feature
into account: making resources like textures visible to multiple QRhi
instances is not neccessarily possible, so the design should be flexible
enough to allow functioning in that case as well (by using per-QRhi
resources instead of a single shared one, and possibly duplicating work).
*/
/*!
......@@ -2531,10 +2543,13 @@ quint32 QRhiImplementation::approxByteSizeForTexture(QRhiTexture::Format format,
such as QRhiTexture available to all the QRhi instances that use the same
QRhiResourceSharingHost.
With some backends the resource sharing host has more tasks than merely
facilitating the reuse of the device objects. With Direct3D 11 for example,
it also performs synchronizing submission to the device context (of which
there is only one, regardless of the number of threads submitting to it).
\note When creating QRhi instances on different threads, using
QRhiResourceSharingHost may not be supported, depending on the backend and
the underlying graphics API. Support for this is indicated by the
QRhi::CrossThreadResourceSharing flag. When not supported, attempting to
create a QRhi in such a threaded scenario with a QRhiResourceSharingHost
will lead to a warning and ignoring resource sharing altogether (as if
QRhiInitParams::resourceSharingHost was not set).
\note The QRhiResourceSharingHost can be created on a thread that is
different than the threads on which the associated QRhi instances will be
......
......@@ -1159,7 +1159,8 @@ public:
Timestamps,
Instancing,
CustomInstanceStepRate,
PrimitiveRestart
PrimitiveRestart,
CrossThreadResourceSharing
};
enum ResourceSizeLimit {
......
......@@ -173,7 +173,25 @@ bool QRhiD3D11::create(QRhi::Flags flags)
{
Q_UNUSED(flags);
QMutexLocker lock(rsh ? &rsh->mtx : nullptr);
// We do not support CrossThreadResourceSharing because the single
// immediate device context and/or DXGI blow up eventually when used from
// multiple threads, even if command submission is synchronized. So no need
// to lock and ignore rsh if there's already an associated QRhi on a
// different thread.
if (rsh) {
bool noRsh = false;
for (QThread *t : qAsConst(rsh->rhiThreads)) {
if (t != QThread::currentThread()) {
noRsh = true;
break;
}
}
if (noRsh) {
qWarning("Attempted to set a QRhiResourceSharingHost with QRhi instances on different threads when "
"QRhi::CrossThreadResourceSharing is not supported. Resource sharing will be disabled.");
rsh = nullptr;
}
}
uint devFlags = 0;
if (debugLayer)
......@@ -245,8 +263,10 @@ bool QRhiD3D11::create(QRhi::Flags flags)
nativeHandlesStruct.dev = dev;
nativeHandlesStruct.context = context;
if (rsh)
if (rsh) {
rsh->rhiCount += 1;
rsh->rhiThreads.append(QThread::currentThread());
}
return true;
}
......@@ -277,6 +297,7 @@ void QRhiD3D11::destroy()
if (rsh) {
rsh->rhiCount -= 1;
rsh->rhiThreads.removeOne(QThread::currentThread());
if (rsh->rhiCount == 0) {
if (rsh->d_d3d11.context) {
reinterpret_cast<ID3D11DeviceContext1 *>(rsh->d_d3d11.context)->Release();
......@@ -381,6 +402,8 @@ bool QRhiD3D11::isFeatureSupported(QRhi::Feature feature) const
return true;
case QRhi::PrimitiveRestart:
return true;
case QRhi::CrossThreadResourceSharing:
return false;
default:
Q_UNREACHABLE();
return false;
......@@ -750,8 +773,6 @@ QRhi::FrameOpResult QRhiD3D11::endFrame(QRhiSwapChain *swapChain)
Q_ASSERT(inFrame);
inFrame = false;
QMutexLocker lock(rsh ? &rsh->mtx : nullptr);
QD3D11SwapChain *swapChainD = QRHI_RES(QD3D11SwapChain, swapChain);
Q_ASSERT(contextState.currentSwapChain = swapChainD);
const int currentFrameSlot = swapChainD->currentFrameSlot;
......@@ -762,12 +783,11 @@ QRhi::FrameOpResult QRhiD3D11::endFrame(QRhiSwapChain *swapChain)
ID3D11Query *tsEnd = swapChainD->timestampQuery[tsIdx + 1];
const bool recordTimestamps = tsDisjoint && tsStart && tsEnd && !swapChainD->timestampActive[currentFrameSlot];
// send all commands to the context. we already do the rsh lock ourselves
// hence lockWithRsh == false.
// send all commands to the context
if (recordTimestamps)
executeCommandBuffer(&swapChainD->cb, swapChainD, false);
executeCommandBuffer(&swapChainD->cb, swapChainD);
else
executeCommandBuffer(&swapChainD->cb, nullptr, false);
executeCommandBuffer(&swapChainD->cb);
if (swapChainD->sampleDesc.Count > 1) {
context->ResolveSubresource(swapChainD->tex[currentFrameSlot], 0,
......@@ -782,9 +802,6 @@ QRhi::FrameOpResult QRhiD3D11::endFrame(QRhiSwapChain *swapChain)
swapChainD->timestampActive[currentFrameSlot] = true;
}
// avoid keeping the mutex when issuing the Present
lock.unlock();
QRhiProfilerPrivate *rhiP = profilerPrivateOrNull();
// this must be done before the Present
QRHI_PROF_F(endSwapChainFrame(swapChain, swapChainD->frameCount + 1));
......@@ -1511,10 +1528,8 @@ void QRhiD3D11::setRenderTarget(QRhiRenderTarget *rt)
context->OMSetRenderTargets(rtD->colorAttCount, rtD->colorAttCount ? rtD->rtv : nullptr, rtD->dsv);
}
void QRhiD3D11::executeCommandBuffer(QD3D11CommandBuffer *cbD, QD3D11SwapChain *timestampSwapChain, bool lockWithRsh)
void QRhiD3D11::executeCommandBuffer(QD3D11CommandBuffer *cbD, QD3D11SwapChain *timestampSwapChain)
{
QMutexLocker lock((lockWithRsh && rsh) ? &rsh->mtx : nullptr);
quint32 stencilRef = 0;
float blendConstants[] = { 1, 1, 1, 1 };
......
......@@ -527,9 +527,7 @@ public:
void executeBufferHostWritesForCurrentFrame(QD3D11Buffer *bufD);
void setShaderResources(QD3D11ShaderResourceBindings *srbD);
void setRenderTarget(QRhiRenderTarget *rt);
void executeCommandBuffer(QD3D11CommandBuffer *cbD,
QD3D11SwapChain *timestampSwapChain = nullptr,
bool lockWithRsh = true);
void executeCommandBuffer(QD3D11CommandBuffer *cbD, QD3D11SwapChain *timestampSwapChain = nullptr);
DXGI_SAMPLE_DESC effectiveSampleCount(int sampleCount) const;
void finishActiveReadbacks();
......
......@@ -288,6 +288,7 @@ bool QRhiGles2::create(QRhi::Flags flags)
if (rsh) {
rsh->rhiCount += 1;
rsh->rhiThreads.append(QThread::currentThread());
if (rshWantsContext)
rsh->d_gles2.context = ctx;
}
......@@ -315,6 +316,7 @@ void QRhiGles2::destroy()
if (rsh) {
rsh->rhiCount -= 1;
rsh->rhiThreads.removeOne(QThread::currentThread());
if (rsh->rhiCount == 0) {
delete rsh->d_gles2.context;
rsh->d_gles2.context = nullptr;
......@@ -460,6 +462,8 @@ bool QRhiGles2::isFeatureSupported(QRhi::Feature feature) const
return false;
case QRhi::PrimitiveRestart:
return false; // say no to madness
case QRhi::CrossThreadResourceSharing:
return true;
default:
Q_UNREACHABLE();
return false;
......
......@@ -453,6 +453,8 @@ bool QRhiMetal::isFeatureSupported(QRhi::Feature feature) const
return true;
case QRhi::PrimitiveRestart:
return true;
case QRhi::CrossThreadResourceSharing:
return true;
default:
Q_UNREACHABLE();
return false;
......
......@@ -58,6 +58,7 @@
#include "qrhimetal.h"
#endif
#include <QThread>
#include <QMutex>
QT_BEGIN_NAMESPACE
......@@ -69,6 +70,7 @@ public:
QMutex mtx;
int rhiCount = 0;
QVector<QThread *> rhiThreads;
QRhiNullNativeHandles d_null;
#ifndef QT_NO_OPENGL
......
......@@ -2884,6 +2884,8 @@ bool QRhiVulkan::isFeatureSupported(QRhi::Feature feature) const
return vertexAttribDivisorAvailable;
case QRhi::PrimitiveRestart:
return true;
case QRhi::CrossThreadResourceSharing:
return true;
default:
Q_UNREACHABLE();
return false;
......
......@@ -49,7 +49,6 @@ hlsl -> dxc -> spirv -> spirv-cross hmmm...
+++ done
res.sh.: example to show using same texture
res.sh.: d3d context sync
revise create() and importing external device objects
revise structs in api
primitive restart
......
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