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 <andy.nichols@qt.io>bb10
parent
042cd97884
commit
c262a69851
|
|
@ -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.
|
||||
*/
|
||||
|
||||
/*!
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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 },
|
||||
|
|
|
|||
|
|
@ -133,6 +133,7 @@ public:
|
|||
SamplerCubeArray,
|
||||
SamplerRect,
|
||||
SamplerBuffer,
|
||||
SamplerExternalOES,
|
||||
|
||||
Image1D,
|
||||
Image2D,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Reference in New Issue