Revision control

Copy as Markdown

// Copyright (C) 2018 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "graphicshelperes3_1_p.h"
#include <qgraphicsutils_p.h>
#include <QOpenGLExtraFunctions>
QT_BEGIN_NAMESPACE
// ES 3.1+
#ifndef GL_SAMPLER_2D_MULTISAMPLE
#define GL_SAMPLER_2D_MULTISAMPLE 0x9108
#endif
#ifndef GL_INT_SAMPLER_2D_MULTISAMPLE
#define GL_INT_SAMPLER_2D_MULTISAMPLE 0x9109
#endif
#ifndef GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE
#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE 0x910A
#endif
#ifndef GL_ACTIVE_RESOURCES
#define GL_ACTIVE_RESOURCES 0x92F5
#endif
#ifndef GL_BUFFER_BINDING
#define GL_BUFFER_BINDING 0x9302
#endif
#ifndef GL_BUFFER_DATA_SIZE
#define GL_BUFFER_DATA_SIZE 0x9303
#endif
#ifndef GL_NUM_ACTIVE_VARIABLES
#define GL_NUM_ACTIVE_VARIABLES 0x9304
#endif
#ifndef GL_SHADER_STORAGE_BLOCK
#define GL_SHADER_STORAGE_BLOCK 0x92E6
#endif
#ifndef GL_ALL_BARRIER_BITS
#define GL_ALL_BARRIER_BITS 0xFFFFFFFF
#endif
#ifndef GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT
#define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT 0x00000001
#endif
#ifndef GL_ELEMENT_ARRAY_BARRIER_BIT
#define GL_ELEMENT_ARRAY_BARRIER_BIT 0x00000002
#endif
#ifndef GL_UNIFORM_BARRIER_BIT
#define GL_UNIFORM_BARRIER_BIT 0x00000004
#endif
#ifndef GL_TEXTURE_FETCH_BARRIER_BIT
#define GL_TEXTURE_FETCH_BARRIER_BIT 0x00000008
#endif
#ifndef GL_SHADER_IMAGE_ACCESS_BARRIER_BIT
#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 0x00000020
#endif
#ifndef GL_COMMAND_BARRIER_BIT
#define GL_COMMAND_BARRIER_BIT 0x00000040
#endif
#ifndef GL_PIXEL_BUFFER_BARRIER_BIT
#define GL_PIXEL_BUFFER_BARRIER_BIT 0x00000080
#endif
#ifndef GL_TEXTURE_UPDATE_BARRIER_BIT
#define GL_TEXTURE_UPDATE_BARRIER_BIT 0x00000100
#endif
#ifndef GL_BUFFER_UPDATE_BARRIER_BIT
#define GL_BUFFER_UPDATE_BARRIER_BIT 0x00000200
#endif
#ifndef GL_FRAMEBUFFER_BARRIER_BIT
#define GL_FRAMEBUFFER_BARRIER_BIT 0x00000400
#endif
#ifndef GL_TRANSFORM_FEEDBACK_BARRIER_BIT
#define GL_TRANSFORM_FEEDBACK_BARRIER_BIT 0x00000800
#endif
#ifndef GL_ATOMIC_COUNTER_BARRIER_BIT
#define GL_ATOMIC_COUNTER_BARRIER_BIT 0x00001000
#endif
#ifndef GL_SHADER_STORAGE_BARRIER_BIT
#define GL_SHADER_STORAGE_BARRIER_BIT 0x00002000
#endif
#ifndef GL_IMAGE_2D
#define GL_IMAGE_2D 0x904D
#endif
#ifndef GL_IMAGE_3D
#define GL_IMAGE_3D 0x904E
#endif
#ifndef GL_IMAGE_CUBE
#define GL_IMAGE_CUBE 0x9050
#endif
#ifndef GL_IMAGE_2D_ARRAY
#define GL_IMAGE_2D_ARRAY 0x9053
#endif
#ifndef GL_INT_IMAGE_2D
#define GL_INT_IMAGE_2D 0x9058
#endif
#ifndef GL_INT_IMAGE_3D
#define GL_INT_IMAGE_3D 0x9059
#endif
#ifndef GL_INT_IMAGE_CUBE
#define GL_INT_IMAGE_CUBE 0x905B
#endif
#ifndef GL_INT_IMAGE_2D_ARRAY
#define GL_INT_IMAGE_2D_ARRAY 0x905E
#endif
#ifndef GL_UNSIGNED_INT_IMAGE_2D
#define GL_UNSIGNED_INT_IMAGE_2D 0x9063
#endif
#ifndef GL_UNSIGNED_INT_IMAGE_3D
#define GL_UNSIGNED_INT_IMAGE_3D 0x9064
#endif
#ifndef GL_UNSIGNED_INT_IMAGE_CUBE
#define GL_UNSIGNED_INT_IMAGE_CUBE 0x9066
#endif
#ifndef GL_UNSIGNED_INT_IMAGE_2D_ARRAY
#define GL_UNSIGNED_INT_IMAGE_2D_ARRAY 0x9069
#endif
namespace Qt3DRender {
namespace Render {
namespace OpenGL {
namespace {
GLbitfield memoryBarrierGL3Bitfield(QMemoryBarrier::Operations barriers)
{
GLbitfield bits = 0;
if (barriers.testFlag(QMemoryBarrier::All)) {
bits |= GL_ALL_BARRIER_BITS;
return bits;
}
if (barriers.testFlag(QMemoryBarrier::VertexAttributeArray))
bits |= GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT;
if (barriers.testFlag(QMemoryBarrier::ElementArray))
bits |= GL_ELEMENT_ARRAY_BARRIER_BIT;
if (barriers.testFlag(QMemoryBarrier::Uniform))
bits |= GL_UNIFORM_BARRIER_BIT;
if (barriers.testFlag(QMemoryBarrier::TextureFetch))
bits |= GL_TEXTURE_FETCH_BARRIER_BIT;
if (barriers.testFlag(QMemoryBarrier::ShaderImageAccess))
bits |= GL_SHADER_IMAGE_ACCESS_BARRIER_BIT;
if (barriers.testFlag(QMemoryBarrier::Command))
bits |= GL_COMMAND_BARRIER_BIT;
if (barriers.testFlag(QMemoryBarrier::PixelBuffer))
bits |= GL_PIXEL_BUFFER_BARRIER_BIT;
if (barriers.testFlag(QMemoryBarrier::TextureUpdate))
bits |= GL_TEXTURE_UPDATE_BARRIER_BIT;
if (barriers.testFlag(QMemoryBarrier::BufferUpdate))
bits |= GL_BUFFER_UPDATE_BARRIER_BIT;
if (barriers.testFlag(QMemoryBarrier::FrameBuffer))
bits |= GL_FRAMEBUFFER_BARRIER_BIT;
if (barriers.testFlag(QMemoryBarrier::TransformFeedback))
bits |= GL_TRANSFORM_FEEDBACK_BARRIER_BIT;
if (barriers.testFlag(QMemoryBarrier::AtomicCounter))
bits |= GL_ATOMIC_COUNTER_BARRIER_BIT;
if (barriers.testFlag(QMemoryBarrier::ShaderStorage))
bits |= GL_SHADER_STORAGE_BARRIER_BIT;
if (barriers.testFlag(QMemoryBarrier::QueryBuffer))
qWarning() << "QueryBuffer barrier not supported by ES 3.1";
return bits;
}
} // anonymous
GraphicsHelperES3_1::GraphicsHelperES3_1()
{
}
GraphicsHelperES3_1::~GraphicsHelperES3_1()
{
}
bool GraphicsHelperES3_1::supportsFeature(GraphicsHelperInterface::Feature feature) const
{
switch (feature) {
case GraphicsHelperInterface::Compute:
case GraphicsHelperInterface::ShaderStorageObject:
case GraphicsHelperInterface::IndirectDrawing:
case GraphicsHelperInterface::ShaderImage:
return true;
default:
break;
}
return GraphicsHelperES3::supportsFeature(feature);
}
void GraphicsHelperES3_1::bindImageTexture(GLuint imageUnit, GLuint texture,
GLint mipLevel, GLboolean layered,
GLint layer, GLenum access, GLenum format)
{
m_extraFuncs->glBindImageTexture(imageUnit,
texture,
mipLevel,
layered,
layer,
access,
format);
}
void GraphicsHelperES3_1::dispatchCompute(GLuint wx, GLuint wy, GLuint wz)
{
m_extraFuncs->glDispatchCompute(wx, wy, wz);
}
void GraphicsHelperES3_1::memoryBarrier(QMemoryBarrier::Operations barriers)
{
m_extraFuncs->glMemoryBarrier(memoryBarrierGL3Bitfield(barriers));
}
void GraphicsHelperES3_1::drawArraysIndirect(GLenum mode, void *indirect)
{
m_extraFuncs->glDrawArraysIndirect(mode, indirect);
}
void GraphicsHelperES3_1::drawElementsIndirect(GLenum mode, GLenum type, void *indirect)
{
m_extraFuncs->glDrawElementsIndirect(mode, type, indirect);
}
void GraphicsHelperES3_1::bindShaderStorageBlock(GLuint , GLuint , GLuint )
{
// ES 3.1 has no API for that, bindings have to be specified directly in the shader
// with layout(std430, binding = 3)
qWarning() << "ES 3.1 has no bindShaderStorageBlock API, it uses binding declaration from the shader storage block";
}
std::vector<ShaderStorageBlock> GraphicsHelperES3_1::programShaderStorageBlocks(GLuint programId)
{
std::vector<ShaderStorageBlock> blocks;
GLint nbrActiveShaderStorageBlocks = 0;
m_extraFuncs->glGetProgramInterfaceiv(programId, GL_SHADER_STORAGE_BLOCK, GL_ACTIVE_RESOURCES, &nbrActiveShaderStorageBlocks);
blocks.reserve(nbrActiveShaderStorageBlocks);
for (GLint i = 0; i < nbrActiveShaderStorageBlocks; ++i) {
QByteArray storageBlockName(256, '\0');
GLsizei length = 0;
ShaderStorageBlock storageBlock;
m_extraFuncs->glGetProgramResourceName(programId, GL_SHADER_STORAGE_BLOCK, i, 256, &length, storageBlockName.data());
storageBlock.m_index = i;
storageBlock.m_name = QString::fromUtf8(storageBlockName.left(length));
GLenum prop = GL_BUFFER_BINDING;
m_extraFuncs->glGetProgramResourceiv(programId, GL_SHADER_STORAGE_BLOCK, i, 1, &prop, 4, NULL, &storageBlock.m_binding);
prop = GL_BUFFER_DATA_SIZE;
m_extraFuncs->glGetProgramResourceiv(programId, GL_SHADER_STORAGE_BLOCK, i, 1, &prop, 4, NULL, &storageBlock.m_size);
prop = GL_NUM_ACTIVE_VARIABLES;
m_extraFuncs->glGetProgramResourceiv(programId, GL_SHADER_STORAGE_BLOCK, i, 1, &prop, 4, NULL, &storageBlock.m_activeVariablesCount);
blocks.push_back(storageBlock);
}
return blocks;
}
UniformType GraphicsHelperES3_1::uniformTypeFromGLType(GLenum glType)
{
switch (glType) {
case GL_SAMPLER_2D_MULTISAMPLE:
case GL_INT_SAMPLER_2D_MULTISAMPLE:
case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
return UniformType::Sampler;
case GL_IMAGE_2D:
case GL_IMAGE_3D:
case GL_IMAGE_CUBE:
case GL_IMAGE_2D_ARRAY:
case GL_INT_IMAGE_2D:
case GL_INT_IMAGE_3D:
case GL_INT_IMAGE_CUBE:
case GL_INT_IMAGE_2D_ARRAY:
case GL_UNSIGNED_INT_IMAGE_2D:
case GL_UNSIGNED_INT_IMAGE_3D:
case GL_UNSIGNED_INT_IMAGE_CUBE:
case GL_UNSIGNED_INT_IMAGE_2D_ARRAY:
return UniformType::Image;
default:
return GraphicsHelperES3::uniformTypeFromGLType(glType);
}
}
uint GraphicsHelperES3_1::uniformByteSize(const ShaderUniform &description)
{
uint rawByteSize = 0;
switch (description.m_type) {
case GL_SAMPLER_2D_MULTISAMPLE:
case GL_INT_SAMPLER_2D_MULTISAMPLE:
case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
case GL_IMAGE_2D:
case GL_IMAGE_3D:
case GL_IMAGE_CUBE:
case GL_IMAGE_2D_ARRAY:
case GL_INT_IMAGE_2D:
case GL_INT_IMAGE_3D:
case GL_INT_IMAGE_CUBE:
case GL_INT_IMAGE_2D_ARRAY:
case GL_UNSIGNED_INT_IMAGE_2D:
case GL_UNSIGNED_INT_IMAGE_3D:
case GL_UNSIGNED_INT_IMAGE_CUBE:
case GL_UNSIGNED_INT_IMAGE_2D_ARRAY:
rawByteSize = 4;
break;
default:
rawByteSize = GraphicsHelperES3::uniformByteSize(description);
break;
}
return rawByteSize;
}
void GraphicsHelperES3_1::buildUniformBuffer(const QVariant &v, const ShaderUniform &description, QByteArray &buffer)
{
char *bufferData = buffer.data();
switch (description.m_type) {
case GL_SAMPLER_2D_MULTISAMPLE:
case GL_INT_SAMPLER_2D_MULTISAMPLE:
case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
{
Q_ASSERT(description.m_size == 1);
int value = v.toInt();
QGraphicsUtils::fillDataArray<GLint>(bufferData, &value, description, 1);
break;
}
default:
GraphicsHelperES3::buildUniformBuffer(v, description, buffer);
break;
}
}
} // namespace OpenGL
} // namespace Render
} // namespace Qt3DRender
QT_END_NAMESPACE