summaryrefslogtreecommitdiffstats
path: root/src/gui/rhi
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/rhi')
-rw-r--r--src/gui/rhi/qrhi.cpp136
-rw-r--r--src/gui/rhi/qrhi_p.h23
-rw-r--r--src/gui/rhi/qrhi_p_p.h7
-rw-r--r--src/gui/rhi/qrhid3d11.cpp73
-rw-r--r--src/gui/rhi/qrhid3d11_p.h5
-rw-r--r--src/gui/rhi/qrhid3d11_p_p.h15
-rw-r--r--src/gui/rhi/qrhigles2.cpp353
-rw-r--r--src/gui/rhi/qrhigles2_p.h5
-rw-r--r--src/gui/rhi/qrhigles2_p_p.h37
-rw-r--r--src/gui/rhi/qrhimetal.mm242
-rw-r--r--src/gui/rhi/qrhimetal_p.h5
-rw-r--r--src/gui/rhi/qrhimetal_p_p.h15
-rw-r--r--src/gui/rhi/qrhinull.cpp30
-rw-r--r--src/gui/rhi/qrhinull_p.h4
-rw-r--r--src/gui/rhi/qrhinull_p_p.h14
-rw-r--r--src/gui/rhi/qrhivulkan.cpp452
-rw-r--r--src/gui/rhi/qrhivulkan_p.h6
-rw-r--r--src/gui/rhi/qrhivulkan_p_p.h41
-rw-r--r--src/gui/rhi/qshader.cpp48
-rw-r--r--src/gui/rhi/qshader_p_p.h7
-rw-r--r--src/gui/rhi/qshaderdescription.cpp382
-rw-r--r--src/gui/rhi/qshaderdescription_p.h47
-rw-r--r--src/gui/rhi/qshaderdescription_p_p.h2
-rw-r--r--src/gui/rhi/rhi.pri6
24 files changed, 1478 insertions, 477 deletions
diff --git a/src/gui/rhi/qrhi.cpp b/src/gui/rhi/qrhi.cpp
index ca835941d6..f0bf19bd91 100644
--- a/src/gui/rhi/qrhi.cpp
+++ b/src/gui/rhi/qrhi.cpp
@@ -48,8 +48,7 @@
#ifdef Q_OS_WIN
#include "qrhid3d11_p_p.h"
#endif
-//#ifdef Q_OS_DARWIN
-#ifdef Q_OS_MACOS
+#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
#include "qrhimetal_p_p.h"
#endif
@@ -2161,6 +2160,32 @@ QRhiResource::Type QRhiRenderBuffer::resourceType() const
*/
/*!
+ \class QRhiTexture::NativeTexture
+ \brief Contains information about the underlying native resources of a texture.
+ */
+
+/*!
+ \variable QRhiTexture::NativeTexture::object
+ \brief a pointer to the native object handle.
+
+ With OpenGL, the native handle is a GLuint value, so \c object is then a
+ pointer to a GLuint. With Vulkan, the native handle is a VkImage, so \c
+ object is a pointer to a VkImage. With Direct3D 11 and Metal \c
+ object is a pointer to a ID3D11Texture2D or MTLTexture pointer, respectively.
+
+ \note Pay attention to the fact that \a object is always a pointer
+ to the native texture handle type, even if the native type itself is a
+ pointer.
+ */
+
+/*!
+ \variable QRhiTexture::NativeTexture::layout
+ \brief Specifies the current image layout for APIs like Vulkan.
+
+ For Vulkan, \c layout contains a \c VkImageLayout value.
+ */
+
+/*!
\internal
*/
QRhiTexture::QRhiTexture(QRhiImplementation *rhi, Format format_, const QSize &pixelSize_,
@@ -2190,21 +2215,20 @@ QRhiResource::Type QRhiTexture::resourceType() const
*/
/*!
- \return a pointer to a backend-specific QRhiNativeHandles subclass, such as
- QRhiVulkanTextureNativeHandles. The returned value is null when exposing
- the underlying native resources is not supported by the backend.
+ \return the underlying native resources for this texture. The returned value
+ will be empty if exposing the underlying native resources is not supported by
+ the backend.
- \sa QRhiVulkanTextureNativeHandles, QRhiD3D11TextureNativeHandles,
- QRhiMetalTextureNativeHandles, QRhiGles2TextureNativeHandles
+ \sa buildFrom()
*/
-const QRhiNativeHandles *QRhiTexture::nativeHandles()
+QRhiTexture::NativeTexture QRhiTexture::nativeTexture()
{
- return nullptr;
+ return {};
}
/*!
Similar to build() except that no new native textures are created. Instead,
- the texture from \a src is used.
+ the native texture resources specified by \a src is used.
This allows importing an existing native texture object (which must belong
to the same device or sharing context, depending on the graphics API) from
@@ -2220,12 +2244,10 @@ const QRhiNativeHandles *QRhiTexture::nativeHandles()
does not free the object or any associated memory.
The opposite of this operation, exposing a QRhiTexture-created native
- texture object to a foreign engine, is possible via nativeHandles().
+ texture object to a foreign engine, is possible via nativeTexture().
- \sa QRhiVulkanTextureNativeHandles, QRhiD3D11TextureNativeHandles,
- QRhiMetalTextureNativeHandles, QRhiGles2TextureNativeHandles
- */
-bool QRhiTexture::buildFrom(const QRhiNativeHandles *src)
+*/
+bool QRhiTexture::buildFrom(QRhiTexture::NativeTexture src)
{
Q_UNUSED(src);
return false;
@@ -2253,9 +2275,7 @@ bool QRhiTexture::buildFrom(const QRhiNativeHandles *src)
\value Repeat
\value ClampToEdge
- \value Border
\value Mirror
- \value MirrorOnce
*/
/*!
@@ -2277,11 +2297,10 @@ bool QRhiTexture::buildFrom(const QRhiNativeHandles *src)
*/
QRhiSampler::QRhiSampler(QRhiImplementation *rhi,
Filter magFilter_, Filter minFilter_, Filter mipmapMode_,
- AddressMode u_, AddressMode v_)
+ AddressMode u_, AddressMode v_, AddressMode w_)
: QRhiResource(rhi),
m_magFilter(magFilter_), m_minFilter(minFilter_), m_mipmapMode(mipmapMode_),
- m_addressU(u_), m_addressV(v_),
- m_addressW(QRhiSampler::ClampToEdge),
+ m_addressU(u_), m_addressV(v_), m_addressW(w_),
m_compareOp(QRhiSampler::Never)
{
}
@@ -2322,8 +2341,26 @@ QRhiResource::Type QRhiRenderPassDescriptor::resourceType() const
}
/*!
+ \fn bool QRhiRenderPassDescriptor::isCompatible(const QRhiRenderPassDescriptor *other) const;
+
+ \return true if the \a other QRhiRenderPassDescriptor is compatible with
+ this one, meaning \c this and \a other can be used interchangebly in
+ QRhiGraphicsPipeline::setRenderPassDescriptor().
+
+ The concept of the compatibility of renderpass descriptors is similar to
+ the \l{QRhiShaderResourceBindings::isLayoutCompatible}{layout
+ compatibility} of QRhiShaderResourceBindings instances. They allow better
+ reuse of QRhiGraphicsPipeline instances: for example, a
+ QRhiGraphicsPipeline instance cache is expected to use these functions to
+ look for a matching pipeline, instead of just comparing pointers, thus
+ allowing a different QRhiRenderPassDescriptor and
+ QRhiShaderResourceBindings to be used in combination with the pipeline, as
+ long as they are compatible.
+ */
+
+/*!
\return a pointer to a backend-specific QRhiNativeHandles subclass, such as
- QRhiVulkanRenderPassNativeHandles. The returned value is null when exposing
+ QRhiVulkanRenderPassNativeHandles. The returned value is \nullptr when exposing
the underlying native resources is not supported by the backend.
\sa QRhiVulkanRenderPassNativeHandles
@@ -3901,6 +3938,12 @@ void QRhiImplementation::textureFormatInfo(QRhiTexture::Format format, const QSi
case QRhiTexture::RGBA32F:
bpc = 16;
break;
+ case QRhiTexture::R16F:
+ bpc = 2;
+ break;
+ case QRhiTexture::R32F:
+ bpc = 4;
+ break;
case QRhiTexture::D16:
bpc = 2;
@@ -4049,8 +4092,7 @@ QRhi *QRhi::create(Implementation impl, QRhiInitParams *params, Flags flags, QRh
break;
#endif
case Metal:
-//#ifdef Q_OS_DARWIN
-#ifdef Q_OS_MACOS
+#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
r->d = new QRhiMetal(static_cast<QRhiMetalInitParams *>(params),
static_cast<QRhiMetalNativeHandles *>(importDevice));
break;
@@ -4890,7 +4932,7 @@ void QRhiCommandBuffer::dispatch(int x, int y, int z)
/*!
\return a pointer to a backend-specific QRhiNativeHandles subclass, such as
- QRhiVulkanCommandBufferNativeHandles. The returned value is null when
+ QRhiVulkanCommandBufferNativeHandles. The returned value is \nullptr when
exposing the underlying native resources is not supported by, or not
applicable to, the backend.
@@ -5016,13 +5058,24 @@ bool QRhi::isYUpInNDC() const
}
/*!
- \return \c true if the underlying graphics API uses depth 0 - 1 in clip
- space.
+ \return \c true if the underlying graphics API uses depth range [0, 1] in
+ clip space.
- In practice this is \c false for OpenGL only.
+ In practice this is \c false for OpenGL only, because OpenGL uses a
+ post-projection depth range of [-1, 1]. (not to be confused with the
+ NDC-to-window mapping controlled by glDepthRange(), which uses a range of
+ [0, 1], unless overridden by the QRhiViewport) In some OpenGL versions
+ glClipControl() could be used to change this, but the OpenGL backend of
+ QRhi does not use that function as it is not available in OpenGL ES or
+ OpenGL versions lower than 4.5.
\note clipSpaceCorrMatrix() includes the corresponding adjustment in its
- returned matrix.
+ returned matrix. Therefore, many users of QRhi do not need to take any
+ further measures apart from pre-multiplying their projection matrices with
+ clipSpaceCorrMatrix(). However, some graphics techniques, such as, some
+ types of shadow mapping, involve working with and outputting depth values
+ in the shaders. These will need to query and take the value of this
+ function into account as appropriate.
*/
bool QRhi::isClipDepthZeroToOne() const
{
@@ -5032,11 +5085,15 @@ bool QRhi::isClipDepthZeroToOne() const
/*!
\return a matrix that can be used to allow applications keep using
OpenGL-targeted vertex data and perspective projection matrices (such as,
- the ones generated by QMatrix4x4::perspective()), regardless of the
- backend. Once \c{this_matrix * mvp} is used instead of just \c mvp, vertex
- data with Y up and viewports with depth range 0 - 1 can be used without
- considering what backend and so graphics API is going to be used at run
- time.
+ the ones generated by QMatrix4x4::perspective()), regardless of the active
+ QRhi backend.
+
+ In a typical renderer, once \c{this_matrix * mvp} is used instead of just
+ \c mvp, vertex data with Y up and viewports with depth range 0 - 1 can be
+ used without considering what backend (and so graphics API) is going to be
+ used at run time. This way branching based on isYUpInNDC() and
+ isClipDepthZeroToOne() can be avoided (although such logic may still become
+ required when implementing certain advanced graphics techniques).
See
\l{https://matthewwellings.com/blog/the-new-vulkan-coordinate-system/}{this
@@ -5278,16 +5335,19 @@ QRhiTexture *QRhi::newTexture(QRhiTexture::Format format,
/*!
\return a new sampler with the specified magnification filter \a magFilter,
- minification filter \a minFilter, mipmapping mode \a mipmapMpde, and S/T
- addressing modes \a u and \a v.
+ minification filter \a minFilter, mipmapping mode \a mipmapMode, and the
+ addressing (wrap) modes \a addressU, \a addressV, and \a addressW.
\sa QRhiResource::release()
*/
-QRhiSampler *QRhi::newSampler(QRhiSampler::Filter magFilter, QRhiSampler::Filter minFilter,
+QRhiSampler *QRhi::newSampler(QRhiSampler::Filter magFilter,
+ QRhiSampler::Filter minFilter,
QRhiSampler::Filter mipmapMode,
- QRhiSampler:: AddressMode u, QRhiSampler::AddressMode v)
+ QRhiSampler::AddressMode addressU,
+ QRhiSampler::AddressMode addressV,
+ QRhiSampler::AddressMode addressW)
{
- return d->createSampler(magFilter, minFilter, mipmapMode, u, v);
+ return d->createSampler(magFilter, minFilter, mipmapMode, addressU, addressV, addressW);
}
/*!
diff --git a/src/gui/rhi/qrhi_p.h b/src/gui/rhi/qrhi_p.h
index 588347d111..e32fc0f4a0 100644
--- a/src/gui/rhi/qrhi_p.h
+++ b/src/gui/rhi/qrhi_p.h
@@ -728,6 +728,8 @@ public:
RGBA16F,
RGBA32F,
+ R16F,
+ R32F,
D16,
D32F,
@@ -760,6 +762,11 @@ public:
ASTC_12x12
};
+ struct NativeTexture {
+ const void *object;
+ int layout;
+ };
+
QRhiResource::Type resourceType() const override;
Format format() const { return m_format; }
@@ -775,8 +782,8 @@ public:
void setSampleCount(int s) { m_sampleCount = s; }
virtual bool build() = 0;
- virtual const QRhiNativeHandles *nativeHandles();
- virtual bool buildFrom(const QRhiNativeHandles *src);
+ virtual NativeTexture nativeTexture();
+ virtual bool buildFrom(NativeTexture src);
protected:
QRhiTexture(QRhiImplementation *rhi, Format format_, const QSize &pixelSize_,
@@ -801,9 +808,7 @@ public:
enum AddressMode {
Repeat,
ClampToEdge,
- Border,
Mirror,
- MirrorOnce
};
enum CompareOp {
@@ -845,7 +850,7 @@ public:
protected:
QRhiSampler(QRhiImplementation *rhi,
Filter magFilter_, Filter minFilter_, Filter mipmapMode_,
- AddressMode u_, AddressMode v_);
+ AddressMode u_, AddressMode v_, AddressMode w_);
Filter m_magFilter;
Filter m_minFilter;
Filter m_mipmapMode;
@@ -902,6 +907,7 @@ class Q_GUI_EXPORT QRhiRenderPassDescriptor : public QRhiResource
public:
QRhiResource::Type resourceType() const override;
+ virtual bool isCompatible(const QRhiRenderPassDescriptor *other) const = 0;
virtual const QRhiNativeHandles *nativeHandles();
protected:
@@ -1468,9 +1474,12 @@ public:
int sampleCount = 1,
QRhiTexture::Flags flags = QRhiTexture::Flags());
- QRhiSampler *newSampler(QRhiSampler::Filter magFilter, QRhiSampler::Filter minFilter,
+ QRhiSampler *newSampler(QRhiSampler::Filter magFilter,
+ QRhiSampler::Filter minFilter,
QRhiSampler::Filter mipmapMode,
- QRhiSampler::AddressMode u, QRhiSampler::AddressMode v);
+ QRhiSampler::AddressMode addressU,
+ QRhiSampler::AddressMode addressV,
+ QRhiSampler::AddressMode addressW = QRhiSampler::Repeat);
QRhiTextureRenderTarget *newTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc,
QRhiTextureRenderTarget::Flags flags = QRhiTextureRenderTarget::Flags());
diff --git a/src/gui/rhi/qrhi_p_p.h b/src/gui/rhi/qrhi_p_p.h
index baffe28202..4a4c044a29 100644
--- a/src/gui/rhi/qrhi_p_p.h
+++ b/src/gui/rhi/qrhi_p_p.h
@@ -85,9 +85,12 @@ public:
const QSize &pixelSize,
int sampleCount,
QRhiTexture::Flags flags) = 0;
- virtual QRhiSampler *createSampler(QRhiSampler::Filter magFilter, QRhiSampler::Filter minFilter,
+ virtual QRhiSampler *createSampler(QRhiSampler::Filter magFilter,
+ QRhiSampler::Filter minFilter,
QRhiSampler::Filter mipmapMode,
- QRhiSampler:: AddressMode u, QRhiSampler::AddressMode v) = 0;
+ QRhiSampler:: AddressMode u,
+ QRhiSampler::AddressMode v,
+ QRhiSampler::AddressMode w) = 0;
virtual QRhiTextureRenderTarget *createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc,
QRhiTextureRenderTarget::Flags flags) = 0;
diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp
index 5e576e9c6a..16f533d582 100644
--- a/src/gui/rhi/qrhid3d11.cpp
+++ b/src/gui/rhi/qrhid3d11.cpp
@@ -108,17 +108,6 @@ QT_BEGIN_NAMESPACE
\c{ID3D11Device *} and \c{ID3D11DeviceContext *}.
*/
-/*!
- \class QRhiD3D11TextureNativeHandles
- \internal
- \inmodule QtGui
- \brief Holds the D3D texture object that is backing a QRhiTexture instance.
-
- \note The class uses \c{void *} as the type since including the COM-based
- \c{d3d11.h} headers is not acceptable here. The actual type is
- \c{ID3D11Texture2D *}.
- */
-
// help mingw with its ancient sdk headers
#ifndef DXGI_ADAPTER_FLAG_SOFTWARE
#define DXGI_ADAPTER_FLAG_SOFTWARE 2
@@ -538,9 +527,9 @@ QRhiTexture *QRhiD3D11::createTexture(QRhiTexture::Format format, const QSize &p
QRhiSampler *QRhiD3D11::createSampler(QRhiSampler::Filter magFilter, QRhiSampler::Filter minFilter,
QRhiSampler::Filter mipmapMode,
- QRhiSampler::AddressMode u, QRhiSampler::AddressMode v)
+ QRhiSampler::AddressMode u, QRhiSampler::AddressMode v, QRhiSampler::AddressMode w)
{
- return new QD3D11Sampler(this, magFilter, minFilter, mipmapMode, u, v);
+ return new QD3D11Sampler(this, magFilter, minFilter, mipmapMode, u, v, w);
}
QRhiTextureRenderTarget *QRhiD3D11::createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc,
@@ -641,9 +630,7 @@ void QRhiD3D11::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind
}
break;
case QRhiShaderResourceBinding::ImageLoad:
- Q_FALLTHROUGH();
case QRhiShaderResourceBinding::ImageStore:
- Q_FALLTHROUGH();
case QRhiShaderResourceBinding::ImageLoadStore:
{
QD3D11Texture *texD = QRHI_RES(QD3D11Texture, b->u.simage.tex);
@@ -655,9 +642,7 @@ void QRhiD3D11::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind
}
break;
case QRhiShaderResourceBinding::BufferLoad:
- Q_FALLTHROUGH();
case QRhiShaderResourceBinding::BufferStore:
- Q_FALLTHROUGH();
case QRhiShaderResourceBinding::BufferLoadStore:
{
QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, b->u.sbuf.buf);
@@ -1117,6 +1102,10 @@ static inline DXGI_FORMAT toD3DTextureFormat(QRhiTexture::Format format, QRhiTex
return DXGI_FORMAT_R16G16B16A16_FLOAT;
case QRhiTexture::RGBA32F:
return DXGI_FORMAT_R32G32B32A32_FLOAT;
+ case QRhiTexture::R16F:
+ return DXGI_FORMAT_R16_FLOAT;
+ case QRhiTexture::R32F:
+ return DXGI_FORMAT_R32_FLOAT;
case QRhiTexture::D16:
return DXGI_FORMAT_R16_TYPELESS;
@@ -1139,39 +1128,24 @@ static inline DXGI_FORMAT toD3DTextureFormat(QRhiTexture::Format format, QRhiTex
return srgb ? DXGI_FORMAT_BC7_UNORM_SRGB : DXGI_FORMAT_BC7_UNORM;
case QRhiTexture::ETC2_RGB8:
- Q_FALLTHROUGH();
case QRhiTexture::ETC2_RGB8A1:
- Q_FALLTHROUGH();
case QRhiTexture::ETC2_RGBA8:
qWarning("QRhiD3D11 does not support ETC2 textures");
return DXGI_FORMAT_R8G8B8A8_UNORM;
case QRhiTexture::ASTC_4x4:
- Q_FALLTHROUGH();
case QRhiTexture::ASTC_5x4:
- Q_FALLTHROUGH();
case QRhiTexture::ASTC_5x5:
- Q_FALLTHROUGH();
case QRhiTexture::ASTC_6x5:
- Q_FALLTHROUGH();
case QRhiTexture::ASTC_6x6:
- Q_FALLTHROUGH();
case QRhiTexture::ASTC_8x5:
- Q_FALLTHROUGH();
case QRhiTexture::ASTC_8x6:
- Q_FALLTHROUGH();
case QRhiTexture::ASTC_8x8:
- Q_FALLTHROUGH();
case QRhiTexture::ASTC_10x5:
- Q_FALLTHROUGH();
case QRhiTexture::ASTC_10x6:
- Q_FALLTHROUGH();
case QRhiTexture::ASTC_10x8:
- Q_FALLTHROUGH();
case QRhiTexture::ASTC_10x10:
- Q_FALLTHROUGH();
case QRhiTexture::ASTC_12x10:
- Q_FALLTHROUGH();
case QRhiTexture::ASTC_12x12:
qWarning("QRhiD3D11 does not support ASTC textures");
return DXGI_FORMAT_R8G8B8A8_UNORM;
@@ -1212,7 +1186,6 @@ static inline bool isDepthTextureFormat(QRhiTexture::Format format)
{
switch (format) {
case QRhiTexture::Format::D16:
- Q_FALLTHROUGH();
case QRhiTexture::Format::D32F:
return true;
@@ -1878,9 +1851,7 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD)
}
break;
case QRhiShaderResourceBinding::ImageLoad:
- Q_FALLTHROUGH();
case QRhiShaderResourceBinding::ImageStore:
- Q_FALLTHROUGH();
case QRhiShaderResourceBinding::ImageLoadStore:
{
QD3D11Texture *texD = QRHI_RES(QD3D11Texture, b->u.simage.tex);
@@ -1896,9 +1867,7 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD)
}
break;
case QRhiShaderResourceBinding::BufferLoad:
- Q_FALLTHROUGH();
case QRhiShaderResourceBinding::BufferStore:
- Q_FALLTHROUGH();
case QRhiShaderResourceBinding::BufferLoadStore:
{
QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, b->u.sbuf.buf);
@@ -2674,8 +2643,6 @@ bool QD3D11Texture::finishBuild()
return false;
}
- nativeHandlesStruct.texture = tex;
-
generation += 1;
return true;
}
@@ -2741,16 +2708,16 @@ bool QD3D11Texture::build()
return true;
}
-bool QD3D11Texture::buildFrom(const QRhiNativeHandles *src)
+bool QD3D11Texture::buildFrom(QRhiTexture::NativeTexture src)
{
- const QRhiD3D11TextureNativeHandles *h = static_cast<const QRhiD3D11TextureNativeHandles *>(src);
- if (!h || !h->texture)
+ auto *srcTex = static_cast<ID3D11Texture2D * const *>(src.object);
+ if (!srcTex || !*srcTex)
return false;
if (!prepareBuild())
return false;
- tex = static_cast<ID3D11Texture2D *>(h->texture);
+ tex = *srcTex;
if (!finishBuild())
return false;
@@ -2764,9 +2731,9 @@ bool QD3D11Texture::buildFrom(const QRhiNativeHandles *src)
return true;
}
-const QRhiNativeHandles *QD3D11Texture::nativeHandles()
+QRhiTexture::NativeTexture QD3D11Texture::nativeTexture()
{
- return &nativeHandlesStruct;
+ return {&tex, 0};
}
ID3D11UnorderedAccessView *QD3D11Texture::unorderedAccessViewForLevel(int level)
@@ -2801,8 +2768,8 @@ ID3D11UnorderedAccessView *QD3D11Texture::unorderedAccessViewForLevel(int level)
}
QD3D11Sampler::QD3D11Sampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
- AddressMode u, AddressMode v)
- : QRhiSampler(rhi, magFilter, minFilter, mipmapMode, u, v)
+ AddressMode u, AddressMode v, AddressMode w)
+ : QRhiSampler(rhi, magFilter, minFilter, mipmapMode, u, v, w)
{
}
@@ -2862,12 +2829,8 @@ static inline D3D11_TEXTURE_ADDRESS_MODE toD3DAddressMode(QRhiSampler::AddressMo
return D3D11_TEXTURE_ADDRESS_WRAP;
case QRhiSampler::ClampToEdge:
return D3D11_TEXTURE_ADDRESS_CLAMP;
- case QRhiSampler::Border:
- return D3D11_TEXTURE_ADDRESS_BORDER;
case QRhiSampler::Mirror:
return D3D11_TEXTURE_ADDRESS_MIRROR;
- case QRhiSampler::MirrorOnce:
- return D3D11_TEXTURE_ADDRESS_MIRROR_ONCE;
default:
Q_UNREACHABLE();
return D3D11_TEXTURE_ADDRESS_CLAMP;
@@ -2944,6 +2907,12 @@ void QD3D11RenderPassDescriptor::release()
// nothing to do here
}
+bool QD3D11RenderPassDescriptor::isCompatible(const QRhiRenderPassDescriptor *other) const
+{
+ Q_UNUSED(other);
+ return true;
+}
+
QD3D11ReferenceRenderTarget::QD3D11ReferenceRenderTarget(QRhiImplementation *rhi)
: QRhiRenderTarget(rhi),
d(rhi)
@@ -3367,11 +3336,9 @@ static inline D3D11_BLEND toD3DBlendFactor(QRhiGraphicsPipeline::BlendFactor f)
case QRhiGraphicsPipeline::OneMinusDstAlpha:
return D3D11_BLEND_INV_DEST_ALPHA;
case QRhiGraphicsPipeline::ConstantColor:
- Q_FALLTHROUGH();
case QRhiGraphicsPipeline::ConstantAlpha:
return D3D11_BLEND_BLEND_FACTOR;
case QRhiGraphicsPipeline::OneMinusConstantColor:
- Q_FALLTHROUGH();
case QRhiGraphicsPipeline::OneMinusConstantAlpha:
return D3D11_BLEND_INV_BLEND_FACTOR;
case QRhiGraphicsPipeline::SrcAlphaSaturate:
diff --git a/src/gui/rhi/qrhid3d11_p.h b/src/gui/rhi/qrhid3d11_p.h
index 5df1843b1e..aba0f37ee7 100644
--- a/src/gui/rhi/qrhid3d11_p.h
+++ b/src/gui/rhi/qrhid3d11_p.h
@@ -69,11 +69,6 @@ struct Q_GUI_EXPORT QRhiD3D11NativeHandles : public QRhiNativeHandles
void *context = nullptr;
};
-struct Q_GUI_EXPORT QRhiD3D11TextureNativeHandles : public QRhiNativeHandles
-{
- void *texture = nullptr; // ID3D11Texture2D*
-};
-
QT_END_NAMESPACE
#endif
diff --git a/src/gui/rhi/qrhid3d11_p_p.h b/src/gui/rhi/qrhid3d11_p_p.h
index 26de34ae0a..c3a4021241 100644
--- a/src/gui/rhi/qrhid3d11_p_p.h
+++ b/src/gui/rhi/qrhid3d11_p_p.h
@@ -99,8 +99,8 @@ struct QD3D11Texture : public QRhiTexture
~QD3D11Texture();
void release() override;
bool build() override;
- bool buildFrom(const QRhiNativeHandles *src) override;
- const QRhiNativeHandles *nativeHandles() override;
+ bool buildFrom(NativeTexture src) override;
+ NativeTexture nativeTexture() override;
bool prepareBuild(QSize *adjustedSize = nullptr);
bool finishBuild();
@@ -112,7 +112,6 @@ struct QD3D11Texture : public QRhiTexture
DXGI_FORMAT dxgiFormat;
uint mipLevelCount = 0;
DXGI_SAMPLE_DESC sampleDesc;
- QRhiD3D11TextureNativeHandles nativeHandlesStruct;
ID3D11UnorderedAccessView *perLevelViews[QRhi::MAX_LEVELS];
uint generation = 0;
friend class QRhiD3D11;
@@ -121,7 +120,7 @@ struct QD3D11Texture : public QRhiTexture
struct QD3D11Sampler : public QRhiSampler
{
QD3D11Sampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
- AddressMode u, AddressMode v);
+ AddressMode u, AddressMode v, AddressMode w);
~QD3D11Sampler();
void release() override;
bool build() override;
@@ -136,6 +135,7 @@ struct QD3D11RenderPassDescriptor : public QRhiRenderPassDescriptor
QD3D11RenderPassDescriptor(QRhiImplementation *rhi);
~QD3D11RenderPassDescriptor();
void release() override;
+ bool isCompatible(const QRhiRenderPassDescriptor *other) const override;
};
struct QD3D11RenderTargetData
@@ -559,9 +559,12 @@ public:
const QSize &pixelSize,
int sampleCount,
QRhiTexture::Flags flags) override;
- QRhiSampler *createSampler(QRhiSampler::Filter magFilter, QRhiSampler::Filter minFilter,
+ QRhiSampler *createSampler(QRhiSampler::Filter magFilter,
+ QRhiSampler::Filter minFilter,
QRhiSampler::Filter mipmapMode,
- QRhiSampler:: AddressMode u, QRhiSampler::AddressMode v) override;
+ QRhiSampler:: AddressMode u,
+ QRhiSampler::AddressMode v,
+ QRhiSampler::AddressMode w) override;
QRhiTextureRenderTarget *createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc,
QRhiTextureRenderTarget::Flags flags) override;
diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp
index b394354787..2620cc4d7b 100644
--- a/src/gui/rhi/qrhigles2.cpp
+++ b/src/gui/rhi/qrhigles2.cpp
@@ -137,13 +137,6 @@ QT_BEGIN_NAMESPACE
\brief Holds the OpenGL context used by the QRhi.
*/
-/*!
- \class QRhiGles2TextureNativeHandles
- \internal
- \inmodule QtGui
- \brief Holds the OpenGL texture object that is backing a QRhiTexture instance.
- */
-
#ifndef GL_BGRA
#define GL_BGRA 0x80E1
#endif
@@ -172,6 +165,14 @@ QT_BEGIN_NAMESPACE
#define GL_RGBA16F 0x881A
#endif
+#ifndef GL_R16F
+#define GL_R16F 0x822D
+#endif
+
+#ifndef GL_R32F
+#define GL_R32F 0x822E
+#endif
+
#ifndef GL_HALF_FLOAT
#define GL_HALF_FLOAT 0x140B
#endif
@@ -268,6 +269,14 @@ QT_BEGIN_NAMESPACE
#define GL_ALL_BARRIER_BITS 0xFFFFFFFF
#endif
+#ifndef GL_SHADER_IMAGE_ACCESS_BARRIER_BIT
+#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 0x00000020
+#endif
+
+#ifndef GL_SHADER_STORAGE_BARRIER_BIT
+#define GL_SHADER_STORAGE_BARRIER_BIT 0x00002000
+#endif
+
#ifndef GL_VERTEX_PROGRAM_POINT_SIZE
#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642
#endif
@@ -688,7 +697,6 @@ bool QRhiGles2::isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture
switch (format) {
case QRhiTexture::D16:
- Q_FALLTHROUGH();
case QRhiTexture::D32F:
return caps.depthTexture;
@@ -702,10 +710,13 @@ bool QRhiGles2::isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture
return caps.r16Format;
case QRhiTexture::RGBA16F:
- Q_FALLTHROUGH();
case QRhiTexture::RGBA32F:
return caps.floatFormats;
+ case QRhiTexture::R16F:
+ case QRhiTexture::R32F:
+ return caps.floatFormats;
+
default:
break;
}
@@ -827,9 +838,9 @@ QRhiTexture *QRhiGles2::createTexture(QRhiTexture::Format format, const QSize &p
QRhiSampler *QRhiGles2::createSampler(QRhiSampler::Filter magFilter, QRhiSampler::Filter minFilter,
QRhiSampler::Filter mipmapMode,
- QRhiSampler::AddressMode u, QRhiSampler::AddressMode v)
+ QRhiSampler::AddressMode u, QRhiSampler::AddressMode v, QRhiSampler::AddressMode w)
{
- return new QGles2Sampler(this, magFilter, minFilter, mipmapMode, u, v);
+ return new QGles2Sampler(this, magFilter, minFilter, mipmapMode, u, v, w);
}
QRhiTextureRenderTarget *QRhiGles2::createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc,
@@ -906,9 +917,7 @@ void QRhiGles2::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind
QRhiPassResourceTracker::toPassTrackerTextureStage(b->stage));
break;
case QRhiShaderResourceBinding::ImageLoad:
- Q_FALLTHROUGH();
case QRhiShaderResourceBinding::ImageStore:
- Q_FALLTHROUGH();
case QRhiShaderResourceBinding::ImageLoadStore:
{
QGles2Texture *texD = QRHI_RES(QGles2Texture, b->u.simage.tex);
@@ -924,9 +933,7 @@ void QRhiGles2::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind
}
break;
case QRhiShaderResourceBinding::BufferLoad:
- Q_FALLTHROUGH();
case QRhiShaderResourceBinding::BufferStore:
- Q_FALLTHROUGH();
case QRhiShaderResourceBinding::BufferLoadStore:
{
QGles2Buffer *bufD = QRHI_RES(QGles2Buffer, b->u.sbuf.buf);
@@ -1308,6 +1315,21 @@ QRhi::FrameOpResult QRhiGles2::finish()
return QRhi::FrameOpSuccess;
}
+static bool bufferAccessIsWrite(QGles2Buffer::Access access)
+{
+ return access == QGles2Buffer::AccessStorageWrite
+ || access == QGles2Buffer::AccessStorageReadWrite
+ || access == QGles2Buffer::AccessUpdate;
+}
+
+static bool textureAccessIsWrite(QGles2Texture::Access access)
+{
+ return access == QGles2Texture::AccessStorageWrite
+ || access == QGles2Texture::AccessStorageReadWrite
+ || access == QGles2Texture::AccessUpdate
+ || access == QGles2Texture::AccessFramebuffer;
+}
+
void QRhiGles2::trackedBufferBarrier(QGles2CommandBuffer *cbD, QGles2Buffer *bufD, QGles2Buffer::Access access)
{
Q_ASSERT(cbD->recordingPass == QGles2CommandBuffer::NoPass); // this is for resource updates only
@@ -1315,7 +1337,7 @@ void QRhiGles2::trackedBufferBarrier(QGles2CommandBuffer *cbD, QGles2Buffer *buf
if (access == prevAccess)
return;
- if (prevAccess == QGles2Buffer::AccessStorageWrite || prevAccess == QGles2Buffer::AccessStorageReadWrite) {
+ if (bufferAccessIsWrite(prevAccess)) {
// Generating the minimal barrier set is way too complicated to do
// correctly (prevAccess is overwritten so we won't have proper
// tracking across multiple passes) so setting all barrier bits will do
@@ -1336,7 +1358,7 @@ void QRhiGles2::trackedImageBarrier(QGles2CommandBuffer *cbD, QGles2Texture *tex
if (access == prevAccess)
return;
- if (prevAccess == QGles2Texture::AccessStorageWrite || prevAccess == QGles2Texture::AccessStorageReadWrite) {
+ if (textureAccessIsWrite(prevAccess)) {
QGles2CommandBuffer::Command cmd;
cmd.cmd = QGles2CommandBuffer::Command::Barrier;
cmd.args.barrier.barriers = GL_ALL_BARRIER_BITS;
@@ -1661,11 +1683,8 @@ static inline GLenum toGlBlendFactor(QRhiGraphicsPipeline::BlendFactor f)
case QRhiGraphicsPipeline::SrcAlphaSaturate:
return GL_SRC_ALPHA_SATURATE;
case QRhiGraphicsPipeline::Src1Color:
- Q_FALLTHROUGH();
case QRhiGraphicsPipeline::OneMinusSrc1Color:
- Q_FALLTHROUGH();
case QRhiGraphicsPipeline::Src1Alpha:
- Q_FALLTHROUGH();
case QRhiGraphicsPipeline::OneMinusSrc1Alpha:
qWarning("Unsupported blend factor %d", f);
return GL_ZERO;
@@ -1785,11 +1804,6 @@ static inline GLenum toGlWrapMode(QRhiSampler::AddressMode m)
return GL_CLAMP_TO_EDGE;
case QRhiSampler::Mirror:
return GL_MIRRORED_REPEAT;
- case QRhiSampler::MirrorOnce:
- Q_FALLTHROUGH();
- case QRhiSampler::Border:
- qWarning("Unsupported wrap mode %d", m);
- return GL_CLAMP_TO_EDGE;
default:
Q_UNREACHABLE();
return GL_CLAMP_TO_EDGE;
@@ -2282,26 +2296,21 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
// subsequent pass.
for (auto it = tracker.cbeginBuffers(), itEnd = tracker.cendBuffers(); it != itEnd; ++it) {
QGles2Buffer::Access accessBeforePass = QGles2Buffer::Access(it->stateAtPassBegin.access);
- if (accessBeforePass == QGles2Buffer::AccessStorageWrite
- || accessBeforePass == QGles2Buffer::AccessStorageReadWrite)
- {
+ if (bufferAccessIsWrite(accessBeforePass))
barriers |= GL_ALL_BARRIER_BITS;
- }
}
for (auto it = tracker.cbeginTextures(), itEnd = tracker.cendTextures(); it != itEnd; ++it) {
QGles2Texture::Access accessBeforePass = QGles2Texture::Access(it->stateAtPassBegin.access);
- if (accessBeforePass == QGles2Texture::AccessStorageWrite
- || accessBeforePass == QGles2Texture::AccessStorageReadWrite)
- {
+ if (textureAccessIsWrite(accessBeforePass))
barriers |= GL_ALL_BARRIER_BITS;
- }
}
- if (barriers)
+ if (barriers && caps.compute)
f->glMemoryBarrier(barriers);
}
break;
case QGles2CommandBuffer::Command::Barrier:
- f->glMemoryBarrier(cmd.args.barrier.barriers);
+ if (caps.compute)
+ f->glMemoryBarrier(cmd.args.barrier.barriers);
break;
default:
break;
@@ -2383,12 +2392,23 @@ void QRhiGles2::executeBindGraphicsPipeline(QRhiGraphicsPipeline *ps)
f->glUseProgram(psD->program);
}
+static inline void qrhi_std140_to_packed(float *dst, int vecSize, int elemCount, const void *src)
+{
+ const float *p = reinterpret_cast<const float *>(src);
+ for (int i = 0; i < elemCount; ++i) {
+ for (int j = 0; j < vecSize; ++j)
+ dst[vecSize * i + j] = *p++;
+ p += 4 - vecSize;
+ }
+}
+
void QRhiGles2::bindShaderResources(QRhiGraphicsPipeline *maybeGraphicsPs, QRhiComputePipeline *maybeComputePs,
QRhiShaderResourceBindings *srb,
const uint *dynOfsPairs, int dynOfsCount)
{
QGles2ShaderResourceBindings *srbD = QRHI_RES(QGles2ShaderResourceBindings, srb);
int texUnit = 0;
+ QVarLengthArray<float, 256> packedFloatArray;
for (int i = 0, ie = srbD->m_bindings.count(); i != ie; ++i) {
const QRhiShaderResourceBinding::Data *b = srbD->m_bindings.at(i).data();
@@ -2416,24 +2436,78 @@ void QRhiGles2::bindShaderResources(QRhiGraphicsPipeline *maybeGraphicsPs, QRhiC
// so this should not cause unaligned reads
const void *src = bufView.constData() + uniform.offset;
+ if (uniform.arrayDim > 0
+ && uniform.type != QShaderDescription::Float
+ && uniform.type != QShaderDescription::Vec2
+ && uniform.type != QShaderDescription::Vec3
+ && uniform.type != QShaderDescription::Vec4)
+ {
+ qWarning("Uniform with buffer binding %d, buffer offset %d, type %d is an array, "
+ "but arrays are only supported for float, vec2, vec3, and vec4. "
+ "Only the first element will be set.",
+ uniform.binding, uniform.offset, uniform.type);
+ }
+
+ // Our input is an std140 layout uniform block. See
+ // "Standard Uniform Block Layout" in section 7.6.2.2 of
+ // the OpenGL spec. This has some peculiar alignment
+ // requirements, which is not what glUniform* wants. Hence
+ // the unpacking/repacking for arrays and certain types.
+
switch (uniform.type) {
case QShaderDescription::Float:
- f->glUniform1f(uniform.glslLocation, *reinterpret_cast<const float *>(src));
+ {
+ const int elemCount = uniform.arrayDim;
+ if (elemCount < 1) {
+ f->glUniform1f(uniform.glslLocation, *reinterpret_cast<const float *>(src));
+ } else {
+ // input is 16 bytes per element as per std140, have to convert to packed
+ packedFloatArray.resize(elemCount);
+ qrhi_std140_to_packed(packedFloatArray.data(), 1, elemCount, src);
+ f->glUniform1fv(uniform.glslLocation, elemCount, packedFloatArray.constData());
+ }
+ }
break;
case QShaderDescription::Vec2:
- f->glUniform2fv(uniform.glslLocation, 1, reinterpret_cast<const float *>(src));
+ {
+ const int elemCount = uniform.arrayDim;
+ if (elemCount < 1) {
+ f->glUniform2fv(uniform.glslLocation, 1, reinterpret_cast<const float *>(src));
+ } else {
+ packedFloatArray.resize(elemCount * 2);
+ qrhi_std140_to_packed(packedFloatArray.data(), 2, elemCount, src);
+ f->glUniform2fv(uniform.glslLocation, elemCount, packedFloatArray.constData());
+ }
+ }
break;
case QShaderDescription::Vec3:
- f->glUniform3fv(uniform.glslLocation, 1, reinterpret_cast<const float *>(src));
+ {
+ const int elemCount = uniform.arrayDim;
+ if (elemCount < 1) {
+ f->glUniform3fv(uniform.glslLocation, 1, reinterpret_cast<const float *>(src));
+ } else {
+ packedFloatArray.resize(elemCount * 3);
+ qrhi_std140_to_packed(packedFloatArray.data(), 3, elemCount, src);
+ f->glUniform3fv(uniform.glslLocation, elemCount, packedFloatArray.constData());
+ }
+ }
break;
case QShaderDescription::Vec4:
- f->glUniform4fv(uniform.glslLocation, 1, reinterpret_cast<const float *>(src));
+ f->glUniform4fv(uniform.glslLocation, qMax(1, uniform.arrayDim), reinterpret_cast<const float *>(src));
break;
case QShaderDescription::Mat2:
f->glUniformMatrix2fv(uniform.glslLocation, 1, GL_FALSE, reinterpret_cast<const float *>(src));
break;
case QShaderDescription::Mat3:
- f->glUniformMatrix3fv(uniform.glslLocation, 1, GL_FALSE, reinterpret_cast<const float *>(src));
+ {
+ // 4 floats per column (or row, if row-major)
+ float mat[9];
+ const float *srcMat = reinterpret_cast<const float *>(src);
+ memcpy(mat, srcMat, 3 * sizeof(float));
+ memcpy(mat + 3, srcMat + 4, 3 * sizeof(float));
+ memcpy(mat + 6, srcMat + 8, 3 * sizeof(float));
+ f->glUniformMatrix3fv(uniform.glslLocation, 1, GL_FALSE, mat);
+ }
break;
case QShaderDescription::Mat4:
f->glUniformMatrix4fv(uniform.glslLocation, 1, GL_FALSE, reinterpret_cast<const float *>(src));
@@ -2474,8 +2548,9 @@ void QRhiGles2::bindShaderResources(QRhiGraphicsPipeline *maybeGraphicsPs, QRhiC
case QShaderDescription::Bool4:
f->glUniform4iv(uniform.glslLocation, 1, reinterpret_cast<const qint32 *>(src));
break;
- // ### more types
default:
+ qWarning("Uniform with buffer binding %d, buffer offset %d has unsupported type %d",
+ uniform.binding, uniform.offset, uniform.type);
break;
}
}
@@ -2519,9 +2594,7 @@ void QRhiGles2::bindShaderResources(QRhiGraphicsPipeline *maybeGraphicsPs, QRhiC
}
break;
case QRhiShaderResourceBinding::ImageLoad:
- Q_FALLTHROUGH();
case QRhiShaderResourceBinding::ImageStore:
- Q_FALLTHROUGH();
case QRhiShaderResourceBinding::ImageLoadStore:
{
QGles2Texture *texD = QRHI_RES(QGles2Texture, b->u.simage.tex);
@@ -2537,9 +2610,7 @@ void QRhiGles2::bindShaderResources(QRhiGraphicsPipeline *maybeGraphicsPs, QRhiC
}
break;
case QRhiShaderResourceBinding::BufferLoad:
- Q_FALLTHROUGH();
case QRhiShaderResourceBinding::BufferStore:
- Q_FALLTHROUGH();
case QRhiShaderResourceBinding::BufferLoadStore:
{
QGles2Buffer *bufD = QRHI_RES(QGles2Buffer, b->u.sbuf.buf);
@@ -2738,6 +2809,8 @@ void QRhiGles2::beginComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch
cbD->recordingPass = QGles2CommandBuffer::ComputePass;
cbD->resetCachedState();
+
+ cbD->computePassState.reset();
}
void QRhiGles2::endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
@@ -2770,11 +2843,96 @@ void QRhiGles2::setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *p
}
}
+template<typename T>
+inline void qrhigl_accumulateComputeResource(T *writtenResources, QRhiResource *resource,
+ QRhiShaderResourceBinding::Type bindingType,
+ int loadTypeVal, int storeTypeVal, int loadStoreTypeVal)
+{
+ int access = 0;
+ if (bindingType == loadTypeVal) {
+ access = QGles2CommandBuffer::ComputePassState::Read;
+ } else {
+ access = QGles2CommandBuffer::ComputePassState::Write;
+ if (bindingType == loadStoreTypeVal)
+ access |= QGles2CommandBuffer::ComputePassState::Read;
+ }
+ auto it = writtenResources->find(resource);
+ if (it != writtenResources->end())
+ it->first |= access;
+ else if (bindingType == storeTypeVal || bindingType == loadStoreTypeVal)
+ writtenResources->insert(resource, { access, true });
+}
+
void QRhiGles2::dispatch(QRhiCommandBuffer *cb, int x, int y, int z)
{
QGles2CommandBuffer *cbD = QRHI_RES(QGles2CommandBuffer, cb);
Q_ASSERT(cbD->recordingPass == QGles2CommandBuffer::ComputePass);
+ if (cbD->currentComputeSrb) {
+ GLbitfield barriers = 0;
+
+ // The key in the writtenResources map indicates that the resource was
+ // written in a previous dispatch, whereas the value accumulates the
+ // access mask in the current one.
+ for (auto &accessAndIsNewFlag : cbD->computePassState.writtenResources)
+ accessAndIsNewFlag = { 0, false };
+
+ QGles2ShaderResourceBindings *srbD = QRHI_RES(QGles2ShaderResourceBindings, cbD->currentComputeSrb);
+ const int bindingCount = srbD->m_bindings.count();
+ for (int i = 0; i < bindingCount; ++i) {
+ const QRhiShaderResourceBinding::Data *b = srbD->m_bindings.at(i).data();
+ switch (b->type) {
+ case QRhiShaderResourceBinding::ImageLoad:
+ case QRhiShaderResourceBinding::ImageStore:
+ case QRhiShaderResourceBinding::ImageLoadStore:
+ qrhigl_accumulateComputeResource(&cbD->computePassState.writtenResources,
+ b->u.simage.tex,
+ b->type,
+ QRhiShaderResourceBinding::ImageLoad,
+ QRhiShaderResourceBinding::ImageStore,
+ QRhiShaderResourceBinding::ImageLoadStore);
+ break;
+ case QRhiShaderResourceBinding::BufferLoad:
+ case QRhiShaderResourceBinding::BufferStore:
+ case QRhiShaderResourceBinding::BufferLoadStore:
+ qrhigl_accumulateComputeResource(&cbD->computePassState.writtenResources,
+ b->u.sbuf.buf,
+ b->type,
+ QRhiShaderResourceBinding::BufferLoad,
+ QRhiShaderResourceBinding::BufferStore,
+ QRhiShaderResourceBinding::BufferLoadStore);
+ break;
+ default:
+ break;
+ }
+ }
+
+ for (auto it = cbD->computePassState.writtenResources.begin(); it != cbD->computePassState.writtenResources.end(); ) {
+ const int accessInThisDispatch = it->first;
+ const bool isNewInThisDispatch = it->second;
+ if (accessInThisDispatch && !isNewInThisDispatch) {
+ if (it.key()->resourceType() == QRhiResource::Texture)
+ barriers |= GL_SHADER_IMAGE_ACCESS_BARRIER_BIT;
+ else
+ barriers |= GL_SHADER_STORAGE_BARRIER_BIT;
+ }
+ // Anything that was previously written, but is only read now, can be
+ // removed from the written list (because that previous write got a
+ // corresponding barrier now).
+ if (accessInThisDispatch == QGles2CommandBuffer::ComputePassState::Read)
+ it = cbD->computePassState.writtenResources.erase(it);
+ else
+ ++it;
+ }
+
+ if (barriers) {
+ QGles2CommandBuffer::Command cmd;
+ cmd.cmd = QGles2CommandBuffer::Command::Barrier;
+ cmd.args.barrier.barriers = barriers;
+ cbD->commands.append(cmd);
+ }
+ }
+
QGles2CommandBuffer::Command cmd;
cmd.cmd = QGles2CommandBuffer::Command::Dispatch;
cmd.args.dispatch.x = GLuint(x);
@@ -2924,21 +3082,65 @@ bool QRhiGles2::linkProgram(GLuint program)
return true;
}
-void QRhiGles2::gatherUniforms(GLuint program, const QShaderDescription::UniformBlock &ub,
+void QRhiGles2::registerUniformIfActive(const QShaderDescription::BlockVariable &var,
+ const QByteArray &namePrefix,
+ int binding,
+ int baseOffset,
+ GLuint program,
+ QVector<QGles2UniformDescription> *dst)
+{
+ if (var.type == QShaderDescription::Struct) {
+ qWarning("Nested structs are not supported at the moment. '%s' ignored.",
+ qPrintable(var.name));
+ return;
+ }
+ QGles2UniformDescription uniform;
+ uniform.type = var.type;
+ const QByteArray name = namePrefix + var.name.toUtf8();
+ uniform.glslLocation = f->glGetUniformLocation(program, name.constData());
+ if (uniform.glslLocation >= 0) {
+ if (var.arrayDims.count() > 1) {
+ qWarning("Array '%s' has more than one dimension. This is not supported.",
+ qPrintable(var.name));
+ return;
+ }
+ uniform.binding = binding;
+ uniform.offset = uint(baseOffset + var.offset);
+ uniform.size = var.size;
+ uniform.arrayDim = var.arrayDims.isEmpty() ? 0 : var.arrayDims.first();
+ dst->append(uniform);
+ }
+}
+
+void QRhiGles2::gatherUniforms(GLuint program,
+ const QShaderDescription::UniformBlock &ub,
QVector<QGles2UniformDescription> *dst)
{
- const QByteArray prefix = ub.structName.toUtf8() + '.';
+ QByteArray prefix = ub.structName.toUtf8() + '.';
for (const QShaderDescription::BlockVariable &blockMember : ub.members) {
- // ### no array support for now
- QGles2UniformDescription uniform;
- uniform.type = blockMember.type;
- const QByteArray name = prefix + blockMember.name.toUtf8();
- uniform.glslLocation = f->glGetUniformLocation(program, name.constData());
- if (uniform.glslLocation >= 0) {
- uniform.binding = ub.binding;
- uniform.offset = uint(blockMember.offset);
- uniform.size = blockMember.size;
- dst->append(uniform);
+ if (blockMember.type == QShaderDescription::Struct) {
+ prefix += blockMember.name.toUtf8();
+ const int baseOffset = blockMember.offset;
+ if (blockMember.arrayDims.isEmpty()) {
+ for (const QShaderDescription::BlockVariable &structMember : blockMember.structMembers)
+ registerUniformIfActive(structMember, prefix, ub.binding, baseOffset, program, dst);
+ } else {
+ if (blockMember.arrayDims.count() > 1) {
+ qWarning("Array of struct '%s' has more than one dimension. Only the first dimension is used.",
+ qPrintable(blockMember.name));
+ }
+ const int dim = blockMember.arrayDims.first();
+ const int elemSize = blockMember.size / dim;
+ int elemOffset = baseOffset;
+ for (int di = 0; di < dim; ++di) {
+ const QByteArray arrayPrefix = prefix + '[' + QByteArray::number(di) + ']' + '.';
+ for (const QShaderDescription::BlockVariable &structMember : blockMember.structMembers)
+ registerUniformIfActive(structMember, arrayPrefix, ub.binding, elemOffset, program, dst);
+ elemOffset += elemSize;
+ }
+ }
+ } else {
+ registerUniformIfActive(blockMember, prefix, ub.binding, 0, program, dst);
}
}
}
@@ -3219,7 +3421,6 @@ void QGles2Texture::release()
texture = 0;
specified = false;
- nativeHandlesStruct.texture = 0;
QRHI_RES_RHI(QRhiGles2);
if (owns)
@@ -3300,6 +3501,18 @@ bool QGles2Texture::prepareBuild(QSize *adjustedSize)
glformat = GL_RGBA;
gltype = GL_FLOAT;
break;
+ case QRhiTexture::R16F:
+ glintformat = GL_R16F;
+ glsizedintformat = glintformat;
+ glformat = GL_RED;
+ gltype = GL_HALF_FLOAT;
+ break;
+ case QRhiTexture::R32F:
+ glintformat = GL_R32F;
+ glsizedintformat = glintformat;
+ glformat = GL_RED;
+ gltype = GL_FLOAT;
+ break;
case QRhiTexture::D16:
glintformat = GL_DEPTH_COMPONENT16;
glsizedintformat = glintformat;
@@ -3378,23 +3591,22 @@ bool QGles2Texture::build()
QRHI_PROF_F(newTexture(this, true, mipLevelCount, isCube ? 6 : 1, 1));
owns = true;
- nativeHandlesStruct.texture = texture;
generation += 1;
rhiD->registerResource(this);
return true;
}
-bool QGles2Texture::buildFrom(const QRhiNativeHandles *src)
+bool QGles2Texture::buildFrom(QRhiTexture::NativeTexture src)
{
- const QRhiGles2TextureNativeHandles *h = static_cast<const QRhiGles2TextureNativeHandles *>(src);
- if (!h || !h->texture)
+ const uint *textureId = static_cast<const uint *>(src.object);
+ if (!textureId || !*textureId)
return false;
if (!prepareBuild())
return false;
- texture = h->texture;
+ texture = *textureId;
specified = true;
QRHI_RES_RHI(QRhiGles2);
@@ -3402,21 +3614,20 @@ bool QGles2Texture::buildFrom(const QRhiNativeHandles *src)
QRHI_PROF_F(newTexture(this, false, mipLevelCount, m_flags.testFlag(CubeMap) ? 6 : 1, 1));
owns = false;
- nativeHandlesStruct.texture = texture;
generation += 1;
rhiD->registerResource(this);
return true;
}
-const QRhiNativeHandles *QGles2Texture::nativeHandles()
+QRhiTexture::NativeTexture QGles2Texture::nativeTexture()
{
- return &nativeHandlesStruct;
+ return {&texture, 0};
}
QGles2Sampler::QGles2Sampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
- AddressMode u, AddressMode v)
- : QRhiSampler(rhi, magFilter, minFilter, mipmapMode, u, v)
+ AddressMode u, AddressMode v, AddressMode w)
+ : QRhiSampler(rhi, magFilter, minFilter, mipmapMode, u, v, w)
{
}
@@ -3459,6 +3670,12 @@ void QGles2RenderPassDescriptor::release()
// nothing to do here
}
+bool QGles2RenderPassDescriptor::isCompatible(const QRhiRenderPassDescriptor *other) const
+{
+ Q_UNUSED(other);
+ return true;
+}
+
QGles2ReferenceRenderTarget::QGles2ReferenceRenderTarget(QRhiImplementation *rhi)
: QRhiRenderTarget(rhi),
d(rhi)
diff --git a/src/gui/rhi/qrhigles2_p.h b/src/gui/rhi/qrhigles2_p.h
index 7f7c8b4c40..8d8f0c7396 100644
--- a/src/gui/rhi/qrhigles2_p.h
+++ b/src/gui/rhi/qrhigles2_p.h
@@ -74,11 +74,6 @@ struct Q_GUI_EXPORT QRhiGles2NativeHandles : public QRhiNativeHandles
QOpenGLContext *context = nullptr;
};
-struct Q_GUI_EXPORT QRhiGles2TextureNativeHandles : public QRhiNativeHandles
-{
- uint texture = 0;
-};
-
QT_END_NAMESPACE
#endif
diff --git a/src/gui/rhi/qrhigles2_p_p.h b/src/gui/rhi/qrhigles2_p_p.h
index cc945876e6..00caf40118 100644
--- a/src/gui/rhi/qrhigles2_p_p.h
+++ b/src/gui/rhi/qrhigles2_p_p.h
@@ -132,8 +132,8 @@ struct QGles2Texture : public QRhiTexture
~QGles2Texture();
void release() override;
bool build() override;
- bool buildFrom(const QRhiNativeHandles *src) override;
- const QRhiNativeHandles *nativeHandles() override;
+ bool buildFrom(NativeTexture src) override;
+ NativeTexture nativeTexture() override;
bool prepareBuild(QSize *adjustedSize = nullptr);
@@ -147,7 +147,7 @@ struct QGles2Texture : public QRhiTexture
QGles2SamplerData samplerState;
bool specified = false;
int mipLevelCount = 0;
- QRhiGles2TextureNativeHandles nativeHandlesStruct;
+
enum Access {
AccessNone,
AccessSample,
@@ -170,7 +170,7 @@ struct QGles2Texture : public QRhiTexture
struct QGles2Sampler : public QRhiSampler
{
QGles2Sampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
- AddressMode u, AddressMode v);
+ AddressMode u, AddressMode v, AddressMode w);
~QGles2Sampler();
void release() override;
bool build() override;
@@ -185,6 +185,7 @@ struct QGles2RenderPassDescriptor : public QRhiRenderPassDescriptor
QGles2RenderPassDescriptor(QRhiImplementation *rhi);
~QGles2RenderPassDescriptor();
void release() override;
+ bool isCompatible(const QRhiRenderPassDescriptor *other) const override;
};
struct QGles2RenderTargetData
@@ -249,6 +250,7 @@ struct QGles2UniformDescription
int binding;
uint offset;
int size;
+ int arrayDim;
};
Q_DECLARE_TYPEINFO(QGles2UniformDescription, Q_MOVABLE_TYPE);
@@ -519,6 +521,17 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer
QRhiShaderResourceBindings *currentComputeSrb;
uint currentSrbGeneration;
+ struct ComputePassState {
+ enum Access {
+ Read = 0x01,
+ Write = 0x02
+ };
+ QHash<QRhiResource *, QPair<int, bool> > writtenResources;
+ void reset() {
+ writtenResources.clear();
+ }
+ } computePassState;
+
QVector<QByteArray> dataRetainPool;
QVector<QImage> imageRetainPool;
@@ -600,9 +613,12 @@ public:
const QSize &pixelSize,
int sampleCount,
QRhiTexture::Flags flags) override;
- QRhiSampler *createSampler(QRhiSampler::Filter magFilter, QRhiSampler::Filter minFilter,
+ QRhiSampler *createSampler(QRhiSampler::Filter magFilter,
+ QRhiSampler::Filter minFilter,
QRhiSampler::Filter mipmapMode,
- QRhiSampler:: AddressMode u, QRhiSampler::AddressMode v) override;
+ QRhiSampler:: AddressMode u,
+ QRhiSampler::AddressMode v,
+ QRhiSampler::AddressMode w) override;
QRhiTextureRenderTarget *createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc,
QRhiTextureRenderTarget::Flags flags) override;
@@ -703,7 +719,14 @@ public:
QByteArray shaderSource(const QRhiShaderStage &shaderStage, int *glslVersion);
bool compileShader(GLuint program, const QRhiShaderStage &shaderStage, int *glslVersion);
bool linkProgram(GLuint program);
- void gatherUniforms(GLuint program, const QShaderDescription::UniformBlock &ub,
+ void registerUniformIfActive(const QShaderDescription::BlockVariable &var,
+ const QByteArray &namePrefix,
+ int binding,
+ int baseOffset,
+ GLuint program,
+ QVector<QGles2UniformDescription> *dst);
+ void gatherUniforms(GLuint program,
+ const QShaderDescription::UniformBlock &ub,
QVector<QGles2UniformDescription> *dst);
void gatherSamplers(GLuint program, const QShaderDescription::InOutVariable &v,
QVector<QGles2SamplerDescription> *dst);
diff --git a/src/gui/rhi/qrhimetal.mm b/src/gui/rhi/qrhimetal.mm
index 83fec31081..e7810abb29 100644
--- a/src/gui/rhi/qrhimetal.mm
+++ b/src/gui/rhi/qrhimetal.mm
@@ -41,6 +41,8 @@
#ifdef Q_OS_MACOS
#include <AppKit/AppKit.h>
+#else
+#include <UIKit/UIKit.h>
#endif
#include <Metal/Metal.h>
@@ -112,15 +114,6 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \class QRhiMetalTextureNativeHandles
- \inmodule QtRhi
- \brief Holds the Metal texture object that is backing a QRhiTexture instance.
-
- \note The class uses \c{void *} as the type since including the Objective C
- headers is not acceptable here. The actual type is \c{id<MTLTexture>}.
- */
-
-/*!
\class QRhiMetalCommandBufferNativeHandles
\inmodule QtRhi
\brief Holds the MTLCommandBuffer and MTLRenderCommandEncoder objects that are backing a QRhiCommandBuffer.
@@ -318,7 +311,13 @@ struct QMetalComputePipelineData
struct QMetalSwapChainData
{
+ // The iOS simulator's headers mark CAMetalLayer as iOS 13.0+ only.
+ // (for real device SDKs it is 8.0+)
+#ifdef TARGET_IPHONE_SIMULATOR
+ API_AVAILABLE(ios(13.0)) CAMetalLayer *layer = nullptr;
+#else
CAMetalLayer *layer = nullptr;
+#endif
id<CAMetalDrawable> curDrawable;
dispatch_semaphore_t sem[QMTL_FRAMES_IN_FLIGHT];
MTLRenderPassDescriptor *rp = nullptr;
@@ -627,9 +626,9 @@ QRhiTexture *QRhiMetal::createTexture(QRhiTexture::Format format, const QSize &p
QRhiSampler *QRhiMetal::createSampler(QRhiSampler::Filter magFilter, QRhiSampler::Filter minFilter,
QRhiSampler::Filter mipmapMode,
- QRhiSampler::AddressMode u, QRhiSampler::AddressMode v)
+ QRhiSampler::AddressMode u, QRhiSampler::AddressMode v, QRhiSampler::AddressMode w)
{
- return new QMetalSampler(this, magFilter, minFilter, mipmapMode, u, v);
+ return new QMetalSampler(this, magFilter, minFilter, mipmapMode, u, v, w);
}
QRhiTextureRenderTarget *QRhiMetal::createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc,
@@ -665,12 +664,17 @@ static inline int mapBinding(int binding,
BindingType type)
{
const QShader::NativeResourceBindingMap *map = nativeResourceBindingMaps[stageIndex];
- if (map) {
- auto it = map->constFind(binding);
- if (it != map->cend())
- return type == BindingType::Sampler ? it->second : it->first;
- }
- return binding;
+ if (!map || map->isEmpty())
+ return binding; // old QShader versions do not have this map, assume 1:1 mapping then
+
+ auto it = map->constFind(binding);
+ if (it != map->cend())
+ return type == BindingType::Sampler ? it->second : it->first; // may be -1, if the resource is inactive
+
+ // Hitting this path is normal too. It is not given that the resource (for
+ // example, a uniform block) is present in the shaders for all the stages
+ // specified by the visibility mask in the QRhiShaderResourceBinding.
+ return -1;
}
void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD,
@@ -704,16 +708,25 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
}
}
if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) {
- res[VERTEX].buffers.feed(mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf);
- res[VERTEX].bufferOffsets.feed(b->binding, offset);
+ const int nativeBinding = mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Buffer);
+ if (nativeBinding >= 0) {
+ res[VERTEX].buffers.feed(nativeBinding, mtlbuf);
+ res[VERTEX].bufferOffsets.feed(b->binding, offset);
+ }
}
if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
- res[FRAGMENT].buffers.feed(mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf);
- res[FRAGMENT].bufferOffsets.feed(b->binding, offset);
+ const int nativeBinding = mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Buffer);
+ if (nativeBinding >= 0) {
+ res[FRAGMENT].buffers.feed(nativeBinding, mtlbuf);
+ res[FRAGMENT].bufferOffsets.feed(b->binding, offset);
+ }
}
if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
- res[COMPUTE].buffers.feed(mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf);
- res[COMPUTE].bufferOffsets.feed(b->binding, offset);
+ const int nativeBinding = mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Buffer);
+ if (nativeBinding >= 0) {
+ res[COMPUTE].buffers.feed(nativeBinding, mtlbuf);
+ res[COMPUTE].bufferOffsets.feed(b->binding, offset);
+ }
}
}
break;
@@ -722,55 +735,81 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
QMetalTexture *texD = QRHI_RES(QMetalTexture, b->u.stex.tex);
QMetalSampler *samplerD = QRHI_RES(QMetalSampler, b->u.stex.sampler);
if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) {
- res[VERTEX].textures.feed(mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Texture), texD->d->tex);
- res[VERTEX].samplers.feed(mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Sampler), samplerD->d->samplerState);
+ const int nativeBindingTexture = mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Texture);
+ const int nativeBindingSampler = mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Sampler);
+ if (nativeBindingTexture >= 0 && nativeBindingSampler >= 0) {
+ res[VERTEX].textures.feed(nativeBindingTexture, texD->d->tex);
+ res[VERTEX].samplers.feed(nativeBindingSampler, samplerD->d->samplerState);
+ }
}
if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
- res[FRAGMENT].textures.feed(mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Texture), texD->d->tex);
- res[FRAGMENT].samplers.feed(mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Sampler), samplerD->d->samplerState);
+ const int nativeBindingTexture = mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Texture);
+ const int nativeBindingSampler = mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Sampler);
+ if (nativeBindingTexture >= 0 && nativeBindingSampler >= 0) {
+ res[FRAGMENT].textures.feed(nativeBindingTexture, texD->d->tex);
+ res[FRAGMENT].samplers.feed(nativeBindingSampler, samplerD->d->samplerState);
+ }
}
if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
- res[COMPUTE].textures.feed(mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Texture), texD->d->tex);
- res[COMPUTE].samplers.feed(mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Sampler), samplerD->d->samplerState);
+ const int nativeBindingTexture = mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Texture);
+ const int nativeBindingSampler = mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Sampler);
+ if (nativeBindingTexture >= 0 && nativeBindingSampler >= 0) {
+ res[COMPUTE].textures.feed(nativeBindingTexture, texD->d->tex);
+ res[COMPUTE].samplers.feed(nativeBindingSampler, samplerD->d->samplerState);
+ }
}
}
break;
case QRhiShaderResourceBinding::ImageLoad:
- Q_FALLTHROUGH();
case QRhiShaderResourceBinding::ImageStore:
- Q_FALLTHROUGH();
case QRhiShaderResourceBinding::ImageLoadStore:
{
QMetalTexture *texD = QRHI_RES(QMetalTexture, b->u.simage.tex);
id<MTLTexture> t = texD->d->viewForLevel(b->u.simage.level);
- if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage))
- res[VERTEX].textures.feed(mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Texture), t);
- if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage))
- res[FRAGMENT].textures.feed(mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Texture), t);
- if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage))
- res[COMPUTE].textures.feed(mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Texture), t);
+ if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) {
+ const int nativeBinding = mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Texture);
+ if (nativeBinding >= 0)
+ res[VERTEX].textures.feed(nativeBinding, t);
+ }
+ if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
+ const int nativeBinding = mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Texture);
+ if (nativeBinding >= 0)
+ res[FRAGMENT].textures.feed(nativeBinding, t);
+ }
+ if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
+ const int nativeBinding = mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Texture);
+ if (nativeBinding >= 0)
+ res[COMPUTE].textures.feed(nativeBinding, t);
+ }
}
break;
case QRhiShaderResourceBinding::BufferLoad:
- Q_FALLTHROUGH();
case QRhiShaderResourceBinding::BufferStore:
- Q_FALLTHROUGH();
case QRhiShaderResourceBinding::BufferLoadStore:
{
QMetalBuffer *bufD = QRHI_RES(QMetalBuffer, b->u.sbuf.buf);
id<MTLBuffer> mtlbuf = bufD->d->buf[0];
uint offset = uint(b->u.sbuf.offset);
if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) {
- res[VERTEX].buffers.feed(mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf);
- res[VERTEX].bufferOffsets.feed(b->binding, offset);
+ const int nativeBinding = mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Buffer);
+ if (nativeBinding >= 0) {
+ res[VERTEX].buffers.feed(nativeBinding, mtlbuf);
+ res[VERTEX].bufferOffsets.feed(b->binding, offset);
+ }
}
if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
- res[FRAGMENT].buffers.feed(mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf);
- res[FRAGMENT].bufferOffsets.feed(b->binding, offset);
+ const int nativeBinding = mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Buffer);
+ if (nativeBinding >= 0) {
+ res[FRAGMENT].buffers.feed(nativeBinding, mtlbuf);
+ res[FRAGMENT].bufferOffsets.feed(b->binding, offset);
+ }
}
if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
- res[COMPUTE].buffers.feed(mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf);
- res[COMPUTE].bufferOffsets.feed(b->binding, offset);
+ const int nativeBinding = mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Buffer);
+ if (nativeBinding >= 0) {
+ res[COMPUTE].buffers.feed(nativeBinding, mtlbuf);
+ res[COMPUTE].bufferOffsets.feed(b->binding, offset);
+ }
}
}
break;
@@ -953,9 +992,7 @@ void QRhiMetal::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind
}
break;
case QRhiShaderResourceBinding::ImageLoad:
- Q_FALLTHROUGH();
case QRhiShaderResourceBinding::ImageStore:
- Q_FALLTHROUGH();
case QRhiShaderResourceBinding::ImageLoadStore:
{
QMetalTexture *texD = QRHI_RES(QMetalTexture, b->u.simage.tex);
@@ -968,9 +1005,7 @@ void QRhiMetal::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind
}
break;
case QRhiShaderResourceBinding::BufferLoad:
- Q_FALLTHROUGH();
case QRhiShaderResourceBinding::BufferStore:
- Q_FALLTHROUGH();
case QRhiShaderResourceBinding::BufferLoadStore:
{
QMetalBuffer *bufD = QRHI_RES(QMetalBuffer, b->u.sbuf.buf);
@@ -1763,8 +1798,10 @@ void QRhiMetal::executeBufferHostWritesForCurrentFrame(QMetalBuffer *bufD)
if (changeEnd == -1 || u.offset + u.data.size() > changeEnd)
changeEnd = u.offset + u.data.size();
}
+#ifdef Q_OS_MACOS
if (changeBegin >= 0 && bufD->d->managed)
[bufD->d->buf[idx] didModifyRange: NSMakeRange(NSUInteger(changeBegin), NSUInteger(changeEnd - changeBegin))];
+#endif
bufD->d->pendingUpdates[idx].clear();
}
@@ -1798,8 +1835,12 @@ void QRhiMetal::beginPass(QRhiCommandBuffer *cb,
if (color0.needsDrawableForTex || color0.needsDrawableForResolveTex) {
Q_ASSERT(currentSwapChain);
QMetalSwapChain *swapChainD = QRHI_RES(QMetalSwapChain, currentSwapChain);
- if (!swapChainD->d->curDrawable)
- swapChainD->d->curDrawable = [swapChainD->d->layer nextDrawable];
+ if (!swapChainD->d->curDrawable) {
+#ifdef TARGET_IPHONE_SIMULATOR
+ if (@available(ios 13.0, *))
+#endif
+ swapChainD->d->curDrawable = [swapChainD->d->layer nextDrawable];
+ }
if (!swapChainD->d->curDrawable) {
qWarning("No drawable");
return;
@@ -2170,12 +2211,13 @@ bool QMetalRenderBuffer::build()
case DepthStencil:
#ifdef Q_OS_MACOS
desc.storageMode = MTLStorageModePrivate;
+ d->format = rhiD->d->dev.depth24Stencil8PixelFormatSupported
+ ? MTLPixelFormatDepth24Unorm_Stencil8 : MTLPixelFormatDepth32Float_Stencil8;
#else
- desc.storageMode = MTLResourceStorageModeMemoryless;
+ desc.storageMode = MTLStorageModeMemoryless;
transientBacking = true;
+ d->format = MTLPixelFormatDepth32Float_Stencil8;
#endif
- d->format = rhiD->d->dev.depth24Stencil8PixelFormatSupported
- ? MTLPixelFormatDepth24Unorm_Stencil8 : MTLPixelFormatDepth32Float_Stencil8;
desc.pixelFormat = d->format;
break;
case Color:
@@ -2237,7 +2279,6 @@ void QMetalTexture::release()
e.texture.texture = d->owns ? d->tex : nil;
d->tex = nil;
- nativeHandlesStruct.texture = nullptr;
for (int i = 0; i < QMTL_FRAMES_IN_FLIGHT; ++i) {
e.texture.stagingBuffers[i] = d->stagingBuf[i];
@@ -2279,6 +2320,10 @@ static inline MTLPixelFormat toMetalTextureFormat(QRhiTexture::Format format, QR
return MTLPixelFormatRGBA16Float;
case QRhiTexture::RGBA32F:
return MTLPixelFormatRGBA32Float;
+ case QRhiTexture::R16F:
+ return MTLPixelFormatR16Float;
+ case QRhiTexture::R32F:
+ return MTLPixelFormatR32Float;
case QRhiTexture::D16:
#ifdef Q_OS_MACOS
@@ -2449,7 +2494,6 @@ bool QMetalTexture::build()
d->tex.label = [NSString stringWithUTF8String: m_objectName.constData()];
d->owns = true;
- nativeHandlesStruct.texture = d->tex;
QRHI_PROF;
QRHI_PROF_F(newTexture(this, true, mipLevelCount, isCube ? 6 : 1, samples));
@@ -2460,19 +2504,18 @@ bool QMetalTexture::build()
return true;
}
-bool QMetalTexture::buildFrom(const QRhiNativeHandles *src)
+bool QMetalTexture::buildFrom(QRhiTexture::NativeTexture src)
{
- const QRhiMetalTextureNativeHandles *h = static_cast<const QRhiMetalTextureNativeHandles *>(src);
- if (!h || !h->texture)
+ void * const * tex = (void * const *) src.object;
+ if (!tex || !*tex)
return false;
if (!prepareBuild())
return false;
- d->tex = (id<MTLTexture>) h->texture;
+ d->tex = (id<MTLTexture>) *tex;
d->owns = false;
- nativeHandlesStruct.texture = d->tex;
QRHI_PROF;
QRHI_PROF_F(newTexture(this, false, mipLevelCount, m_flags.testFlag(CubeMap) ? 6 : 1, samples));
@@ -2484,9 +2527,9 @@ bool QMetalTexture::buildFrom(const QRhiNativeHandles *src)
return true;
}
-const QRhiNativeHandles *QMetalTexture::nativeHandles()
+QRhiTexture::NativeTexture QMetalTexture::nativeTexture()
{
- return &nativeHandlesStruct;
+ return {&d->tex, 0};
}
id<MTLTexture> QMetalTextureData::viewForLevel(int level)
@@ -2505,8 +2548,8 @@ id<MTLTexture> QMetalTextureData::viewForLevel(int level)
}
QMetalSampler::QMetalSampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
- AddressMode u, AddressMode v)
- : QRhiSampler(rhi, magFilter, minFilter, mipmapMode, u, v),
+ AddressMode u, AddressMode v, AddressMode w)
+ : QRhiSampler(rhi, magFilter, minFilter, mipmapMode, u, v, w),
d(new QMetalSamplerData)
{
}
@@ -2569,12 +2612,8 @@ static inline MTLSamplerAddressMode toMetalAddressMode(QRhiSampler::AddressMode
return MTLSamplerAddressModeRepeat;
case QRhiSampler::ClampToEdge:
return MTLSamplerAddressModeClampToEdge;
- case QRhiSampler::Border:
- return MTLSamplerAddressModeClampToBorderColor;
case QRhiSampler::Mirror:
return MTLSamplerAddressModeMirrorRepeat;
- case QRhiSampler::MirrorOnce:
- return MTLSamplerAddressModeMirrorClampToEdge;
default:
Q_UNREACHABLE();
return MTLSamplerAddressModeClampToEdge;
@@ -2647,6 +2686,32 @@ void QMetalRenderPassDescriptor::release()
// nothing to do here
}
+bool QMetalRenderPassDescriptor::isCompatible(const QRhiRenderPassDescriptor *other) const
+{
+ if (!other)
+ return false;
+
+ const QMetalRenderPassDescriptor *o = QRHI_RES(const QMetalRenderPassDescriptor, other);
+
+ if (colorAttachmentCount != o->colorAttachmentCount)
+ return false;
+
+ if (hasDepthStencil != o->hasDepthStencil)
+ return false;
+
+ for (int i = 0; i < colorAttachmentCount; ++i) {
+ if (colorFormat[i] != o->colorFormat[i])
+ return false;
+ }
+
+ if (hasDepthStencil) {
+ if (dsFormat != o->dsFormat)
+ return false;
+ }
+
+ return true;
+}
+
QMetalReferenceRenderTarget::QMetalReferenceRenderTarget(QRhiImplementation *rhi)
: QRhiRenderTarget(rhi),
d(new QMetalRenderTargetData)
@@ -2859,9 +2924,7 @@ bool QMetalShaderResourceBindings::build()
}
break;
case QRhiShaderResourceBinding::ImageLoad:
- Q_FALLTHROUGH();
case QRhiShaderResourceBinding::ImageStore:
- Q_FALLTHROUGH();
case QRhiShaderResourceBinding::ImageLoadStore:
{
QMetalTexture *texD = QRHI_RES(QMetalTexture, b->u.simage.tex);
@@ -2870,9 +2933,7 @@ bool QMetalShaderResourceBindings::build()
}
break;
case QRhiShaderResourceBinding::BufferLoad:
- Q_FALLTHROUGH();
case QRhiShaderResourceBinding::BufferStore:
- Q_FALLTHROUGH();
case QRhiShaderResourceBinding::BufferLoadStore:
{
QMetalBuffer *bufD = QRHI_RES(QMetalBuffer, b->u.sbuf.buf);
@@ -3314,7 +3375,11 @@ bool QMetalGraphicsPipeline::build()
// validation blows up otherwise.
MTLPixelFormat fmt = MTLPixelFormat(rpD->dsFormat);
rpDesc.depthAttachmentPixelFormat = fmt;
+#ifdef Q_OS_MACOS
if (fmt != MTLPixelFormatDepth16Unorm && fmt != MTLPixelFormatDepth32Float)
+#else
+ if (fmt != MTLPixelFormatDepth32Float)
+#endif
rpDesc.stencilAttachmentPixelFormat = fmt;
}
@@ -3531,6 +3596,10 @@ QMetalSwapChain::~QMetalSwapChain()
void QMetalSwapChain::release()
{
+#ifdef TARGET_IPHONE_SIMULATOR
+ if (@available(ios 13.0, *)) {
+#endif
+
if (!d->layer)
return;
@@ -3559,6 +3628,10 @@ void QMetalSwapChain::release()
QRHI_PROF_F(releaseSwapChain(this));
rhiD->unregisterResource(this);
+
+#ifdef TARGET_IPHONE_SIMULATOR
+ }
+#endif
}
QRhiCommandBuffer *QMetalSwapChain::currentFrameCommandBuffer()
@@ -3581,16 +3654,20 @@ QRhiRenderPassDescriptor *QMetalSwapChain::newCompatibleRenderPassDescriptor()
{
chooseFormats(); // ensure colorFormat and similar are filled out
- QRHI_RES_RHI(QRhiMetal);
QMetalRenderPassDescriptor *rpD = new QMetalRenderPassDescriptor(m_rhi);
rpD->colorAttachmentCount = 1;
rpD->hasDepthStencil = m_depthStencil != nullptr;
rpD->colorFormat[0] = int(d->colorFormat);
+#ifdef Q_OS_MACOS
// m_depthStencil may not be built yet so cannot rely on computed fields in it
+ QRHI_RES_RHI(QRhiMetal);
rpD->dsFormat = rhiD->d->dev.depth24Stencil8PixelFormatSupported
? MTLPixelFormatDepth24Unorm_Stencil8 : MTLPixelFormatDepth32Float_Stencil8;
+#else
+ rpD->dsFormat = MTLPixelFormatDepth32Float_Stencil8;
+#endif
return rpD;
}
@@ -3606,6 +3683,10 @@ void QMetalSwapChain::chooseFormats()
bool QMetalSwapChain::buildOrResize()
{
+#ifdef TARGET_IPHONE_SIMULATOR
+ if (@available(ios 13.0, *)) {
+#endif
+
Q_ASSERT(m_window);
const bool needsRegistration = !window || window != m_window;
@@ -3625,7 +3706,11 @@ bool QMetalSwapChain::buildOrResize()
return false;
}
+#ifdef Q_OS_MACOS
NSView *view = reinterpret_cast<NSView *>(window->winId());
+#else
+ UIView *view = reinterpret_cast<UIView *>(window->winId());
+#endif
Q_ASSERT(view);
d->layer = static_cast<CAMetalLayer *>(view.layer);
Q_ASSERT(d->layer);
@@ -3729,6 +3814,15 @@ bool QMetalSwapChain::buildOrResize()
rhiD->registerResource(this);
return true;
+
+#ifdef TARGET_IPHONE_SIMULATOR
+ } else {
+ // Won't ever get here in a normal app because MTLDevice creation would
+ // fail too. Print a warning, just in case.
+ qWarning("No CAMetalLayer support in this version of the iOS Simulator");
+ return false;
+ }
+#endif
}
QT_END_NAMESPACE
diff --git a/src/gui/rhi/qrhimetal_p.h b/src/gui/rhi/qrhimetal_p.h
index 094801c58c..17e28b2c0f 100644
--- a/src/gui/rhi/qrhimetal_p.h
+++ b/src/gui/rhi/qrhimetal_p.h
@@ -64,11 +64,6 @@ struct Q_GUI_EXPORT QRhiMetalNativeHandles : public QRhiNativeHandles
void *cmdQueue = nullptr; // id<MTLCommandQueue>
};
-struct Q_GUI_EXPORT QRhiMetalTextureNativeHandles : public QRhiNativeHandles
-{
- void *texture = nullptr; // id<MTLTexture>
-};
-
struct Q_GUI_EXPORT QRhiMetalCommandBufferNativeHandles : public QRhiNativeHandles
{
void *commandBuffer = nullptr; // id<MTLCommandBuffer>
diff --git a/src/gui/rhi/qrhimetal_p_p.h b/src/gui/rhi/qrhimetal_p_p.h
index 2be86db5c8..24f3340db1 100644
--- a/src/gui/rhi/qrhimetal_p_p.h
+++ b/src/gui/rhi/qrhimetal_p_p.h
@@ -100,13 +100,12 @@ struct QMetalTexture : public QRhiTexture
~QMetalTexture();
void release() override;
bool build() override;
- bool buildFrom(const QRhiNativeHandles *src) override;
- const QRhiNativeHandles *nativeHandles() override;
+ bool buildFrom(NativeTexture src) override;
+ NativeTexture nativeTexture() override;
bool prepareBuild(QSize *adjustedSize = nullptr);
QMetalTextureData *d;
- QRhiMetalTextureNativeHandles nativeHandlesStruct;
int mipLevelCount = 0;
int samples = 1;
uint generation = 0;
@@ -121,7 +120,7 @@ struct QMetalSamplerData;
struct QMetalSampler : public QRhiSampler
{
QMetalSampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
- AddressMode u, AddressMode v);
+ AddressMode u, AddressMode v, AddressMode w);
~QMetalSampler();
void release() override;
bool build() override;
@@ -138,6 +137,7 @@ struct QMetalRenderPassDescriptor : public QRhiRenderPassDescriptor
QMetalRenderPassDescriptor(QRhiImplementation *rhi);
~QMetalRenderPassDescriptor();
void release() override;
+ bool isCompatible(const QRhiRenderPassDescriptor *other) const override;
// there is no MTLRenderPassDescriptor here as one will be created for each pass in beginPass()
@@ -349,9 +349,12 @@ public:
const QSize &pixelSize,
int sampleCount,
QRhiTexture::Flags flags) override;
- QRhiSampler *createSampler(QRhiSampler::Filter magFilter, QRhiSampler::Filter minFilter,
+ QRhiSampler *createSampler(QRhiSampler::Filter magFilter,
+ QRhiSampler::Filter minFilter,
QRhiSampler::Filter mipmapMode,
- QRhiSampler:: AddressMode u, QRhiSampler::AddressMode v) override;
+ QRhiSampler:: AddressMode u,
+ QRhiSampler::AddressMode v,
+ QRhiSampler::AddressMode w) override;
QRhiTextureRenderTarget *createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc,
QRhiTextureRenderTarget::Flags flags) override;
diff --git a/src/gui/rhi/qrhinull.cpp b/src/gui/rhi/qrhinull.cpp
index fe606f971f..4c59900aa6 100644
--- a/src/gui/rhi/qrhinull.cpp
+++ b/src/gui/rhi/qrhinull.cpp
@@ -67,13 +67,6 @@ QT_BEGIN_NAMESPACE
\brief Empty.
*/
-/*!
- \class QRhiNullTextureNativeHandles
- \internal
- \inmodule QtGui
- \brief Empty.
- */
-
QRhiNull::QRhiNull(QRhiNullInitParams *params)
: offscreenCommandBuffer(this)
{
@@ -200,9 +193,9 @@ QRhiTexture *QRhiNull::createTexture(QRhiTexture::Format format, const QSize &pi
QRhiSampler *QRhiNull::createSampler(QRhiSampler::Filter magFilter, QRhiSampler::Filter minFilter,
QRhiSampler::Filter mipmapMode,
- QRhiSampler::AddressMode u, QRhiSampler::AddressMode v)
+ QRhiSampler::AddressMode u, QRhiSampler::AddressMode v, QRhiSampler::AddressMode w)
{
- return new QNullSampler(this, magFilter, minFilter, mipmapMode, u, v);
+ return new QNullSampler(this, magFilter, minFilter, mipmapMode, u, v, w);
}
QRhiTextureRenderTarget *QRhiNull::createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc,
@@ -638,9 +631,9 @@ bool QNullTexture::build()
return true;
}
-bool QNullTexture::buildFrom(const QRhiNativeHandles *src)
+bool QNullTexture::buildFrom(QRhiTexture::NativeTexture src)
{
- Q_UNUSED(src);
+ Q_UNUSED(src)
QRHI_RES_RHI(QRhiNull);
const bool isCube = m_flags.testFlag(CubeMap);
const bool hasMipMaps = m_flags.testFlag(MipMapped);
@@ -651,14 +644,9 @@ bool QNullTexture::buildFrom(const QRhiNativeHandles *src)
return true;
}
-const QRhiNativeHandles *QNullTexture::nativeHandles()
-{
- return &nativeHandlesStruct;
-}
-
QNullSampler::QNullSampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
- AddressMode u, AddressMode v)
- : QRhiSampler(rhi, magFilter, minFilter, mipmapMode, u, v)
+ AddressMode u, AddressMode v, AddressMode w)
+ : QRhiSampler(rhi, magFilter, minFilter, mipmapMode, u, v, w)
{
}
@@ -690,6 +678,12 @@ void QNullRenderPassDescriptor::release()
{
}
+bool QNullRenderPassDescriptor::isCompatible(const QRhiRenderPassDescriptor *other) const
+{
+ Q_UNUSED(other);
+ return true;
+}
+
QNullReferenceRenderTarget::QNullReferenceRenderTarget(QRhiImplementation *rhi)
: QRhiRenderTarget(rhi),
d(rhi)
diff --git a/src/gui/rhi/qrhinull_p.h b/src/gui/rhi/qrhinull_p.h
index 7d3ce5dbf1..dbf385555d 100644
--- a/src/gui/rhi/qrhinull_p.h
+++ b/src/gui/rhi/qrhinull_p.h
@@ -60,10 +60,6 @@ struct Q_GUI_EXPORT QRhiNullNativeHandles : public QRhiNativeHandles
{
};
-struct Q_GUI_EXPORT QRhiNullTextureNativeHandles : public QRhiNativeHandles
-{
-};
-
QT_END_NAMESPACE
#endif
diff --git a/src/gui/rhi/qrhinull_p_p.h b/src/gui/rhi/qrhinull_p_p.h
index ce517bfa63..0b3d40f1aa 100644
--- a/src/gui/rhi/qrhinull_p_p.h
+++ b/src/gui/rhi/qrhinull_p_p.h
@@ -80,17 +80,15 @@ struct QNullTexture : public QRhiTexture
~QNullTexture();
void release() override;
bool build() override;
- bool buildFrom(const QRhiNativeHandles *src) override;
- const QRhiNativeHandles *nativeHandles() override;
+ bool buildFrom(NativeTexture src) override;
- QRhiNullTextureNativeHandles nativeHandlesStruct;
QImage image[QRhi::MAX_LAYERS][QRhi::MAX_LEVELS];
};
struct QNullSampler : public QRhiSampler
{
QNullSampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
- AddressMode u, AddressMode v);
+ AddressMode u, AddressMode v, AddressMode w);
~QNullSampler();
void release() override;
bool build() override;
@@ -101,6 +99,7 @@ struct QNullRenderPassDescriptor : public QRhiRenderPassDescriptor
QNullRenderPassDescriptor(QRhiImplementation *rhi);
~QNullRenderPassDescriptor();
void release() override;
+ bool isCompatible(const QRhiRenderPassDescriptor *other) const override;
};
struct QNullRenderTargetData
@@ -213,9 +212,12 @@ public:
const QSize &pixelSize,
int sampleCount,
QRhiTexture::Flags flags) override;
- QRhiSampler *createSampler(QRhiSampler::Filter magFilter, QRhiSampler::Filter minFilter,
+ QRhiSampler *createSampler(QRhiSampler::Filter magFilter,
+ QRhiSampler::Filter minFilter,
QRhiSampler::Filter mipmapMode,
- QRhiSampler:: AddressMode u, QRhiSampler::AddressMode v) override;
+ QRhiSampler:: AddressMode u,
+ QRhiSampler::AddressMode v,
+ QRhiSampler::AddressMode w) override;
QRhiTextureRenderTarget *createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc,
QRhiTextureRenderTarget::Flags flags) override;
diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp
index a200a6e271..cf6f14368c 100644
--- a/src/gui/rhi/qrhivulkan.cpp
+++ b/src/gui/rhi/qrhivulkan.cpp
@@ -177,21 +177,6 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \class QRhiVulkanTextureNativeHandles
- \internal
- \inmodule QtGui
- \brief Holds the Vulkan image object that is backing a QRhiTexture.
-
- Importing and exporting Vulkan image objects that back a QRhiTexture when
- running with the Vulkan backend is supported via this class. Ownership of
- the Vulkan object is never transferred.
-
- \note Memory allocation details are not exposed. This is intentional since
- memory is typically suballocated from a bigger chunk of VkDeviceMemory, and
- exposing the allocator details is not desirable for now.
- */
-
-/*!
\class QRhiVulkanCommandBufferNativeHandles
\internal
\inmodule QtGui
@@ -501,6 +486,17 @@ bool QRhiVulkan::create(QRhi::Flags flags)
}
}
+ QByteArrayList envExtList;
+ if (qEnvironmentVariableIsSet("QT_VULKAN_DEVICE_EXTENSIONS")) {
+ envExtList = qgetenv("QT_VULKAN_DEVICE_EXTENSIONS").split(';');
+ for (auto ext : requestedDevExts)
+ envExtList.removeAll(ext);
+ for (const QByteArray &ext : envExtList) {
+ if (!ext.isEmpty())
+ requestedDevExts.append(ext.constData());
+ }
+ }
+
VkDeviceCreateInfo devInfo;
memset(&devInfo, 0, sizeof(devInfo));
devInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
@@ -771,6 +767,10 @@ static inline VkFormat toVkTextureFormat(QRhiTexture::Format format, QRhiTexture
return VK_FORMAT_R16G16B16A16_SFLOAT;
case QRhiTexture::RGBA32F:
return VK_FORMAT_R32G32B32A32_SFLOAT;
+ case QRhiTexture::R16F:
+ return VK_FORMAT_R16_SFLOAT;
+ case QRhiTexture::R32F:
+ return VK_FORMAT_R32_SFLOAT;
case QRhiTexture::D16:
return VK_FORMAT_D16_UNORM;
@@ -868,7 +868,6 @@ static inline bool isDepthTextureFormat(QRhiTexture::Format format)
{
switch (format) {
case QRhiTexture::Format::D16:
- Q_FALLTHROUGH();
case QRhiTexture::Format::D32F:
return true;
@@ -1032,54 +1031,62 @@ VkFormat QRhiVulkan::optimalDepthStencilFormat()
return optimalDsFormat;
}
-bool QRhiVulkan::createDefaultRenderPass(VkRenderPass *rp, bool hasDepthStencil, VkSampleCountFlagBits samples, VkFormat colorFormat)
+bool QRhiVulkan::createDefaultRenderPass(QVkRenderPassDescriptor *rpD, bool hasDepthStencil, VkSampleCountFlagBits samples, VkFormat colorFormat)
{
- VkAttachmentDescription attDesc[3];
- memset(attDesc, 0, sizeof(attDesc));
-
// attachment list layout is color (1), ds (0-1), resolve (0-1)
- attDesc[0].format = colorFormat;
- attDesc[0].samples = samples;
- attDesc[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
- attDesc[0].storeOp = samples > VK_SAMPLE_COUNT_1_BIT ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE;
- attDesc[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
- attDesc[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
- attDesc[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
- attDesc[0].finalLayout = samples > VK_SAMPLE_COUNT_1_BIT ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
-
- // clear on load + no store + lazy alloc + transient image should play
- // nicely with tiled GPUs (no physical backing necessary for ds buffer)
- attDesc[1].format = optimalDepthStencilFormat();
- attDesc[1].samples = samples;
- attDesc[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
- attDesc[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
- attDesc[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
- attDesc[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
- attDesc[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
- attDesc[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+ VkAttachmentDescription attDesc;
+ memset(&attDesc, 0, sizeof(attDesc));
+ attDesc.format = colorFormat;
+ attDesc.samples = samples;
+ attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
+ attDesc.storeOp = samples > VK_SAMPLE_COUNT_1_BIT ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE;
+ attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+ attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+ attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ attDesc.finalLayout = samples > VK_SAMPLE_COUNT_1_BIT ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
+ rpD->attDescs.append(attDesc);
- if (samples > VK_SAMPLE_COUNT_1_BIT) {
- attDesc[2].format = colorFormat;
- attDesc[2].samples = VK_SAMPLE_COUNT_1_BIT;
- attDesc[2].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
- attDesc[2].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
- attDesc[2].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
- attDesc[2].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
- attDesc[2].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
- attDesc[2].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
+ rpD->colorRefs.append({ 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL });
+
+ if (hasDepthStencil) {
+ // clear on load + no store + lazy alloc + transient image should play
+ // nicely with tiled GPUs (no physical backing necessary for ds buffer)
+ memset(&attDesc, 0, sizeof(attDesc));
+ attDesc.format = optimalDepthStencilFormat();
+ attDesc.samples = samples;
+ attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
+ attDesc.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+ attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
+ attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+ attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ attDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+ rpD->attDescs.append(attDesc);
+
+ rpD->dsRef = { 1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
}
- VkAttachmentReference colorRef = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
- VkAttachmentReference dsRef = { 1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
- VkAttachmentReference resolveRef = { 2, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
+ if (samples > VK_SAMPLE_COUNT_1_BIT) {
+ memset(&attDesc, 0, sizeof(attDesc));
+ attDesc.format = colorFormat;
+ attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
+ attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
+ attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
+ attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+ attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+ attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ attDesc.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
+ rpD->attDescs.append(attDesc);
+
+ rpD->resolveRefs.append({ 2, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL });
+ }
VkSubpassDescription subpassDesc;
memset(&subpassDesc, 0, sizeof(subpassDesc));
subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpassDesc.colorAttachmentCount = 1;
- subpassDesc.pColorAttachments = &colorRef;
- subpassDesc.pDepthStencilAttachment = hasDepthStencil ? &dsRef : nullptr;
+ subpassDesc.pColorAttachments = rpD->colorRefs.constData();
+ subpassDesc.pDepthStencilAttachment = hasDepthStencil ? &rpD->dsRef : nullptr;
// Replace the first implicit dep (TOP_OF_PIPE / ALL_COMMANDS) with our own.
VkSubpassDependency subpassDep;
@@ -1095,7 +1102,7 @@ bool QRhiVulkan::createDefaultRenderPass(VkRenderPass *rp, bool hasDepthStencil,
memset(&rpInfo, 0, sizeof(rpInfo));
rpInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
rpInfo.attachmentCount = 1;
- rpInfo.pAttachments = attDesc;
+ rpInfo.pAttachments = rpD->attDescs.constData();
rpInfo.subpassCount = 1;
rpInfo.pSubpasses = &subpassDesc;
rpInfo.dependencyCount = 1;
@@ -1106,19 +1113,21 @@ bool QRhiVulkan::createDefaultRenderPass(VkRenderPass *rp, bool hasDepthStencil,
if (samples > VK_SAMPLE_COUNT_1_BIT) {
rpInfo.attachmentCount += 1;
- subpassDesc.pResolveAttachments = &resolveRef;
+ subpassDesc.pResolveAttachments = rpD->resolveRefs.constData();
}
- VkResult err = df->vkCreateRenderPass(dev, &rpInfo, nullptr, rp);
+ VkResult err = df->vkCreateRenderPass(dev, &rpInfo, nullptr, &rpD->rp);
if (err != VK_SUCCESS) {
qWarning("Failed to create renderpass: %d", err);
return false;
}
+ rpD->hasDepthStencil = hasDepthStencil;
+
return true;
}
-bool QRhiVulkan::createOffscreenRenderPass(VkRenderPass *rp,
+bool QRhiVulkan::createOffscreenRenderPass(QVkRenderPassDescriptor *rpD,
const QRhiColorAttachment *firstColorAttachment,
const QRhiColorAttachment *lastColorAttachment,
bool preserveColor,
@@ -1126,10 +1135,6 @@ bool QRhiVulkan::createOffscreenRenderPass(VkRenderPass *rp,
QRhiRenderBuffer *depthStencilBuffer,
QRhiTexture *depthTexture)
{
- QVarLengthArray<VkAttachmentDescription, 8> attDescs;
- QVarLengthArray<VkAttachmentReference, 8> colorRefs;
- QVarLengthArray<VkAttachmentReference, 8> resolveRefs;
-
// attachment list layout is color (0-8), ds (0-1), resolve (0-8)
for (auto it = firstColorAttachment; it != lastColorAttachment; ++it) {
@@ -1150,14 +1155,14 @@ bool QRhiVulkan::createOffscreenRenderPass(VkRenderPass *rp,
// this has to interact correctly with activateTextureRenderTarget(), hence leaving in COLOR_ATT
attDesc.initialLayout = preserveColor ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_UNDEFINED;
attDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
- attDescs.append(attDesc);
+ rpD->attDescs.append(attDesc);
- const VkAttachmentReference ref = { uint32_t(attDescs.count() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
- colorRefs.append(ref);
+ const VkAttachmentReference ref = { uint32_t(rpD->attDescs.count() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
+ rpD->colorRefs.append(ref);
}
- const bool hasDepthStencil = depthStencilBuffer || depthTexture;
- if (hasDepthStencil) {
+ rpD->hasDepthStencil = depthStencilBuffer || depthTexture;
+ if (rpD->hasDepthStencil) {
const VkFormat dsFormat = depthTexture ? QRHI_RES(QVkTexture, depthTexture)->vkformat
: QRHI_RES(QVkRenderBuffer, depthStencilBuffer)->vkformat;
const VkSampleCountFlagBits samples = depthTexture ? QRHI_RES(QVkTexture, depthTexture)->samples
@@ -1174,9 +1179,9 @@ bool QRhiVulkan::createOffscreenRenderPass(VkRenderPass *rp,
attDesc.stencilStoreOp = storeOp;
attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
- attDescs.append(attDesc);
+ rpD->attDescs.append(attDesc);
}
- VkAttachmentReference dsRef = { uint32_t(attDescs.count() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
+ rpD->dsRef = { uint32_t(rpD->attDescs.count() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
for (auto it = firstColorAttachment; it != lastColorAttachment; ++it) {
if (it->resolveTexture()) {
@@ -1194,37 +1199,37 @@ bool QRhiVulkan::createOffscreenRenderPass(VkRenderPass *rp,
attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
- attDescs.append(attDesc);
+ rpD->attDescs.append(attDesc);
- const VkAttachmentReference ref = { uint32_t(attDescs.count() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
- resolveRefs.append(ref);
+ const VkAttachmentReference ref = { uint32_t(rpD->attDescs.count() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
+ rpD->resolveRefs.append(ref);
} else {
const VkAttachmentReference ref = { VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
- resolveRefs.append(ref);
+ rpD->resolveRefs.append(ref);
}
}
VkSubpassDescription subpassDesc;
memset(&subpassDesc, 0, sizeof(subpassDesc));
subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
- subpassDesc.colorAttachmentCount = uint32_t(colorRefs.count());
- Q_ASSERT(colorRefs.count() == resolveRefs.count());
- subpassDesc.pColorAttachments = !colorRefs.isEmpty() ? colorRefs.constData() : nullptr;
- subpassDesc.pDepthStencilAttachment = hasDepthStencil ? &dsRef : nullptr;
- subpassDesc.pResolveAttachments = !resolveRefs.isEmpty() ? resolveRefs.constData() : nullptr;
+ subpassDesc.colorAttachmentCount = uint32_t(rpD->colorRefs.count());
+ Q_ASSERT(rpD->colorRefs.count() == rpD->resolveRefs.count());
+ subpassDesc.pColorAttachments = !rpD->colorRefs.isEmpty() ? rpD->colorRefs.constData() : nullptr;
+ subpassDesc.pDepthStencilAttachment = rpD->hasDepthStencil ? &rpD->dsRef : nullptr;
+ subpassDesc.pResolveAttachments = !rpD->resolveRefs.isEmpty() ? rpD->resolveRefs.constData() : nullptr;
VkRenderPassCreateInfo rpInfo;
memset(&rpInfo, 0, sizeof(rpInfo));
rpInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
- rpInfo.attachmentCount = uint32_t(attDescs.count());
- rpInfo.pAttachments = attDescs.constData();
+ rpInfo.attachmentCount = uint32_t(rpD->attDescs.count());
+ rpInfo.pAttachments = rpD->attDescs.constData();
rpInfo.subpassCount = 1;
rpInfo.pSubpasses = &subpassDesc;
// don't yet know the correct initial/final access and stage stuff for the
// implicit deps at this point, so leave it to the resource tracking to
// generate barriers
- VkResult err = df->vkCreateRenderPass(dev, &rpInfo, nullptr, rp);
+ VkResult err = df->vkCreateRenderPass(dev, &rpInfo, nullptr, &rpD->rp);
if (err != VK_SUCCESS) {
qWarning("Failed to create renderpass: %d", err);
return false;
@@ -1346,8 +1351,8 @@ bool QRhiVulkan::recreateSwapChain(QRhiSwapChain *swapChain)
quint32 actualSwapChainBufferCount = 0;
err = vkGetSwapchainImagesKHR(dev, swapChainD->sc, &actualSwapChainBufferCount, nullptr);
- if (err != VK_SUCCESS || actualSwapChainBufferCount < 2) {
- qWarning("Failed to get swapchain images: %d (count=%u)", err, actualSwapChainBufferCount);
+ if (err != VK_SUCCESS || actualSwapChainBufferCount == 0) {
+ qWarning("Failed to get swapchain images: %d", err);
return false;
}
@@ -1523,7 +1528,8 @@ void QRhiVulkan::releaseSwapChainResources(QRhiSwapChain *swapChain)
QRhi::FrameOpResult QRhiVulkan::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags)
{
QVkSwapChain *swapChainD = QRHI_RES(QVkSwapChain, swapChain);
- QVkSwapChain::FrameResources &frame(swapChainD->frameRes[swapChainD->currentFrameSlot]);
+ const int frameResIndex = swapChainD->bufferCount > 1 ? swapChainD->currentFrameSlot : 0;
+ QVkSwapChain::FrameResources &frame(swapChainD->frameRes[frameResIndex]);
QRhiProfilerPrivate *rhiP = profilerPrivateOrNull();
if (!frame.imageAcquired) {
@@ -1566,7 +1572,7 @@ QRhi::FrameOpResult QRhiVulkan::beginFrame(QRhiSwapChain *swapChain, QRhi::Begin
// will make B wait for A's frame 0 commands, so if a resource is written
// in B's frame or when B checks for pending resource releases, that won't
// mess up A's in-flight commands (as they are not in flight anymore).
- waitCommandCompletion(int(swapChainD->currentFrameSlot));
+ waitCommandCompletion(frameResIndex);
// Now is the time to read the timestamps for the previous frame for this slot.
if (frame.timestampQueryIndex >= 0) {
@@ -1601,7 +1607,7 @@ QRhi::FrameOpResult QRhiVulkan::beginFrame(QRhiSwapChain *swapChain, QRhi::Begin
// when profiling is enabled, pick a free query (pair) from the pool
int timestampQueryIdx = -1;
- if (profilerPrivateOrNull()) {
+ if (profilerPrivateOrNull() && swapChainD->bufferCount > 1) { // no timestamps if not having at least 2 frames in flight
for (int i = 0; i < timestampQueryPoolMap.count(); ++i) {
if (!timestampQueryPoolMap.testBit(i)) {
timestampQueryPoolMap.setBit(i);
@@ -1643,7 +1649,8 @@ QRhi::FrameOpResult QRhiVulkan::endFrame(QRhiSwapChain *swapChain, QRhi::EndFram
recordPrimaryCommandBuffer(&swapChainD->cbWrapper);
- QVkSwapChain::FrameResources &frame(swapChainD->frameRes[swapChainD->currentFrameSlot]);
+ int frameResIndex = swapChainD->bufferCount > 1 ? swapChainD->currentFrameSlot : 0;
+ QVkSwapChain::FrameResources &frame(swapChainD->frameRes[frameResIndex]);
QVkSwapChain::ImageResources &image(swapChainD->imageRes[swapChainD->currentImageIndex]);
if (image.lastUse != QVkSwapChain::ImageResources::ScImageUseRender) {
@@ -1710,6 +1717,10 @@ QRhi::FrameOpResult QRhiVulkan::endFrame(QRhiSwapChain *swapChain, QRhi::EndFram
presInfo.waitSemaphoreCount = 1;
presInfo.pWaitSemaphores = &frame.drawSem; // gfxQueueFamilyIdx == presQueueFamilyIdx ? &frame.drawSem : &frame.presTransSem;
+ // Do platform-specific WM notification. F.ex. essential on Wayland in
+ // order to circumvent driver frame callbacks
+ inst->presentAboutToBeQueued(swapChainD->window);
+
VkResult err = vkQueuePresentKHR(gfxQueue, &presInfo);
if (err != VK_SUCCESS) {
if (err == VK_ERROR_OUT_OF_DATE_KHR) {
@@ -1851,7 +1862,8 @@ QRhi::FrameOpResult QRhiVulkan::endAndSubmitPrimaryCommandBuffer(VkCommandBuffer
void QRhiVulkan::waitCommandCompletion(int frameSlot)
{
for (QVkSwapChain *sc : qAsConst(swapchains)) {
- QVkSwapChain::FrameResources &frame(sc->frameRes[frameSlot]);
+ const int frameResIndex = sc->bufferCount > 1 ? frameSlot : 0;
+ QVkSwapChain::FrameResources &frame(sc->frameRes[frameResIndex]);
if (frame.cmdFenceWaitable) {
df->vkWaitForFences(dev, 1, &frame.cmdFence, VK_TRUE, UINT64_MAX);
df->vkResetFences(dev, 1, &frame.cmdFence);
@@ -2210,6 +2222,8 @@ void QRhiVulkan::beginComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch
cbD->recordingPass = QVkCommandBuffer::ComputePass;
+ cbD->computePassState.reset();
+
if (cbD->useSecondaryCb)
cbD->secondaryCbs.append(startSecondaryCommandBuffer());
}
@@ -2258,15 +2272,152 @@ void QRhiVulkan::setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *
psD->lastActiveFrameSlot = currentFrameSlot;
}
+template<typename T>
+inline void qrhivk_accumulateComputeResource(T *writtenResources, QRhiResource *resource,
+ QRhiShaderResourceBinding::Type bindingType,
+ int loadTypeVal, int storeTypeVal, int loadStoreTypeVal)
+{
+ VkAccessFlags access = 0;
+ if (bindingType == loadTypeVal) {
+ access = VK_ACCESS_SHADER_READ_BIT;
+ } else {
+ access = VK_ACCESS_SHADER_WRITE_BIT;
+ if (bindingType == loadStoreTypeVal)
+ access |= VK_ACCESS_SHADER_READ_BIT;
+ }
+ auto it = writtenResources->find(resource);
+ if (it != writtenResources->end())
+ it->first |= access;
+ else if (bindingType == storeTypeVal || bindingType == loadStoreTypeVal)
+ writtenResources->insert(resource, { access, true });
+}
+
void QRhiVulkan::dispatch(QRhiCommandBuffer *cb, int x, int y, int z)
{
QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
Q_ASSERT(cbD->recordingPass == QVkCommandBuffer::ComputePass);
+ // When there are multiple dispatches, read-after-write and
+ // write-after-write need a barrier.
+ QVarLengthArray<VkImageMemoryBarrier, 8> imageBarriers;
+ QVarLengthArray<VkBufferMemoryBarrier, 8> bufferBarriers;
+ if (cbD->currentComputeSrb) {
+ // The key in the writtenResources map indicates that the resource was
+ // written in a previous dispatch, whereas the value accumulates the
+ // access mask in the current one.
+ for (auto &accessAndIsNewFlag : cbD->computePassState.writtenResources)
+ accessAndIsNewFlag = { 0, false };
+
+ QVkShaderResourceBindings *srbD = QRHI_RES(QVkShaderResourceBindings, cbD->currentComputeSrb);
+ const int bindingCount = srbD->m_bindings.count();
+ for (int i = 0; i < bindingCount; ++i) {
+ const QRhiShaderResourceBinding::Data *b = srbD->m_bindings.at(i).data();
+ switch (b->type) {
+ case QRhiShaderResourceBinding::ImageLoad:
+ case QRhiShaderResourceBinding::ImageStore:
+ case QRhiShaderResourceBinding::ImageLoadStore:
+ qrhivk_accumulateComputeResource(&cbD->computePassState.writtenResources,
+ b->u.simage.tex,
+ b->type,
+ QRhiShaderResourceBinding::ImageLoad,
+ QRhiShaderResourceBinding::ImageStore,
+ QRhiShaderResourceBinding::ImageLoadStore);
+ break;
+ case QRhiShaderResourceBinding::BufferLoad:
+ case QRhiShaderResourceBinding::BufferStore:
+ case QRhiShaderResourceBinding::BufferLoadStore:
+ qrhivk_accumulateComputeResource(&cbD->computePassState.writtenResources,
+ b->u.sbuf.buf,
+ b->type,
+ QRhiShaderResourceBinding::BufferLoad,
+ QRhiShaderResourceBinding::BufferStore,
+ QRhiShaderResourceBinding::BufferLoadStore);
+ break;
+ default:
+ break;
+ }
+ }
+
+ for (auto it = cbD->computePassState.writtenResources.begin(); it != cbD->computePassState.writtenResources.end(); ) {
+ const int accessInThisDispatch = it->first;
+ const bool isNewInThisDispatch = it->second;
+ if (accessInThisDispatch && !isNewInThisDispatch) {
+ if (it.key()->resourceType() == QRhiResource::Texture) {
+ QVkTexture *texD = QRHI_RES(QVkTexture, it.key());
+ VkImageMemoryBarrier barrier;
+ memset(&barrier, 0, sizeof(barrier));
+ barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+ barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ // won't care about subresources, pretend the whole resource was written
+ barrier.subresourceRange.baseMipLevel = 0;
+ barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
+ barrier.subresourceRange.baseArrayLayer = 0;
+ barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
+ barrier.oldLayout = texD->usageState.layout;
+ barrier.newLayout = texD->usageState.layout;
+ barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
+ barrier.dstAccessMask = accessInThisDispatch;
+ barrier.image = texD->image;
+ imageBarriers.append(barrier);
+ } else {
+ QVkBuffer *bufD = QRHI_RES(QVkBuffer, it.key());
+ VkBufferMemoryBarrier barrier;
+ memset(&barrier, 0, sizeof(barrier));
+ barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
+ barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+ barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
+ barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
+ barrier.dstAccessMask = accessInThisDispatch;
+ barrier.buffer = bufD->buffers[bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0];
+ barrier.size = VK_WHOLE_SIZE;
+ bufferBarriers.append(barrier);
+ }
+ }
+ // Anything that was previously written, but is only read now, can be
+ // removed from the written list (because that previous write got a
+ // corresponding barrier now).
+ if (accessInThisDispatch == VK_ACCESS_SHADER_READ_BIT)
+ it = cbD->computePassState.writtenResources.erase(it);
+ else
+ ++it;
+ }
+ }
+
if (cbD->useSecondaryCb) {
- df->vkCmdDispatch(cbD->secondaryCbs.last(), uint32_t(x), uint32_t(y), uint32_t(z));
+ VkCommandBuffer secondaryCb = cbD->secondaryCbs.last();
+ if (!imageBarriers.isEmpty()) {
+ df->vkCmdPipelineBarrier(secondaryCb, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
+ 0, 0, nullptr,
+ 0, nullptr,
+ imageBarriers.count(), imageBarriers.constData());
+ }
+ if (!bufferBarriers.isEmpty()) {
+ df->vkCmdPipelineBarrier(secondaryCb, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
+ 0, 0, nullptr,
+ bufferBarriers.count(), bufferBarriers.constData(),
+ 0, nullptr);
+ }
+ df->vkCmdDispatch(secondaryCb, uint32_t(x), uint32_t(y), uint32_t(z));
} else {
QVkCommandBuffer::Command cmd;
+ if (!imageBarriers.isEmpty()) {
+ cmd.cmd = QVkCommandBuffer::Command::ImageBarrier;
+ cmd.args.imageBarrier.srcStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
+ cmd.args.imageBarrier.dstStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
+ cmd.args.imageBarrier.count = imageBarriers.count();
+ cmd.args.imageBarrier.index = cbD->pools.imageBarrier.count();
+ cbD->pools.imageBarrier.append(imageBarriers.constData(), imageBarriers.count());
+ cbD->commands.append(cmd);
+ }
+ if (!bufferBarriers.isEmpty()) {
+ cmd.cmd = QVkCommandBuffer::Command::BufferBarrier;
+ cmd.args.bufferBarrier.srcStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
+ cmd.args.bufferBarrier.dstStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
+ cmd.args.bufferBarrier.count = bufferBarriers.count();
+ cmd.args.bufferBarrier.index = cbD->pools.bufferBarrier.count();
+ cbD->pools.bufferBarrier.append(bufferBarriers.constData(), bufferBarriers.count());
+ cbD->commands.append(cmd);
+ }
cmd.cmd = QVkCommandBuffer::Command::Dispatch;
cmd.args.dispatch.x = x;
cmd.args.dispatch.y = y;
@@ -2367,9 +2518,7 @@ void QRhiVulkan::updateShaderResourceBindings(QRhiShaderResourceBindings *srb, i
}
break;
case QRhiShaderResourceBinding::ImageLoad:
- Q_FALLTHROUGH();
case QRhiShaderResourceBinding::ImageStore:
- Q_FALLTHROUGH();
case QRhiShaderResourceBinding::ImageLoadStore:
{
QVkTexture *texD = QRHI_RES(QVkTexture, b->u.simage.tex);
@@ -2388,9 +2537,7 @@ void QRhiVulkan::updateShaderResourceBindings(QRhiShaderResourceBindings *srb, i
}
break;
case QRhiShaderResourceBinding::BufferLoad:
- Q_FALLTHROUGH();
case QRhiShaderResourceBinding::BufferStore:
- Q_FALLTHROUGH();
case QRhiShaderResourceBinding::BufferLoadStore:
{
QVkBuffer *bufD = QRHI_RES(QVkBuffer, b->u.sbuf.buf);
@@ -2460,7 +2607,9 @@ void QRhiVulkan::trackedBufferBarrier(QVkCommandBuffer *cbD, QVkBuffer *bufD, in
cmd.cmd = QVkCommandBuffer::Command::BufferBarrier;
cmd.args.bufferBarrier.srcStageMask = s.stage;
cmd.args.bufferBarrier.dstStageMask = stage;
- cmd.args.bufferBarrier.desc = bufMemBarrier;
+ cmd.args.bufferBarrier.count = 1;
+ cmd.args.bufferBarrier.index = cbD->pools.bufferBarrier.count();
+ cbD->pools.bufferBarrier.append(bufMemBarrier);
cbD->commands.append(cmd);
s.access = access;
@@ -2502,7 +2651,9 @@ void QRhiVulkan::trackedImageBarrier(QVkCommandBuffer *cbD, QVkTexture *texD,
cmd.cmd = QVkCommandBuffer::Command::ImageBarrier;
cmd.args.imageBarrier.srcStageMask = srcStage;
cmd.args.imageBarrier.dstStageMask = stage;
- cmd.args.imageBarrier.desc = barrier;
+ cmd.args.imageBarrier.count = 1;
+ cmd.args.imageBarrier.index = cbD->pools.imageBarrier.count();
+ cbD->pools.imageBarrier.append(barrier);
cbD->commands.append(cmd);
s.layout = layout;
@@ -2536,7 +2687,9 @@ void QRhiVulkan::subresourceBarrier(QVkCommandBuffer *cbD, VkImage image,
cmd.cmd = QVkCommandBuffer::Command::ImageBarrier;
cmd.args.imageBarrier.srcStageMask = srcStage;
cmd.args.imageBarrier.dstStageMask = dstStage;
- cmd.args.imageBarrier.desc = barrier;
+ cmd.args.imageBarrier.count = 1;
+ cmd.args.imageBarrier.index = cbD->pools.imageBarrier.count();
+ cbD->pools.imageBarrier.append(barrier);
cbD->commands.append(cmd);
}
@@ -3404,12 +3557,12 @@ void QRhiVulkan::recordPrimaryCommandBuffer(QVkCommandBuffer *cbD)
case QVkCommandBuffer::Command::ImageBarrier:
df->vkCmdPipelineBarrier(cbD->cb, cmd.args.imageBarrier.srcStageMask, cmd.args.imageBarrier.dstStageMask,
0, 0, nullptr, 0, nullptr,
- 1, &cmd.args.imageBarrier.desc);
+ cmd.args.imageBarrier.count, cbD->pools.imageBarrier.constData() + cmd.args.imageBarrier.index);
break;
case QVkCommandBuffer::Command::BufferBarrier:
df->vkCmdPipelineBarrier(cbD->cb, cmd.args.bufferBarrier.srcStageMask, cmd.args.bufferBarrier.dstStageMask,
0, 0, nullptr,
- 1, &cmd.args.bufferBarrier.desc,
+ cmd.args.bufferBarrier.count, cbD->pools.bufferBarrier.constData() + cmd.args.bufferBarrier.index,
0, nullptr);
break;
case QVkCommandBuffer::Command::BlitImage:
@@ -3558,9 +3711,7 @@ static inline VkImageLayout toVkLayout(QRhiPassResourceTracker::TextureAccess ac
case QRhiPassResourceTracker::TexDepthOutput:
return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
case QRhiPassResourceTracker::TexStorageLoad:
- Q_FALLTHROUGH();
case QRhiPassResourceTracker::TexStorageStore:
- Q_FALLTHROUGH();
case QRhiPassResourceTracker::TexStorageLoadStore:
return VK_IMAGE_LAYOUT_GENERAL;
default:
@@ -3895,9 +4046,9 @@ QRhiTexture *QRhiVulkan::createTexture(QRhiTexture::Format format, const QSize &
QRhiSampler *QRhiVulkan::createSampler(QRhiSampler::Filter magFilter, QRhiSampler::Filter minFilter,
QRhiSampler::Filter mipmapMode,
- QRhiSampler::AddressMode u, QRhiSampler::AddressMode v)
+ QRhiSampler::AddressMode u, QRhiSampler::AddressMode v, QRhiSampler::AddressMode w)
{
- return new QVkSampler(this, magFilter, minFilter, mipmapMode, u, v);
+ return new QVkSampler(this, magFilter, minFilter, mipmapMode, u, v, w);
}
QRhiTextureRenderTarget *QRhiVulkan::createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc,
@@ -4039,9 +4190,7 @@ void QRhiVulkan::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBin
}
break;
case QRhiShaderResourceBinding::ImageLoad:
- Q_FALLTHROUGH();
case QRhiShaderResourceBinding::ImageStore:
- Q_FALLTHROUGH();
case QRhiShaderResourceBinding::ImageLoadStore:
{
QVkTexture *texD = QRHI_RES(QVkTexture, b->u.simage.tex);
@@ -4066,9 +4215,7 @@ void QRhiVulkan::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBin
}
break;
case QRhiShaderResourceBinding::BufferLoad:
- Q_FALLTHROUGH();
case QRhiShaderResourceBinding::BufferStore:
- Q_FALLTHROUGH();
case QRhiShaderResourceBinding::BufferLoadStore:
{
QVkBuffer *bufD = QRHI_RES(QVkBuffer, b->u.sbuf.buf);
@@ -4613,12 +4760,8 @@ static inline VkSamplerAddressMode toVkAddressMode(QRhiSampler::AddressMode m)
return VK_SAMPLER_ADDRESS_MODE_REPEAT;
case QRhiSampler::ClampToEdge:
return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
- case QRhiSampler::Border:
- return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
case QRhiSampler::Mirror:
return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;
- case QRhiSampler::MirrorOnce:
- return VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE;
default:
Q_UNREACHABLE();
return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
@@ -4861,16 +5004,12 @@ static inline VkDescriptorType toVkDescriptorType(const QRhiShaderResourceBindin
return VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
case QRhiShaderResourceBinding::ImageLoad:
- Q_FALLTHROUGH();
case QRhiShaderResourceBinding::ImageStore:
- Q_FALLTHROUGH();
case QRhiShaderResourceBinding::ImageLoadStore:
return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
case QRhiShaderResourceBinding::BufferLoad:
- Q_FALLTHROUGH();
case QRhiShaderResourceBinding::BufferStore:
- Q_FALLTHROUGH();
case QRhiShaderResourceBinding::BufferLoadStore:
return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
@@ -5181,7 +5320,6 @@ void QVkTexture::release()
image = VK_NULL_HANDLE;
imageView = VK_NULL_HANDLE;
imageAlloc = nullptr;
- nativeHandlesStruct.image = VK_NULL_HANDLE;
QRHI_RES_RHI(QRhiVulkan);
rhiD->releaseQueue.append(e);
@@ -5266,8 +5404,6 @@ bool QVkTexture::finishBuild()
return false;
}
- nativeHandlesStruct.image = image;
-
lastActiveFrameSlot = -1;
generation += 1;
@@ -5339,16 +5475,16 @@ bool QVkTexture::build()
return true;
}
-bool QVkTexture::buildFrom(const QRhiNativeHandles *src)
+bool QVkTexture::buildFrom(QRhiTexture::NativeTexture src)
{
- const QRhiVulkanTextureNativeHandles *h = static_cast<const QRhiVulkanTextureNativeHandles *>(src);
- if (!h || !h->image)
+ auto *img = static_cast<const VkImage*>(src.object);
+ if (!img || !*img)
return false;
if (!prepareBuild())
return false;
- image = h->image;
+ image = *img;
if (!finishBuild())
return false;
@@ -5356,7 +5492,7 @@ bool QVkTexture::buildFrom(const QRhiNativeHandles *src)
QRHI_PROF;
QRHI_PROF_F(newTexture(this, false, int(mipLevelCount), m_flags.testFlag(CubeMap) ? 6 : 1, samples));
- usageState.layout = h->layout;
+ usageState.layout = VkImageLayout(src.layout);
owns = false;
QRHI_RES_RHI(QRhiVulkan);
@@ -5364,10 +5500,9 @@ bool QVkTexture::buildFrom(const QRhiNativeHandles *src)
return true;
}
-const QRhiNativeHandles *QVkTexture::nativeHandles()
+QRhiTexture::NativeTexture QVkTexture::nativeTexture()
{
- nativeHandlesStruct.layout = usageState.layout;
- return &nativeHandlesStruct;
+ return {&image, usageState.layout};
}
VkImageView QVkTexture::imageViewForLevel(int level)
@@ -5408,8 +5543,8 @@ VkImageView QVkTexture::imageViewForLevel(int level)
}
QVkSampler::QVkSampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
- AddressMode u, AddressMode v)
- : QRhiSampler(rhi, magFilter, minFilter, mipmapMode, u, v)
+ AddressMode u, AddressMode v, AddressMode w)
+ : QRhiSampler(rhi, magFilter, minFilter, mipmapMode, u, v, w)
{
}
@@ -5501,6 +5636,61 @@ void QVkRenderPassDescriptor::release()
rhiD->unregisterResource(this);
}
+static inline bool attachmentDescriptionEquals(const VkAttachmentDescription &a, const VkAttachmentDescription &b)
+{
+ return a.format == b.format
+ && a.samples == b.samples
+ && a.loadOp == b.loadOp
+ && a.storeOp == b.storeOp
+ && a.stencilLoadOp == b.stencilLoadOp
+ && a.stencilStoreOp == b.stencilStoreOp
+ && a.initialLayout == b.initialLayout
+ && a.finalLayout == b.finalLayout;
+}
+
+bool QVkRenderPassDescriptor::isCompatible(const QRhiRenderPassDescriptor *other) const
+{
+ if (!other)
+ return false;
+
+ const QVkRenderPassDescriptor *o = QRHI_RES(const QVkRenderPassDescriptor, other);
+
+ if (attDescs.count() != o->attDescs.count())
+ return false;
+ if (colorRefs.count() != o->colorRefs.count())
+ return false;
+ if (resolveRefs.count() != o->resolveRefs.count())
+ return false;
+ if (hasDepthStencil != o->hasDepthStencil)
+ return false;
+
+ for (int i = 0, ie = colorRefs.count(); i != ie; ++i) {
+ const uint32_t attIdx = colorRefs[i].attachment;
+ if (attIdx != o->colorRefs[i].attachment)
+ return false;
+ if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
+ return false;
+ }
+
+ if (hasDepthStencil) {
+ const uint32_t attIdx = dsRef.attachment;
+ if (attIdx != o->dsRef.attachment)
+ return false;
+ if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
+ return false;
+ }
+
+ for (int i = 0, ie = resolveRefs.count(); i != ie; ++i) {
+ const uint32_t attIdx = resolveRefs[i].attachment;
+ if (attIdx != o->resolveRefs[i].attachment)
+ return false;
+ if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
+ return false;
+ }
+
+ return true;
+}
+
const QRhiNativeHandles *QVkRenderPassDescriptor::nativeHandles()
{
nativeHandlesStruct.renderPass = rp;
@@ -5584,7 +5774,7 @@ QRhiRenderPassDescriptor *QVkTextureRenderTarget::newCompatibleRenderPassDescrip
QRHI_RES_RHI(QRhiVulkan);
QVkRenderPassDescriptor *rp = new QVkRenderPassDescriptor(m_rhi);
- if (!rhiD->createOffscreenRenderPass(&rp->rp,
+ if (!rhiD->createOffscreenRenderPass(rp,
m_desc.cbeginColorAttachments(),
m_desc.cendColorAttachments(),
m_flags.testFlag(QRhiTextureRenderTarget::PreserveColorContents),
@@ -6285,7 +6475,7 @@ QRhiRenderPassDescriptor *QVkSwapChain::newCompatibleRenderPassDescriptor()
QRHI_RES_RHI(QRhiVulkan);
QVkRenderPassDescriptor *rp = new QVkRenderPassDescriptor(m_rhi);
- if (!rhiD->createDefaultRenderPass(&rp->rp,
+ if (!rhiD->createDefaultRenderPass(rp,
m_depthStencil != nullptr,
samples,
colorFormat))
@@ -6303,17 +6493,11 @@ static inline bool isSrgbFormat(VkFormat format)
{
switch (format) {
case VK_FORMAT_R8_SRGB:
- Q_FALLTHROUGH();
case VK_FORMAT_R8G8_SRGB:
- Q_FALLTHROUGH();
case VK_FORMAT_R8G8B8_SRGB:
- Q_FALLTHROUGH();
case VK_FORMAT_B8G8R8_SRGB:
- Q_FALLTHROUGH();
case VK_FORMAT_R8G8B8A8_SRGB:
- Q_FALLTHROUGH();
case VK_FORMAT_B8G8R8A8_SRGB:
- Q_FALLTHROUGH();
case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
return true;
default:
diff --git a/src/gui/rhi/qrhivulkan_p.h b/src/gui/rhi/qrhivulkan_p.h
index ff19c7a54e..d495919671 100644
--- a/src/gui/rhi/qrhivulkan_p.h
+++ b/src/gui/rhi/qrhivulkan_p.h
@@ -69,12 +69,6 @@ struct Q_GUI_EXPORT QRhiVulkanNativeHandles : public QRhiNativeHandles
void *vmemAllocator = nullptr;
};
-struct Q_GUI_EXPORT QRhiVulkanTextureNativeHandles : public QRhiNativeHandles
-{
- VkImage image = VK_NULL_HANDLE;
- VkImageLayout layout = VK_IMAGE_LAYOUT_GENERAL;
-};
-
struct Q_GUI_EXPORT QRhiVulkanCommandBufferNativeHandles : public QRhiNativeHandles
{
VkCommandBuffer commandBuffer = VK_NULL_HANDLE;
diff --git a/src/gui/rhi/qrhivulkan_p_p.h b/src/gui/rhi/qrhivulkan_p_p.h
index d0e1e6758b..d42b83b882 100644
--- a/src/gui/rhi/qrhivulkan_p_p.h
+++ b/src/gui/rhi/qrhivulkan_p_p.h
@@ -120,8 +120,8 @@ struct QVkTexture : public QRhiTexture
~QVkTexture();
void release() override;
bool build() override;
- bool buildFrom(const QRhiNativeHandles *src) override;
- const QRhiNativeHandles *nativeHandles() override;
+ bool buildFrom(NativeTexture src) override;
+ NativeTexture nativeTexture() override;
bool prepareBuild(QSize *adjustedSize = nullptr);
bool finishBuild();
@@ -134,7 +134,6 @@ struct QVkTexture : public QRhiTexture
QVkAlloc stagingAllocations[QVK_FRAMES_IN_FLIGHT];
VkImageView perLevelImageViews[QRhi::MAX_LEVELS];
bool owns = true;
- QRhiVulkanTextureNativeHandles nativeHandlesStruct;
struct UsageState {
// no tracking of subresource layouts (some operations can keep
// subresources in different layouts for some time, but that does not
@@ -155,7 +154,7 @@ struct QVkTexture : public QRhiTexture
struct QVkSampler : public QRhiSampler
{
QVkSampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
- AddressMode u, AddressMode v);
+ AddressMode u, AddressMode v, AddressMode w);
~QVkSampler();
void release() override;
bool build() override;
@@ -171,10 +170,16 @@ struct QVkRenderPassDescriptor : public QRhiRenderPassDescriptor
QVkRenderPassDescriptor(QRhiImplementation *rhi);
~QVkRenderPassDescriptor();
void release() override;
+ bool isCompatible(const QRhiRenderPassDescriptor *other) const override;
const QRhiNativeHandles *nativeHandles() override;
VkRenderPass rp = VK_NULL_HANDLE;
bool ownsRp = false;
+ QVarLengthArray<VkAttachmentDescription, 8> attDescs;
+ QVarLengthArray<VkAttachmentReference, 8> colorRefs;
+ QVarLengthArray<VkAttachmentReference, 8> resolveRefs;
+ bool hasDepthStencil = false;
+ VkAttachmentReference dsRef;
QRhiVulkanRenderPassNativeHandles nativeHandlesStruct;
int lastActiveFrameSlot = -1;
};
@@ -365,6 +370,13 @@ struct QVkCommandBuffer : public QRhiCommandBuffer
QVarLengthArray<VkCommandBuffer, 4> secondaryCbs;
bool inExternal;
+ struct {
+ QHash<QRhiResource *, QPair<VkAccessFlags, bool> > writtenResources;
+ void reset() {
+ writtenResources.clear();
+ }
+ } computePassState;
+
struct Command {
enum Cmd {
CopyBuffer,
@@ -424,12 +436,14 @@ struct QVkCommandBuffer : public QRhiCommandBuffer
struct {
VkPipelineStageFlags srcStageMask;
VkPipelineStageFlags dstStageMask;
- VkImageMemoryBarrier desc;
+ int count;
+ int index;
} imageBarrier;
struct {
VkPipelineStageFlags srcStageMask;
VkPipelineStageFlags dstStageMask;
- VkBufferMemoryBarrier desc;
+ int count;
+ int index;
} bufferBarrier;
struct {
VkImage src;
@@ -532,6 +546,8 @@ struct QVkCommandBuffer : public QRhiCommandBuffer
pools.vertexBuffer.clear();
pools.vertexBufferOffset.clear();
pools.debugMarkerData.clear();
+ pools.imageBarrier.clear();
+ pools.bufferBarrier.clear();
}
struct {
@@ -541,6 +557,8 @@ struct QVkCommandBuffer : public QRhiCommandBuffer
QVarLengthArray<VkBuffer, 4> vertexBuffer;
QVarLengthArray<VkDeviceSize, 4> vertexBufferOffset;
QVarLengthArray<QByteArray, 4> debugMarkerData;
+ QVarLengthArray<VkImageMemoryBarrier, 8> imageBarrier;
+ QVarLengthArray<VkBufferMemoryBarrier, 8> bufferBarrier;
} pools;
friend class QRhiVulkan;
@@ -639,9 +657,12 @@ public:
const QSize &pixelSize,
int sampleCount,
QRhiTexture::Flags flags) override;
- QRhiSampler *createSampler(QRhiSampler::Filter magFilter, QRhiSampler::Filter minFilter,
+ QRhiSampler *createSampler(QRhiSampler::Filter magFilter,
+ QRhiSampler::Filter minFilter,
QRhiSampler::Filter mipmapMode,
- QRhiSampler:: AddressMode u, QRhiSampler::AddressMode v) override;
+ QRhiSampler:: AddressMode u,
+ QRhiSampler::AddressMode v,
+ QRhiSampler::AddressMode w) override;
QRhiTextureRenderTarget *createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc,
QRhiTextureRenderTarget::Flags flags) override;
@@ -727,11 +748,11 @@ public:
VkFormat optimalDepthStencilFormat();
VkSampleCountFlagBits effectiveSampleCount(int sampleCount);
- bool createDefaultRenderPass(VkRenderPass *rp,
+ bool createDefaultRenderPass(QVkRenderPassDescriptor *rpD,
bool hasDepthStencil,
VkSampleCountFlagBits samples,
VkFormat colorFormat);
- bool createOffscreenRenderPass(VkRenderPass *rp,
+ bool createOffscreenRenderPass(QVkRenderPassDescriptor *rpD,
const QRhiColorAttachment *firstColorAttachment,
const QRhiColorAttachment *lastColorAttachment,
bool preserveColor,
diff --git a/src/gui/rhi/qshader.cpp b/src/gui/rhi/qshader.cpp
index 9d35d83336..69f4a68215 100644
--- a/src/gui/rhi/qshader.cpp
+++ b/src/gui/rhi/qshader.cpp
@@ -214,9 +214,6 @@ QT_BEGIN_NAMESPACE
QShader, it indicates no shader code was found for the requested key.
*/
-static const int QSB_VERSION = 2;
-static const int QSB_VERSION_WITHOUT_BINDINGS = 1;
-
/*!
Constructs a new, empty (and thus invalid) QShader instance.
*/
@@ -368,9 +365,9 @@ QByteArray QShader::serialized() const
if (!buf.open(QIODevice::WriteOnly))
return QByteArray();
- ds << QSB_VERSION;
+ ds << QShaderPrivate::QSB_VERSION;
ds << int(d->stage);
- ds << d->desc.toBinaryJson();
+ d->desc.serialize(&ds);
ds << d->shaders.count();
for (auto it = d->shaders.cbegin(), itEnd = d->shaders.cend(); it != itEnd; ++it) {
const QShaderKey &k(it.key());
@@ -429,17 +426,37 @@ QShader QShader::fromSerialized(const QByteArray &data)
Q_ASSERT(d->ref.loadRelaxed() == 1); // must be detached
int intVal;
ds >> intVal;
- const int qsbVersion = intVal;
- if (qsbVersion != QSB_VERSION && qsbVersion != QSB_VERSION_WITHOUT_BINDINGS) {
- qWarning("Attempted to deserialize QShader with unknown version %d.", qsbVersion);
+ d->qsbVersion = intVal;
+ if (d->qsbVersion != QShaderPrivate::QSB_VERSION
+ && d->qsbVersion != QShaderPrivate::QSB_VERSION_WITH_CBOR
+ && d->qsbVersion != QShaderPrivate::QSB_VERSION_WITH_BINARY_JSON
+ && d->qsbVersion != QShaderPrivate::QSB_VERSION_WITHOUT_BINDINGS)
+ {
+ qWarning("Attempted to deserialize QShader with unknown version %d.", d->qsbVersion);
return QShader();
}
ds >> intVal;
d->stage = Stage(intVal);
- QByteArray descBin;
- ds >> descBin;
- d->desc = QShaderDescription::fromBinaryJson(descBin);
+ if (d->qsbVersion > QShaderPrivate::QSB_VERSION_WITH_CBOR) {
+ d->desc = QShaderDescription::deserialize(&ds);
+ } else if (d->qsbVersion > QShaderPrivate::QSB_VERSION_WITH_BINARY_JSON) {
+ QByteArray descBin;
+ ds >> descBin;
+ d->desc = QShaderDescription::fromCbor(descBin);
+ } else {
+#if QT_CONFIG(binaryjson) && QT_DEPRECATED_SINCE(5, 15)
+ QT_WARNING_PUSH
+ QT_WARNING_DISABLE_DEPRECATED
+ QByteArray descBin;
+ ds >> descBin;
+ d->desc = QShaderDescription::fromBinaryJson(descBin);
+ QT_WARNING_POP
+#else
+ qWarning("Cannot load QShaderDescription from binary JSON due to disabled binaryjson feature");
+ d->desc = QShaderDescription();
+#endif
+ }
int count;
ds >> count;
for (int i = 0; i < count; ++i) {
@@ -454,7 +471,7 @@ QShader QShader::fromSerialized(const QByteArray &data)
d->shaders[k] = shader;
}
- if (qsbVersion != QSB_VERSION_WITHOUT_BINDINGS) {
+ if (d->qsbVersion > QShaderPrivate::QSB_VERSION_WITHOUT_BINDINGS) {
ds >> count;
for (int i = 0; i < count; ++i) {
QShaderKey k;
@@ -657,6 +674,13 @@ QDebug operator<<(QDebug dbg, const QShaderVersion &v)
pair, because combined image samplers may map to two native resources (a
texture and a sampler) in some shading languages. In that case the second
value refers to the sampler.
+
+ \note The native binding may be -1, in case there is no active binding for
+ the resource in the shader. (for example, there is a uniform block
+ declared, but it is not used in the shader code) The map is always
+ complete, meaning there is an entry for all declared uniform blocks,
+ storage blocks, image objects, and combined samplers, but the value will be
+ -1 for those that are not actually referenced in the shader functions.
*/
/*!
diff --git a/src/gui/rhi/qshader_p_p.h b/src/gui/rhi/qshader_p_p.h
index 4535e01491..66ef18f391 100644
--- a/src/gui/rhi/qshader_p_p.h
+++ b/src/gui/rhi/qshader_p_p.h
@@ -57,6 +57,11 @@ QT_BEGIN_NAMESPACE
struct Q_GUI_EXPORT QShaderPrivate
{
+ static const int QSB_VERSION = 4;
+ static const int QSB_VERSION_WITH_CBOR = 3;
+ static const int QSB_VERSION_WITH_BINARY_JSON = 2;
+ static const int QSB_VERSION_WITHOUT_BINDINGS = 1;
+
QShaderPrivate()
: ref(1)
{
@@ -64,6 +69,7 @@ struct Q_GUI_EXPORT QShaderPrivate
QShaderPrivate(const QShaderPrivate *other)
: ref(1),
+ qsbVersion(other->qsbVersion),
stage(other->stage),
desc(other->desc),
shaders(other->shaders),
@@ -75,6 +81,7 @@ struct Q_GUI_EXPORT QShaderPrivate
static const QShaderPrivate *get(const QShader *s) { return s->d; }
QAtomicInt ref;
+ int qsbVersion = QSB_VERSION;
QShader::Stage stage = QShader::VertexStage;
QShaderDescription desc;
QHash<QShaderKey, QShaderCode> shaders;
diff --git a/src/gui/rhi/qshaderdescription.cpp b/src/gui/rhi/qshaderdescription.cpp
index 179d5f3a07..96c8d082fc 100644
--- a/src/gui/rhi/qshaderdescription.cpp
+++ b/src/gui/rhi/qshaderdescription.cpp
@@ -36,8 +36,12 @@
#include "qshaderdescription_p_p.h"
#include <QDebug>
+#include <QDataStream>
#include <QJsonObject>
#include <QJsonArray>
+#include <QCborValue>
+#include <QCborMap>
+#include <QCborArray>
QT_BEGIN_NAMESPACE
@@ -99,8 +103,8 @@ QT_BEGIN_NAMESPACE
float \c opacity at offset 64.
All this is described by a QShaderDescription object. QShaderDescription
- can also be serialized to JSON and binary JSON, and can be deserialized
- from binary JSON. In practice this is rarely needed since QShader
+ can also be serialized to JSON and CBOR, and can be deserialized
+ from CBOR. In practice this is rarely needed since QShader
takes care of the associated QShaderDescription automatically, but if the
QShaderDescription of the above shader would be written out as JSON, it
would look like the following:
@@ -333,13 +337,14 @@ bool QShaderDescription::isValid() const
}
/*!
- \return a serialized binary version of the data.
+ \return a serialized binary version of the data in CBOR (Concise Binary
+ Object Representation) format.
- \sa toJson()
+ \sa QCborValue, toJson()
*/
-QByteArray QShaderDescription::toBinaryJson() const
+QByteArray QShaderDescription::toCbor() const
{
- return d->makeDoc().toBinaryData();
+ return QCborValue::fromJsonValue(d->makeDoc().object()).toCbor();
}
/*!
@@ -347,21 +352,60 @@ QByteArray QShaderDescription::toBinaryJson() const
\note There is no deserialization method provided for JSON text.
- \sa toBinaryJson()
+ \sa toCbor()
*/
QByteArray QShaderDescription::toJson() const
{
return d->makeDoc().toJson();
}
+void QShaderDescription::serialize(QDataStream *stream) const
+{
+ d->writeToStream(stream);
+}
+
+#if QT_CONFIG(binaryjson) && QT_DEPRECATED_SINCE(5, 15)
/*!
+ \deprecated
+
Deserializes the given binary JSON \a data and returns a new
QShaderDescription.
+
+ \sa fromCbor()
*/
QShaderDescription QShaderDescription::fromBinaryJson(const QByteArray &data)
{
QShaderDescription desc;
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
QShaderDescriptionPrivate::get(&desc)->loadDoc(QJsonDocument::fromBinaryData(data));
+QT_WARNING_POP
+ return desc;
+}
+#endif
+
+/*!
+ Deserializes the given CBOR \a data and returns a new QShaderDescription.
+ */
+QShaderDescription QShaderDescription::fromCbor(const QByteArray &data)
+{
+ QShaderDescription desc;
+ const QCborValue cbor = QCborValue::fromCbor(data);
+ if (cbor.isMap()) {
+ const QJsonDocument doc(cbor.toMap().toJsonObject());
+ QShaderDescriptionPrivate::get(&desc)->loadDoc(doc);
+ }
+ if (cbor.isArray()) {
+ const QJsonDocument doc(cbor.toArray().toJsonArray());
+ QShaderDescriptionPrivate::get(&desc)->loadDoc(doc);
+ }
+ return desc;
+}
+
+QShaderDescription QShaderDescription::deserialize(QDataStream *stream)
+{
+ QShaderDescription desc;
+ QShaderDescriptionPrivate::get(&desc)->loadFromStream(stream);
return desc;
}
@@ -836,6 +880,15 @@ static void addDeco(QJsonObject *obj, const QShaderDescription::InOutVariable &v
(*obj)[imageFlagsKey] = int(v.imageFlags);
}
+static void serializeDecorations(QDataStream *stream, const QShaderDescription::InOutVariable &v)
+{
+ (*stream) << v.location;
+ (*stream) << v.binding;
+ (*stream) << v.descriptorSet;
+ (*stream) << int(v.imageFormat);
+ (*stream) << int(v.imageFlags);
+}
+
static QJsonObject inOutObject(const QShaderDescription::InOutVariable &v)
{
QJsonObject obj;
@@ -845,6 +898,13 @@ static QJsonObject inOutObject(const QShaderDescription::InOutVariable &v)
return obj;
}
+static void serializeInOutVar(QDataStream *stream, const QShaderDescription::InOutVariable &v)
+{
+ (*stream) << v.name;
+ (*stream) << int(v.type);
+ serializeDecorations(stream, v);
+}
+
static QJsonObject blockMemberObject(const QShaderDescription::BlockVariable &v)
{
QJsonObject obj;
@@ -873,6 +933,23 @@ static QJsonObject blockMemberObject(const QShaderDescription::BlockVariable &v)
return obj;
}
+static void serializeBlockMemberVar(QDataStream *stream, const QShaderDescription::BlockVariable &v)
+{
+ (*stream) << v.name;
+ (*stream) << int(v.type);
+ (*stream) << v.offset;
+ (*stream) << v.size;
+ (*stream) << v.arrayDims.count();
+ for (int dim : v.arrayDims)
+ (*stream) << dim;
+ (*stream) << v.arrayStride;
+ (*stream) << v.matrixStride;
+ (*stream) << v.matrixIsRowMajor;
+ (*stream) << v.structMembers.count();
+ for (const QShaderDescription::BlockVariable &sv : v.structMembers)
+ serializeBlockMemberVar(stream, sv);
+}
+
QJsonDocument QShaderDescriptionPrivate::makeDoc()
{
QJsonObject root;
@@ -971,6 +1048,67 @@ QJsonDocument QShaderDescriptionPrivate::makeDoc()
return QJsonDocument(root);
}
+void QShaderDescriptionPrivate::writeToStream(QDataStream *stream)
+{
+ (*stream) << inVars.count();
+ for (const QShaderDescription::InOutVariable &v : qAsConst(inVars))
+ serializeInOutVar(stream, v);
+
+ (*stream) << outVars.count();
+ for (const QShaderDescription::InOutVariable &v : qAsConst(outVars))
+ serializeInOutVar(stream, v);
+
+ (*stream) << uniformBlocks.count();
+ for (const QShaderDescription::UniformBlock &b : uniformBlocks) {
+ (*stream) << b.blockName;
+ (*stream) << b.structName;
+ (*stream) << b.size;
+ (*stream) << b.binding;
+ (*stream) << b.descriptorSet;
+ (*stream) << b.members.count();
+ for (const QShaderDescription::BlockVariable &v : b.members)
+ serializeBlockMemberVar(stream, v);
+ }
+
+ (*stream) << pushConstantBlocks.count();
+ for (const QShaderDescription::PushConstantBlock &b : pushConstantBlocks) {
+ (*stream) << b.name;
+ (*stream) << b.size;
+ (*stream) << b.members.count();
+ for (const QShaderDescription::BlockVariable &v : b.members)
+ serializeBlockMemberVar(stream, v);
+ }
+
+ (*stream) << storageBlocks.count();
+ for (const QShaderDescription::StorageBlock &b : storageBlocks) {
+ (*stream) << b.blockName;
+ (*stream) << b.instanceName;
+ (*stream) << b.knownSize;
+ (*stream) << b.binding;
+ (*stream) << b.descriptorSet;
+ (*stream) << b.members.count();
+ for (const QShaderDescription::BlockVariable &v : b.members)
+ serializeBlockMemberVar(stream, v);
+ }
+
+ (*stream) << combinedImageSamplers.count();
+ for (const QShaderDescription::InOutVariable &v : qAsConst(combinedImageSamplers)) {
+ (*stream) << v.name;
+ (*stream) << int(v.type);
+ serializeDecorations(stream, v);
+ }
+
+ (*stream) << storageImages.count();
+ for (const QShaderDescription::InOutVariable &v : qAsConst(storageImages)) {
+ (*stream) << v.name;
+ (*stream) << int(v.type);
+ serializeDecorations(stream, v);
+ }
+
+ for (size_t i = 0; i < 3; ++i)
+ (*stream) << localSize[i];
+}
+
static QShaderDescription::InOutVariable inOutVar(const QJsonObject &obj)
{
QShaderDescription::InOutVariable var;
@@ -989,6 +1127,29 @@ static QShaderDescription::InOutVariable inOutVar(const QJsonObject &obj)
return var;
}
+static void deserializeDecorations(QDataStream *stream, QShaderDescription::InOutVariable *v)
+{
+ (*stream) >> v->location;
+ (*stream) >> v->binding;
+ (*stream) >> v->descriptorSet;
+ int f;
+ (*stream) >> f;
+ v->imageFormat = QShaderDescription::ImageFormat(f);
+ (*stream) >> f;
+ v->imageFlags = QShaderDescription::ImageFlags(f);
+}
+
+static QShaderDescription::InOutVariable deserializeInOutVar(QDataStream *stream)
+{
+ QShaderDescription::InOutVariable var;
+ (*stream) >> var.name;
+ int t;
+ (*stream) >> t;
+ var.type = QShaderDescription::VariableType(t);
+ deserializeDecorations(stream, &var);
+ return var;
+}
+
static QShaderDescription::BlockVariable blockVar(const QJsonObject &obj)
{
QShaderDescription::BlockVariable var;
@@ -1015,6 +1176,30 @@ static QShaderDescription::BlockVariable blockVar(const QJsonObject &obj)
return var;
}
+static QShaderDescription::BlockVariable deserializeBlockMemberVar(QDataStream *stream)
+{
+ QShaderDescription::BlockVariable var;
+ (*stream) >> var.name;
+ int t;
+ (*stream) >> t;
+ var.type = QShaderDescription::VariableType(t);
+ (*stream) >> var.offset;
+ (*stream) >> var.size;
+ int count;
+ (*stream) >> count;
+ var.arrayDims.resize(count);
+ for (int i = 0; i < count; ++i)
+ (*stream) >> var.arrayDims[i];
+ (*stream) >> var.arrayStride;
+ (*stream) >> var.matrixStride;
+ (*stream) >> var.matrixIsRowMajor;
+ (*stream) >> count;
+ var.structMembers.resize(count);
+ for (int i = 0; i < count; ++i)
+ var.structMembers[i] = deserializeBlockMemberVar(stream);
+ return var;
+}
+
void QShaderDescriptionPrivate::loadDoc(const QJsonDocument &doc)
{
if (doc.isNull()) {
@@ -1119,4 +1304,187 @@ void QShaderDescriptionPrivate::loadDoc(const QJsonDocument &doc)
}
}
+void QShaderDescriptionPrivate::loadFromStream(QDataStream *stream)
+{
+ Q_ASSERT(ref.loadRelaxed() == 1); // must be detached
+
+ int count;
+ (*stream) >> count;
+ inVars.resize(count);
+ for (int i = 0; i < count; ++i)
+ inVars[i] = deserializeInOutVar(stream);
+
+ (*stream) >> count;
+ outVars.resize(count);
+ for (int i = 0; i < count; ++i)
+ outVars[i] = deserializeInOutVar(stream);
+
+ (*stream) >> count;
+ uniformBlocks.resize(count);
+ for (int i = 0; i < count; ++i) {
+ (*stream) >> uniformBlocks[i].blockName;
+ (*stream) >> uniformBlocks[i].structName;
+ (*stream) >> uniformBlocks[i].size;
+ (*stream) >> uniformBlocks[i].binding;
+ (*stream) >> uniformBlocks[i].descriptorSet;
+ int memberCount;
+ (*stream) >> memberCount;
+ uniformBlocks[i].members.resize(memberCount);
+ for (int memberIdx = 0; memberIdx < memberCount; ++memberIdx)
+ uniformBlocks[i].members[memberIdx] = deserializeBlockMemberVar(stream);
+ }
+
+ (*stream) >> count;
+ pushConstantBlocks.resize(count);
+ for (int i = 0; i < count; ++i) {
+ (*stream) >> pushConstantBlocks[i].name;
+ (*stream) >> pushConstantBlocks[i].size;
+ int memberCount;
+ (*stream) >> memberCount;
+ pushConstantBlocks[i].members.resize(memberCount);
+ for (int memberIdx = 0; memberIdx < memberCount; ++memberIdx)
+ pushConstantBlocks[i].members[memberIdx] = deserializeBlockMemberVar(stream);
+ }
+
+ (*stream) >> count;
+ storageBlocks.resize(count);
+ for (int i = 0; i < count; ++i) {
+ (*stream) >> storageBlocks[i].blockName;
+ (*stream) >> storageBlocks[i].instanceName;
+ (*stream) >> storageBlocks[i].knownSize;
+ (*stream) >> storageBlocks[i].binding;
+ (*stream) >> storageBlocks[i].descriptorSet;
+ int memberCount;
+ (*stream) >> memberCount;
+ storageBlocks[i].members.resize(memberCount);
+ for (int memberIdx = 0; memberIdx < memberCount; ++memberIdx)
+ storageBlocks[i].members[memberIdx] = deserializeBlockMemberVar(stream);
+ }
+
+ (*stream) >> count;
+ combinedImageSamplers.resize(count);
+ for (int i = 0; i < count; ++i) {
+ (*stream) >> combinedImageSamplers[i].name;
+ int t;
+ (*stream) >> t;
+ combinedImageSamplers[i].type = QShaderDescription::VariableType(t);
+ deserializeDecorations(stream, &combinedImageSamplers[i]);
+ }
+
+ (*stream) >> count;
+ storageImages.resize(count);
+ for (int i = 0; i < count; ++i) {
+ (*stream) >> storageImages[i].name;
+ int t;
+ (*stream) >> t;
+ storageImages[i].type = QShaderDescription::VariableType(t);
+ deserializeDecorations(stream, &storageImages[i]);
+ }
+
+ for (size_t i = 0; i < 3; ++i)
+ (*stream) >> localSize[i];
+}
+
+/*!
+ Returns \c true if the two QShaderDescription objects \a lhs and \a rhs are
+ equal.
+
+ \relates QShaderDescription
+ */
+bool operator==(const QShaderDescription &lhs, const QShaderDescription &rhs) Q_DECL_NOTHROW
+{
+ if (lhs.d == rhs.d)
+ return true;
+
+ return lhs.d->inVars == rhs.d->inVars
+ && lhs.d->outVars == rhs.d->outVars
+ && lhs.d->uniformBlocks == rhs.d->uniformBlocks
+ && lhs.d->pushConstantBlocks == rhs.d->pushConstantBlocks
+ && lhs.d->storageBlocks == rhs.d->storageBlocks
+ && lhs.d->combinedImageSamplers == rhs.d->combinedImageSamplers
+ && lhs.d->storageImages == rhs.d->storageImages
+ && lhs.d->localSize == rhs.d->localSize;
+}
+
+/*!
+ Returns \c true if the two InOutVariable objects \a lhs and \a rhs are
+ equal.
+
+ \relates QShaderDescription::InOutVariable
+ */
+bool operator==(const QShaderDescription::InOutVariable &lhs, const QShaderDescription::InOutVariable &rhs) Q_DECL_NOTHROW
+{
+ return lhs.name == rhs.name
+ && lhs.type == rhs.type
+ && lhs.location == rhs.location
+ && lhs.binding == rhs.binding
+ && lhs.descriptorSet == rhs.descriptorSet
+ && lhs.imageFormat == rhs.imageFormat
+ && lhs.imageFlags == rhs.imageFlags;
+}
+
+/*!
+ Returns \c true if the two BlockVariable objects \a lhs and \a rhs are
+ equal.
+
+ \relates QShaderDescription::BlockVariable
+ */
+bool operator==(const QShaderDescription::BlockVariable &lhs, const QShaderDescription::BlockVariable &rhs) Q_DECL_NOTHROW
+{
+ return lhs.name == rhs.name
+ && lhs.type == rhs.type
+ && lhs.offset == rhs.offset
+ && lhs.size == rhs.size
+ && lhs.arrayDims == rhs.arrayDims
+ && lhs.arrayStride == rhs.arrayStride
+ && lhs.matrixStride == rhs.matrixStride
+ && lhs.matrixIsRowMajor == rhs.matrixIsRowMajor
+ && lhs.structMembers == rhs.structMembers;
+}
+
+/*!
+ Returns \c true if the two UniformBlock objects \a lhs and \a rhs are
+ equal.
+
+ \relates QShaderDescription::UniformBlock
+ */
+bool operator==(const QShaderDescription::UniformBlock &lhs, const QShaderDescription::UniformBlock &rhs) Q_DECL_NOTHROW
+{
+ return lhs.blockName == rhs.blockName
+ && lhs.structName == rhs.structName
+ && lhs.size == rhs.size
+ && lhs.binding == rhs.binding
+ && lhs.descriptorSet == rhs.descriptorSet
+ && lhs.members == rhs.members;
+}
+
+/*!
+ Returns \c true if the two PushConstantBlock objects \a lhs and \a rhs are
+ equal.
+
+ \relates QShaderDescription::PushConstantBlock
+ */
+bool operator==(const QShaderDescription::PushConstantBlock &lhs, const QShaderDescription::PushConstantBlock &rhs) Q_DECL_NOTHROW
+{
+ return lhs.name == rhs.name
+ && lhs.size == rhs.size
+ && lhs.members == rhs.members;
+}
+
+/*!
+ Returns \c true if the two StorageBlock objects \a lhs and \a rhs are
+ equal.
+
+ \relates QShaderDescription::StorageBlock
+ */
+bool operator==(const QShaderDescription::StorageBlock &lhs, const QShaderDescription::StorageBlock &rhs) Q_DECL_NOTHROW
+{
+ return lhs.blockName == rhs.blockName
+ && lhs.instanceName == rhs.instanceName
+ && lhs.knownSize == rhs.knownSize
+ && lhs.binding == rhs.binding
+ && lhs.descriptorSet == rhs.descriptorSet
+ && lhs.members == rhs.members;
+}
+
QT_END_NAMESPACE
diff --git a/src/gui/rhi/qshaderdescription_p.h b/src/gui/rhi/qshaderdescription_p.h
index 5a63b998cd..108fc32a56 100644
--- a/src/gui/rhi/qshaderdescription_p.h
+++ b/src/gui/rhi/qshaderdescription_p.h
@@ -56,6 +56,7 @@
QT_BEGIN_NAMESPACE
struct QShaderDescriptionPrivate;
+class QDataStream;
class Q_GUI_EXPORT QShaderDescription
{
@@ -68,10 +69,16 @@ public:
bool isValid() const;
- QByteArray toBinaryJson() const;
+ QByteArray toCbor() const;
+ void serialize(QDataStream *stream) const;
QByteArray toJson() const;
+#if QT_CONFIG(binaryjson) && QT_DEPRECATED_SINCE(5, 15)
+ QT_DEPRECATED_X("Use CBOR format instead")
static QShaderDescription fromBinaryJson(const QByteArray &data);
+#endif
+ static QShaderDescription fromCbor(const QByteArray &data);
+ static QShaderDescription deserialize(QDataStream *stream);
enum VariableType {
Unknown = 0,
@@ -263,6 +270,7 @@ private:
#ifndef QT_NO_DEBUG_STREAM
friend Q_GUI_EXPORT QDebug operator<<(QDebug, const QShaderDescription &);
#endif
+ friend Q_GUI_EXPORT bool operator==(const QShaderDescription &lhs, const QShaderDescription &rhs) Q_DECL_NOTHROW;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QShaderDescription::ImageFlags)
@@ -276,6 +284,43 @@ Q_GUI_EXPORT QDebug operator<<(QDebug, const QShaderDescription::PushConstantBlo
Q_GUI_EXPORT QDebug operator<<(QDebug, const QShaderDescription::StorageBlock &);
#endif
+Q_GUI_EXPORT bool operator==(const QShaderDescription &lhs, const QShaderDescription &rhs) Q_DECL_NOTHROW;
+Q_GUI_EXPORT bool operator==(const QShaderDescription::InOutVariable &lhs, const QShaderDescription::InOutVariable &rhs) Q_DECL_NOTHROW;
+Q_GUI_EXPORT bool operator==(const QShaderDescription::BlockVariable &lhs, const QShaderDescription::BlockVariable &rhs) Q_DECL_NOTHROW;
+Q_GUI_EXPORT bool operator==(const QShaderDescription::UniformBlock &lhs, const QShaderDescription::UniformBlock &rhs) Q_DECL_NOTHROW;
+Q_GUI_EXPORT bool operator==(const QShaderDescription::PushConstantBlock &lhs, const QShaderDescription::PushConstantBlock &rhs) Q_DECL_NOTHROW;
+Q_GUI_EXPORT bool operator==(const QShaderDescription::StorageBlock &lhs, const QShaderDescription::StorageBlock &rhs) Q_DECL_NOTHROW;
+
+inline bool operator!=(const QShaderDescription &lhs, const QShaderDescription &rhs) Q_DECL_NOTHROW
+{
+ return !(lhs == rhs);
+}
+
+inline bool operator!=(const QShaderDescription::InOutVariable &lhs, const QShaderDescription::InOutVariable &rhs) Q_DECL_NOTHROW
+{
+ return !(lhs == rhs);
+}
+
+inline bool operator!=(const QShaderDescription::BlockVariable &lhs, const QShaderDescription::BlockVariable &rhs) Q_DECL_NOTHROW
+{
+ return !(lhs == rhs);
+}
+
+inline bool operator!=(const QShaderDescription::UniformBlock &lhs, const QShaderDescription::UniformBlock &rhs) Q_DECL_NOTHROW
+{
+ return !(lhs == rhs);
+}
+
+inline bool operator!=(const QShaderDescription::PushConstantBlock &lhs, const QShaderDescription::PushConstantBlock &rhs) Q_DECL_NOTHROW
+{
+ return !(lhs == rhs);
+}
+
+inline bool operator!=(const QShaderDescription::StorageBlock &lhs, const QShaderDescription::StorageBlock &rhs) Q_DECL_NOTHROW
+{
+ return !(lhs == rhs);
+}
+
QT_END_NAMESPACE
#endif
diff --git a/src/gui/rhi/qshaderdescription_p_p.h b/src/gui/rhi/qshaderdescription_p_p.h
index 1caee24984..69b6e811a1 100644
--- a/src/gui/rhi/qshaderdescription_p_p.h
+++ b/src/gui/rhi/qshaderdescription_p_p.h
@@ -80,7 +80,9 @@ struct Q_GUI_EXPORT QShaderDescriptionPrivate
static const QShaderDescriptionPrivate *get(const QShaderDescription *desc) { return desc->d; }
QJsonDocument makeDoc();
+ void writeToStream(QDataStream *stream);
void loadDoc(const QJsonDocument &doc);
+ void loadFromStream(QDataStream *stream);
QAtomicInt ref;
QVector<QShaderDescription::InOutVariable> inVars;
diff --git a/src/gui/rhi/rhi.pri b/src/gui/rhi/rhi.pri
index 4297a5602b..ccd9592634 100644
--- a/src/gui/rhi/rhi.pri
+++ b/src/gui/rhi/rhi.pri
@@ -43,15 +43,15 @@ win32 {
LIBS += -ld3d11 -ldxgi -ldxguid
}
-# darwin {
-macos {
+macos|ios {
HEADERS += \
rhi/qrhimetal_p.h \
rhi/qrhimetal_p_p.h
SOURCES += \
rhi/qrhimetal.mm
- LIBS += -framework AppKit -framework Metal
+ macos: LIBS += -framework AppKit
+ LIBS += -framework Metal
}
include($$PWD/../../3rdparty/VulkanMemoryAllocator.pri)