Skip to content

Commit

Permalink
rhi: gl: Add some enablers for supporting GL_TEXTURE_EXTERNAL_OES
Browse files Browse the repository at this point in the history
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]>
  • Loading branch information
alpqr committed Jan 13, 2021
1 parent 042cd97 commit c262a69
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 1 deletion.
3 changes: 3 additions & 0 deletions src/gui/rhi/qrhi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/

/*!
Expand Down
3 changes: 2 additions & 1 deletion src/gui/rhi/qrhi_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -745,7 +745,8 @@ class Q_GUI_EXPORT QRhiTexture : public QRhiResource
UsedAsTransferSource = 1 << 5,
UsedWithGenerateMips = 1 << 6,
UsedWithLoadStore = 1 << 7,
UsedAsCompressedAtlas = 1 << 8
UsedAsCompressedAtlas = 1 << 8,
ExternalOES = 1 << 9
};
Q_DECLARE_FLAGS(Flags, Flag)

Expand Down
7 changes: 7 additions & 0 deletions src/gui/rhi/qrhigles2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;

Expand Down
2 changes: 2 additions & 0 deletions src/gui/rhi/qshaderdescription.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ QT_BEGIN_NAMESPACE
\value SamplerCubeArray
\value SamplerRect
\value SamplerBuffer
\value SamplerExternalOES
\value Image1D
\value Image2D
\value Image2DMS
Expand Down Expand Up @@ -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 },
Expand Down
1 change: 1 addition & 0 deletions src/gui/rhi/qshaderdescription_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ class Q_GUI_EXPORT QShaderDescription
SamplerCubeArray,
SamplerRect,
SamplerBuffer,
SamplerExternalOES,

Image1D,
Image2D,
Expand Down
115 changes: 115 additions & 0 deletions tests/auto/gui/rhi/qshader/tst_qshader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ private slots:
void serializeShaderDesc();
void comparison();
void loadV4();
void manualShaderPackCreation();
};

static QShader getShader(const QString &name)
Expand Down Expand Up @@ -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)

0 comments on commit c262a69

Please sign in to comment.