diff --git a/src/gui/rhi/qrhi.cpp b/src/gui/rhi/qrhi.cpp index 1eb26985bf..6a118d20c8 100644 --- a/src/gui/rhi/qrhi.cpp +++ b/src/gui/rhi/qrhi.cpp @@ -2123,9 +2123,11 @@ QRhiBuffer::NativeBuffer QRhiBuffer::nativeBuffer() \internal */ QRhiRenderBuffer::QRhiRenderBuffer(QRhiImplementation *rhi, Type type_, const QSize &pixelSize_, - int sampleCount_, Flags flags_) + int sampleCount_, Flags flags_, + QRhiTexture::Format backingFormatHint_) : QRhiResource(rhi), - m_type(type_), m_pixelSize(pixelSize_), m_sampleCount(sampleCount_), m_flags(flags_) + m_type(type_), m_pixelSize(pixelSize_), m_sampleCount(sampleCount_), m_flags(flags_), + m_backingFormatHint(backingFormatHint_) { } @@ -5488,14 +5490,29 @@ QRhiBuffer *QRhi::newBuffer(QRhiBuffer::Type type, \return a new renderbuffer with the specified \a type, \a pixelSize, \a sampleCount, and \a flags. + When \a backingFormatHint is set to a texture format other than + QRhiTexture::UnknownFormat, it may be used by the backend to decide what + format to use for the storage backing the renderbuffer. + + \note \a backingFormatHint becomes relevant typically when multisampling + and floating point texture formats are involved: rendering into a + multisample QRhiRenderBuffer and then resolving into a non-RGBA8 + QRhiTexture implies (with some graphics APIs) that the storage backing the + QRhiRenderBuffer uses the matching non-RGBA8 format. That means that + passing a format like QRhiTexture::RGBA32F is important, because backends + will typically opt for QRhiTexture::RGBA8 by default, which would then + break later on due to attempting to set up RGBA8->RGBA32F multisample + resolve in the color attachment(s) of the QRhiTextureRenderTarget. + \sa QRhiResource::release() */ QRhiRenderBuffer *QRhi::newRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize, int sampleCount, - QRhiRenderBuffer::Flags flags) + QRhiRenderBuffer::Flags flags, + QRhiTexture::Format backingFormatHint) { - return d->createRenderBuffer(type, pixelSize, sampleCount, flags); + return d->createRenderBuffer(type, pixelSize, sampleCount, flags, backingFormatHint); } /*! diff --git a/src/gui/rhi/qrhi_p.h b/src/gui/rhi/qrhi_p.h index 5ef415e96c..e63a828bfc 100644 --- a/src/gui/rhi/qrhi_p.h +++ b/src/gui/rhi/qrhi_p.h @@ -908,11 +908,12 @@ public: protected: QRhiRenderBuffer(QRhiImplementation *rhi, Type type_, const QSize &pixelSize_, - int sampleCount_, Flags flags_); + int sampleCount_, Flags flags_, QRhiTexture::Format backingFormatHint_); Type m_type; QSize m_pixelSize; int m_sampleCount; Flags m_flags; + QRhiTexture::Format m_backingFormatHint; }; Q_DECLARE_OPERATORS_FOR_FLAGS(QRhiRenderBuffer::Flags) @@ -1493,7 +1494,8 @@ public: QRhiRenderBuffer *newRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize, int sampleCount = 1, - QRhiRenderBuffer::Flags flags = QRhiRenderBuffer::Flags()); + QRhiRenderBuffer::Flags flags = QRhiRenderBuffer::Flags(), + QRhiTexture::Format backingFormatHint = QRhiTexture::UnknownFormat); QRhiTexture *newTexture(QRhiTexture::Format format, const QSize &pixelSize, diff --git a/src/gui/rhi/qrhi_p_p.h b/src/gui/rhi/qrhi_p_p.h index 4a4c044a29..95f04fbd1b 100644 --- a/src/gui/rhi/qrhi_p_p.h +++ b/src/gui/rhi/qrhi_p_p.h @@ -80,7 +80,8 @@ public: virtual QRhiRenderBuffer *createRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize, int sampleCount, - QRhiRenderBuffer::Flags flags) = 0; + QRhiRenderBuffer::Flags flags, + QRhiTexture::Format backingFormatHint) = 0; virtual QRhiTexture *createTexture(QRhiTexture::Format format, const QSize &pixelSize, int sampleCount, diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp index c3c40b4cc4..8336d43ff6 100644 --- a/src/gui/rhi/qrhid3d11.cpp +++ b/src/gui/rhi/qrhid3d11.cpp @@ -528,9 +528,10 @@ bool QRhiD3D11::isDeviceLost() const } QRhiRenderBuffer *QRhiD3D11::createRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize, - int sampleCount, QRhiRenderBuffer::Flags flags) + int sampleCount, QRhiRenderBuffer::Flags flags, + QRhiTexture::Format backingFormatHint) { - return new QD3D11RenderBuffer(this, type, pixelSize, sampleCount, flags); + return new QD3D11RenderBuffer(this, type, pixelSize, sampleCount, flags, backingFormatHint); } QRhiTexture *QRhiD3D11::createTexture(QRhiTexture::Format format, const QSize &pixelSize, @@ -2613,8 +2614,9 @@ ID3D11UnorderedAccessView *QD3D11Buffer::unorderedAccessView() } QD3D11RenderBuffer::QD3D11RenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize, - int sampleCount, QRhiRenderBuffer::Flags flags) - : QRhiRenderBuffer(rhi, type, pixelSize, sampleCount, flags) + int sampleCount, QRhiRenderBuffer::Flags flags, + QRhiTexture::Format backingFormatHint) + : QRhiRenderBuffer(rhi, type, pixelSize, sampleCount, flags, backingFormatHint) { } @@ -2668,7 +2670,8 @@ bool QD3D11RenderBuffer::build() desc.Usage = D3D11_USAGE_DEFAULT; if (m_type == Color) { - dxgiFormat = DXGI_FORMAT_R8G8B8A8_UNORM; + dxgiFormat = m_backingFormatHint == QRhiTexture::UnknownFormat ? DXGI_FORMAT_R8G8B8A8_UNORM + : toD3DTextureFormat(m_backingFormatHint, {}); desc.Format = dxgiFormat; desc.BindFlags = D3D11_BIND_RENDER_TARGET; HRESULT hr = rhiD->dev->CreateTexture2D(&desc, nullptr, &tex); @@ -2721,7 +2724,10 @@ bool QD3D11RenderBuffer::build() QRhiTexture::Format QD3D11RenderBuffer::backingFormat() const { - return m_type == Color ? QRhiTexture::RGBA8 : QRhiTexture::UnknownFormat; + if (m_backingFormatHint != QRhiTexture::UnknownFormat) + return m_backingFormatHint; + else + return m_type == Color ? QRhiTexture::RGBA8 : QRhiTexture::UnknownFormat; } QD3D11Texture::QD3D11Texture(QRhiImplementation *rhi, Format format, const QSize &pixelSize, diff --git a/src/gui/rhi/qrhid3d11_p_p.h b/src/gui/rhi/qrhid3d11_p_p.h index 33412b8011..2cb59b32b5 100644 --- a/src/gui/rhi/qrhid3d11_p_p.h +++ b/src/gui/rhi/qrhid3d11_p_p.h @@ -79,7 +79,8 @@ struct QD3D11Buffer : public QRhiBuffer struct QD3D11RenderBuffer : public QRhiRenderBuffer { QD3D11RenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize, - int sampleCount, QRhiRenderBuffer::Flags flags); + int sampleCount, QRhiRenderBuffer::Flags flags, + QRhiTexture::Format backingFormatHint); ~QD3D11RenderBuffer(); void release() override; bool build() override; @@ -567,7 +568,8 @@ public: QRhiRenderBuffer *createRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize, int sampleCount, - QRhiRenderBuffer::Flags flags) override; + QRhiRenderBuffer::Flags flags, + QRhiTexture::Format backingFormatHint) override; QRhiTexture *createTexture(QRhiTexture::Format format, const QSize &pixelSize, int sampleCount, diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp index 1e97d2ed0c..d8c64c7408 100644 --- a/src/gui/rhi/qrhigles2.cpp +++ b/src/gui/rhi/qrhigles2.cpp @@ -690,6 +690,87 @@ static inline GLenum toGlCompressedTextureFormat(QRhiTexture::Format format, QRh } } +static inline void toGlTextureFormat(QRhiTexture::Format format, const QRhiGles2::Caps &caps, + GLenum *glintformat, GLenum *glsizedintformat, + GLenum *glformat, GLenum *gltype) +{ + switch (format) { + case QRhiTexture::RGBA8: + *glintformat = GL_RGBA; + *glsizedintformat = caps.rgba8Format ? GL_RGBA8 : GL_RGBA; + *glformat = GL_RGBA; + *gltype = GL_UNSIGNED_BYTE; + break; + case QRhiTexture::BGRA8: + *glintformat = caps.bgraInternalFormat ? GL_BGRA : GL_RGBA; + *glsizedintformat = caps.rgba8Format ? GL_RGBA8 : GL_RGBA; + *glformat = GL_BGRA; + *gltype = GL_UNSIGNED_BYTE; + break; + case QRhiTexture::R16: + *glintformat = GL_R16; + *glsizedintformat = *glintformat; + *glformat = GL_RED; + *gltype = GL_UNSIGNED_SHORT; + break; + case QRhiTexture::R8: + *glintformat = GL_R8; + *glsizedintformat = *glintformat; + *glformat = GL_RED; + *gltype = GL_UNSIGNED_BYTE; + break; + case QRhiTexture::RED_OR_ALPHA8: + *glintformat = caps.coreProfile ? GL_R8 : GL_ALPHA; + *glsizedintformat = *glintformat; + *glformat = caps.coreProfile ? GL_RED : GL_ALPHA; + *gltype = GL_UNSIGNED_BYTE; + break; + case QRhiTexture::RGBA16F: + *glintformat = GL_RGBA16F; + *glsizedintformat = *glintformat; + *glformat = GL_RGBA; + *gltype = GL_HALF_FLOAT; + break; + case QRhiTexture::RGBA32F: + *glintformat = GL_RGBA32F; + *glsizedintformat = *glintformat; + *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; + *glformat = GL_DEPTH_COMPONENT; + *gltype = GL_UNSIGNED_SHORT; + break; + case QRhiTexture::D32F: + *glintformat = GL_DEPTH_COMPONENT32F; + *glsizedintformat = *glintformat; + *glformat = GL_DEPTH_COMPONENT; + *gltype = GL_FLOAT; + break; + default: + Q_UNREACHABLE(); + *glintformat = GL_RGBA; + *glsizedintformat = caps.rgba8Format ? GL_RGBA8 : GL_RGBA; + *glformat = GL_RGBA; + *gltype = GL_UNSIGNED_BYTE; + break; + } +} + bool QRhiGles2::isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const { if (isCompressedFormat(format)) @@ -833,9 +914,10 @@ bool QRhiGles2::isDeviceLost() const } QRhiRenderBuffer *QRhiGles2::createRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize, - int sampleCount, QRhiRenderBuffer::Flags flags) + int sampleCount, QRhiRenderBuffer::Flags flags, + QRhiTexture::Format backingFormatHint) { - return new QGles2RenderBuffer(this, type, pixelSize, sampleCount, flags); + return new QGles2RenderBuffer(this, type, pixelSize, sampleCount, flags, backingFormatHint); } QRhiTexture *QRhiGles2::createTexture(QRhiTexture::Format format, const QSize &pixelSize, @@ -3435,8 +3517,9 @@ QRhiBuffer::NativeBuffer QGles2Buffer::nativeBuffer() } QGles2RenderBuffer::QGles2RenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize, - int sampleCount, QRhiRenderBuffer::Flags flags) - : QRhiRenderBuffer(rhi, type, pixelSize, sampleCount, flags) + int sampleCount, QRhiRenderBuffer::Flags flags, + QRhiTexture::Format backingFormatHint) + : QRhiRenderBuffer(rhi, type, pixelSize, sampleCount, flags, backingFormatHint) { } @@ -3522,13 +3605,26 @@ bool QGles2RenderBuffer::build() QRHI_PROF_F(newRenderBuffer(this, false, false, samples)); break; case QRhiRenderBuffer::Color: - if (rhiD->caps.msaaRenderBuffer && samples > 1) - rhiD->f->glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, GL_RGBA8, + { + GLenum internalFormat = GL_RGBA4; // ES 2.0 + if (rhiD->caps.rgba8Format) { + internalFormat = GL_RGBA8; + if (m_backingFormatHint != QRhiTexture::UnknownFormat) { + GLenum glintformat, glformat, gltype; + // only care about the sized internal format, the rest is not used here + toGlTextureFormat(m_backingFormatHint, rhiD->caps, + &glintformat, &internalFormat, &glformat, &gltype); + } + } + if (rhiD->caps.msaaRenderBuffer && samples > 1) { + rhiD->f->glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, internalFormat, size.width(), size.height()); - else - rhiD->f->glRenderbufferStorage(GL_RENDERBUFFER, rhiD->caps.rgba8Format ? GL_RGBA8 : GL_RGBA4, + } else { + rhiD->f->glRenderbufferStorage(GL_RENDERBUFFER, internalFormat, size.width(), size.height()); + } QRHI_PROF_F(newRenderBuffer(this, false, false, samples)); + } break; default: Q_UNREACHABLE(); @@ -3541,7 +3637,10 @@ bool QGles2RenderBuffer::build() QRhiTexture::Format QGles2RenderBuffer::backingFormat() const { - return m_type == Color ? QRhiTexture::RGBA8 : QRhiTexture::UnknownFormat; + if (m_backingFormatHint != QRhiTexture::UnknownFormat) + return m_backingFormatHint; + else + return m_type == Color ? QRhiTexture::RGBA8 : QRhiTexture::UnknownFormat; } QGles2Texture::QGles2Texture(QRhiImplementation *rhi, Format format, const QSize &pixelSize, @@ -3608,76 +3707,8 @@ bool QGles2Texture::prepareBuild(QSize *adjustedSize) glsizedintformat = glintformat; glformat = GL_RGBA; } else { - switch (m_format) { - case QRhiTexture::RGBA8: - glintformat = GL_RGBA; - glsizedintformat = rhiD->caps.rgba8Format ? GL_RGBA8 : GL_RGBA; - glformat = GL_RGBA; - break; - case QRhiTexture::BGRA8: - glintformat = rhiD->caps.bgraInternalFormat ? GL_BGRA : GL_RGBA; - glsizedintformat = rhiD->caps.rgba8Format ? GL_RGBA8 : GL_RGBA; - glformat = GL_BGRA; - break; - case QRhiTexture::R16: - glintformat = GL_R16; - glsizedintformat = glintformat; - glformat = GL_RED; - gltype = GL_UNSIGNED_SHORT; - break; - case QRhiTexture::R8: - glintformat = GL_R8; - glsizedintformat = glintformat; - glformat = GL_RED; - break; - case QRhiTexture::RED_OR_ALPHA8: - glintformat = rhiD->caps.coreProfile ? GL_R8 : GL_ALPHA; - glsizedintformat = glintformat; - glformat = rhiD->caps.coreProfile ? GL_RED : GL_ALPHA; - break; - case QRhiTexture::RGBA16F: - glintformat = GL_RGBA16F; - glsizedintformat = glintformat; - glformat = GL_RGBA; - gltype = GL_HALF_FLOAT; - break; - case QRhiTexture::RGBA32F: - glintformat = GL_RGBA32F; - glsizedintformat = glintformat; - 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; - glformat = GL_DEPTH_COMPONENT; - gltype = GL_UNSIGNED_SHORT; - break; - case QRhiTexture::D32F: - glintformat = GL_DEPTH_COMPONENT32F; - glsizedintformat = glintformat; - glformat = GL_DEPTH_COMPONENT; - gltype = GL_FLOAT; - break; - default: - Q_UNREACHABLE(); - glintformat = GL_RGBA; - glsizedintformat = rhiD->caps.rgba8Format ? GL_RGBA8 : GL_RGBA; - glformat = GL_RGBA; - break; - } + toGlTextureFormat(m_format, rhiD->caps, + &glintformat, &glsizedintformat, &glformat, &gltype); } samplerState = QGles2SamplerData(); diff --git a/src/gui/rhi/qrhigles2_p_p.h b/src/gui/rhi/qrhigles2_p_p.h index ac7b384cb6..e326b661d9 100644 --- a/src/gui/rhi/qrhigles2_p_p.h +++ b/src/gui/rhi/qrhigles2_p_p.h @@ -89,7 +89,8 @@ struct QGles2Buffer : public QRhiBuffer struct QGles2RenderBuffer : public QRhiRenderBuffer { QGles2RenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize, - int sampleCount, QRhiRenderBuffer::Flags flags); + int sampleCount, QRhiRenderBuffer::Flags flags, + QRhiTexture::Format backingFormatHint); ~QGles2RenderBuffer(); void release() override; bool build() override; @@ -694,7 +695,8 @@ public: QRhiRenderBuffer *createRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize, int sampleCount, - QRhiRenderBuffer::Flags flags) override; + QRhiRenderBuffer::Flags flags, + QRhiTexture::Format backingFormatHint) override; QRhiTexture *createTexture(QRhiTexture::Format format, const QSize &pixelSize, int sampleCount, diff --git a/src/gui/rhi/qrhimetal.mm b/src/gui/rhi/qrhimetal.mm index f021e78097..c5afdf63eb 100644 --- a/src/gui/rhi/qrhimetal.mm +++ b/src/gui/rhi/qrhimetal.mm @@ -621,9 +621,10 @@ bool QRhiMetal::isDeviceLost() const } QRhiRenderBuffer *QRhiMetal::createRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize, - int sampleCount, QRhiRenderBuffer::Flags flags) + int sampleCount, QRhiRenderBuffer::Flags flags, + QRhiTexture::Format backingFormatHint) { - return new QMetalRenderBuffer(this, type, pixelSize, sampleCount, flags); + return new QMetalRenderBuffer(this, type, pixelSize, sampleCount, flags, backingFormatHint); } QRhiTexture *QRhiMetal::createTexture(QRhiTexture::Format format, const QSize &pixelSize, @@ -2232,149 +2233,6 @@ QRhiBuffer::NativeBuffer QMetalBuffer::nativeBuffer() return { { &d->buf[0] }, 1 }; } -QMetalRenderBuffer::QMetalRenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize, - int sampleCount, QRhiRenderBuffer::Flags flags) - : QRhiRenderBuffer(rhi, type, pixelSize, sampleCount, flags), - d(new QMetalRenderBufferData) -{ -} - -QMetalRenderBuffer::~QMetalRenderBuffer() -{ - release(); - delete d; -} - -void QMetalRenderBuffer::release() -{ - if (!d->tex) - return; - - QRhiMetalData::DeferredReleaseEntry e; - e.type = QRhiMetalData::DeferredReleaseEntry::RenderBuffer; - e.lastActiveFrameSlot = lastActiveFrameSlot; - - e.renderbuffer.texture = d->tex; - d->tex = nil; - - QRHI_RES_RHI(QRhiMetal); - rhiD->d->releaseQueue.append(e); - QRHI_PROF; - QRHI_PROF_F(releaseRenderBuffer(this)); - rhiD->unregisterResource(this); -} - -bool QMetalRenderBuffer::build() -{ - if (d->tex) - release(); - - if (m_pixelSize.isEmpty()) - return false; - - QRHI_RES_RHI(QRhiMetal); - samples = rhiD->effectiveSampleCount(m_sampleCount); - - MTLTextureDescriptor *desc = [[MTLTextureDescriptor alloc] init]; - desc.textureType = samples > 1 ? MTLTextureType2DMultisample : MTLTextureType2D; - desc.width = NSUInteger(m_pixelSize.width()); - desc.height = NSUInteger(m_pixelSize.height()); - if (samples > 1) - desc.sampleCount = NSUInteger(samples); - desc.resourceOptions = MTLResourceStorageModePrivate; - desc.usage = MTLTextureUsageRenderTarget; - - bool transientBacking = false; - switch (m_type) { - case DepthStencil: -#ifdef Q_OS_MACOS - desc.storageMode = MTLStorageModePrivate; - d->format = rhiD->d->dev.depth24Stencil8PixelFormatSupported - ? MTLPixelFormatDepth24Unorm_Stencil8 : MTLPixelFormatDepth32Float_Stencil8; -#else - desc.storageMode = MTLStorageModeMemoryless; - transientBacking = true; - d->format = MTLPixelFormatDepth32Float_Stencil8; -#endif - desc.pixelFormat = d->format; - break; - case Color: - desc.storageMode = MTLStorageModePrivate; - d->format = MTLPixelFormatRGBA8Unorm; - desc.pixelFormat = d->format; - break; - default: - Q_UNREACHABLE(); - break; - } - - d->tex = [rhiD->d->dev newTextureWithDescriptor: desc]; - [desc release]; - - if (!m_objectName.isEmpty()) - d->tex.label = [NSString stringWithUTF8String: m_objectName.constData()]; - - QRHI_PROF; - QRHI_PROF_F(newRenderBuffer(this, transientBacking, false, samples)); - - lastActiveFrameSlot = -1; - generation += 1; - rhiD->registerResource(this); - return true; -} - -QRhiTexture::Format QMetalRenderBuffer::backingFormat() const -{ - return m_type == Color ? QRhiTexture::RGBA8 : QRhiTexture::UnknownFormat; -} - -QMetalTexture::QMetalTexture(QRhiImplementation *rhi, Format format, const QSize &pixelSize, - int sampleCount, Flags flags) - : QRhiTexture(rhi, format, pixelSize, sampleCount, flags), - d(new QMetalTextureData(this)) -{ - for (int i = 0; i < QMTL_FRAMES_IN_FLIGHT; ++i) - d->stagingBuf[i] = nil; - - for (int i = 0; i < QRhi::MAX_LEVELS; ++i) - d->perLevelViews[i] = nil; -} - -QMetalTexture::~QMetalTexture() -{ - release(); - delete d; -} - -void QMetalTexture::release() -{ - if (!d->tex) - return; - - QRhiMetalData::DeferredReleaseEntry e; - e.type = QRhiMetalData::DeferredReleaseEntry::Texture; - e.lastActiveFrameSlot = lastActiveFrameSlot; - - e.texture.texture = d->owns ? d->tex : nil; - d->tex = nil; - - for (int i = 0; i < QMTL_FRAMES_IN_FLIGHT; ++i) { - e.texture.stagingBuffers[i] = d->stagingBuf[i]; - d->stagingBuf[i] = nil; - } - - for (int i = 0; i < QRhi::MAX_LEVELS; ++i) { - e.texture.views[i] = d->perLevelViews[i]; - d->perLevelViews[i] = nil; - } - - QRHI_RES_RHI(QRhiMetal); - rhiD->d->releaseQueue.append(e); - QRHI_PROF; - QRHI_PROF_F(releaseTexture(this)); - rhiD->unregisterResource(this); -} - static inline MTLPixelFormat toMetalTextureFormat(QRhiTexture::Format format, QRhiTexture::Flags flags) { const bool srgb = flags.testFlag(QRhiTexture::sRGB); @@ -2507,6 +2365,156 @@ static inline MTLPixelFormat toMetalTextureFormat(QRhiTexture::Format format, QR } } +QMetalRenderBuffer::QMetalRenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize, + int sampleCount, QRhiRenderBuffer::Flags flags, + QRhiTexture::Format backingFormatHint) + : QRhiRenderBuffer(rhi, type, pixelSize, sampleCount, flags, backingFormatHint), + d(new QMetalRenderBufferData) +{ +} + +QMetalRenderBuffer::~QMetalRenderBuffer() +{ + release(); + delete d; +} + +void QMetalRenderBuffer::release() +{ + if (!d->tex) + return; + + QRhiMetalData::DeferredReleaseEntry e; + e.type = QRhiMetalData::DeferredReleaseEntry::RenderBuffer; + e.lastActiveFrameSlot = lastActiveFrameSlot; + + e.renderbuffer.texture = d->tex; + d->tex = nil; + + QRHI_RES_RHI(QRhiMetal); + rhiD->d->releaseQueue.append(e); + QRHI_PROF; + QRHI_PROF_F(releaseRenderBuffer(this)); + rhiD->unregisterResource(this); +} + +bool QMetalRenderBuffer::build() +{ + if (d->tex) + release(); + + if (m_pixelSize.isEmpty()) + return false; + + QRHI_RES_RHI(QRhiMetal); + samples = rhiD->effectiveSampleCount(m_sampleCount); + + MTLTextureDescriptor *desc = [[MTLTextureDescriptor alloc] init]; + desc.textureType = samples > 1 ? MTLTextureType2DMultisample : MTLTextureType2D; + desc.width = NSUInteger(m_pixelSize.width()); + desc.height = NSUInteger(m_pixelSize.height()); + if (samples > 1) + desc.sampleCount = NSUInteger(samples); + desc.resourceOptions = MTLResourceStorageModePrivate; + desc.usage = MTLTextureUsageRenderTarget; + + bool transientBacking = false; + switch (m_type) { + case DepthStencil: +#ifdef Q_OS_MACOS + desc.storageMode = MTLStorageModePrivate; + d->format = rhiD->d->dev.depth24Stencil8PixelFormatSupported + ? MTLPixelFormatDepth24Unorm_Stencil8 : MTLPixelFormatDepth32Float_Stencil8; +#else + desc.storageMode = MTLStorageModeMemoryless; + transientBacking = true; + d->format = MTLPixelFormatDepth32Float_Stencil8; +#endif + desc.pixelFormat = d->format; + break; + case Color: + desc.storageMode = MTLStorageModePrivate; + if (m_backingFormatHint != QRhiTexture::UnknownFormat) + d->format = toMetalTextureFormat(m_backingFormatHint, {}); + else + d->format = MTLPixelFormatRGBA8Unorm; + desc.pixelFormat = d->format; + break; + default: + Q_UNREACHABLE(); + break; + } + + d->tex = [rhiD->d->dev newTextureWithDescriptor: desc]; + [desc release]; + + if (!m_objectName.isEmpty()) + d->tex.label = [NSString stringWithUTF8String: m_objectName.constData()]; + + QRHI_PROF; + QRHI_PROF_F(newRenderBuffer(this, transientBacking, false, samples)); + + lastActiveFrameSlot = -1; + generation += 1; + rhiD->registerResource(this); + return true; +} + +QRhiTexture::Format QMetalRenderBuffer::backingFormat() const +{ + if (m_backingFormatHint != QRhiTexture::UnknownFormat) + return m_backingFormatHint; + else + return m_type == Color ? QRhiTexture::RGBA8 : QRhiTexture::UnknownFormat; +} + +QMetalTexture::QMetalTexture(QRhiImplementation *rhi, Format format, const QSize &pixelSize, + int sampleCount, Flags flags) + : QRhiTexture(rhi, format, pixelSize, sampleCount, flags), + d(new QMetalTextureData(this)) +{ + for (int i = 0; i < QMTL_FRAMES_IN_FLIGHT; ++i) + d->stagingBuf[i] = nil; + + for (int i = 0; i < QRhi::MAX_LEVELS; ++i) + d->perLevelViews[i] = nil; +} + +QMetalTexture::~QMetalTexture() +{ + release(); + delete d; +} + +void QMetalTexture::release() +{ + if (!d->tex) + return; + + QRhiMetalData::DeferredReleaseEntry e; + e.type = QRhiMetalData::DeferredReleaseEntry::Texture; + e.lastActiveFrameSlot = lastActiveFrameSlot; + + e.texture.texture = d->owns ? d->tex : nil; + d->tex = nil; + + for (int i = 0; i < QMTL_FRAMES_IN_FLIGHT; ++i) { + e.texture.stagingBuffers[i] = d->stagingBuf[i]; + d->stagingBuf[i] = nil; + } + + for (int i = 0; i < QRhi::MAX_LEVELS; ++i) { + e.texture.views[i] = d->perLevelViews[i]; + d->perLevelViews[i] = nil; + } + + QRHI_RES_RHI(QRhiMetal); + rhiD->d->releaseQueue.append(e); + QRHI_PROF; + QRHI_PROF_F(releaseTexture(this)); + rhiD->unregisterResource(this); +} + bool QMetalTexture::prepareBuild(QSize *adjustedSize) { if (d->tex) diff --git a/src/gui/rhi/qrhimetal_p_p.h b/src/gui/rhi/qrhimetal_p_p.h index cb4b777d88..30f5e8b74e 100644 --- a/src/gui/rhi/qrhimetal_p_p.h +++ b/src/gui/rhi/qrhimetal_p_p.h @@ -79,7 +79,8 @@ struct QMetalRenderBufferData; struct QMetalRenderBuffer : public QRhiRenderBuffer { QMetalRenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize, - int sampleCount, QRhiRenderBuffer::Flags flags); + int sampleCount, QRhiRenderBuffer::Flags flags, + QRhiTexture::Format backingFormatHint); ~QMetalRenderBuffer(); void release() override; bool build() override; @@ -349,7 +350,8 @@ public: QRhiRenderBuffer *createRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize, int sampleCount, - QRhiRenderBuffer::Flags flags) override; + QRhiRenderBuffer::Flags flags, + QRhiTexture::Format backingFormatHint) override; QRhiTexture *createTexture(QRhiTexture::Format format, const QSize &pixelSize, int sampleCount, diff --git a/src/gui/rhi/qrhinull.cpp b/src/gui/rhi/qrhinull.cpp index 7b18c9156b..b1ce9b7599 100644 --- a/src/gui/rhi/qrhinull.cpp +++ b/src/gui/rhi/qrhinull.cpp @@ -182,9 +182,10 @@ bool QRhiNull::isDeviceLost() const } QRhiRenderBuffer *QRhiNull::createRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize, - int sampleCount, QRhiRenderBuffer::Flags flags) + int sampleCount, QRhiRenderBuffer::Flags flags, + QRhiTexture::Format backingFormatHint) { - return new QNullRenderBuffer(this, type, pixelSize, sampleCount, flags); + return new QNullRenderBuffer(this, type, pixelSize, sampleCount, flags, backingFormatHint); } QRhiTexture *QRhiNull::createTexture(QRhiTexture::Format format, const QSize &pixelSize, @@ -564,8 +565,9 @@ bool QNullBuffer::build() } QNullRenderBuffer::QNullRenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize, - int sampleCount, QRhiRenderBuffer::Flags flags) - : QRhiRenderBuffer(rhi, type, pixelSize, sampleCount, flags) + int sampleCount, QRhiRenderBuffer::Flags flags, + QRhiTexture::Format backingFormatHint) + : QRhiRenderBuffer(rhi, type, pixelSize, sampleCount, flags, backingFormatHint) { } diff --git a/src/gui/rhi/qrhinull_p_p.h b/src/gui/rhi/qrhinull_p_p.h index 0b3d40f1aa..347da4d71c 100644 --- a/src/gui/rhi/qrhinull_p_p.h +++ b/src/gui/rhi/qrhinull_p_p.h @@ -66,7 +66,8 @@ struct QNullBuffer : public QRhiBuffer struct QNullRenderBuffer : public QRhiRenderBuffer { QNullRenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize, - int sampleCount, QRhiRenderBuffer::Flags flags); + int sampleCount, QRhiRenderBuffer::Flags flags, + QRhiTexture::Format backingFormatHint); ~QNullRenderBuffer(); void release() override; bool build() override; @@ -207,7 +208,8 @@ public: QRhiRenderBuffer *createRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize, int sampleCount, - QRhiRenderBuffer::Flags flags) override; + QRhiRenderBuffer::Flags flags, + QRhiTexture::Format backingFormatHint) override; QRhiTexture *createTexture(QRhiTexture::Format format, const QSize &pixelSize, int sampleCount, diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp index 49e634e248..16de7e0aea 100644 --- a/src/gui/rhi/qrhivulkan.cpp +++ b/src/gui/rhi/qrhivulkan.cpp @@ -4084,9 +4084,10 @@ bool QRhiVulkan::isDeviceLost() const } QRhiRenderBuffer *QRhiVulkan::createRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize, - int sampleCount, QRhiRenderBuffer::Flags flags) + int sampleCount, QRhiRenderBuffer::Flags flags, + QRhiTexture::Format backingFormatHint) { - return new QVkRenderBuffer(this, type, pixelSize, sampleCount, flags); + return new QVkRenderBuffer(this, type, pixelSize, sampleCount, flags, backingFormatHint); } QRhiTexture *QRhiVulkan::createTexture(QRhiTexture::Format format, const QSize &pixelSize, @@ -5241,8 +5242,9 @@ QRhiBuffer::NativeBuffer QVkBuffer::nativeBuffer() } QVkRenderBuffer::QVkRenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize, - int sampleCount, Flags flags) - : QRhiRenderBuffer(rhi, type, pixelSize, sampleCount, flags) + int sampleCount, Flags flags, + QRhiTexture::Format backingFormatHint) + : QRhiRenderBuffer(rhi, type, pixelSize, sampleCount, flags, backingFormatHint) { } @@ -5300,7 +5302,7 @@ bool QVkRenderBuffer::build() case QRhiRenderBuffer::Color: { if (!backingTexture) { - backingTexture = QRHI_RES(QVkTexture, rhiD->createTexture(QRhiTexture::RGBA8, + backingTexture = QRHI_RES(QVkTexture, rhiD->createTexture(backingFormat(), m_pixelSize, m_sampleCount, QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource)); @@ -5344,7 +5346,10 @@ bool QVkRenderBuffer::build() QRhiTexture::Format QVkRenderBuffer::backingFormat() const { - return m_type == Color ? QRhiTexture::RGBA8 : QRhiTexture::UnknownFormat; + if (m_backingFormatHint != QRhiTexture::UnknownFormat) + return m_backingFormatHint; + else + return m_type == Color ? QRhiTexture::RGBA8 : QRhiTexture::UnknownFormat; } QVkTexture::QVkTexture(QRhiImplementation *rhi, Format format, const QSize &pixelSize, diff --git a/src/gui/rhi/qrhivulkan_p_p.h b/src/gui/rhi/qrhivulkan_p_p.h index d90b1d1364..1b2e4d0ebb 100644 --- a/src/gui/rhi/qrhivulkan_p_p.h +++ b/src/gui/rhi/qrhivulkan_p_p.h @@ -98,7 +98,8 @@ struct QVkTexture; struct QVkRenderBuffer : public QRhiRenderBuffer { QVkRenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize, - int sampleCount, Flags flags); + int sampleCount, Flags flags, + QRhiTexture::Format backingFormatHint); ~QVkRenderBuffer(); void release() override; bool build() override; @@ -658,7 +659,8 @@ public: QRhiRenderBuffer *createRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize, int sampleCount, - QRhiRenderBuffer::Flags flags) override; + QRhiRenderBuffer::Flags flags, + QRhiTexture::Format backingFormatHint) override; QRhiTexture *createTexture(QRhiTexture::Format format, const QSize &pixelSize, int sampleCount,