rhi: Improve base vertex/instance support

Have feature flags as appropriate. OpenGL is causing a mess here
but let's support what we can since some of this will become relevant
in more sophisticated mesh drawing cases with 3D in particular.

Change-Id: Idfa7b4642ec87147978e03d78d6233efbd151491
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
This commit is contained in:
Laszlo Agocs 2019-06-28 15:06:06 +02:00
parent 201a22a4d2
commit 058c52fc2a
8 changed files with 92 additions and 25 deletions

View File

@ -511,6 +511,14 @@ QT_BEGIN_NAMESPACE
dropped from the generated code) Note that some APIs (Metal, Vulkan)
require the point size to be set in the shader explicitly whenever drawing
points, even when the size is 1, as they do not automatically default to 1.
\value BaseVertex Indicates that \l{QRhiCommandBuffer::drawIndexed()}{drawIndexed()}
supports the \c vertexOffset argument. When reported as not supported, the
vertexOffset value in an indexed draw is ignored.
\value BaseInstance Indicates that instanced draw commands support the \c
firstInstance argument. When reported as not supported, the firstInstance
value is ignored and the instance ID starts from 0.
*/
/*!
@ -4483,15 +4491,21 @@ void QRhiCommandBuffer::setStencilRef(quint32 refValue)
Records a non-indexed draw.
The number of vertices is specified in \a vertexCount. For instanced
drawing set \a instanceCount to a value other than 1. \a firstVertex is
the index of the first vertex to draw. \a firstInstance is the instance ID
of the first instance to draw.
drawing set \a instanceCount to a value other than 1. \a firstVertex is the
index of the first vertex to draw. When drawing multiple instances, the
first instance ID is specified by \a firstInstance.
\note \a firstInstance may not be supported, and is ignored when the
QRhi::BaseInstance feature is reported as not supported. The first ID is
always 0 in that case.
\note This function can only be called inside a render pass, meaning
between a beginPass() and endPass() call.
*/
void QRhiCommandBuffer::draw(quint32 vertexCount,
quint32 instanceCount, quint32 firstVertex, quint32 firstInstance)
quint32 instanceCount,
quint32 firstVertex,
quint32 firstInstance)
{
m_rhi->draw(this, vertexCount, instanceCount, firstVertex, firstInstance);
}
@ -4509,17 +4523,27 @@ void QRhiCommandBuffer::draw(quint32 vertexCount,
\l{QRhi::NonFourAlignedEffectiveIndexBufferOffset}{NonFourAlignedEffectiveIndexBufferOffset}
feature will be reported as not-supported.
For instanced drawing set \a instanceCount to a value other than 1. \a
firstInstance is the instance ID of the first instance to draw.
For instanced drawing set \a instanceCount to a value other than 1. When
drawing multiple instances, the first instance ID is specified by \a
firstInstance.
\a vertexOffset is added to the vertex index.
\note \a firstInstance may not be supported, and is ignored when the
QRhi::BaseInstance feature is reported as not supported. The first ID is
always 0 in that case.
\a vertexOffset (also called \c{base vertex}) is a signed value that is
added to the element index before indexing into the vertex buffer. Support
for this is not always available, and the value is ignored when the feature
QRhi::BaseVertex is reported as unsupported.
\note This function can only be called inside a render pass, meaning
between a beginPass() and endPass() call.
*/
void QRhiCommandBuffer::drawIndexed(quint32 indexCount,
quint32 instanceCount, quint32 firstIndex,
qint32 vertexOffset, quint32 firstInstance)
quint32 instanceCount,
quint32 firstIndex,
qint32 vertexOffset,
quint32 firstInstance)
{
m_rhi->drawIndexed(this, indexCount, instanceCount, firstIndex, vertexOffset, firstInstance);
}

View File

@ -1318,7 +1318,9 @@ public:
ElementIndexUint,
Compute,
WideLines,
VertexShaderPointSize
VertexShaderPointSize,
BaseVertex,
BaseInstance
};
enum BeginFrameFlag {

View File

@ -382,6 +382,10 @@ bool QRhiD3D11::isFeatureSupported(QRhi::Feature feature) const
return false;
case QRhi::VertexShaderPointSize:
return false;
case QRhi::BaseVertex:
return true;
case QRhi::BaseInstance:
return true;
default:
Q_UNREACHABLE();
return false;

View File

@ -426,6 +426,7 @@ bool QRhiGles2::create(QRhi::Flags flags)
caps.depth24 = f->hasOpenGLExtension(QOpenGLExtensions::Depth24);
caps.rgba8Format = f->hasOpenGLExtension(QOpenGLExtensions::Sized8Formats);
caps.instancing = caps.ctxMajor >= 3 && (caps.gles || caps.ctxMinor >= 3);
caps.baseVertex = caps.ctxMajor >= 3 && caps.ctxMinor >= 2;
nativeHandlesStruct.context = ctx;
@ -687,6 +688,10 @@ bool QRhiGles2::isFeatureSupported(QRhi::Feature feature) const
return true;
case QRhi::VertexShaderPointSize:
return true;
case QRhi::BaseVertex:
return caps.baseVertex;
case QRhi::BaseInstance:
return false; // not in ES 3.2, so won't bother
default:
Q_UNREACHABLE();
return false;
@ -934,7 +939,6 @@ void QRhiGles2::setStencilRef(QRhiCommandBuffer *cb, quint32 refValue)
void QRhiGles2::draw(QRhiCommandBuffer *cb, quint32 vertexCount,
quint32 instanceCount, quint32 firstVertex, quint32 firstInstance)
{
Q_UNUSED(firstInstance);
QGles2CommandBuffer *cbD = QRHI_RES(QGles2CommandBuffer, cb);
Q_ASSERT(cbD->recordingPass == QGles2CommandBuffer::RenderPass);
@ -944,14 +948,13 @@ void QRhiGles2::draw(QRhiCommandBuffer *cb, quint32 vertexCount,
cmd.args.draw.vertexCount = vertexCount;
cmd.args.draw.firstVertex = firstVertex;
cmd.args.draw.instanceCount = instanceCount;
cmd.args.draw.baseInstance = firstInstance;
cbD->commands.append(cmd);
}
void QRhiGles2::drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance)
{
Q_UNUSED(firstInstance);
Q_UNUSED(vertexOffset); // no glDrawElementsBaseVertex
QGles2CommandBuffer *cbD = QRHI_RES(QGles2CommandBuffer, cb);
Q_ASSERT(cbD->recordingPass == QGles2CommandBuffer::RenderPass);
@ -961,6 +964,8 @@ void QRhiGles2::drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
cmd.args.drawIndexed.indexCount = indexCount;
cmd.args.drawIndexed.firstIndex = firstIndex;
cmd.args.drawIndexed.instanceCount = instanceCount;
cmd.args.drawIndexed.baseInstance = firstInstance;
cmd.args.drawIndexed.baseVertex = vertexOffset;
cbD->commands.append(cmd);
}
@ -1705,16 +1710,33 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
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);
if (cmd.args.drawIndexed.baseVertex != 0 && caps.baseVertex) {
f->glDrawElementsBaseVertex(psD->drawMode,
cmd.args.drawIndexed.indexCount,
indexType,
ofs,
cmd.args.drawIndexed.baseVertex);
} else {
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);
if (cmd.args.drawIndexed.baseVertex != 0 && caps.baseVertex) {
f->glDrawElementsInstancedBaseVertex(psD->drawMode,
cmd.args.drawIndexed.indexCount,
indexType,
ofs,
cmd.args.drawIndexed.instanceCount,
cmd.args.drawIndexed.baseVertex);
} 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

@ -325,12 +325,15 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer
quint32 vertexCount;
quint32 firstVertex;
quint32 instanceCount;
quint32 baseInstance;
} draw;
struct {
QRhiGraphicsPipeline *ps;
quint32 indexCount;
quint32 firstIndex;
quint32 instanceCount;
quint32 baseInstance;
qint32 baseVertex;
} drawIndexed;
struct {
QRhiGraphicsPipeline *ps;
@ -648,7 +651,8 @@ public:
elementIndexUint(false),
depth24(false),
rgba8Format(false),
instancing(false)
instancing(false),
baseVertex(false)
{ }
int ctxMajor;
int ctxMinor;
@ -677,6 +681,7 @@ public:
uint depth24 : 1;
uint rgba8Format : 1;
uint instancing : 1;
uint baseVertex : 1;
} caps;
QGles2SwapChain *currentSwapChain = nullptr;
QVector<GLint> supportedCompressedFormats;

View File

@ -527,6 +527,10 @@ bool QRhiMetal::isFeatureSupported(QRhi::Feature feature) const
return false;
case QRhi::VertexShaderPointSize:
return true;
case QRhi::BaseVertex:
return true;
case QRhi::BaseInstance:
return true;
default:
Q_UNREACHABLE();
return false;

View File

@ -3549,6 +3549,10 @@ bool QRhiVulkan::isFeatureSupported(QRhi::Feature feature) const
return hasWideLines;
case QRhi::VertexShaderPointSize:
return true;
case QRhi::BaseVertex:
return true;
case QRhi::BaseInstance:
return true;
default:
Q_UNREACHABLE();
return false;
@ -4063,7 +4067,7 @@ void QRhiVulkan::setStencilRef(QRhiCommandBuffer *cb, quint32 refValue)
}
void QRhiVulkan::draw(QRhiCommandBuffer *cb, quint32 vertexCount,
quint32 instanceCount, quint32 firstVertex, quint32 firstInstance)
quint32 instanceCount, quint32 firstVertex, quint32 firstInstance)
{
QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
Q_ASSERT(cbD->recordingPass == QVkCommandBuffer::RenderPass);
@ -4078,7 +4082,7 @@ void QRhiVulkan::draw(QRhiCommandBuffer *cb, quint32 vertexCount,
}
void QRhiVulkan::drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance)
quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance)
{
QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
Q_ASSERT(cbD->recordingPass == QVkCommandBuffer::RenderPass);

View File

@ -174,6 +174,8 @@ void Window::customInit()
qDebug("isFeatureSupported(Compute): %d", m_r->isFeatureSupported(QRhi::Compute));
qDebug("isFeatureSupported(WideLines): %d", m_r->isFeatureSupported(QRhi::WideLines));
qDebug("isFeatureSupported(VertexShaderPointSize): %d", m_r->isFeatureSupported(QRhi::VertexShaderPointSize));
qDebug("isFeatureSupported(BaseVertex): %d", m_r->isFeatureSupported(QRhi::BaseVertex));
qDebug("isFeatureSupported(BaseInstance): %d", m_r->isFeatureSupported(QRhi::BaseInstance));
qDebug("Min 2D texture width/height: %d", m_r->resourceLimit(QRhi::TextureSizeMin));
qDebug("Max 2D texture width/height: %d", m_r->resourceLimit(QRhi::TextureSizeMax));
qDebug("Max color attachment count: %d", m_r->resourceLimit(QRhi::MaxColorAttachments));