Commit b8d5e754 authored by Laszlo Agocs's avatar Laszlo Agocs

Introduce dynamic uniform buffer offsets

Shader resources are now set via a dedicated API (setShaderResources)
instead of setGraphicsPipeline.

Also extend docs about command buffers and defered command execution.

Do a little cleanup for gl and d3d when it comes to the "fake" command
queues.
parent eca4dba9
......@@ -200,6 +200,7 @@ void Window::customRender()
cb->setGraphicsPipeline(d.ps);
cb->setViewport({ 0, 0, float(outputSizeInPixels.width()), float(outputSizeInPixels.height()) });
cb->setShaderResources();
cb->setVertexInput(0, { { d.vbuf, 0 }, { d.vbuf, 36 * 3 * sizeof(float) } });
cb->draw(36);
......
......@@ -216,6 +216,7 @@ void Window::customRender()
cb->setGraphicsPipeline(d.ps);
cb->setViewport({ 0, 0, float(outputSizeInPixels.width()), float(outputSizeInPixels.height()) });
cb->setShaderResources();
cb->setVertexInput(0, { { d.vbuf, 0 }, { d.vbuf, 36 * 3 * sizeof(float) } });
cb->draw(36);
......
......@@ -172,6 +172,7 @@ void Window::customRender()
cb->beginPass(m_sc->currentFrameRenderTarget(), { 0.4f, 0.7f, 0.0f, 1.0f }, { 1.0f, 0 }, u);
cb->setGraphicsPipeline(d.ps);
cb->setViewport(QRhiViewport(0, 0, outputSizeInPixels.width(), outputSizeInPixels.height()));
cb->setShaderResources();
cb->setVertexInput(0, { { d.vbuf, 0 } });
cb->draw(36);
cb->endPass();
......
......@@ -453,6 +453,7 @@ void Window::render()
cb->setGraphicsPipeline(m_ps);
cb->setViewport({ 0, 0, float(outputSizeInPixels.width()), float(outputSizeInPixels.height()) });
cb->setShaderResources();
cb->setVertexInput(0, { { m_vbuf, 0 } });
cb->draw(3);
......
......@@ -157,6 +157,7 @@ void Window::customRender()
cb->setGraphicsPipeline(d.ps);
cb->setViewport(QRhiViewport(0, 0, outputSizeInPixels.width(), outputSizeInPixels.height()));
cb->setShaderResources();
cb->setVertexInput(0, { { d.vbuf, 0 } });
cb->draw(3);
......
......@@ -271,7 +271,8 @@ void QRhiImgui::queueFrame(QRhiCommandBuffer *cb)
const QPointF scissorPixelBottomLeft = QPointF(cmd->ClipRect.x, d->lastOutputSize.height() - cmd->ClipRect.w);
const QSizeF scissorPixelSize = QSizeF(cmd->ClipRect.z - cmd->ClipRect.x, cmd->ClipRect.w - cmd->ClipRect.y);
const int textureIndex = int(reinterpret_cast<qintptr>(cmd->TextureId));
cb->setGraphicsPipeline(d->ps, d->textures[textureIndex].srb);
cb->setGraphicsPipeline(d->ps);
cb->setShaderResources(d->textures[textureIndex].srb);
cb->setScissor({ int(scissorPixelBottomLeft.x()), int(scissorPixelBottomLeft.y()),
int(scissorPixelSize.width()), int(scissorPixelSize.height()) });
cb->setVertexInput(0, vertexInput, d->ibuf, indexOffset, QRhiCommandBuffer::IndexUInt32);
......
......@@ -241,6 +241,7 @@ void Window::customRender()
cb->beginPass(d.rt, { 0.5f, 0.2f, 0, 1 }, { 1, 0 }, u);
cb->setGraphicsPipeline(d.triPs);
cb->setViewport({ 0, 0, float(d.rb->pixelSize().width()), float(d.rb->pixelSize().height()) });
cb->setShaderResources();
cb->setVertexInput(0, { { d.vbuf, sizeof(vertexData) } });
cb->draw(3);
cb->endPass();
......@@ -250,6 +251,7 @@ void Window::customRender()
cb->beginPass(m_sc->currentFrameRenderTarget(), { 0.4f, 0.7f, 0.0f, 1.0f }, { 1.0f, 0 });
cb->setGraphicsPipeline(d.ps);
cb->setViewport({ 0, 0, float(outputSizeInPixels.width()), float(outputSizeInPixels.height()) });
cb->setShaderResources();
cb->setVertexInput(0, { { d.vbuf, 0 } }, d.ibuf, 0, QRhiCommandBuffer::IndexUInt16);
cb->drawIndexed(6);
cb->endPass();
......
......@@ -299,6 +299,7 @@ void Window::customRender()
cb->beginPass(d.rt, { 0.5f, 0.2f, 0, 1 }, { 1, 0 });
cb->setGraphicsPipeline(d.triPs);
cb->setViewport({ 0, 0, float(d.msaaTex->pixelSize().width()), float(d.msaaTex->pixelSize().height()) });
cb->setShaderResources();
cb->setVertexInput(0, { { d.vbuf, sizeof(vertexData) } });
cb->draw(3);
cb->endPass();
......@@ -307,6 +308,7 @@ void Window::customRender()
cb->beginPass(d.msaaRt, { 0.5f, 0.2f, 0, 1 }, { 1, 0 });
cb->setGraphicsPipeline(d.msaaTriPs);
cb->setViewport({ 0, 0, float(d.msaaTex->pixelSize().width()), float(d.msaaTex->pixelSize().height()) });
cb->setShaderResources();
cb->setVertexInput(0, { { d.vbuf, sizeof(vertexData) } });
cb->draw(3);
cb->endPass();
......@@ -316,9 +318,11 @@ void Window::customRender()
cb->beginPass(m_sc->currentFrameRenderTarget(), { 0.4f, 0.7f, 0.0f, 1.0f }, { 1.0f, 0 });
cb->setGraphicsPipeline(d.psLeft); // showing the non-msaa version
cb->setViewport({ 0, 0, float(outputSizeInPixels.width()), float(outputSizeInPixels.height()) });
cb->setShaderResources();
cb->setVertexInput(0, { { d.vbuf, 0 } }, d.ibuf, 0, QRhiCommandBuffer::IndexUInt16);
cb->drawIndexed(6);
cb->setGraphicsPipeline(d.psRight); // showing the msaa version, resolved in the shader
cb->setShaderResources();
cb->drawIndexed(6);
cb->endPass();
}
......@@ -493,6 +493,7 @@ void Window::render()
cb->setGraphicsPipeline(d.ps);
cb->setViewport({ 0, 0, float(outputSizeInPixels.width()), float(outputSizeInPixels.height()) });
cb->setShaderResources();
cb->setVertexInput(0, { { d.vbuf, 0 } });
cb->draw(3);
......
......@@ -629,6 +629,7 @@ void Renderer::render(bool newlyExposed, bool wakeBeforePresent)
cb->setGraphicsPipeline(m_ps);
cb->setViewport(QRhiViewport(0, 0, outputSize.width(), outputSize.height()));
cb->setShaderResources();
cb->setVertexInput(0, { { m_vbuf, 0 }, { m_vbuf, 36 * 3 * sizeof(float) } });
cb->draw(36);
......
......@@ -297,6 +297,7 @@ int main(int argc, char **argv)
cb->beginPass(rt, { 0, 1, 0, 1 }, { 1, 0 }, u);
cb->setGraphicsPipeline(ps);
cb->setViewport({ 0, 0, 1280, 720 });
cb->setShaderResources();
cb->setVertexInput(0, { { vbuf, 0 } });
cb->draw(3);
......
......@@ -481,6 +481,7 @@ void Window::render()
cb->setGraphicsPipeline(ps);
cb->setViewport({ 0, 0, float(outputSizeInPixels.width()), float(outputSizeInPixels.height()) });
cb->setShaderResources();
cb->setVertexInput(0, { { vbuf, 0 } }, ibuf, 0, QRhiCommandBuffer::IndexUInt16);
cb->drawIndexed(6);
......
......@@ -280,6 +280,7 @@ void Window::customRender()
cb->setGraphicsPipeline(d.ps);
cb->setViewport({ 0, 0, float(outputSizeInPixels.width()), float(outputSizeInPixels.height()) });
cb->setShaderResources();
cb->setVertexInput(0, { { d.vbuf, 0 }, { d.vbuf, 36 * 3 * sizeof(float) } });
cb->draw(36);
......
......@@ -147,8 +147,9 @@ void QuadRenderer::queueResourceUpdates(QRhiResourceUpdateBatch *resourceUpdates
void QuadRenderer::queueDraw(QRhiCommandBuffer *cb, const QSize &/*outputSizeInPixels*/)
{
cb->setGraphicsPipeline(m_ps, m_srb);
cb->setGraphicsPipeline(m_ps);
//cb->setViewport(QRhiViewport(0, 0, outputSizeInPixels.width(), outputSizeInPixels.height()));
cb->setShaderResources(m_srb);
cb->setVertexInput(0, { { m_vbuf, 0 } }, m_ibuf, 0, QRhiCommandBuffer::IndexUInt16);
cb->drawIndexed(6);
}
......@@ -227,6 +227,7 @@ void TexturedCubeRenderer::queueDraw(QRhiCommandBuffer *cb, const QSize &outputS
{
cb->setGraphicsPipeline(m_ps);
cb->setViewport(QRhiViewport(0, 0, outputSizeInPixels.width(), outputSizeInPixels.height()));
cb->setShaderResources();
cb->setVertexInput(0, { { m_vbuf, 0 }, { m_vbuf, 36 * 3 * sizeof(float) } });
cb->draw(36);
}
......@@ -304,6 +304,7 @@ void TriangleOnCubeRenderer::queueDraw(QRhiCommandBuffer *cb, const QSize &outpu
{
cb->setGraphicsPipeline(m_ps);
cb->setViewport(QRhiViewport(0, 0, outputSizeInPixels.width(), outputSizeInPixels.height()));
cb->setShaderResources();
cb->setVertexInput(0, { { m_vbuf, 0 }, { m_vbuf, 36 * 3 * sizeof(float) } });
cb->draw(36);
}
......@@ -167,7 +167,7 @@ void TriangleRenderer::queueResourceUpdates(QRhiResourceUpdateBatch *resourceUpd
#if 0
static int messWithBufferTrigger = 0;
// recreate the underlying VkBuffer every second frame
// to exercise setGraphicsPipeline's built-in smartness
// to exercise setShaderResources' built-in smartness
if (!(messWithBufferTrigger & 1)) {
m_ubuf->release();
m_ubuf->build();
......@@ -203,6 +203,7 @@ void TriangleRenderer::queueDraw(QRhiCommandBuffer *cb, const QSize &outputSizeI
{
cb->setGraphicsPipeline(m_ps);
cb->setViewport(QRhiViewport(0, 0, outputSizeInPixels.width(), outputSizeInPixels.height()));
cb->setShaderResources();
cb->setVertexInput(0, { { m_vbuf, 0 } });
cb->draw(3);
}
......@@ -171,6 +171,7 @@ void TriangleRenderer::queueDraw(QRhiCommandBuffer *cb, const QSize &outputSizeI
{
cb->setGraphicsPipeline(m_ps);
cb->setViewport(QRhiViewport(0, 0, outputSizeInPixels.width(), outputSizeInPixels.height()));
cb->setShaderResources();
cb->setVertexInput(0, { { m_vbuf, 0 } });
cb->draw(3);
}
This diff is collapsed.
......@@ -337,6 +337,7 @@ public:
static QRhiShaderResourceBinding uniformBuffer(int binding, StageFlags stage, QRhiBuffer *buf);
static QRhiShaderResourceBinding uniformBuffer(int binding, StageFlags stage, QRhiBuffer *buf, int offset, int size);
static QRhiShaderResourceBinding uniformBufferWithDynamicOffset(int binding, StageFlags stage, QRhiBuffer *buf, int size);
static QRhiShaderResourceBinding sampledTexture(int binding, StageFlags stage, QRhiTexture *tex, QRhiSampler *sampler);
private:
......@@ -1126,9 +1127,10 @@ public:
QRhiResourceUpdateBatch *resourceUpdates = nullptr);
void endPass(QRhiResourceUpdateBatch *resourceUpdates = nullptr);
void setGraphicsPipeline(QRhiGraphicsPipeline *ps,
QRhiShaderResourceBindings *srb = nullptr);
void setGraphicsPipeline(QRhiGraphicsPipeline *ps);
using DynamicOffset = QPair<int, quint32>; // binding, offset
void setShaderResources(QRhiShaderResourceBindings *srb = nullptr,
const QVector<DynamicOffset> &dynamicOffsets = QVector<DynamicOffset>());
using VertexInput = QPair<QRhiBuffer *, quint32>; // buffer, offset
void setVertexInput(int startBinding, const QVector<VertexInput> &bindings,
QRhiBuffer *indexBuf = nullptr, quint32 indexOffset = 0,
......
......@@ -105,8 +105,11 @@ public:
virtual void endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) = 0;
virtual void setGraphicsPipeline(QRhiCommandBuffer *cb,
QRhiGraphicsPipeline *ps,
QRhiShaderResourceBindings *srb = nullptr) = 0;
QRhiGraphicsPipeline *ps) = 0;
virtual void setShaderResources(QRhiCommandBuffer *cb,
QRhiShaderResourceBindings *srb,
const QVector<QRhiCommandBuffer::DynamicOffset> &dynamicOffsets) = 0;
virtual void setVertexInput(QRhiCommandBuffer *cb,
int startBinding, const QVector<QRhiCommandBuffer::VertexInput> &bindings,
......@@ -313,6 +316,7 @@ public:
QRhiBuffer *buf;
int offset;
int maybeSize;
bool hasDynamicOffset;
};
struct SampledTextureData {
QRhiTexture *tex;
......
This diff is collapsed.
......@@ -246,9 +246,6 @@ struct QD3D11CommandBuffer : public QRhiCommandBuffer
QD3D11CommandBuffer(QRhiImplementation *rhi);
void release() override;
// Technically it's not like we really need to queue up the commands, but
// have it this way since it helps keeping things concise and may become
// essential if "command buffers" become application creatable some day.
struct Command {
enum Cmd {
SetRenderTarget,
......@@ -258,6 +255,7 @@ struct QD3D11CommandBuffer : public QRhiCommandBuffer
BindVertexBuffers,
BindIndexBuffer,
BindGraphicsPipeline,
BindShaderResources,
StencilRef,
BlendConstants,
Draw,
......@@ -272,6 +270,11 @@ struct QD3D11CommandBuffer : public QRhiCommandBuffer
};
enum ClearFlag { Color = 1, Depth = 2, Stencil = 4 };
Cmd cmd;
static const int MAX_UBUF_BINDINGS = 32; // should be D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT but 128 is a waste of space for our purposes
// QRhi*/QD3D11* references should be kept at minimum (so no
// QRhiTexture/Buffer/etc. pointers).
union {
struct {
QRhiRenderTarget *rt;
......@@ -304,9 +307,13 @@ struct QD3D11CommandBuffer : public QRhiCommandBuffer
} bindIndexBuffer;
struct {
QD3D11GraphicsPipeline *ps;
QD3D11ShaderResourceBindings *srb;
bool srbOnlyChange;
} bindGraphicsPipeline;
struct {
QD3D11ShaderResourceBindings *srb;
bool offsetOnlyChange;
int dynamicOffsetCount;
uint dynamicOffsetPairs[MAX_UBUF_BINDINGS * 2]; // binding, offsetInConstants
} bindShaderResources;
struct {
QD3D11GraphicsPipeline *ps;
quint32 ref;
......@@ -356,7 +363,7 @@ struct QD3D11CommandBuffer : public QRhiCommandBuffer
DXGI_FORMAT format;
} resolveSubRes;
struct {
QD3D11Texture *tex;
ID3D11ShaderResourceView *srv;
} genMip;
struct {
char s[64];
......@@ -421,7 +428,7 @@ struct QD3D11SwapChain : public QRhiSwapChain
QSize surfacePixelSize() override;
QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
bool buildOrResize();
bool buildOrResize() override;
void releaseBuffers();
bool newColorBuffer(const QSize &size, DXGI_FORMAT format, DXGI_SAMPLE_DESC sampleDesc,
......@@ -493,8 +500,11 @@ public:
void endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
void setGraphicsPipeline(QRhiCommandBuffer *cb,
QRhiGraphicsPipeline *ps,
QRhiShaderResourceBindings *srb) override;
QRhiGraphicsPipeline *ps) override;
void setShaderResources(QRhiCommandBuffer *cb,
QRhiShaderResourceBindings *srb,
const QVector<QRhiCommandBuffer::DynamicOffset> &dynamicOffsets) override;
void setVertexInput(QRhiCommandBuffer *cb,
int startBinding, const QVector<QRhiCommandBuffer::VertexInput> &bindings,
......@@ -530,7 +540,9 @@ public:
void enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates);
void updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD);
void executeBufferHostWritesForCurrentFrame(QD3D11Buffer *bufD);
void setShaderResources(QD3D11ShaderResourceBindings *srbD);
void bindShaderResources(QD3D11ShaderResourceBindings *srbD,
const uint *dynOfsPairs, int dynOfsPairCount,
bool offsetOnlyChange);
void setRenderTarget(QRhiRenderTarget *rt);
void executeCommandBuffer(QD3D11CommandBuffer *cbD, QD3D11SwapChain *timestampSwapChain = nullptr);
DXGI_SAMPLE_DESC effectiveSampleCount(int sampleCount) const;
......
This diff is collapsed.
......@@ -248,6 +248,7 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer
Draw,
DrawIndexed,
BindGraphicsPipeline,
BindShaderResources,
BindFramebuffer,
Clear,
BufferData,
......@@ -261,6 +262,11 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer
GenMip
};
Cmd cmd;
static const int MAX_UBUF_BINDINGS = 32; // should be more than enough
// QRhi*/QGles2* references should be kept at minimum (so no
// QRhiTexture/Buffer/etc. pointers).
union {
struct {
float x, y, w, h;
......@@ -299,9 +305,13 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer
} drawIndexed;
struct {
QRhiGraphicsPipeline *ps;
QRhiShaderResourceBindings *srb;
bool resOnlyChange;
} bindGraphicsPipeline;
struct {
QRhiGraphicsPipeline *ps;
QRhiShaderResourceBindings *srb;
int dynamicOffsetCount;
uint dynamicOffsetPairs[MAX_UBUF_BINDINGS * 2]; // binding, offsetInConstants
} bindShaderResources;
struct {
GLbitfield mask;
float c[4];
......@@ -309,7 +319,7 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer
quint32 s;
} clear;
struct {
QRhiTextureRenderTarget *rt;
GLuint fbo;
} bindFramebuffer;
struct {
GLenum target;
......@@ -324,7 +334,8 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer
int srcLevel;
int srcX;
int srcY;
QGles2Texture *dst;
GLenum dstTarget;
GLuint dstTexture;
GLenum dstFaceTarget;
int dstLevel;
int dstX;
......@@ -334,12 +345,16 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer
} copyTex;
struct {
QRhiReadbackResult *result;
QGles2Texture *texture;
int layer;
GLuint texture;
int w;
int h;
QRhiTexture::Format format;
GLenum readTarget;
int level;
} readPixels;
struct {
QGles2Texture *dst;
GLenum target;
GLuint texture;
GLenum faceTarget;
int level;
int dx;
......@@ -351,7 +366,8 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer
const void *data; // must come from retainImage()
} subImage;
struct {
QGles2Texture *dst;
GLenum target;
GLuint texture;
GLenum faceTarget;
int level;
GLenum glintformat;
......@@ -361,7 +377,8 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer
const void *data; // must come from retainData()
} compressedImage;
struct {
QGles2Texture *dst;
GLenum target;
GLuint texture;
GLenum faceTarget;
int level;
int dx;
......@@ -376,12 +393,13 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer
GLuint renderbuffer;
int w;
int h;
QGles2Texture *dst;
int dstLayer;
GLenum target;
GLuint texture;
int dstLevel;
} blitFromRb;
struct {
QGles2Texture *tex;
GLenum target;
GLuint texture;
} genMip;
} args;
};
......@@ -487,8 +505,11 @@ public:
void endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
void setGraphicsPipeline(QRhiCommandBuffer *cb,
QRhiGraphicsPipeline *ps,
QRhiShaderResourceBindings *srb) override;
QRhiGraphicsPipeline *ps) override;
void setShaderResources(QRhiCommandBuffer *cb,
QRhiShaderResourceBindings *srb,
const QVector<QRhiCommandBuffer::DynamicOffset> &dynamicOffsets) override;
void setVertexInput(QRhiCommandBuffer *cb,
int startBinding, const QVector<QRhiCommandBuffer::VertexInput> &bindings,
......@@ -525,8 +546,10 @@ public:
void executeDeferredReleases();
void enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates);
void executeCommandBuffer(QRhiCommandBuffer *cb);
void executeBindGraphicsPipeline(QRhiGraphicsPipeline *ps, QRhiShaderResourceBindings *srb);
void setChangedUniforms(QGles2GraphicsPipeline *psD, QRhiShaderResourceBindings *srb, bool changedOnly);
void executeBindGraphicsPipeline(QRhiGraphicsPipeline *ps);
void setChangedUniforms(QRhiGraphicsPipeline *ps, QRhiShaderResourceBindings *srb,
const uint *dynOfsPairs, int dynOfsCount,
bool changedOnly);
QOpenGLContext *ctx = nullptr;
bool importedContext = false;
......
......@@ -574,7 +574,9 @@ QRhiShaderResourceBindings *QRhiMetal::createShaderResourceBindings()
return new QMetalShaderResourceBindings(this);
}
void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD, QMetalCommandBuffer *cbD)
void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD, QMetalCommandBuffer *cbD,
const QVector<QRhiCommandBuffer::DynamicOffset> &dynamicOffsets,
bool offsetOnlyChange)
{
static const int KNOWN_STAGES = 2;
struct {
......@@ -591,13 +593,22 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
{
QMetalBuffer *bufD = QRHI_RES(QMetalBuffer, b->u.ubuf.buf);
id<MTLBuffer> mtlbuf = bufD->d->buf[bufD->m_type == QRhiBuffer::Immutable ? 0 : currentFrameSlot];
uint offset = b->u.ubuf.offset;
if (!dynamicOffsets.isEmpty()) {
for (const QRhiCommandBuffer::DynamicOffset &dynOfs : dynamicOffsets) {
if (dynOfs.first == b->binding) {
offset = dynOfs.second;
break;
}
}
}
if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) {
res[0].buffers.feed(b->binding, mtlbuf);
res[0].bufferOffsets.feed(b->binding, b->u.ubuf.offset);
res[0].bufferOffsets.feed(b->binding, offset);
}
if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
res[1].buffers.feed(b->binding, mtlbuf);
res[1].bufferOffsets.feed(b->binding, b->u.ubuf.offset);
res[1].bufferOffsets.feed(b->binding, offset);
}
}
break;
......@@ -624,8 +635,7 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
for (int idx = 0; idx < KNOWN_STAGES; ++idx) {
res[idx].buffers.finish();
res[idx].bufferOffsets.finish();
res[idx].textures.finish();
res[idx].samplers.finish();
for (int i = 0, ie = res[idx].buffers.batches.count(); i != ie; ++i) {
const auto &bufferBatch(res[idx].buffers.batches[i]);
const auto &offsetBatch(res[idx].bufferOffsets.batches[i]);
......@@ -645,6 +655,13 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
break;
}
}
if (offsetOnlyChange)
continue;
res[idx].textures.finish();
res[idx].samplers.finish();
for (int i = 0, ie = res[idx].textures.batches.count(); i != ie; ++i) {
const auto &batch(res[idx].textures.batches[i]);
switch (idx) {
......@@ -680,16 +697,39 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
}
}
void QRhiMetal::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline *ps, QRhiShaderResourceBindings *srb)
void QRhiMetal::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline *ps)
{
Q_ASSERT(inPass);
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
QMetalGraphicsPipeline *psD = QRHI_RES(QMetalGraphicsPipeline, ps);
if (cbD->currentPipeline != ps || cbD->currentPipelineGeneration != psD->generation) {
cbD->currentPipeline = ps;
cbD->currentPipelineGeneration = psD->generation;
[cbD->d->currentPassEncoder setRenderPipelineState: psD->d->ps];
[cbD->d->currentPassEncoder setDepthStencilState: psD->d->ds];
[cbD->d->currentPassEncoder setCullMode: psD->d->cullMode];
[cbD->d->currentPassEncoder setFrontFacingWinding: psD->d->winding];
}
psD->lastActiveFrameSlot = currentFrameSlot;
}
void QRhiMetal::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBindings *srb,
const QVector<QRhiCommandBuffer::DynamicOffset> &dynamicOffsets)
{
Q_ASSERT(inPass);
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
Q_ASSERT(cbD->currentPipeline);
if (!srb)
srb = psD->m_shaderResourceBindings;
srb = QRHI_RES(QMetalGraphicsPipeline, cbD->currentPipeline)->m_shaderResourceBindings;
QMetalShaderResourceBindings *srbD = QRHI_RES(QMetalShaderResourceBindings, srb);
bool hasSlottedResourceInSrb = false;
bool hasDynamicOffsetInSrb = false;
bool resNeedsRebind = false;
// do buffer writes, figure out if we need to rebind, and mark as in-use
......@@ -704,6 +744,8 @@ void QRhiMetal::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline
executeBufferHostWritesForCurrentFrame(bufD);
if (bufD->m_type != QRhiBuffer::Immutable)
hasSlottedResourceInSrb = true;
if (b->u.ubuf.hasDynamicOffset)
hasDynamicOffsetInSrb = true;
if (bufD->generation != bd.ubuf.generation) {
resNeedsRebind = true;
bd.ubuf.generation = bufD->generation;
......@@ -732,31 +774,22 @@ void QRhiMetal::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline
}
}
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
// make sure the resources for the correct slot get bound
const int resSlot = hasSlottedResourceInSrb ? currentFrameSlot : 0;
if (hasSlottedResourceInSrb && cbD->currentResSlot != resSlot)
resNeedsRebind = true;
if (cbD->currentPipeline != ps || cbD->currentPipelineGeneration != psD->generation) {
cbD->currentPipeline = ps;
cbD->currentPipelineGeneration = psD->generation;
[cbD->d->currentPassEncoder setRenderPipelineState: psD->d->ps];
[cbD->d->currentPassEncoder setDepthStencilState: psD->d->ds];
[cbD->d->currentPassEncoder setCullMode: psD->d->cullMode];
[cbD->d->currentPassEncoder setFrontFacingWinding: psD->d->winding];
}
const bool srbChange = cbD->currentSrb != srb || cbD->currentSrbGeneration != srbD->generation;
if (resNeedsRebind || cbD->currentSrb != srb || cbD->currentSrbGeneration != srbD->generation) {
// dynamic uniform buffer offsets always trigger a rebind
if (hasDynamicOffsetInSrb || resNeedsRebind || srbChange) {
cbD->currentSrb = srb;
cbD->currentSrbGeneration = srbD->generation;
cbD->currentResSlot = resSlot;
enqueueShaderResourceBindings(srbD, cbD);
const bool offsetOnlyChange = hasDynamicOffsetInSrb && !resNeedsRebind && !srbChange;
enqueueShaderResourceBindings(srbD, cbD, dynamicOffsets, offsetOnlyChange);
}
psD->lastActiveFrameSlot = currentFrameSlot;
}
void QRhiMetal::setVertexInput(QRhiCommandBuffer *cb, int startBinding, const QVector<QRhiCommandBuffer::VertexInput> &bindings,
......
......@@ -319,8 +319,11 @@ public:
void endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
void setGraphicsPipeline(QRhiCommandBuffer *cb,
QRhiGraphicsPipeline *ps,
QRhiShaderResourceBindings *srb) override;
QRhiGraphicsPipeline *ps) override;
void setShaderResources(QRhiCommandBuffer *cb,
QRhiShaderResourceBindings *srb,
const QVector<QRhiCommandBuffer::DynamicOffset> &dynamicOffsets) override;
void setVertexInput(QRhiCommandBuffer *cb,
int startBinding, const QVector<QRhiCommandBuffer::VertexInput> &bindings,
......@@ -357,7 +360,9 @@ public:
void finishActiveReadbacks(bool forced = false);
void enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates);
void executeBufferHostWritesForCurrentFrame(QMetalBuffer *bufD);
void enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD, QMetalCommandBuffer *cbD);
void enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD, QMetalCommandBuffer *cbD,
const QVector<QRhiCommandBuffer::DynamicOffset> &dynamicOffsets,
bool offsetOnlyChange);
int effectiveSampleCount(int sampleCount) const;
bool importedDevice = false;
......
......@@ -186,11 +186,18 @@ QRhiShaderResourceBindings *QRhiNull::createShaderResourceBindings()
return new QNullShaderResourceBindings(this);
}
void QRhiNull::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline *ps, QRhiShaderResourceBindings *srb)
void QRhiNull::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline *ps)
{
Q_UNUSED(cb);
Q_UNUSED(ps);
}
void QRhiNull::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBindings *srb,
const QVector<QRhiCommandBuffer::DynamicOffset> &dynamicOffsets)
{
Q_UNUSED(cb);
Q_UNUSED(srb);
Q_UNUSED(dynamicOffsets);
}
void QRhiNull::setVertexInput(QRhiCommandBuffer *cb, int startBinding, const QVector<QRhiCommandBuffer::VertexInput> &bindings,
......
......@@ -206,8 +206,11 @@ public:
void endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
void setGraphicsPipeline(QRhiCommandBuffer *cb,
QRhiGraphicsPipeline *ps,
QRhiShaderResourceBindings *srb) override;
QRhiGraphicsPipeline *ps) override;
void setShaderResources(QRhiCommandBuffer *cb,
QRhiShaderResourceBindings *srb,
const QVector<QRhiCommandBuffer::DynamicOffset> &dynamicOffsets) override;
void setVertexInput(QRhiCommandBuffer *cb,
int startBinding, const QVector<QRhiCommandBuffer::VertexInput> &bindings,
......
......@@ -631,6 +631,7 @@ VkResult QRhiVulkan::createDescriptorPool(VkDescriptorPool *pool)
{
VkDescriptorPoolSize descPoolSizes[] = {
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, QVK_UNIFORM_BUFFERS_PER_POOL },
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, QVK_UNIFORM_BUFFERS_PER_POOL },
{ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, QVK_COMBINED_IMAGE_SAMPLERS_PER_POOL }
};
VkDescriptorPoolCreateInfo descPoolInfo;
......@@ -2086,9 +2087,9 @@ void QRhiVulkan::updateShaderResourceBindings(QRhiShaderResourceBindings *srb, i
const bool updateAll = descSetIdx < 0;
int frameSlot = updateAll ? 0 : descSetIdx;
while (frameSlot < (updateAll ? QVK_FRAMES_IN_FLIGHT : descSetIdx + 1)) {
srbD->boundResourceData[frameSlot].resize(srbD->m_bindings.count());
for (int i = 0, ie = srbD->m_bindings.count(); i != ie; ++i) {
const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&srbD->m_bindings[i]);
srbD->boundResourceData[frameSlot].resize(srbD->sortedBindings.count());
for (int i = 0, ie = srbD->sortedBindings.count(); i != ie; ++i) {
const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&srbD->sortedBindings[i]);
QVkShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[frameSlot][i]);
VkWriteDescriptorSet writeInfo;
......@@ -2101,7 +2102,8 @@ void QRhiVulkan::updateShaderResourceBindings(QRhiShaderResourceBindings *srb, i
switch (b->type) {
case QRhiShaderResourceBinding::UniformBuffer:
{
writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
writeInfo.descriptorType = b->u.ubuf.hasDynamicOffset ? VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC
: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
QRhiBuffer *buf = b->u.ubuf.buf;
QVkBuffer *bufD = QRHI_RES(QVkBuffer, buf);
bd.ubuf.generation = bufD->generation;
......@@ -3108,24 +3110,46 @@ QRhiShaderResourceBindings *QRhiVulkan::createShaderResourceBindings()
return new QVkShaderResourceBindings(this);
}
void QRhiVulkan::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline *ps, QRhiShaderResourceBindings *srb)
void QRhiVulkan::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline *ps)
{
Q_ASSERT(inPass);
QVkGraphicsPipeline *psD = QRHI_RES(QVkGraphicsPipeline, ps);
Q_ASSERT(psD->pipeline);
QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);