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:
parent
201a22a4d2
commit
058c52fc2a
@ -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);
|
||||
}
|
||||
|
@ -1318,7 +1318,9 @@ public:
|
||||
ElementIndexUint,
|
||||
Compute,
|
||||
WideLines,
|
||||
VertexShaderPointSize
|
||||
VertexShaderPointSize,
|
||||
BaseVertex,
|
||||
BaseInstance
|
||||
};
|
||||
|
||||
enum BeginFrameFlag {
|
||||
|
@ -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;
|
||||
|
@ -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");
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
|
Loading…
Reference in New Issue
Block a user