rhi: gl: Add GLES-specific multisample rendering to texture path

One is not enough, we have to have three code paths for three sets of
APIs/extensions.

Task-number: QTBUG-122669
Change-Id: Id10e19dfcfe16a8c21b6c932965f09539f061549
Reviewed-by: Andy Nichols <andy.nichols@qt.io>
bb10
Laszlo Agocs 2024-03-12 14:09:24 +01:00
parent c956eb8edd
commit 4c49e0fde4
2 changed files with 62 additions and 7 deletions

View File

@ -1074,6 +1074,28 @@ bool QRhiGles2::create(QRhi::Flags flags)
ctx->getProcAddress(QByteArrayLiteral("glObjectLabel")));
}
if (caps.gles) {
// This is the third way to get multisample rendering with GLES. (1. is
// multisample render buffer -> resolve to texture; 2. is multisample
// texture with GLES 3.1; 3. is this, avoiding the explicit multisample
// buffer and should be more efficient with tiled architectures.
// Interesting also because 2. does not seem to work in practice on
// devices such as the Quest 3)
caps.glesMultisampleRenderToTexture = ctx->hasExtension("GL_EXT_multisampled_render_to_texture");
if (caps.glesMultisampleRenderToTexture) {
glFramebufferTexture2DMultisampleEXT = reinterpret_cast<void(QOPENGLF_APIENTRYP)(GLenum, GLenum, GLenum, GLuint, GLint, GLsizei)>(
ctx->getProcAddress(QByteArrayLiteral("glFramebufferTexture2DMultisampleEXT")));
}
caps.glesMultiviewMultisampleRenderToTexture = ctx->hasExtension("GL_OVR_multiview_multisampled_render_to_texture");
if (caps.glesMultiviewMultisampleRenderToTexture) {
glFramebufferTextureMultisampleMultiviewOVR = reinterpret_cast<void(QOPENGLF_APIENTRYP)(GLenum, GLenum, GLuint, GLint, GLsizei, GLint, GLsizei)>(
ctx->getProcAddress(QByteArrayLiteral("glFramebufferTextureMultisampleMultiviewOVR")));
}
} else {
caps.glesMultisampleRenderToTexture = false;
caps.glesMultiviewMultisampleRenderToTexture = false;
}
nativeHandlesStruct.context = ctx;
contextLost = false;
@ -4484,7 +4506,7 @@ void QRhiGles2::endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resource
const bool hasZ = resolveTexD->m_flags.testFlag(QRhiTexture::ThreeDimensional)
|| resolveTexD->m_flags.testFlag(QRhiTexture::TextureArray);
cmd.args.blitFromRenderbuffer.dstLayer = hasZ ? colorAtt.resolveLayer() : 0;
} else {
} else if (!caps.glesMultisampleRenderToTexture) {
Q_ASSERT(colorAtt.texture());
QGles2Texture *texD = QRHI_RES(QGles2Texture, colorAtt.texture());
if (texD->pixelSize() != size) {
@ -5792,17 +5814,47 @@ bool QGles2TextureRenderTarget::create()
colorAtt.level(), colorAtt.layer());
} else {
multiViewCount = colorAtt.multiViewCount();
rhiD->glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uint(attIndex), texD->texture,
colorAtt.level(), colorAtt.layer(), colorAtt.multiViewCount());
if (texD->sampleCount() > 1 && rhiD->caps.glesMultiviewMultisampleRenderToTexture && colorAtt.resolveTexture()) {
// Special path for GLES and GL_OVR_multiview_multisampled_render_to_texture:
// ignore the color attachment's (multisample) texture
// array and give the resolve texture array to GL. (no
// explicit resolving is needed by us later on)
QGles2Texture *resolveTexD = QRHI_RES(QGles2Texture, colorAtt.resolveTexture());
rhiD->glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0 + uint(attIndex),
resolveTexD->texture,
colorAtt.resolveLevel(),
texD->sampleCount(),
colorAtt.resolveLayer(),
multiViewCount);
} else {
rhiD->glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0 + uint(attIndex),
texD->texture,
colorAtt.level(),
colorAtt.layer(),
multiViewCount);
}
}
} else if (texD->flags().testFlag(QRhiTexture::OneDimensional)) {
rhiD->glFramebufferTexture1D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uint(attIndex),
texD->target + uint(colorAtt.layer()), texD->texture,
colorAtt.level());
} else {
const GLenum faceTargetBase = texD->flags().testFlag(QRhiTexture::CubeMap) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : texD->target;
rhiD->f->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uint(attIndex), faceTargetBase + uint(colorAtt.layer()),
texD->texture, colorAtt.level());
if (texD->sampleCount() > 1 && rhiD->caps.glesMultisampleRenderToTexture && colorAtt.resolveTexture()) {
// Special path for GLES and GL_EXT_multisampled_render_to_texture:
// ignore the color attachment's (multisample) texture and
// give the resolve texture to GL. (no explicit resolving is
// needed by us later on)
QGles2Texture *resolveTexD = QRHI_RES(QGles2Texture, colorAtt.resolveTexture());
const GLenum faceTargetBase = resolveTexD->flags().testFlag(QRhiTexture::CubeMap) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : resolveTexD->target;
rhiD->glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uint(attIndex), faceTargetBase + uint(colorAtt.resolveLayer()),
resolveTexD->texture, colorAtt.level(), texD->sampleCount());
} else {
const GLenum faceTargetBase = texD->flags().testFlag(QRhiTexture::CubeMap) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : texD->target;
rhiD->f->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uint(attIndex), faceTargetBase + uint(colorAtt.layer()),
texD->texture, colorAtt.level());
}
}
if (attIndex == 0) {
d.pixelSize = rhiD->q->sizeForMipLevel(colorAtt.level(), texD->pixelSize());

View File

@ -949,7 +949,8 @@ public:
void (QOPENGLF_APIENTRYP glQueryCounter)(GLuint, GLenum) = nullptr;
void (QOPENGLF_APIENTRYP glGetQueryObjectui64v)(GLuint, GLenum, quint64 *) = nullptr;
void (QOPENGLF_APIENTRYP glObjectLabel)(GLenum, GLuint, GLsizei, const GLchar *) = nullptr;
void (QOPENGLF_APIENTRYP glFramebufferTexture2DMultisampleEXT)(GLenum, GLenum, GLenum, GLuint, GLint, GLsizei) = nullptr;
void (QOPENGLF_APIENTRYP glFramebufferTextureMultisampleMultiviewOVR)(GLenum, GLenum, GLuint, GLint, GLsizei, GLint, GLsizei) = nullptr;
uint vao = 0;
struct Caps {
Caps()
@ -1062,6 +1063,8 @@ public:
uint multiView : 1;
uint timestamps : 1;
uint objectLabel : 1;
uint glesMultisampleRenderToTexture : 1;
uint glesMultiviewMultisampleRenderToTexture : 1;
} caps;
QGles2SwapChain *currentSwapChain = nullptr;
QSet<GLint> supportedCompressedFormats;