summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaszlo Agocs <[email protected]>2021-01-11 15:11:16 +0100
committerLaszlo Agocs <[email protected]>2021-01-13 10:08:23 +0100
commitc262a698511519a57866b2c5fce386b0ec1e6905 (patch)
treebc9eeb197b6fcac04904f919207440a1f37bfb12
parent042cd97884bb86dfd0bedaa63480d99846ab06bb (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.cpp3
-rw-r--r--src/gui/rhi/qrhi_p.h3
-rw-r--r--src/gui/rhi/qrhigles2.cpp7
-rw-r--r--src/gui/rhi/qshaderdescription.cpp2
-rw-r--r--src/gui/rhi/qshaderdescription_p.h1
-rw-r--r--tests/auto/gui/rhi/qshader/tst_qshader.cpp115
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)