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)
|
dropped from the generated code) Note that some APIs (Metal, Vulkan)
|
||||||
require the point size to be set in the shader explicitly whenever drawing
|
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.
|
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.
|
Records a non-indexed draw.
|
||||||
|
|
||||||
The number of vertices is specified in \a vertexCount. For instanced
|
The number of vertices is specified in \a vertexCount. For instanced
|
||||||
drawing set \a instanceCount to a value other than 1. \a firstVertex is
|
drawing set \a instanceCount to a value other than 1. \a firstVertex is the
|
||||||
the index of the first vertex to draw. \a firstInstance is the instance ID
|
index of the first vertex to draw. When drawing multiple instances, the
|
||||||
of the first instance to draw.
|
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
|
\note This function can only be called inside a render pass, meaning
|
||||||
between a beginPass() and endPass() call.
|
between a beginPass() and endPass() call.
|
||||||
*/
|
*/
|
||||||
void QRhiCommandBuffer::draw(quint32 vertexCount,
|
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);
|
m_rhi->draw(this, vertexCount, instanceCount, firstVertex, firstInstance);
|
||||||
}
|
}
|
||||||
@ -4509,17 +4523,27 @@ void QRhiCommandBuffer::draw(quint32 vertexCount,
|
|||||||
\l{QRhi::NonFourAlignedEffectiveIndexBufferOffset}{NonFourAlignedEffectiveIndexBufferOffset}
|
\l{QRhi::NonFourAlignedEffectiveIndexBufferOffset}{NonFourAlignedEffectiveIndexBufferOffset}
|
||||||
feature will be reported as not-supported.
|
feature will be reported as not-supported.
|
||||||
|
|
||||||
For instanced drawing set \a instanceCount to a value other than 1. \a
|
For instanced drawing set \a instanceCount to a value other than 1. When
|
||||||
firstInstance is the instance ID of the first instance to draw.
|
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
|
\note This function can only be called inside a render pass, meaning
|
||||||
between a beginPass() and endPass() call.
|
between a beginPass() and endPass() call.
|
||||||
*/
|
*/
|
||||||
void QRhiCommandBuffer::drawIndexed(quint32 indexCount,
|
void QRhiCommandBuffer::drawIndexed(quint32 indexCount,
|
||||||
quint32 instanceCount, quint32 firstIndex,
|
quint32 instanceCount,
|
||||||
qint32 vertexOffset, quint32 firstInstance)
|
quint32 firstIndex,
|
||||||
|
qint32 vertexOffset,
|
||||||
|
quint32 firstInstance)
|
||||||
{
|
{
|
||||||
m_rhi->drawIndexed(this, indexCount, instanceCount, firstIndex, vertexOffset, firstInstance);
|
m_rhi->drawIndexed(this, indexCount, instanceCount, firstIndex, vertexOffset, firstInstance);
|
||||||
}
|
}
|
||||||
|
@ -1318,7 +1318,9 @@ public:
|
|||||||
ElementIndexUint,
|
ElementIndexUint,
|
||||||
Compute,
|
Compute,
|
||||||
WideLines,
|
WideLines,
|
||||||
VertexShaderPointSize
|
VertexShaderPointSize,
|
||||||
|
BaseVertex,
|
||||||
|
BaseInstance
|
||||||
};
|
};
|
||||||
|
|
||||||
enum BeginFrameFlag {
|
enum BeginFrameFlag {
|
||||||
|
@ -382,6 +382,10 @@ bool QRhiD3D11::isFeatureSupported(QRhi::Feature feature) const
|
|||||||
return false;
|
return false;
|
||||||
case QRhi::VertexShaderPointSize:
|
case QRhi::VertexShaderPointSize:
|
||||||
return false;
|
return false;
|
||||||
|
case QRhi::BaseVertex:
|
||||||
|
return true;
|
||||||
|
case QRhi::BaseInstance:
|
||||||
|
return true;
|
||||||
default:
|
default:
|
||||||
Q_UNREACHABLE();
|
Q_UNREACHABLE();
|
||||||
return false;
|
return false;
|
||||||
|
@ -426,6 +426,7 @@ bool QRhiGles2::create(QRhi::Flags flags)
|
|||||||
caps.depth24 = f->hasOpenGLExtension(QOpenGLExtensions::Depth24);
|
caps.depth24 = f->hasOpenGLExtension(QOpenGLExtensions::Depth24);
|
||||||
caps.rgba8Format = f->hasOpenGLExtension(QOpenGLExtensions::Sized8Formats);
|
caps.rgba8Format = f->hasOpenGLExtension(QOpenGLExtensions::Sized8Formats);
|
||||||
caps.instancing = caps.ctxMajor >= 3 && (caps.gles || caps.ctxMinor >= 3);
|
caps.instancing = caps.ctxMajor >= 3 && (caps.gles || caps.ctxMinor >= 3);
|
||||||
|
caps.baseVertex = caps.ctxMajor >= 3 && caps.ctxMinor >= 2;
|
||||||
|
|
||||||
nativeHandlesStruct.context = ctx;
|
nativeHandlesStruct.context = ctx;
|
||||||
|
|
||||||
@ -687,6 +688,10 @@ bool QRhiGles2::isFeatureSupported(QRhi::Feature feature) const
|
|||||||
return true;
|
return true;
|
||||||
case QRhi::VertexShaderPointSize:
|
case QRhi::VertexShaderPointSize:
|
||||||
return true;
|
return true;
|
||||||
|
case QRhi::BaseVertex:
|
||||||
|
return caps.baseVertex;
|
||||||
|
case QRhi::BaseInstance:
|
||||||
|
return false; // not in ES 3.2, so won't bother
|
||||||
default:
|
default:
|
||||||
Q_UNREACHABLE();
|
Q_UNREACHABLE();
|
||||||
return false;
|
return false;
|
||||||
@ -934,7 +939,6 @@ void QRhiGles2::setStencilRef(QRhiCommandBuffer *cb, quint32 refValue)
|
|||||||
void QRhiGles2::draw(QRhiCommandBuffer *cb, quint32 vertexCount,
|
void QRhiGles2::draw(QRhiCommandBuffer *cb, quint32 vertexCount,
|
||||||
quint32 instanceCount, quint32 firstVertex, quint32 firstInstance)
|
quint32 instanceCount, quint32 firstVertex, quint32 firstInstance)
|
||||||
{
|
{
|
||||||
Q_UNUSED(firstInstance);
|
|
||||||
QGles2CommandBuffer *cbD = QRHI_RES(QGles2CommandBuffer, cb);
|
QGles2CommandBuffer *cbD = QRHI_RES(QGles2CommandBuffer, cb);
|
||||||
Q_ASSERT(cbD->recordingPass == QGles2CommandBuffer::RenderPass);
|
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.vertexCount = vertexCount;
|
||||||
cmd.args.draw.firstVertex = firstVertex;
|
cmd.args.draw.firstVertex = firstVertex;
|
||||||
cmd.args.draw.instanceCount = instanceCount;
|
cmd.args.draw.instanceCount = instanceCount;
|
||||||
|
cmd.args.draw.baseInstance = firstInstance;
|
||||||
cbD->commands.append(cmd);
|
cbD->commands.append(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QRhiGles2::drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
|
void QRhiGles2::drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
|
||||||
quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance)
|
quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance)
|
||||||
{
|
{
|
||||||
Q_UNUSED(firstInstance);
|
|
||||||
Q_UNUSED(vertexOffset); // no glDrawElementsBaseVertex
|
|
||||||
QGles2CommandBuffer *cbD = QRHI_RES(QGles2CommandBuffer, cb);
|
QGles2CommandBuffer *cbD = QRHI_RES(QGles2CommandBuffer, cb);
|
||||||
Q_ASSERT(cbD->recordingPass == QGles2CommandBuffer::RenderPass);
|
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.indexCount = indexCount;
|
||||||
cmd.args.drawIndexed.firstIndex = firstIndex;
|
cmd.args.drawIndexed.firstIndex = firstIndex;
|
||||||
cmd.args.drawIndexed.instanceCount = instanceCount;
|
cmd.args.drawIndexed.instanceCount = instanceCount;
|
||||||
|
cmd.args.drawIndexed.baseInstance = firstInstance;
|
||||||
|
cmd.args.drawIndexed.baseVertex = vertexOffset;
|
||||||
cbD->commands.append(cmd);
|
cbD->commands.append(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1705,16 +1710,33 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
|
|||||||
const GLvoid *ofs = reinterpret_cast<const GLvoid *>(
|
const GLvoid *ofs = reinterpret_cast<const GLvoid *>(
|
||||||
quintptr(cmd.args.drawIndexed.firstIndex * indexStride + indexOffset));
|
quintptr(cmd.args.drawIndexed.firstIndex * indexStride + indexOffset));
|
||||||
if (cmd.args.drawIndexed.instanceCount == 1 || !caps.instancing) {
|
if (cmd.args.drawIndexed.instanceCount == 1 || !caps.instancing) {
|
||||||
f->glDrawElements(psD->drawMode,
|
if (cmd.args.drawIndexed.baseVertex != 0 && caps.baseVertex) {
|
||||||
cmd.args.drawIndexed.indexCount,
|
f->glDrawElementsBaseVertex(psD->drawMode,
|
||||||
indexType,
|
cmd.args.drawIndexed.indexCount,
|
||||||
ofs);
|
indexType,
|
||||||
|
ofs,
|
||||||
|
cmd.args.drawIndexed.baseVertex);
|
||||||
|
} else {
|
||||||
|
f->glDrawElements(psD->drawMode,
|
||||||
|
cmd.args.drawIndexed.indexCount,
|
||||||
|
indexType,
|
||||||
|
ofs);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
f->glDrawElementsInstanced(psD->drawMode,
|
if (cmd.args.drawIndexed.baseVertex != 0 && caps.baseVertex) {
|
||||||
cmd.args.drawIndexed.indexCount,
|
f->glDrawElementsInstancedBaseVertex(psD->drawMode,
|
||||||
indexType,
|
cmd.args.drawIndexed.indexCount,
|
||||||
ofs,
|
indexType,
|
||||||
cmd.args.drawIndexed.instanceCount);
|
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 {
|
} else {
|
||||||
qWarning("No graphics pipeline active for drawIndexed; ignored");
|
qWarning("No graphics pipeline active for drawIndexed; ignored");
|
||||||
|
@ -325,12 +325,15 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer
|
|||||||
quint32 vertexCount;
|
quint32 vertexCount;
|
||||||
quint32 firstVertex;
|
quint32 firstVertex;
|
||||||
quint32 instanceCount;
|
quint32 instanceCount;
|
||||||
|
quint32 baseInstance;
|
||||||
} draw;
|
} draw;
|
||||||
struct {
|
struct {
|
||||||
QRhiGraphicsPipeline *ps;
|
QRhiGraphicsPipeline *ps;
|
||||||
quint32 indexCount;
|
quint32 indexCount;
|
||||||
quint32 firstIndex;
|
quint32 firstIndex;
|
||||||
quint32 instanceCount;
|
quint32 instanceCount;
|
||||||
|
quint32 baseInstance;
|
||||||
|
qint32 baseVertex;
|
||||||
} drawIndexed;
|
} drawIndexed;
|
||||||
struct {
|
struct {
|
||||||
QRhiGraphicsPipeline *ps;
|
QRhiGraphicsPipeline *ps;
|
||||||
@ -648,7 +651,8 @@ public:
|
|||||||
elementIndexUint(false),
|
elementIndexUint(false),
|
||||||
depth24(false),
|
depth24(false),
|
||||||
rgba8Format(false),
|
rgba8Format(false),
|
||||||
instancing(false)
|
instancing(false),
|
||||||
|
baseVertex(false)
|
||||||
{ }
|
{ }
|
||||||
int ctxMajor;
|
int ctxMajor;
|
||||||
int ctxMinor;
|
int ctxMinor;
|
||||||
@ -677,6 +681,7 @@ public:
|
|||||||
uint depth24 : 1;
|
uint depth24 : 1;
|
||||||
uint rgba8Format : 1;
|
uint rgba8Format : 1;
|
||||||
uint instancing : 1;
|
uint instancing : 1;
|
||||||
|
uint baseVertex : 1;
|
||||||
} caps;
|
} caps;
|
||||||
QGles2SwapChain *currentSwapChain = nullptr;
|
QGles2SwapChain *currentSwapChain = nullptr;
|
||||||
QVector<GLint> supportedCompressedFormats;
|
QVector<GLint> supportedCompressedFormats;
|
||||||
|
@ -527,6 +527,10 @@ bool QRhiMetal::isFeatureSupported(QRhi::Feature feature) const
|
|||||||
return false;
|
return false;
|
||||||
case QRhi::VertexShaderPointSize:
|
case QRhi::VertexShaderPointSize:
|
||||||
return true;
|
return true;
|
||||||
|
case QRhi::BaseVertex:
|
||||||
|
return true;
|
||||||
|
case QRhi::BaseInstance:
|
||||||
|
return true;
|
||||||
default:
|
default:
|
||||||
Q_UNREACHABLE();
|
Q_UNREACHABLE();
|
||||||
return false;
|
return false;
|
||||||
|
@ -3549,6 +3549,10 @@ bool QRhiVulkan::isFeatureSupported(QRhi::Feature feature) const
|
|||||||
return hasWideLines;
|
return hasWideLines;
|
||||||
case QRhi::VertexShaderPointSize:
|
case QRhi::VertexShaderPointSize:
|
||||||
return true;
|
return true;
|
||||||
|
case QRhi::BaseVertex:
|
||||||
|
return true;
|
||||||
|
case QRhi::BaseInstance:
|
||||||
|
return true;
|
||||||
default:
|
default:
|
||||||
Q_UNREACHABLE();
|
Q_UNREACHABLE();
|
||||||
return false;
|
return false;
|
||||||
@ -4063,7 +4067,7 @@ void QRhiVulkan::setStencilRef(QRhiCommandBuffer *cb, quint32 refValue)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void QRhiVulkan::draw(QRhiCommandBuffer *cb, quint32 vertexCount,
|
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);
|
QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
|
||||||
Q_ASSERT(cbD->recordingPass == QVkCommandBuffer::RenderPass);
|
Q_ASSERT(cbD->recordingPass == QVkCommandBuffer::RenderPass);
|
||||||
@ -4078,7 +4082,7 @@ void QRhiVulkan::draw(QRhiCommandBuffer *cb, quint32 vertexCount,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void QRhiVulkan::drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
|
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);
|
QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
|
||||||
Q_ASSERT(cbD->recordingPass == QVkCommandBuffer::RenderPass);
|
Q_ASSERT(cbD->recordingPass == QVkCommandBuffer::RenderPass);
|
||||||
|
@ -174,6 +174,8 @@ void Window::customInit()
|
|||||||
qDebug("isFeatureSupported(Compute): %d", m_r->isFeatureSupported(QRhi::Compute));
|
qDebug("isFeatureSupported(Compute): %d", m_r->isFeatureSupported(QRhi::Compute));
|
||||||
qDebug("isFeatureSupported(WideLines): %d", m_r->isFeatureSupported(QRhi::WideLines));
|
qDebug("isFeatureSupported(WideLines): %d", m_r->isFeatureSupported(QRhi::WideLines));
|
||||||
qDebug("isFeatureSupported(VertexShaderPointSize): %d", m_r->isFeatureSupported(QRhi::VertexShaderPointSize));
|
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("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 2D texture width/height: %d", m_r->resourceLimit(QRhi::TextureSizeMax));
|
||||||
qDebug("Max color attachment count: %d", m_r->resourceLimit(QRhi::MaxColorAttachments));
|
qDebug("Max color attachment count: %d", m_r->resourceLimit(QRhi::MaxColorAttachments));
|
||||||
|
Loading…
Reference in New Issue
Block a user