diff options
author | Laszlo Agocs <[email protected]> | 2021-01-11 15:11:16 +0100 |
---|---|---|
committer | Laszlo Agocs <[email protected]> | 2021-01-13 10:08:23 +0100 |
commit | c262a698511519a57866b2c5fce386b0ec1e6905 (patch) | |
tree | bc9eeb197b6fcac04904f919207440a1f37bfb12 | |
parent | 042cd97884bb86dfd0bedaa63480d99846ab06bb (diff) |
rhi: gl: Add some enablers for supporting GL_TEXTURE_EXTERNAL_OES
From QRhi's perspective this consists of two things:
- A shader with samplerExternalOES in it cannot go through the standard
pipeline. Rather, a QShader with suitable GLSL code in it has to be
constructed manually. As this is something useful as an autotest
anyway, add a test case to the qshader autotest that demonstrates
this.
- When it comes to correctly calling glBindTexture, add a QRhiTexture
flag. The expectation is that an OpenGL-only client sets this in
combination with QRhiTexture::createFrom(), thus wrapping an existing
texture that then gets bound to the GL_TEXTURE_EXTERNAL_OES target
instead of our usual GL_TEXTURE_2D.
For completeness we also add a SamplerExternalOES variable type to
QShaderDescription, but the sampler type is not actually used by the
QRhi OpenGL backend, as it is the QRhiTexture that defines the
texture target.
Change-Id: I36b52325deb3703b59186ee3d726d0c3015bfc4b
Reviewed-by: Andy Nichols <[email protected]>
-rw-r--r-- | src/gui/rhi/qrhi.cpp | 3 | ||||
-rw-r--r-- | src/gui/rhi/qrhi_p.h | 3 | ||||
-rw-r--r-- | src/gui/rhi/qrhigles2.cpp | 7 | ||||
-rw-r--r-- | src/gui/rhi/qshaderdescription.cpp | 2 | ||||
-rw-r--r-- | src/gui/rhi/qshaderdescription_p.h | 1 | ||||
-rw-r--r-- | tests/auto/gui/rhi/qshader/tst_qshader.cpp | 115 |
6 files changed, 130 insertions, 1 deletions
diff --git a/src/gui/rhi/qrhi.cpp b/src/gui/rhi/qrhi.cpp index 718835ad8ff..838385aeed6 100644 --- a/src/gui/rhi/qrhi.cpp +++ b/src/gui/rhi/qrhi.cpp @@ -2311,6 +2311,9 @@ QRhiResource::Type QRhiRenderBuffer::resourceType() const \value UsedAsCompressedAtlas The texture has a compressed format and the dimensions of subresource uploads may not match the texture size. + + \value ExternalOES The texture should use the GL_TEXTURE_EXTERNAL_OES + target with OpenGL. This flag is ignored with other graphics APIs. */ /*! diff --git a/src/gui/rhi/qrhi_p.h b/src/gui/rhi/qrhi_p.h index fc65587408f..647f469dcfd 100644 --- a/src/gui/rhi/qrhi_p.h +++ b/src/gui/rhi/qrhi_p.h @@ -745,7 +745,8 @@ public: UsedAsTransferSource = 1 << 5, UsedWithGenerateMips = 1 << 6, UsedWithLoadStore = 1 << 7, - UsedAsCompressedAtlas = 1 << 8 + UsedAsCompressedAtlas = 1 << 8, + ExternalOES = 1 << 9 }; Q_DECLARE_FLAGS(Flags, Flag) diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp index 014d6037243..3c71086de0f 100644 --- a/src/gui/rhi/qrhigles2.cpp +++ b/src/gui/rhi/qrhigles2.cpp @@ -305,6 +305,10 @@ QT_BEGIN_NAMESPACE #define GL_TEXTURE_2D_MULTISAMPLE 0x9100 #endif +#ifndef GL_TEXTURE_EXTERNAL_OES +#define GL_TEXTURE_EXTERNAL_OES 0x8D65 +#endif + #ifndef GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS #define GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS 0x90EB #endif @@ -4134,6 +4138,9 @@ bool QGles2Texture::prepareCreate(QSize *adjustedSize) target = isCube ? GL_TEXTURE_CUBE_MAP : m_sampleCount > 1 ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D; + if (m_flags.testFlag(ExternalOES)) + target = GL_TEXTURE_EXTERNAL_OES; + mipLevelCount = hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1; gltype = GL_UNSIGNED_BYTE; diff --git a/src/gui/rhi/qshaderdescription.cpp b/src/gui/rhi/qshaderdescription.cpp index b20ed8b1787..08972587ed1 100644 --- a/src/gui/rhi/qshaderdescription.cpp +++ b/src/gui/rhi/qshaderdescription.cpp @@ -218,6 +218,7 @@ QT_BEGIN_NAMESPACE \value SamplerCubeArray \value SamplerRect \value SamplerBuffer + \value SamplerExternalOES \value Image1D \value Image2D \value Image2DMS @@ -574,6 +575,7 @@ static struct TypeTab { { QLatin1String("samplerCubeArray"), QShaderDescription::SamplerCubeArray }, { QLatin1String("samplerRect"), QShaderDescription::SamplerRect }, { QLatin1String("samplerBuffer"), QShaderDescription::SamplerBuffer }, + { QLatin1String("samplerExternalOES"), QShaderDescription::SamplerExternalOES }, { QLatin1String("mat2x3"), QShaderDescription::Mat2x3 }, { QLatin1String("mat2x4"), QShaderDescription::Mat2x4 }, diff --git a/src/gui/rhi/qshaderdescription_p.h b/src/gui/rhi/qshaderdescription_p.h index 238efc2455c..6879c531d3b 100644 --- a/src/gui/rhi/qshaderdescription_p.h +++ b/src/gui/rhi/qshaderdescription_p.h @@ -133,6 +133,7 @@ public: SamplerCubeArray, SamplerRect, SamplerBuffer, + SamplerExternalOES, Image1D, Image2D, diff --git a/tests/auto/gui/rhi/qshader/tst_qshader.cpp b/tests/auto/gui/rhi/qshader/tst_qshader.cpp index d84053dfa7a..1a57daf220a 100644 --- a/tests/auto/gui/rhi/qshader/tst_qshader.cpp +++ b/tests/auto/gui/rhi/qshader/tst_qshader.cpp @@ -47,6 +47,7 @@ private slots: void serializeShaderDesc(); void comparison(); void loadV4(); + void manualShaderPackCreation(); }; static QShader getShader(const QString &name) @@ -455,5 +456,119 @@ void tst_QShader::loadV4() } } +void tst_QShader::manualShaderPackCreation() +{ + // Exercise manually building a QShader (instead of loading it from + // serialized form). Some Qt modules may do this, in particular when OpenGL + // and GLSL code that cannot be processed through the normal pipeline with + // Vulkan SPIR-V as the primary target. + + static const char *FS = + "#extension GL_OES_EGL_image_external : require\n" + "varying vec2 v_texcoord;\n" + "struct buf {\n" + " mat4 qt_Matrix;\n" + " float qt_Opacity;\n" + "};\n" + "uniform buf ubuf;\n" + "uniform samplerExternalOES tex0;\n" + "void main()\n" + "{\n" + " gl_FragColor = ubuf.qt_Opacity * texture2D(tex0, v_texcoord);\n" + "}\n"; + static const char *FS_GLES_PREAMBLE = + "precision highp float;\n"; + // not necessarily sensible given the OES stuff but just for testing + static const char *FS_GL_PREAMBLE = + "#version 120\n"; + QByteArray fs_gles = FS_GLES_PREAMBLE; + fs_gles += FS; + QByteArray fs_gl = FS_GL_PREAMBLE; + fs_gl += FS; + + QShaderDescription desc; + QShaderDescriptionPrivate *descData = QShaderDescriptionPrivate::get(&desc); + QCOMPARE(descData->ref.loadRelaxed(), 1); + + // Inputs + QShaderDescription::InOutVariable texCoordInput; + texCoordInput.name = "v_texcoord"; + texCoordInput.type = QShaderDescription::Vec2; + texCoordInput.location = 0; + + descData->inVars = { + texCoordInput + }; + + // Outputs (just here for completeness, not strictly needed with OpenGL, the + // OpenGL backend of QRhi does not care) + QShaderDescription::InOutVariable fragColorOutput; + texCoordInput.name = "gl_FragColor"; + texCoordInput.type = QShaderDescription::Vec4; + texCoordInput.location = 0; + + descData->outVars = { + fragColorOutput + }; + + // No real uniform blocks in GLSL shaders used with QRhi, but metadata-wise + // that's what the struct maps to in others shading languages. + QShaderDescription::BlockVariable matrixBlockVar; + matrixBlockVar.name = "qt_Matrix"; + matrixBlockVar.type = QShaderDescription::Mat4; + matrixBlockVar.offset = 0; + matrixBlockVar.size = 64; + + QShaderDescription::BlockVariable opacityBlockVar; + opacityBlockVar.name = "qt_Opacity"; + opacityBlockVar.type = QShaderDescription::Float; + opacityBlockVar.offset = 64; + opacityBlockVar.size = 4; + + QShaderDescription::UniformBlock ubufStruct; + ubufStruct.blockName = "buf"; + ubufStruct.structName = "ubuf"; + ubufStruct.size = 64 + 4; + ubufStruct.binding = 0; + ubufStruct.members = { + matrixBlockVar, + opacityBlockVar + }; + + descData->uniformBlocks = { + ubufStruct + }; + + // Samplers + QShaderDescription::InOutVariable samplerTex0; + samplerTex0.name = "tex0"; + samplerTex0.type = QShaderDescription::SamplerExternalOES; + // the struct with the "uniform block" content should be binding 0, samplers can then use 1, 2, ... + samplerTex0.binding = 1; + + descData->combinedImageSamplers = { + samplerTex0 + }; + + // Now we have everything needed to construct a QShader suitable for OpenGL ES >=2.0 and OpenGL >=2.1 + QShader shaderPack; + shaderPack.setStage(QShader::FragmentStage); + shaderPack.setDescription(desc); + shaderPack.setShader(QShaderKey(QShader::GlslShader, QShaderVersion(100, QShaderVersion::GlslEs)), QShaderCode(fs_gles)); + shaderPack.setShader(QShaderKey(QShader::GlslShader, QShaderVersion(120)), QShaderCode(fs_gl)); + + // real world code would then pass the QShader to QSGMaterialShader::setShader() etc. + + const QByteArray serialized = shaderPack.serialized(); + QShader newShaderPack = QShader::fromSerialized(serialized); + QCOMPARE(newShaderPack.availableShaders().count(), 2); + QCOMPARE(newShaderPack.description().inputVariables().count(), 1); + QCOMPARE(newShaderPack.description().outputVariables().count(), 1); + QCOMPARE(newShaderPack.description().uniformBlocks().count(), 1); + QCOMPARE(newShaderPack.description().combinedImageSamplers().count(), 1); + QCOMPARE(newShaderPack.shader(QShaderKey(QShader::GlslShader, QShaderVersion(100, QShaderVersion::GlslEs))).shader(), fs_gles); + QCOMPARE(newShaderPack.shader(QShaderKey(QShader::GlslShader, QShaderVersion(120))).shader(), fs_gl); +} + #include <tst_qshader.moc> QTEST_MAIN(tst_QShader) |