rhi: gl: Add support for instanced drawing

...when having a 3.3+ or ES 3.0+ context.

Change-Id: Ie92815263e190912d8f0b7b92ae6da55e062af05
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
bb10
Laszlo Agocs 2019-06-28 12:36:35 +02:00
parent 9452c963c8
commit 201a22a4d2
2 changed files with 45 additions and 16 deletions

View File

@ -425,6 +425,7 @@ bool QRhiGles2::create(QRhi::Flags flags)
caps.elementIndexUint = f->hasOpenGLExtension(QOpenGLExtensions::ElementIndexUint);
caps.depth24 = f->hasOpenGLExtension(QOpenGLExtensions::Depth24);
caps.rgba8Format = f->hasOpenGLExtension(QOpenGLExtensions::Sized8Formats);
caps.instancing = caps.ctxMajor >= 3 && (caps.gles || caps.ctxMinor >= 3);
nativeHandlesStruct.context = ctx;
@ -665,7 +666,7 @@ bool QRhiGles2::isFeatureSupported(QRhi::Feature feature) const
case QRhi::Timestamps:
return false;
case QRhi::Instancing:
return false;
return caps.instancing;
case QRhi::CustomInstanceStepRate:
return false;
case QRhi::PrimitiveRestart:
@ -933,7 +934,6 @@ void QRhiGles2::setStencilRef(QRhiCommandBuffer *cb, quint32 refValue)
void QRhiGles2::draw(QRhiCommandBuffer *cb, quint32 vertexCount,
quint32 instanceCount, quint32 firstVertex, quint32 firstInstance)
{
Q_UNUSED(instanceCount); // no instancing
Q_UNUSED(firstInstance);
QGles2CommandBuffer *cbD = QRHI_RES(QGles2CommandBuffer, cb);
Q_ASSERT(cbD->recordingPass == QGles2CommandBuffer::RenderPass);
@ -943,13 +943,13 @@ void QRhiGles2::draw(QRhiCommandBuffer *cb, quint32 vertexCount,
cmd.args.draw.ps = cbD->currentPipeline;
cmd.args.draw.vertexCount = vertexCount;
cmd.args.draw.firstVertex = firstVertex;
cmd.args.draw.instanceCount = instanceCount;
cbD->commands.append(cmd);
}
void QRhiGles2::drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance)
{
Q_UNUSED(instanceCount); // no instancing
Q_UNUSED(firstInstance);
Q_UNUSED(vertexOffset); // no glDrawElementsBaseVertex
QGles2CommandBuffer *cbD = QRHI_RES(QGles2CommandBuffer, cb);
@ -960,6 +960,7 @@ void QRhiGles2::drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
cmd.args.drawIndexed.ps = cbD->currentPipeline;
cmd.args.drawIndexed.indexCount = indexCount;
cmd.args.drawIndexed.firstIndex = firstIndex;
cmd.args.drawIndexed.instanceCount = instanceCount;
cbD->commands.append(cmd);
}
@ -1613,13 +1614,14 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
const QVector<QRhiVertexInputBinding> bindings = psD->m_vertexInputLayout.bindings();
const QVector<QRhiVertexInputAttribute> attributes = psD->m_vertexInputLayout.attributes();
for (const QRhiVertexInputAttribute &a : attributes) {
if (a.binding() != cmd.args.bindVertexBuffer.binding)
const int bindingIdx = a.binding();
if (bindingIdx != cmd.args.bindVertexBuffer.binding)
continue;
// we do not support more than one vertex buffer
f->glBindBuffer(GL_ARRAY_BUFFER, cmd.args.bindVertexBuffer.buffer);
const int stride = bindings[a.binding()].stride();
const int stride = bindings[bindingIdx].stride();
int size = 1;
GLenum type = GL_FLOAT;
bool normalize = false;
@ -1658,10 +1660,17 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
default:
break;
}
const int locationIdx = a.location();
quint32 ofs = a.offset() + cmd.args.bindVertexBuffer.offset;
f->glVertexAttribPointer(a.location(), size, type, normalize, stride,
f->glVertexAttribPointer(locationIdx, size, type, normalize, stride,
reinterpret_cast<const GLvoid *>(quintptr(ofs)));
f->glEnableVertexAttribArray(a.location());
f->glEnableVertexAttribArray(locationIdx);
if (bindings[bindingIdx].classification() == QRhiVertexInputBinding::PerInstance
&& caps.instancing)
{
f->glVertexAttribDivisor(locationIdx, bindings[bindingIdx].instanceStepRate());
}
}
} else {
qWarning("No graphics pipeline active for setVertexInput; ignored");
@ -1677,21 +1686,36 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
case QGles2CommandBuffer::Command::Draw:
{
QGles2GraphicsPipeline *psD = QRHI_RES(QGles2GraphicsPipeline, cmd.args.draw.ps);
if (psD)
f->glDrawArrays(psD->drawMode, cmd.args.draw.firstVertex, cmd.args.draw.vertexCount);
else
if (psD) {
if (cmd.args.draw.instanceCount == 1 || !caps.instancing) {
f->glDrawArrays(psD->drawMode, cmd.args.draw.firstVertex, cmd.args.draw.vertexCount);
} else {
f->glDrawArraysInstanced(psD->drawMode, cmd.args.draw.firstVertex, cmd.args.draw.vertexCount,
cmd.args.draw.instanceCount);
}
} else {
qWarning("No graphics pipeline active for draw; ignored");
}
}
break;
case QGles2CommandBuffer::Command::DrawIndexed:
{
QGles2GraphicsPipeline *psD = QRHI_RES(QGles2GraphicsPipeline, cmd.args.drawIndexed.ps);
if (psD) {
quint32 ofs = cmd.args.drawIndexed.firstIndex * indexStride + indexOffset;
f->glDrawElements(psD->drawMode,
cmd.args.drawIndexed.indexCount,
indexType,
reinterpret_cast<const GLvoid *>(quintptr(ofs)));
const GLvoid *ofs = reinterpret_cast<const GLvoid *>(
quintptr(cmd.args.drawIndexed.firstIndex * indexStride + indexOffset));
if (cmd.args.drawIndexed.instanceCount == 1 || !caps.instancing) {
f->glDrawElements(psD->drawMode,
cmd.args.drawIndexed.indexCount,
indexType,
ofs);
} else {
f->glDrawElementsInstanced(psD->drawMode,
cmd.args.drawIndexed.indexCount,
indexType,
ofs,
cmd.args.drawIndexed.instanceCount);
}
} else {
qWarning("No graphics pipeline active for drawIndexed; ignored");
}

View File

@ -324,11 +324,13 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer
QRhiGraphicsPipeline *ps;
quint32 vertexCount;
quint32 firstVertex;
quint32 instanceCount;
} draw;
struct {
QRhiGraphicsPipeline *ps;
quint32 indexCount;
quint32 firstIndex;
quint32 instanceCount;
} drawIndexed;
struct {
QRhiGraphicsPipeline *ps;
@ -644,7 +646,9 @@ public:
coreProfile(false),
uniformBuffers(false),
elementIndexUint(false),
depth24(false)
depth24(false),
rgba8Format(false),
instancing(false)
{ }
int ctxMajor;
int ctxMinor;
@ -672,6 +676,7 @@ public:
uint elementIndexUint : 1;
uint depth24 : 1;
uint rgba8Format : 1;
uint instancing : 1;
} caps;
QGles2SwapChain *currentSwapChain = nullptr;
QVector<GLint> supportedCompressedFormats;