Commit d4269c27 authored by Laszlo Agocs's avatar Laszlo Agocs

Add MRT example

parent 4f9b99f5
qsb --glsl "100 es,120" --hlsl 50 --msl 12 mrt.vert -o mrt.vert.qsb
qsb --glsl "100 es,120" --hlsl 50 --msl 12 mrt.frag -o mrt.frag.qsb
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of The Qt Company Ltd nor the names of its
** contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "../shared/examplefw.h"
static float quadVertexData[] =
{ // Y up, CCW
-0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, 1.0f, 1.0f,
0.5f, 0.5f, 1.0f, 0.0f
};
static quint16 quadIndexData[] =
{
0, 1, 2, 0, 2, 3
};
static float triangleData[] =
{ // Y up, CCW
0.0f, 0.5f, 1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
0.5f, -0.5f, 0.0f, 0.0f, 1.0f,
};
struct {
QVector<QRhiResource *> releasePool;
QRhiBuffer *vbuf = nullptr;
QRhiBuffer *ibuf = nullptr;
QRhiBuffer *ubuf = nullptr;
QRhiTextureRenderTarget *rt = nullptr;
QRhiRenderPassDescriptor *rtRp = nullptr;
QRhiTexture *tex = nullptr;
QRhiSampler *sampler = nullptr;
QRhiShaderResourceBindings *srb = nullptr;
QRhiGraphicsPipeline *ps = nullptr;
QRhiResourceUpdateBatch *initialUpdates = nullptr;
QMatrix4x4 winProj;
QRhiBuffer *triUbuf = nullptr;
QRhiShaderResourceBindings *triSrb = nullptr;
QRhiGraphicsPipeline *triPs = nullptr;
float triRot = 0;
QMatrix4x4 triBaseMvp;
} d;
void Window::customInit()
{
qDebug("Max color attachments: %d", m_r->resourceLimit(QRhi::MaxColorAttachments));
if (m_r->resourceLimit(QRhi::MaxColorAttachments) < 4)
qWarning("MRT is not supported");
d.vbuf = m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(quadVertexData) + sizeof(triangleData));
d.vbuf->build();
d.releasePool << d.vbuf;
d.ibuf = m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::IndexBuffer, sizeof(quadIndexData));
d.ibuf->build();
d.releasePool << d.ibuf;
d.ubuf = m_r->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 68);
d.ubuf->build();
d.releasePool << d.ubuf;
d.tex = m_r->newTexture(QRhiTexture::RGBA8, QSize(512, 512), 1, QRhiTexture::RenderTarget);
d.releasePool << d.tex;
d.tex->build();
d.rt = m_r->newTextureRenderTarget({ d.tex });
d.releasePool << d.rt;
d.rtRp = d.rt->newCompatibleRenderPassDescriptor();
d.releasePool << d.rtRp;
d.rt->setRenderPassDescriptor(d.rtRp);
d.rt->build();
d.sampler = m_r->newSampler(QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge);
d.releasePool << d.sampler;
d.sampler->build();
d.srb = m_r->newShaderResourceBindings();
d.releasePool << d.srb;
d.srb->setBindings({
QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d.ubuf),
QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.tex, d.sampler)
});
d.srb->build();
d.ps = m_r->newGraphicsPipeline();
d.releasePool << d.ps;
d.ps->setShaderStages({
{ QRhiGraphicsShaderStage::Vertex, getShader(QLatin1String(":/texture.vert.qsb")) },
{ QRhiGraphicsShaderStage::Fragment, getShader(QLatin1String(":/texture.frag.qsb")) }
});
QRhiVertexInputLayout inputLayout;
inputLayout.setBindings({
{ 4 * sizeof(float) }
});
inputLayout.setAttributes({
{ 0, 0, QRhiVertexInputAttribute::Float2, 0 },
{ 0, 1, QRhiVertexInputAttribute::Float2, 2 * sizeof(float) }
});
d.ps->setVertexInputLayout(inputLayout);
d.ps->setShaderResourceBindings(d.srb);
d.ps->setRenderPassDescriptor(m_rp);
d.ps->build();
d.initialUpdates = m_r->nextResourceUpdateBatch();
d.initialUpdates->uploadStaticBuffer(d.vbuf, 0, sizeof(quadVertexData), quadVertexData);
d.initialUpdates->uploadStaticBuffer(d.vbuf, sizeof(quadVertexData), sizeof(triangleData), triangleData);
d.initialUpdates->uploadStaticBuffer(d.ibuf, quadIndexData);
qint32 flip = m_r->isYUpInFramebuffer() ? 1 : 0;
d.initialUpdates->updateDynamicBuffer(d.ubuf, 64, 4, &flip);
// triangle
d.triUbuf = m_r->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 68);
d.releasePool << d.triUbuf;
d.triUbuf->build();
d.triSrb = m_r->newShaderResourceBindings();
d.releasePool << d.triSrb;
d.triSrb->setBindings({
QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d.triUbuf)
});
d.triSrb->build();
d.triPs = m_r->newGraphicsPipeline();
d.releasePool << d.triPs;
d.triPs->setShaderStages({
{ QRhiGraphicsShaderStage::Vertex, getShader(QLatin1String(":/mrt.vert.qsb")) },
{ QRhiGraphicsShaderStage::Fragment, getShader(QLatin1String(":/mrt.frag.qsb")) }
});
inputLayout.setBindings({
{ 5 * sizeof(float) }
});
inputLayout.setAttributes({
{ 0, 0, QRhiVertexInputAttribute::Float2, 0 },
{ 0, 1, QRhiVertexInputAttribute::Float3, 2 * sizeof(float) }
});
d.triPs->setVertexInputLayout(inputLayout);
d.triPs->setShaderResourceBindings(d.triSrb);
d.triPs->setRenderPassDescriptor(d.rtRp);
d.triPs->build();
d.triBaseMvp = m_r->clipSpaceCorrMatrix();
d.triBaseMvp.perspective(45.0f, d.rt->sizeInPixels().width() / float(d.rt->sizeInPixels().height()), 0.01f, 1000.0f);
d.triBaseMvp.translate(0, 0, -2);
float opacity = 1.0f;
d.initialUpdates->updateDynamicBuffer(d.triUbuf, 64, 4, &opacity);
}
void Window::customRelease()
{
for (QRhiResource *r : d.releasePool)
r->releaseAndDestroy();
d.releasePool.clear();
}
void Window::customRender()
{
QRhiCommandBuffer *cb = m_sc->currentFrameCommandBuffer();
QRhiResourceUpdateBatch *u = m_r->nextResourceUpdateBatch();
if (d.initialUpdates) {
u->merge(d.initialUpdates);
d.initialUpdates->release();
d.initialUpdates = nullptr;
}
if (d.winProj != m_proj) {
d.winProj = m_proj;
QMatrix4x4 mvp = m_proj;
mvp.scale(2.5f);
u->updateDynamicBuffer(d.ubuf, 0, 64, mvp.constData());
}
QMatrix4x4 triMvp = d.triBaseMvp;
triMvp.rotate(d.triRot, 0, 1, 0);
d.triRot += 1;
u->updateDynamicBuffer(d.triUbuf, 0, 64, triMvp.constData());
cb->beginPass(d.rt, { 0.5f, 0.2f, 0, 1 }, { 1, 0 }, u);
cb->setGraphicsPipeline(d.triPs);
cb->setViewport({ 0, 0, float(d.rt->sizeInPixels().width()), float(d.rt->sizeInPixels().height()) });
cb->setShaderResources();
cb->setVertexInput(0, { { d.vbuf, sizeof(quadVertexData) } });
cb->draw(3);
cb->endPass();
const QSize outputSizeInPixels = m_sc->currentPixelSize();
cb->beginPass(m_sc->currentFrameRenderTarget(), { 0.4f, 0.7f, 0.0f, 1.0f }, { 1.0f, 0 });
cb->setGraphicsPipeline(d.ps);
cb->setViewport({ 0, 0, float(outputSizeInPixels.width()), float(outputSizeInPixels.height()) });
cb->setShaderResources();
cb->setVertexInput(0, { { d.vbuf, 0 } }, d.ibuf, 0, QRhiCommandBuffer::IndexUInt16);
cb->drawIndexed(6);
cb->endPass();
}
#version 440
layout(location = 0) in vec3 v_color;
layout(location = 0) out vec4 c0;
layout(location = 1) out vec4 c1;
layout(location = 2) out vec4 c2;
layout(location = 3) out vec4 c3;
layout(std140, binding = 0) uniform buf {
mat4 mvp;
float opacity;
} ubuf;
void main()
{
vec4 c = vec4(v_color * ubuf.opacity, ubuf.opacity);
c0 = c;
c1 = c;
c2 = c;
c3 = c;
}
TEMPLATE = app
QT += shadertools rhi
SOURCES = \
mrt.cpp
RESOURCES = mrt.qrc
target.path = $$[QT_INSTALL_EXAMPLES]/rhi/mrt
INSTALLS += target
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file>mrt.vert.qsb</file>
<file>mrt.frag.qsb</file>
<file alias="texture.vert.qsb">../shared/texture.vert.qsb</file>
<file alias="texture.frag.qsb">../shared/texture.frag.qsb</file>
</qresource>
</RCC>
#version 440
layout(location = 0) in vec4 position;
layout(location = 1) in vec3 color;
layout(location = 0) out vec3 v_color;
layout(std140, binding = 0) uniform buf {
mat4 mvp;
float opacity;
} ubuf;
out gl_PerVertex { vec4 gl_Position; };
void main()
{
v_color = color;
gl_Position = ubuf.mvp * position;
}
...@@ -13,7 +13,8 @@ SUBDIRS += \ ...@@ -13,7 +13,8 @@ SUBDIRS += \
imguidemo \ imguidemo \
triquadcube \ triquadcube \
offscreen \ offscreen \
floattexture floattexture \
mrt
qtConfig(vulkan) { qtConfig(vulkan) {
SUBDIRS += \ SUBDIRS += \
......
...@@ -108,7 +108,7 @@ void TriangleOnCubeRenderer::initResources(QRhiRenderPassDescriptor *rp) ...@@ -108,7 +108,7 @@ void TriangleOnCubeRenderer::initResources(QRhiRenderPassDescriptor *rp)
if (DEPTH_TEXTURE) { if (DEPTH_TEXTURE) {
m_offscreenTriangle.setDepthWrite(true); m_offscreenTriangle.setDepthWrite(true);
m_depthTex = m_r->newTexture(QRhiTexture::D32, OFFSCREEN_SIZE, 1, QRhiTexture::RenderTarget); m_depthTex = m_r->newTexture(QRhiTexture::D32F, OFFSCREEN_SIZE, 1, QRhiTexture::RenderTarget);
m_depthTex->build(); m_depthTex->build();
} }
......
...@@ -166,8 +166,10 @@ void Window::customInit() ...@@ -166,8 +166,10 @@ void Window::customInit()
qDebug("isFeatureSupported(NonDynamicUniformBuffers): %d", m_r->isFeatureSupported(QRhi::NonDynamicUniformBuffers)); qDebug("isFeatureSupported(NonDynamicUniformBuffers): %d", m_r->isFeatureSupported(QRhi::NonDynamicUniformBuffers));
qDebug("isFeatureSupported(NonFourAlignedEffectiveIndexBufferOffset): %d", m_r->isFeatureSupported(QRhi::NonFourAlignedEffectiveIndexBufferOffset)); qDebug("isFeatureSupported(NonFourAlignedEffectiveIndexBufferOffset): %d", m_r->isFeatureSupported(QRhi::NonFourAlignedEffectiveIndexBufferOffset));
qDebug("isFeatureSupported(NPOTTextureRepeat): %d", m_r->isFeatureSupported(QRhi::NPOTTextureRepeat)); qDebug("isFeatureSupported(NPOTTextureRepeat): %d", m_r->isFeatureSupported(QRhi::NPOTTextureRepeat));
qDebug("Min 2D texture width/height: %d", m_r->resourceSizeLimit(QRhi::TextureSizeMin)); qDebug("isFeatureSupported(RedOrAlpha8IsRed): %d", m_r->isFeatureSupported(QRhi::RedOrAlpha8IsRed));
qDebug("Max 2D texture width/height: %d", m_r->resourceSizeLimit(QRhi::TextureSizeMax)); qDebug("Min 2D texture width/height: %d", m_r->resourceLimit(QRhi::TextureSizeMin));
qDebug("Max 2D texture width/height: %d", m_r->resourceLimit(QRhi::TextureSizeMax));
qDebug("Max color attachment count: %d", m_r->resourceLimit(QRhi::MaxColorAttachments));
} }
void Window::customRelease() void Window::customRelease()
......
...@@ -431,7 +431,7 @@ QT_BEGIN_NAMESPACE ...@@ -431,7 +431,7 @@ QT_BEGIN_NAMESPACE
*/ */
/*! /*!
\enum QRhi::ResourceSizeLimit \enum QRhi::ResourceLimit
Describes the resource limit to query. Describes the resource limit to query.
\value TextureSizeMin Minimum texture width and height. This is typically \value TextureSizeMin Minimum texture width and height. This is typically
...@@ -443,6 +443,12 @@ QT_BEGIN_NAMESPACE ...@@ -443,6 +443,12 @@ QT_BEGIN_NAMESPACE
graphics API and sometimes the platform or implementation as well. graphics API and sometimes the platform or implementation as well.
Typically the value is in the range 4096 - 16384. Attempting to create Typically the value is in the range 4096 - 16384. Attempting to create
textures larger than this is expected to fail. textures larger than this is expected to fail.
\value MaxColorAttachments The maximum number of color attachments for a
QRhiTextureRenderTarget, in case multiple render targets are supported. When
MRT is not supported, the value is 1. Otherwise this is typically 8, but
watch out for the fact that OpenGL only mandates 4 as the minimum, and that
is what some OpenGL ES implementations provide.
*/ */
/*! /*!
...@@ -4126,9 +4132,9 @@ bool QRhi::isFeatureSupported(QRhi::Feature feature) const ...@@ -4126,9 +4132,9 @@ bool QRhi::isFeatureSupported(QRhi::Feature feature) const
The values are expected to be queried by the backends upon initialization, The values are expected to be queried by the backends upon initialization,
meaning calling this function is a light operation. meaning calling this function is a light operation.
*/ */
int QRhi::resourceSizeLimit(ResourceSizeLimit limit) const int QRhi::resourceLimit(ResourceLimit limit) const
{ {
return d->resourceSizeLimit(limit); return d->resourceLimit(limit);
} }
/*! /*!
......
...@@ -1254,9 +1254,10 @@ public: ...@@ -1254,9 +1254,10 @@ public:
}; };
Q_DECLARE_FLAGS(EndFrameFlags, EndFrameFlag) Q_DECLARE_FLAGS(EndFrameFlags, EndFrameFlag)
enum ResourceSizeLimit { enum ResourceLimit {
TextureSizeMin = 1, TextureSizeMin = 1,
TextureSizeMax TextureSizeMax,
MaxColorAttachments
}; };
~QRhi(); ~QRhi();
...@@ -1319,7 +1320,7 @@ public: ...@@ -1319,7 +1320,7 @@ public:
bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags = QRhiTexture::Flags()) const; bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags = QRhiTexture::Flags()) const;
bool isFeatureSupported(QRhi::Feature feature) const; bool isFeatureSupported(QRhi::Feature feature) const;
int resourceSizeLimit(ResourceSizeLimit limit) const; int resourceLimit(ResourceLimit limit) const;
const QRhiNativeHandles *nativeHandles(); const QRhiNativeHandles *nativeHandles();
......
...@@ -133,7 +133,7 @@ public: ...@@ -133,7 +133,7 @@ public:
virtual QMatrix4x4 clipSpaceCorrMatrix() const = 0; virtual QMatrix4x4 clipSpaceCorrMatrix() const = 0;
virtual bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const = 0; virtual bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const = 0;
virtual bool isFeatureSupported(QRhi::Feature feature) const = 0; virtual bool isFeatureSupported(QRhi::Feature feature) const = 0;
virtual int resourceSizeLimit(QRhi::ResourceSizeLimit limit) const = 0; virtual int resourceLimit(QRhi::ResourceLimit limit) const = 0;
virtual const QRhiNativeHandles *nativeHandles() = 0; virtual const QRhiNativeHandles *nativeHandles() = 0;
virtual void sendVMemStatsToProfiler(); virtual void sendVMemStatsToProfiler();
......
...@@ -365,13 +365,15 @@ bool QRhiD3D11::isFeatureSupported(QRhi::Feature feature) const ...@@ -365,13 +365,15 @@ bool QRhiD3D11::isFeatureSupported(QRhi::Feature feature) const
} }
} }
int QRhiD3D11::resourceSizeLimit(QRhi::ResourceSizeLimit limit) const int QRhiD3D11::resourceLimit(QRhi::ResourceLimit limit) const
{ {
switch (limit) { switch (limit) {
case QRhi::TextureSizeMin: case QRhi::TextureSizeMin:
return 1; return 1;
case QRhi::TextureSizeMax: case QRhi::TextureSizeMax:
return D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION; return D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION;
case QRhi::MaxColorAttachments:
return 8;
default: default:
Q_UNREACHABLE(); Q_UNREACHABLE();
return 0; return 0;
......
...@@ -535,7 +535,7 @@ public: ...@@ -535,7 +535,7 @@ public:
QMatrix4x4 clipSpaceCorrMatrix() const override; QMatrix4x4 clipSpaceCorrMatrix() const override;
bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const override; bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const override;
bool isFeatureSupported(QRhi::Feature feature) const override; bool isFeatureSupported(QRhi::Feature feature) const override;
int resourceSizeLimit(QRhi::ResourceSizeLimit limit) const override; int resourceLimit(QRhi::ResourceLimit limit) const override;
const QRhiNativeHandles *nativeHandles() override; const QRhiNativeHandles *nativeHandles() override;
void enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates); void enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates);
......
...@@ -196,6 +196,10 @@ QT_BEGIN_NAMESPACE ...@@ -196,6 +196,10 @@ QT_BEGIN_NAMESPACE
#define GL_FRAMEBUFFER_SRGB 0x8DB9 #define GL_FRAMEBUFFER_SRGB 0x8DB9
#endif #endif
#ifndef GL_MAX_DRAW_BUFFERS
#define GL_MAX_DRAW_BUFFERS 0x8824
#endif
static QSurfaceFormat qrhigles2_effectiveFormat() static QSurfaceFormat qrhigles2_effectiveFormat()
{ {
QSurfaceFormat fmt = QSurfaceFormat::defaultFormat(); QSurfaceFormat fmt = QSurfaceFormat::defaultFormat();
...@@ -297,6 +301,8 @@ bool QRhiGles2::create(QRhi::Flags flags) ...@@ -297,6 +301,8 @@ bool QRhiGles2::create(QRhi::Flags flags)
if (vendor && renderer && version) if (vendor && renderer && version)
qDebug("OpenGL VENDOR: %s RENDERER: %s VERSION: %s", vendor, renderer, version); qDebug("OpenGL VENDOR: %s RENDERER: %s VERSION: %s", vendor, renderer, version);
const QSurfaceFormat actualFormat = ctx->format();
GLint n = 0; GLint n = 0;
f->glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &n); f->glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &n);
supportedCompressedFormats.resize(n); supportedCompressedFormats.resize(n);
...@@ -305,13 +311,17 @@ bool QRhiGles2::create(QRhi::Flags flags) ...@@ -305,13 +311,17 @@ bool QRhiGles2::create(QRhi::Flags flags)
f->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &caps.maxTextureSize); f->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &caps.maxTextureSize);
if (actualFormat.renderableType() == QSurfaceFormat::OpenGL || actualFormat.version() >= qMakePair(3, 0))
f->glGetIntegerv(GL_MAX_DRAW_BUFFERS, &caps.maxDrawBuffers);
else
caps.maxDrawBuffers = 1;
caps.msaaRenderBuffer = f->hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample) caps.msaaRenderBuffer = f->hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample)
&& f->hasOpenGLExtension(QOpenGLExtensions::FramebufferBlit); && f->hasOpenGLExtension(QOpenGLExtensions::FramebufferBlit);
caps.npotTexture = f->hasOpenGLFeature(QOpenGLFunctions::NPOTTextures); caps.npotTexture = f->hasOpenGLFeature(QOpenGLFunctions::NPOTTextures);
caps.npotTextureRepeat = f->hasOpenGLFeature(QOpenGLFunctions::NPOTTextureRepeat); caps.npotTextureRepeat = f->hasOpenGLFeature(QOpenGLFunctions::NPOTTextureRepeat);
const QSurfaceFormat actualFormat = ctx->format();
if (actualFormat.renderableType() == QSurfaceFormat::OpenGLES) if (actualFormat.renderableType() == QSurfaceFormat::OpenGLES)
caps.fixedIndexPrimitiveRestart = actualFormat.version() >= qMakePair(3, 0); caps.fixedIndexPrimitiveRestart = actualFormat.version() >= qMakePair(3, 0);
else else
...@@ -532,13 +542,15 @@ bool QRhiGles2::isFeatureSupported(QRhi::Feature feature) const ...@@ -532,13 +542,15 @@ bool QRhiGles2::isFeatureSupported(QRhi::Feature feature) const
} }
} }
int QRhiGles2::resourceSizeLimit(QRhi::ResourceSizeLimit limit) const int QRhiGles2::resourceLimit(QRhi::ResourceLimit limit) const
{ {
switch (limit) { switch (limit) {
case QRhi::TextureSizeMin: case QRhi::TextureSizeMin:
return 1; return 1;
case QRhi::TextureSizeMax: case QRhi::TextureSizeMax:
return caps.maxTextureSize; return caps.maxTextureSize;
case QRhi::MaxColorAttachments:
return caps.maxDrawBuffers;
default: default:
Q_UNREACHABLE(); Q_UNREACHABLE();
return 0; return 0;
......
...@@ -534,7 +534,7 @@ public: ...@@ -534,7 +534,7 @@ public:
QMatrix4x4 clipSpaceCorrMatrix() const override; QMatrix4x4 clipSpaceCorrMatrix() const override;
bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const override; bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const override;
bool isFeatureSupported(QRhi::Feature feature) const override; bool isFeatureSupported(QRhi::Feature feature) const override;
int resourceSizeLimit(QRhi::ResourceSizeLimit limit) const override; int resourceLimit(QRhi::ResourceLimit limit) const override;
const QRhiNativeHandles *nativeHandles() override; const QRhiNativeHandles *nativeHandles() override;
bool ensureContext(QSurface *surface = nullptr) const; bool ensureContext(QSurface *surface = nullptr) const;
...@@ -554,6 +554,7 @@ public: ...@@ -554,6 +554,7 @@ public:
struct Caps { struct Caps {
Caps() Caps()
: maxTextureSize(2048), : maxTextureSize(2048),
maxDrawBuffers(4),
msaaRenderBuffer(false), msaaRenderBuffer(false),
npotTexture(true), npotTexture(true),
npotTextureRepeat(true), npotTextureRepeat(true),
...@@ -567,6 +568,7 @@ public: ...@@ -567,6 +568,7 @@ public:
srgbCapableDefaultFramebuffer(false) srgbCapableDefaultFramebuffer(false)
{ } { }
int maxTextureSize; int maxTextureSize;
int maxDrawBuffers;
// Multisample fb and blit are supported (GLES 3.0 or OpenGL 3.x). Not // Multisample fb and blit are supported (GLES 3.0 or OpenGL 3.x). Not
// the same as multisample textures! // the same as multisample textures!
uint msaaRenderBuffer : 1; uint msaaRenderBuffer : 1;
......
...@@ -484,13 +484,15 @@ bool QRhiMetal::isFeatureSupported(QRhi::Feature feature) const ...@@ -484,13 +484,15 @@ bool QRhiMetal::isFeatureSupported(QRhi::Feature feature) const
} }
} }
int QRhiMetal::resourceSizeLimit(QRhi::ResourceSizeLimit limit) const int QRhiMetal::resourceLimit(QRhi::ResourceLimit limit) const
{ {
switch (limit) { switch (limit) {
case QRhi::TextureSizeMin: case QRhi::TextureSizeMin:
return 1; return 1;
case QRhi::TextureSizeMax: case QRhi::TextureSizeMax:
return caps.maxTextureSize; return caps.maxTextureSize;
case QRhi::MaxColorAttachments:
return 8;
default: default:
Q_UNREACHABLE(); Q_UNREACHABLE();
return 0; return 0;
......
...@@ -357,7 +357,7 @@ public: ...@@ -357,7 +357,7 @@ public:
QMatrix4x4 clipSpaceCorrMatrix() const override; QMatrix4x4 clipSpaceCorrMatrix() const override;
bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const override; bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const override;
bool isFeatureSupported(QRhi::Feature feature) const override; bool isFeatureSupported(QRhi::Feature feature) const override;
int resourceSizeLimit(QRhi::ResourceSizeLimit limit) const override; int resourceLimit(QRhi::ResourceLimit limit) const override;
const QRhiNativeHandles *nativeHandles() override; const QRhiNativeHandles *nativeHandles() override;
void executeDeferredReleases(bool forced = false); void executeDeferredReleases(bool forced = false);
......
...@@ -133,13 +133,15 @@ bool QRhiNull::isFeatureSupported(QRhi::Feature feature) const ...@@ -133,13 +133,15 @@ bool QRhiNull::isFeatureSupported(QRhi::Feature feature) const
return true; return true;
} }
int QRhiNull::resourceSizeLimit(QRhi::ResourceSizeLimit limit) const int QRhiNull::resourceLimit(QRhi::ResourceLimit limit) const
{ {
switch (limit) { switch (limit) {
case QRhi::TextureSizeMin: case QRhi::TextureSizeMin:
return 1; return 1;
case QRhi::TextureSizeMax: case QRhi::TextureSizeMax:
return 16384; return 16384;
case QRhi::MaxColorAttachments:
return 8;
default: default:
Q_UNREACHABLE(); Q_UNREACHABLE();
return 0; return 0;
......
...@@ -243,7 +243,7 @@ public: ...@@ -243,7 +243,7 @@ public:
QMatrix4x4 clipSpaceCorrMatrix() const override; QMatrix4x4 clipSpaceCorrMatrix() const override;
bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const override; bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const override;
bool isFeatureSupported(QRhi::Feature feature) const override; bool isFeatureSupported(QRhi::Feature feature) const override;
int resourceSizeLimit(QRhi::ResourceSizeLimit limit) const override; int resourceLimit(QRhi::ResourceLimit limit) const override;
const QRhiNativeHandles *nativeHandles() override; const QRhiNativeHandles *nativeHandles() override;
QRhiNullNativeHandles nativeHandlesStruct; QRhiNullNativeHandles nativeHandlesStruct;
......
...@@ -2976,13 +2976,15 @@ bool QRhiVulkan::isFeatureSupported(QRhi::Feature feature) const ...@@ -2976,13 +2976,15 @@ bool QRhiVulkan::isFeatureSupported(QRhi::Feature feature) const
} }
} }
int QRhiVulkan::resourceSizeLimit(QRhi::ResourceSizeLimit limit) const int QRhiVulkan::resourceLimit(QRhi::ResourceLimit limit) const
{ {
switch (limit) { switch (limit) {
case QRhi::TextureSizeMin: case QRhi::TextureSizeMin:
return 1; return 1;
case QRhi::TextureSizeMax: