From 913146ccd401216f71f037ea304b5e61b7a138cf Mon Sep 17 00:00:00 2001 From: Paul Olav Tvete Date: Fri, 29 Nov 2019 12:41:38 +0100 Subject: RHI: new native texture API The new version takes/returns a value that can be unpacked and passed to other functions without knowing which backend is in use. The old API will be removed in a later change when dependent modules have been updated Task-number: QTBUG-78570 Change-Id: I18d928ceef3cb617c0c509ecccb345551a7990af Reviewed-by: Laszlo Agocs --- src/gui/rhi/qrhi.cpp | 67 ++++++++++++++++++++++++++++++++++++++++++++ src/gui/rhi/qrhi_p.h | 7 +++++ src/gui/rhi/qrhid3d11.cpp | 28 ++++++++++++++++++ src/gui/rhi/qrhid3d11_p_p.h | 2 ++ src/gui/rhi/qrhigles2.cpp | 29 +++++++++++++++++++ src/gui/rhi/qrhigles2_p_p.h | 2 ++ src/gui/rhi/qrhimetal.mm | 29 +++++++++++++++++++ src/gui/rhi/qrhimetal_p_p.h | 2 ++ src/gui/rhi/qrhinull.cpp | 6 ++++ src/gui/rhi/qrhinull_p_p.h | 1 + src/gui/rhi/qrhivulkan.cpp | 30 ++++++++++++++++++++ src/gui/rhi/qrhivulkan_p_p.h | 2 ++ 12 files changed, 205 insertions(+) (limited to 'src/gui') diff --git a/src/gui/rhi/qrhi.cpp b/src/gui/rhi/qrhi.cpp index ece5190ff7..58f30deb41 100644 --- a/src/gui/rhi/qrhi.cpp +++ b/src/gui/rhi/qrhi.cpp @@ -2159,6 +2159,32 @@ QRhiResource::Type QRhiRenderBuffer::resourceType() const \value ASTC_12x12 */ +/*! + \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 */ @@ -2196,11 +2222,24 @@ QRhiResource::Type QRhiTexture::resourceType() const \sa QRhiVulkanTextureNativeHandles, QRhiD3D11TextureNativeHandles, QRhiMetalTextureNativeHandles, QRhiGles2TextureNativeHandles */ +// TODO: remove this version once QtQuick has stopped using it const QRhiNativeHandles *QRhiTexture::nativeHandles() { return nullptr; } +/*! + \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 buildFrom() + */ +QRhiTexture::NativeTexture QRhiTexture::nativeTexture() +{ + return {}; +} + /*! Similar to build() except that no new native textures are created. Instead, the texture from \a src is used. @@ -2224,12 +2263,40 @@ const QRhiNativeHandles *QRhiTexture::nativeHandles() \sa QRhiVulkanTextureNativeHandles, QRhiD3D11TextureNativeHandles, QRhiMetalTextureNativeHandles, QRhiGles2TextureNativeHandles */ +// TODO: remove this version once QtQuick has stopped using it bool QRhiTexture::buildFrom(const QRhiNativeHandles *src) { Q_UNUSED(src); return false; } +/*! + Similar to build() except that no new native textures are created. Instead, + 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 + an external graphics engine. + + \note format(), pixelSize(), sampleCount(), and flags() must still be set + correctly. Passing incorrect sizes and other values to QRhi::newTexture() + and then following it with a buildFrom() expecting that the native texture + object alone is sufficient to deduce such values is \b wrong and will lead + to problems. + + \note QRhiTexture does not take ownership of the texture object. release() + 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 nativeTexture(). + +*/ +bool QRhiTexture::buildFrom(QRhiTexture::NativeTexture src) +{ + Q_UNUSED(src); + return false; +} + /*! \class QRhiSampler \internal diff --git a/src/gui/rhi/qrhi_p.h b/src/gui/rhi/qrhi_p.h index 6fb9c44ae6..44118b2f10 100644 --- a/src/gui/rhi/qrhi_p.h +++ b/src/gui/rhi/qrhi_p.h @@ -760,6 +760,11 @@ public: ASTC_12x12 }; + struct NativeTexture { + const void *object; + int layout; + }; + QRhiResource::Type resourceType() const override; Format format() const { return m_format; } @@ -776,7 +781,9 @@ public: virtual bool build() = 0; virtual const QRhiNativeHandles *nativeHandles(); + virtual NativeTexture nativeTexture(); virtual bool buildFrom(const QRhiNativeHandles *src); + virtual bool buildFrom(NativeTexture src); protected: QRhiTexture(QRhiImplementation *rhi, Format format_, const QSize &pixelSize_, diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp index 52109edce0..ba2488bffb 100644 --- a/src/gui/rhi/qrhid3d11.cpp +++ b/src/gui/rhi/qrhid3d11.cpp @@ -2764,11 +2764,39 @@ bool QD3D11Texture::buildFrom(const QRhiNativeHandles *src) return true; } +bool QD3D11Texture::buildFrom(QRhiTexture::NativeTexture src) +{ + auto *srcTex = static_cast(src.object); + if (!srcTex || !*srcTex) + return false; + + if (!prepareBuild()) + return false; + + tex = *srcTex; + + if (!finishBuild()) + return false; + + QRHI_PROF; + QRHI_PROF_F(newTexture(this, false, int(mipLevelCount), m_flags.testFlag(CubeMap) ? 6 : 1, int(sampleDesc.Count))); + + owns = false; + QRHI_RES_RHI(QRhiD3D11); + rhiD->registerResource(this); + return true; +} + const QRhiNativeHandles *QD3D11Texture::nativeHandles() { return &nativeHandlesStruct; } +QRhiTexture::NativeTexture QD3D11Texture::nativeTexture() +{ + return {&nativeHandlesStruct.texture, 0}; +} + ID3D11UnorderedAccessView *QD3D11Texture::unorderedAccessViewForLevel(int level) { if (perLevelViews[level]) diff --git a/src/gui/rhi/qrhid3d11_p_p.h b/src/gui/rhi/qrhid3d11_p_p.h index 13c56b1d6d..8f02c4300b 100644 --- a/src/gui/rhi/qrhid3d11_p_p.h +++ b/src/gui/rhi/qrhid3d11_p_p.h @@ -100,7 +100,9 @@ struct QD3D11Texture : public QRhiTexture void release() override; bool build() override; bool buildFrom(const QRhiNativeHandles *src) override; + bool buildFrom(NativeTexture src) override; const QRhiNativeHandles *nativeHandles() override; + NativeTexture nativeTexture() override; bool prepareBuild(QSize *adjustedSize = nullptr); bool finishBuild(); diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp index b551980bb3..563d59b318 100644 --- a/src/gui/rhi/qrhigles2.cpp +++ b/src/gui/rhi/qrhigles2.cpp @@ -3404,11 +3404,40 @@ bool QGles2Texture::buildFrom(const QRhiNativeHandles *src) return true; } +bool QGles2Texture::buildFrom(QRhiTexture::NativeTexture src) +{ + const uint *textureId = static_cast(src.object); + if (!textureId || !*textureId) + return false; + + if (!prepareBuild()) + return false; + + texture = *textureId; + specified = true; + + QRHI_RES_RHI(QRhiGles2); + QRHI_PROF; + 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() { return &nativeHandlesStruct; } +QRhiTexture::NativeTexture QGles2Texture::nativeTexture() +{ + return {&nativeHandlesStruct.texture, 0}; +} + QGles2Sampler::QGles2Sampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode, AddressMode u, AddressMode v) : QRhiSampler(rhi, magFilter, minFilter, mipmapMode, u, v) diff --git a/src/gui/rhi/qrhigles2_p_p.h b/src/gui/rhi/qrhigles2_p_p.h index b0f5e340fb..0283fadb4e 100644 --- a/src/gui/rhi/qrhigles2_p_p.h +++ b/src/gui/rhi/qrhigles2_p_p.h @@ -133,7 +133,9 @@ struct QGles2Texture : public QRhiTexture void release() override; bool build() override; bool buildFrom(const QRhiNativeHandles *src) override; + bool buildFrom(NativeTexture src) override; const QRhiNativeHandles *nativeHandles() override; + NativeTexture nativeTexture() override; bool prepareBuild(QSize *adjustedSize = nullptr); diff --git a/src/gui/rhi/qrhimetal.mm b/src/gui/rhi/qrhimetal.mm index e5af1cfab1..555ed5e79f 100644 --- a/src/gui/rhi/qrhimetal.mm +++ b/src/gui/rhi/qrhimetal.mm @@ -2499,11 +2499,40 @@ bool QMetalTexture::buildFrom(const QRhiNativeHandles *src) return true; } +bool QMetalTexture::buildFrom(QRhiTexture::NativeTexture src) +{ + void * const * tex = (void * const *) src.object; + if (!tex || !*tex) + return false; + + if (!prepareBuild()) + return false; + + d->tex = (id) *tex; + + d->owns = false; + nativeHandlesStruct.texture = d->tex; + + QRHI_PROF; + QRHI_PROF_F(newTexture(this, false, mipLevelCount, m_flags.testFlag(CubeMap) ? 6 : 1, samples)); + + lastActiveFrameSlot = -1; + generation += 1; + QRHI_RES_RHI(QRhiMetal); + rhiD->registerResource(this); + return true; +} + const QRhiNativeHandles *QMetalTexture::nativeHandles() { return &nativeHandlesStruct; } +QRhiTexture::NativeTexture QMetalTexture::nativeTexture() +{ + return {&nativeHandlesStruct.texture, 0}; +} + id QMetalTextureData::viewForLevel(int level) { Q_ASSERT(level >= 0 && level < int(q->mipLevelCount)); diff --git a/src/gui/rhi/qrhimetal_p_p.h b/src/gui/rhi/qrhimetal_p_p.h index 7876539fcd..8e655fd98b 100644 --- a/src/gui/rhi/qrhimetal_p_p.h +++ b/src/gui/rhi/qrhimetal_p_p.h @@ -101,7 +101,9 @@ struct QMetalTexture : public QRhiTexture void release() override; bool build() override; bool buildFrom(const QRhiNativeHandles *src) override; + bool buildFrom(NativeTexture src) override; const QRhiNativeHandles *nativeHandles() override; + NativeTexture nativeTexture() override; bool prepareBuild(QSize *adjustedSize = nullptr); diff --git a/src/gui/rhi/qrhinull.cpp b/src/gui/rhi/qrhinull.cpp index 0baea1b9d6..80f004e049 100644 --- a/src/gui/rhi/qrhinull.cpp +++ b/src/gui/rhi/qrhinull.cpp @@ -651,6 +651,12 @@ bool QNullTexture::buildFrom(const QRhiNativeHandles *src) return true; } +bool QNullTexture::buildFrom(QRhiTexture::NativeTexture src) +{ + Q_UNUSED(src) + return buildFrom(nullptr); +} + const QRhiNativeHandles *QNullTexture::nativeHandles() { return &nativeHandlesStruct; diff --git a/src/gui/rhi/qrhinull_p_p.h b/src/gui/rhi/qrhinull_p_p.h index c96f279f7d..57c3de0418 100644 --- a/src/gui/rhi/qrhinull_p_p.h +++ b/src/gui/rhi/qrhinull_p_p.h @@ -81,6 +81,7 @@ struct QNullTexture : public QRhiTexture void release() override; bool build() override; bool buildFrom(const QRhiNativeHandles *src) override; + bool buildFrom(NativeTexture src) override; const QRhiNativeHandles *nativeHandles() override; QRhiNullTextureNativeHandles nativeHandlesStruct; diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp index 49ca2326bc..21ae142b1d 100644 --- a/src/gui/rhi/qrhivulkan.cpp +++ b/src/gui/rhi/qrhivulkan.cpp @@ -5370,12 +5370,42 @@ bool QVkTexture::buildFrom(const QRhiNativeHandles *src) return true; } +bool QVkTexture::buildFrom(QRhiTexture::NativeTexture src) +{ + auto *img = static_cast(src.object); + if (!img || !*img) + return false; + + if (!prepareBuild()) + return false; + + image = *img; + + if (!finishBuild()) + return false; + + QRHI_PROF; + QRHI_PROF_F(newTexture(this, false, int(mipLevelCount), m_flags.testFlag(CubeMap) ? 6 : 1, samples)); + + usageState.layout = VkImageLayout(src.layout); + + owns = false; + QRHI_RES_RHI(QRhiVulkan); + rhiD->registerResource(this); + return true; +} + const QRhiNativeHandles *QVkTexture::nativeHandles() { nativeHandlesStruct.layout = usageState.layout; return &nativeHandlesStruct; } +QRhiTexture::NativeTexture QVkTexture::nativeTexture() +{ + return {&nativeHandlesStruct.image, usageState.layout}; +} + VkImageView QVkTexture::imageViewForLevel(int level) { Q_ASSERT(level >= 0 && level < int(mipLevelCount)); diff --git a/src/gui/rhi/qrhivulkan_p_p.h b/src/gui/rhi/qrhivulkan_p_p.h index ffa8c59ed5..d1b77870a1 100644 --- a/src/gui/rhi/qrhivulkan_p_p.h +++ b/src/gui/rhi/qrhivulkan_p_p.h @@ -121,7 +121,9 @@ struct QVkTexture : public QRhiTexture void release() override; bool build() override; bool buildFrom(const QRhiNativeHandles *src) override; + bool buildFrom(NativeTexture src) override; const QRhiNativeHandles *nativeHandles() override; + NativeTexture nativeTexture() override; bool prepareBuild(QSize *adjustedSize = nullptr); bool finishBuild(); -- cgit v1.2.3