Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Laszlo Agocs
qtrhi
Commits
282383ca
Commit
282383ca
authored
Jan 24, 2019
by
Laszlo Agocs
Browse files
gl: rsh
parent
2ae78fee
Changes
6
Hide whitespace changes
Inline
Side-by-side
examples/rhi/multiwindow_threaded/multiwindow_threaded.cpp
View file @
282383ca
...
...
@@ -787,8 +787,8 @@ int main(int argc, char **argv)
"
\n\n
Using API: "
)
+
graphicsApiName
());
info
->
setReadOnly
(
true
);
layout
->
addWidget
(
info
);
QCheckBox
*
rshCb
=
new
QCheckBox
(
QLatin1String
(
"Use QRhiResourceSharingHost for new window
(use same device "
"
(
e.g. VkDevice+VkQueue on Vulkan
)
or sharing contexts
(
OpenGL)
)
"
));
QCheckBox
*
rshCb
=
new
QCheckBox
(
QLatin1String
(
"Use QRhiResourceSharingHost for new window
\n
(use same device
,
"
"e.g. VkDevice+VkQueue on Vulkan
, ID3D11Device+Context on D3D;
or sharing contexts
on
OpenGL)"
));
rshCb
->
setChecked
(
false
);
layout
->
addWidget
(
rshCb
);
QLabel
*
label
=
new
QLabel
(
QLatin1String
(
"Window and thread count: 0"
));
...
...
src/rhi/qrhi.cpp
View file @
282383ca
...
...
@@ -227,11 +227,27 @@ QT_BEGIN_NAMESPACE
\section3 Threading
A QRhi instance can be created and used on any thread but all usage must be
limited to that one single thread. When it comes to native objects, such as
OpenGL contexts, passed in via a QRhiNativeHandles subclass, it is up to
the application to ensure they are not misused by other threads.
limited to that one single thread.
\sa {Qt Shader Tools}
When it comes to externally created native objects, such as OpenGL contexts
passed in via QRhiGles2NativeHandles, it is up to the application to ensure
they are not misused by other threads.
By default any QRhiResource created from one QRhi must only be used with
that one QRhi and must be released before the QRhi is destroyed. This rule
is relaxed when a QRhi is created with an associated
QRhiResourceSharingHost. From then on any QRhiResource that reports \c true
from \l{QRhiResource::isShareable()}{isShareable()} is usable with other
QRhi instances as well, as long as they are associated with the same
QRhiResourceSharingHost. Resources can also outlive their creating QRhi in
this case, as long as there is at least one QRhi left in the "sharing
group". When the QRhi instances live and operate on different threads,
additional synchronization may be required. When writing to resources,
additional synchronization may be required even when the QRhi instances
live on the same thread. See QRhiResourceSharingHost for further
discussion.
\sa {Qt Shader Tools}, QRhiResourceSharingHost
*/
/*!
...
...
@@ -2607,6 +2623,13 @@ quint32 QRhiImplementation::approxByteSizeForTexture(QRhiTexture::Format format,
way that the QRhiResourceSharingHost is only destroyed after all associated
QRhi instances have been fully destroyed.
\note Having a QRhiResourceSharingHost associated with a QRhi triggers
mutex-based synchronization for native objects like the graphics queue or
device context, with backends where applicable. This allows having two or
more QRhi instances on two or more different threads with the same
QRhiResourceSharingHost and so sharing the same device, queue, or device
context.
To illustrate resource sharing, take the following code snippets.
In many cases an application will use a single QRhi. Resources created from it
...
...
@@ -2668,8 +2691,10 @@ quint32 QRhiImplementation::approxByteSizeForTexture(QRhiTexture::Format format,
delete rsh;
\endcode
This is valid as well. After the \c{delete rhi} \c tex is in an orphaned
state so calling \c build() on it for instance would fail.
This is valid as well. After the \c{delete rhi} statement \c tex is in an
orphaned state so calling \c build() on it for example would fail. On the
other hand, it is still valid to use \c{tex} as it is for rendering, with
its existing underlying native texture.
\note Moving the \c{tex->releaseAndDestroy()} call between the \c{delete
rhi2} and \c{delete rsh} statements would be incorrect.
...
...
src/rhi/qrhigles2.cpp
View file @
282383ca
...
...
@@ -251,8 +251,8 @@ bool QRhiGles2::create(QRhi::Flags flags)
rsh
->
d_gles2
.
dummyShareContext
=
new
QOpenGLContext
;
rsh
->
d_gles2
.
dummyShareContext
->
setFormat
(
effectiveFormat
);
rsh
->
d_gles2
.
dummyShareContext
->
create
();
shareContext
=
rsh
->
d_gles2
.
dummyShareContext
;
}
shareContext
=
rsh
->
d_gles2
.
dummyShareContext
;
}
if
(
!
importedContext
)
{
...
...
@@ -293,7 +293,8 @@ bool QRhiGles2::create(QRhi::Flags flags)
nativeHandlesStruct
.
context
=
ctx
;
if
(
rsh
)
{
qDebug
(
"Attached to QRhiResourceSharingHost %p, currently %d other QRhi instances"
,
rsh
,
rsh
->
rhiCount
);
qDebug
(
"Attached to QRhiResourceSharingHost %p, currently %d other QRhi instances sharing via %p"
,
rsh
,
rsh
->
rhiCount
,
rsh
->
d_gles2
.
dummyShareContext
);
rsh
->
rhiCount
+=
1
;
}
...
...
@@ -308,21 +309,28 @@ void QRhiGles2::destroy()
ensureContext
();
executeDeferredReleases
();
f
=
nullptr
;
QMutexLocker
lock
(
rsh
?
&
rsh
->
mtx
:
nullptr
);
if
(
!
importedContext
)
{
delete
ctx
;
ctx
=
nullptr
;
}
if
(
rsh
)
{
if
(
--
rsh
->
rhiCount
==
0
)
{
if
(
rsh
->
d_gles2
.
releaseQueue
)
{
auto
rshRelQueue
=
static_cast
<
QVector
<
DeferredReleaseEntry
>
*>
(
rsh
->
d_gles2
.
releaseQueue
);
// with ctx still current
QRhiGles2
::
executeDeferredReleasesOnRshNow
(
rshRelQueue
);
delete
rshRelQueue
;
}
delete
rsh
->
d_gles2
.
dummyShareContext
;
rsh
->
d_gles2
.
dummyShareContext
=
nullptr
;
rsh
->
d_gles2
.
releaseQueue
=
nullptr
;
}
}
if
(
!
importedContext
)
{
delete
ctx
;
ctx
=
nullptr
;
}
f
=
nullptr
;
}
// Strictly speaking this is not necessary since we could do the deletes in
...
...
@@ -350,12 +358,37 @@ void QRhiGles2::executeDeferredReleases()
f
->
glDeleteFramebuffers
(
1
,
&
e
.
textureRenderTarget
.
framebuffer
);
break
;
default:
Q_UNREACHABLE
();
break
;
}
releaseQueue
.
removeAt
(
i
);
}
}
void
QRhiGles2
::
executeDeferredReleasesOnRshNow
(
QVector
<
QRhiGles2
::
DeferredReleaseEntry
>
*
rshRelQueue
)
{
for
(
int
i
=
rshRelQueue
->
count
()
-
1
;
i
>=
0
;
--
i
)
{
const
QRhiGles2
::
DeferredReleaseEntry
&
e
((
*
rshRelQueue
)[
i
]);
// only need to handle resources that report isShareable() == true
switch
(
e
.
type
)
{
case
QRhiGles2
::
DeferredReleaseEntry
::
Buffer
:
f
->
glDeleteBuffers
(
1
,
&
e
.
buffer
.
buffer
);
break
;
case
QRhiGles2
::
DeferredReleaseEntry
::
Texture
:
f
->
glDeleteTextures
(
1
,
&
e
.
texture
.
texture
);
break
;
case
QRhiGles2
::
DeferredReleaseEntry
::
RenderBuffer
:
f
->
glDeleteRenderbuffers
(
1
,
&
e
.
renderbuffer
.
renderbuffer
);
break
;
// samplers have no backing GL object
default:
Q_UNREACHABLE
();
break
;
}
rshRelQueue
->
removeAt
(
i
);
}
}
QVector
<
int
>
QRhiGles2
::
supportedSampleCounts
()
const
{
return
{
1
};
...
...
@@ -1717,11 +1750,27 @@ void QRhiGles2::endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resource
enqueueResourceUpdates
(
cb
,
resourceUpdates
);
}
static
void
addToRshReleaseQueue
(
QRhiResourceSharingHostPrivate
*
rsh
,
const
QRhiGles2
::
DeferredReleaseEntry
&
e
)
{
QVector
<
QRhiGles2
::
DeferredReleaseEntry
>
*
rshRelQueue
=
static_cast
<
QVector
<
QRhiGles2
::
DeferredReleaseEntry
>
*>
(
rsh
->
d_gles2
.
releaseQueue
);
if
(
!
rshRelQueue
)
{
rshRelQueue
=
new
QVector
<
QRhiGles2
::
DeferredReleaseEntry
>
;
rsh
->
d_gles2
.
releaseQueue
=
rshRelQueue
;
}
rshRelQueue
->
append
(
e
);
}
QGles2Buffer
::
QGles2Buffer
(
QRhiImplementation
*
rhi
,
Type
type
,
UsageFlags
usage
,
int
size
)
:
QRhiBuffer
(
rhi
,
type
,
usage
,
size
)
{
}
bool
QGles2Buffer
::
isShareable
()
const
{
return
true
;
}
void
QGles2Buffer
::
release
()
{
if
(
!
buffer
)
...
...
@@ -1734,23 +1783,29 @@ void QGles2Buffer::release()
buffer
=
0
;
QRHI_RES_RHI
(
QRhiGles2
);
rhiD
->
releaseQueue
.
append
(
e
);
QRHI_PROF
;
QRHI_PROF_F
(
releaseBuffer
(
this
));
rhiD
->
unregisterResource
(
this
);
if
(
!
orphanedWithRsh
)
{
QRHI_RES_RHI
(
QRhiGles2
);
rhiD
->
releaseQueue
.
append
(
e
);
QRHI_PROF
;
QRHI_PROF_F
(
releaseBuffer
(
this
));
rhiD
->
unregisterResource
(
this
);
}
else
{
// associated rhi is already gone, queue the deferred release to the rsh instead
addToRshReleaseQueue
(
orphanedWithRsh
,
e
);
}
}
bool
QGles2Buffer
::
build
()
{
QRHI_RES_RHI
(
QRhiGles2
);
QRHI_PROF
;
if
(
!
QRhiImplementation
::
orphanCheck
(
this
))
return
false
;
if
(
buffer
)
release
();
QRHI_RES_RHI
(
QRhiGles2
);
QRHI_PROF
;
if
(
m_usage
.
testFlag
(
QRhiBuffer
::
UniformBuffer
))
{
// special since we do not support uniform blocks in this backend
ubuf
.
resize
(
m_size
);
...
...
@@ -1781,6 +1836,11 @@ QGles2RenderBuffer::QGles2RenderBuffer(QRhiImplementation *rhi, Type type, const
{
}
bool
QGles2RenderBuffer
::
isShareable
()
const
{
return
true
;
}
void
QGles2RenderBuffer
::
release
()
{
if
(
!
renderbuffer
)
...
...
@@ -1793,22 +1853,27 @@ void QGles2RenderBuffer::release()
renderbuffer
=
0
;
QRHI_RES_RHI
(
QRhiGles2
);
rhiD
->
releaseQueue
.
append
(
e
);
QRHI_PROF
;
QRHI_PROF_F
(
releaseRenderBuffer
(
this
));
rhiD
->
unregisterResource
(
this
);
if
(
!
orphanedWithRsh
)
{
QRHI_RES_RHI
(
QRhiGles2
);
rhiD
->
releaseQueue
.
append
(
e
);
QRHI_PROF
;
QRHI_PROF_F
(
releaseRenderBuffer
(
this
));
rhiD
->
unregisterResource
(
this
);
}
else
{
// associated rhi is already gone, queue the deferred release to the rsh instead
addToRshReleaseQueue
(
orphanedWithRsh
,
e
);
}
}
bool
QGles2RenderBuffer
::
build
()
{
QRHI_RES_RHI
(
QRhiGles2
);
if
(
!
QRhiImplementation
::
orphanCheck
(
this
))
return
false
;
if
(
renderbuffer
)
release
();
QRHI_RES_RHI
(
QRhiGles2
);
QRHI_PROF
;
samples
=
qMax
(
1
,
m_sampleCount
);
...
...
@@ -1869,6 +1934,11 @@ QGles2Texture::QGles2Texture(QRhiImplementation *rhi, Format format, const QSize
{
}
bool
QGles2Texture
::
isShareable
()
const
{
return
true
;
}
void
QGles2Texture
::
release
()
{
if
(
!
texture
)
...
...
@@ -1883,14 +1953,17 @@ void QGles2Texture::release()
specified
=
false
;
nativeHandlesStruct
.
texture
=
0
;
QRHI_RES_RHI
(
QRhiGles2
);
if
(
owns
)
rhiD
->
releaseQueue
.
append
(
e
);
QRHI_PROF
;
QRHI_PROF_F
(
releaseTexture
(
this
));
rhiD
->
unregisterResource
(
this
);
if
(
!
orphanedWithRsh
)
{
QRHI_RES_RHI
(
QRhiGles2
);
if
(
owns
)
rhiD
->
releaseQueue
.
append
(
e
);
QRHI_PROF
;
QRHI_PROF_F
(
releaseTexture
(
this
));
rhiD
->
unregisterResource
(
this
);
}
else
{
// associated rhi is already gone, queue the deferred release to the rsh instead
addToRshReleaseQueue
(
orphanedWithRsh
,
e
);
}
}
static
inline
bool
isPowerOfTwo
(
int
x
)
...
...
@@ -1901,11 +1974,13 @@ static inline bool isPowerOfTwo(int x)
bool
QGles2Texture
::
prepareBuild
(
QSize
*
adjustedSize
)
{
QRHI_RES_RHI
(
QRhiGles2
);
if
(
!
QRhiImplementation
::
orphanCheck
(
this
))
return
false
;
if
(
texture
)
release
();
QRHI_RES_RHI
(
QRhiGles2
);
if
(
!
rhiD
->
ensureContext
())
return
false
;
...
...
@@ -1943,12 +2018,11 @@ bool QGles2Texture::prepareBuild(QSize *adjustedSize)
bool
QGles2Texture
::
build
()
{
QRHI_RES_RHI
(
QRhiGles2
);
QSize
size
;
if
(
!
prepareBuild
(
&
size
))
return
false
;
QRHI_RES_RHI
(
QRhiGles2
);
rhiD
->
f
->
glGenTextures
(
1
,
&
texture
);
const
bool
isCube
=
m_flags
.
testFlag
(
CubeMap
);
...
...
@@ -1990,8 +2064,6 @@ bool QGles2Texture::build()
bool
QGles2Texture
::
buildFrom
(
const
QRhiNativeHandles
*
src
)
{
QRHI_RES_RHI
(
QRhiGles2
);
const
QRhiGles2TextureNativeHandles
*
h
=
static_cast
<
const
QRhiGles2TextureNativeHandles
*>
(
src
);
if
(
!
h
||
!
h
->
texture
)
return
false
;
...
...
@@ -2002,6 +2074,7 @@ bool QGles2Texture::buildFrom(const QRhiNativeHandles *src)
texture
=
h
->
texture
;
specified
=
true
;
QRHI_RES_RHI
(
QRhiGles2
);
QRHI_PROF
;
QRHI_PROF_F
(
newTexture
(
this
,
false
,
mipLevelCount
,
m_flags
.
testFlag
(
CubeMap
)
?
6
:
1
,
1
));
...
...
@@ -2024,6 +2097,11 @@ QGles2Sampler::QGles2Sampler(QRhiImplementation *rhi, Filter magFilter, Filter m
{
}
bool
QGles2Sampler
::
isShareable
()
const
{
return
true
;
}
void
QGles2Sampler
::
release
()
{
// nothing to do here
...
...
@@ -2031,6 +2109,8 @@ void QGles2Sampler::release()
bool
QGles2Sampler
::
build
()
{
// no backing GL object -> no orphanCheck() since it is never registered
glminfilter
=
toGlMinFilter
(
m_minFilter
,
m_mipmapMode
);
glmagfilter
=
toGlMagFilter
(
m_magFilter
);
glwraps
=
toGlWrapMode
(
m_addressU
);
...
...
src/rhi/qrhigles2_p.h
View file @
282383ca
...
...
@@ -55,6 +55,7 @@ class QRhiResourceSharingHostPrivate;
struct
QGles2Buffer
:
public
QRhiBuffer
{
QGles2Buffer
(
QRhiImplementation
*
rhi
,
Type
type
,
UsageFlags
usage
,
int
size
);
bool
isShareable
()
const
override
;
void
release
()
override
;
bool
build
()
override
;
...
...
@@ -77,6 +78,7 @@ struct QGles2RenderBuffer : public QRhiRenderBuffer
{
QGles2RenderBuffer
(
QRhiImplementation
*
rhi
,
Type
type
,
const
QSize
&
pixelSize
,
int
sampleCount
,
QRhiRenderBuffer
::
Flags
flags
);
bool
isShareable
()
const
override
;
void
release
()
override
;
bool
build
()
override
;
QRhiTexture
::
Format
backingFormat
()
const
override
;
...
...
@@ -90,6 +92,7 @@ struct QGles2Texture : public QRhiTexture
{
QGles2Texture
(
QRhiImplementation
*
rhi
,
Format
format
,
const
QSize
&
pixelSize
,
int
sampleCount
,
Flags
flags
);
bool
isShareable
()
const
override
;
void
release
()
override
;
bool
build
()
override
;
bool
buildFrom
(
const
QRhiNativeHandles
*
src
)
override
;
...
...
@@ -115,6 +118,7 @@ struct QGles2Sampler : public QRhiSampler
{
QGles2Sampler
(
QRhiImplementation
*
rhi
,
Filter
magFilter
,
Filter
minFilter
,
Filter
mipmapMode
,
AddressMode
u
,
AddressMode
v
,
AddressMode
w
);
bool
isShareable
()
const
override
;
void
release
()
override
;
bool
build
()
override
;
...
...
@@ -570,6 +574,8 @@ public:
};
QVector
<
DeferredReleaseEntry
>
releaseQueue
;
void
executeDeferredReleasesOnRshNow
(
QVector
<
QRhiGles2
::
DeferredReleaseEntry
>
*
rshRelQueue
);
struct
OffscreenFrame
{
OffscreenFrame
(
QRhiImplementation
*
rhi
)
:
cbWrapper
(
rhi
)
{
}
bool
active
=
false
;
...
...
src/rhi/qrhirsh_p.h
View file @
282383ca
...
...
@@ -72,6 +72,7 @@ public:
#ifndef QT_NO_OPENGL
struct
{
QOpenGLContext
*
dummyShareContext
=
nullptr
;
void
*
releaseQueue
=
nullptr
;
}
d_gles2
;
#endif
#if QT_CONFIG(vulkan)
...
...
todo.txt
View file @
282383ca
res.sh.: gl
res.sh.: mtl
res.sh.: example to show read/write same texture
threading with rsh with resource - more external sync needed
...
...
@@ -49,6 +48,7 @@ dxc for d3d as an alternative to fxc?
hlsl -> dxc -> spirv -> spirv-cross hmmm...
+++ done
res.sh.: gl
res.sh.: exercise it in multiwindow_threaded too
res.sh.: vk, d3d
res.sh.: rhi resource tracking, isSharable, orphaning, ...
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment