Commit 3cee5983 authored by Laszlo Agocs's avatar Laszlo Agocs

Make QRhiShaderResourceBinding a proper class

Here we choose to go the heavy weight route and turn it into a
d-pointered (implicitly shared, even) class since the data a binding
description needs may grow in yet-unknown ways when introducing support
for other resource types.
parent c9911761
......@@ -215,7 +215,7 @@ void Window::customRender()
// Now replace d.tex with d.newTex as the shader resource.
auto bindings = d.srb->bindings();
bindings[1].stex.tex = d.newTex; // see customInit, this was d.tex originally
bindings[1] = QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.newTex, d.sampler);
d.srb->setBindings(bindings);
// "rebuild", whatever that means for a given backend. This srb is
// already live as the ps in the setGraphicsPipeline references it,
......@@ -264,7 +264,7 @@ void Window::customRender()
// switch to showing d.importedTex
auto bindings = d.srb->bindings();
bindings[1].stex.tex = d.importedTex;
bindings[1] = QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.importedTex, d.sampler);
d.srb->setBindings(bindings);
d.srb->build();
} else {
......
......@@ -1516,7 +1516,7 @@ void QRhiResource::releaseAndDestroy()
}
/*!
Returns the currently set object name. By default the name is empty.
\return the currently set object name. By default the name is empty.
*/
QByteArray QRhiResource::name() const
{
......@@ -1782,58 +1782,117 @@ QRhiShaderResourceBindings::QRhiShaderResourceBindings(QRhiImplementation *rhi)
}
/*!
Returns a shader resource binding for the given binding number, pipeline
stage, and buffer specified by \a binding_, \a stage_, and \a buf_.
\internal
*/
QRhiShaderResourceBinding::QRhiShaderResourceBinding()
: d(new QRhiShaderResourceBindingPrivate)
{
}
/*!
\internal
*/
void QRhiShaderResourceBinding::detach()
{
if (d->ref.load() != 1) {
QRhiShaderResourceBindingPrivate *newd = new QRhiShaderResourceBindingPrivate(d);
if (!d->ref.deref())
delete d;
d = newd;
}
}
/*!
\internal
*/
QRhiShaderResourceBinding::QRhiShaderResourceBinding(const QRhiShaderResourceBinding &other)
{
d = other.d;
d->ref.ref();
}
/*!
\internal
*/
QRhiShaderResourceBinding &QRhiShaderResourceBinding::operator=(const QRhiShaderResourceBinding &other)
{
if (d != other.d) {
other.d->ref.ref();
if (!d->ref.deref())
delete d;
d = other.d;
}
return *this;
}
/*!
Destructor.
*/
QRhiShaderResourceBinding::~QRhiShaderResourceBinding()
{
if (!d->ref.deref())
delete d;
}
/*!
\return a shader resource binding for the given binding number, pipeline
stage, and buffer specified by \a binding, \a stage, and \a buf.
*/
QRhiShaderResourceBinding QRhiShaderResourceBinding::uniformBuffer(
int binding_, StageFlags stage_, QRhiBuffer *buf_)
int binding, StageFlags stage, QRhiBuffer *buf)
{
QRhiShaderResourceBinding b;
b.binding = binding_;
b.stage = stage_;
b.type = UniformBuffer;
b.ubuf.buf = buf_;
b.ubuf.offset = 0;
b.ubuf.maybeSize = 0; // entire buffer
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
Q_ASSERT(d->ref.load() == 1);
d->binding = binding;
d->stage = stage;
d->type = UniformBuffer;
d->u.ubuf.buf = buf;
d->u.ubuf.offset = 0;
d->u.ubuf.maybeSize = 0; // entire buffer
return b;
}
/*!
Returns a shader resource binding for the given binding number, pipeline
stage, and buffer specified by \a binding_, \a stage_, and \a buf_. This
overload binds a region only, as specified by \a offset_ and \a size_.
\return a shader resource binding for the given binding number, pipeline
stage, and buffer specified by \a binding, \a stage, and \a buf. This
overload binds a region only, as specified by \a offset and \a size.
\note It is up to the user to ensure the offset is aligned to
QRhi::ubufAlignment().
*/
QRhiShaderResourceBinding QRhiShaderResourceBinding::uniformBuffer(
int binding_, StageFlags stage_, QRhiBuffer *buf_, int offset_, int size_)
int binding, StageFlags stage, QRhiBuffer *buf, int offset, int size)
{
Q_ASSERT(size_ > 0);
Q_ASSERT(size > 0);
QRhiShaderResourceBinding b;
b.binding = binding_;
b.stage = stage_;
b.type = UniformBuffer;
b.ubuf.buf = buf_;
b.ubuf.offset = offset_;
b.ubuf.maybeSize = size_;
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
Q_ASSERT(d->ref.load() == 1);
d->binding = binding;
d->stage = stage;
d->type = UniformBuffer;
d->u.ubuf.buf = buf;
d->u.ubuf.offset = offset;
d->u.ubuf.maybeSize = size;
return b;
}
/*!
Returns a shader resource binding for the given binding number, pipeline
stage, texture, and sampler specified by \a binding_, \a stage_, \a tex_,
\a sampler_.
\return a shader resource binding for the given binding number, pipeline
stage, texture, and sampler specified by \a binding, \a stage, \a tex,
\a sampler.
*/
QRhiShaderResourceBinding QRhiShaderResourceBinding::sampledTexture(
int binding_, StageFlags stage_, QRhiTexture *tex_, QRhiSampler *sampler_)
int binding, StageFlags stage, QRhiTexture *tex, QRhiSampler *sampler)
{
QRhiShaderResourceBinding b;
b.binding = binding_;
b.stage = stage_;
b.type = SampledTexture;
b.stex.tex = tex_;
b.stex.sampler = sampler_;
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
Q_ASSERT(d->ref.load() == 1);
d->binding = binding;
d->stage = stage;
d->type = SampledTexture;
d->u.stex.tex = tex;
d->u.stex.sampler = sampler;
return b;
}
......@@ -2851,7 +2910,7 @@ bool QRhi::isYUpInFramebuffer() const
}
/*!
Returns a matrix that can be used allow applications keep using
\return a matrix that can be used allow applications keep using
OpenGL-targeted vertex data and projection matrices (for example, the ones
generated by QMatrix4x4::perspective()) regardless of the backed. Once
\c{this_matrix * mvp} is used instead of just \c mvp, vertex data with Y up
......
......@@ -59,6 +59,7 @@ class QRhiCommandBuffer;
class QRhiResourceUpdateBatch;
class QRhiResourceUpdateBatchPrivate;
class QRhiProfiler;
class QRhiShaderResourceBindingPrivate;
class Q_RHI_EXPORT QRhiColorClearValue
{
......@@ -165,6 +166,7 @@ private:
quint32 m_stride;
Classification m_classification;
int m_instanceStepRate;
void *m_reserved;
};
Q_DECLARE_TYPEINFO(QRhiVertexInputBinding, Q_MOVABLE_TYPE);
......@@ -204,6 +206,7 @@ private:
int m_location;
Format m_format;
quint32 m_offset;
void *m_reserved;
};
Q_DECLARE_TYPEINFO(QRhiVertexInputAttribute, Q_MOVABLE_TYPE);
......@@ -220,6 +223,7 @@ public:
private:
QVector<QRhiVertexInputBinding> m_bindings;
QVector<QRhiVertexInputAttribute> m_attributes;
void *m_reserved;
};
Q_DECLARE_TYPEINFO(QRhiVertexInputLayout, Q_MOVABLE_TYPE);
......@@ -248,12 +252,14 @@ public:
private:
Type m_type;
QBakedShader m_shader;
void *m_reserved;
};
Q_DECLARE_TYPEINFO(QRhiGraphicsShaderStage, Q_MOVABLE_TYPE);
struct Q_RHI_EXPORT QRhiShaderResourceBinding
class Q_RHI_EXPORT QRhiShaderResourceBinding
{
public:
enum Type {
UniformBuffer,
SampledTexture
......@@ -267,26 +273,19 @@ struct Q_RHI_EXPORT QRhiShaderResourceBinding
};
Q_DECLARE_FLAGS(StageFlags, StageFlag)
static QRhiShaderResourceBinding uniformBuffer(int binding_, StageFlags stage_, QRhiBuffer *buf_);
static QRhiShaderResourceBinding uniformBuffer(int binding_, StageFlags stage_, QRhiBuffer *buf_, int offset_, int size_);
static QRhiShaderResourceBinding sampledTexture(int binding_, StageFlags stage_, QRhiTexture *tex_, QRhiSampler *sampler_);
int binding;
StageFlags stage;
Type type;
struct UniformBufferData {
QRhiBuffer *buf;
int offset;
int maybeSize;
};
struct SampledTextureData {
QRhiTexture *tex;
QRhiSampler *sampler;
};
union {
UniformBufferData ubuf;
SampledTextureData stex;
};
QRhiShaderResourceBinding();
QRhiShaderResourceBinding(const QRhiShaderResourceBinding &other);
QRhiShaderResourceBinding &operator=(const QRhiShaderResourceBinding &other);
~QRhiShaderResourceBinding();
void detach();
static QRhiShaderResourceBinding uniformBuffer(int binding, StageFlags stage, QRhiBuffer *buf);
static QRhiShaderResourceBinding uniformBuffer(int binding, StageFlags stage, QRhiBuffer *buf, int offset, int size);
static QRhiShaderResourceBinding sampledTexture(int binding, StageFlags stage, QRhiTexture *tex, QRhiSampler *sampler);
private:
QRhiShaderResourceBindingPrivate *d;
friend class QRhiShaderResourceBindingPrivate;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QRhiShaderResourceBinding::StageFlags)
......@@ -323,13 +322,12 @@ public:
private:
QRhiTexture *m_texture = nullptr;
QRhiRenderBuffer *m_renderBuffer = nullptr;
int m_layer = 0;
int m_level = 0;
QRhiTexture *m_resolveTexture = nullptr;
int m_resolveLayer = 0;
int m_resolveLevel = 0;
void *m_reserved;
};
Q_DECLARE_TYPEINFO(QRhiColorAttachment, Q_MOVABLE_TYPE);
......@@ -361,6 +359,7 @@ private:
QVector<QRhiColorAttachment> m_colorAttachments;
QRhiRenderBuffer *m_depthStencilBuffer = nullptr;
QRhiTexture *m_depthTexture = nullptr;
void *m_reserved;
};
Q_DECLARE_TYPEINFO(QRhiTextureRenderTargetDescription, Q_MOVABLE_TYPE);
......@@ -393,6 +392,7 @@ private:
QPoint m_destinationTopLeft;
QSize m_sourceSize;
QPoint m_sourceTopLeft;
void *m_reserved;
};
Q_DECLARE_TYPEINFO(QRhiTextureMipLevel, Q_MOVABLE_TYPE);
......@@ -408,6 +408,7 @@ public:
private:
QVector<QRhiTextureMipLevel> m_mipImages;
void *m_reserved;
};
Q_DECLARE_TYPEINFO(QRhiTextureLayer, Q_MOVABLE_TYPE);
......@@ -423,6 +424,7 @@ public:
private:
QVector<QRhiTextureLayer> m_layers;
void *m_reserved;
};
Q_DECLARE_TYPEINFO(QRhiTextureUploadDescription, Q_MOVABLE_TYPE);
......@@ -455,14 +457,13 @@ public:
private:
QSize m_pixelSize;
int m_sourceLayer = 0;
int m_sourceLevel = 0;
QPoint m_sourceTopLeft;
int m_destinationLayer = 0;
int m_destinationLevel = 0;
QPoint m_destinationTopLeft;
void *m_reserved;
};
Q_DECLARE_TYPEINFO(QRhiTextureCopyDescription, Q_MOVABLE_TYPE);
......@@ -486,6 +487,7 @@ private:
QRhiTexture *m_texture = nullptr;
int m_layer = 0;
int m_level = 0;
void *m_reserved;
};
Q_DECLARE_TYPEINFO(QRhiReadbackDescription, Q_MOVABLE_TYPE);
......
......@@ -45,6 +45,7 @@
#include "qrhi.h"
#include "qrhiprofiler_p.h"
#include <QBitArray>
#include <QAtomicInt>
QT_BEGIN_NAMESPACE
......@@ -263,6 +264,45 @@ Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::TextureRead, Q_MOVABLE_TYPE);
Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::TextureMipGen, Q_MOVABLE_TYPE);
Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::TexturePrepare, Q_MOVABLE_TYPE);
class Q_RHI_PRIVATE_EXPORT QRhiShaderResourceBindingPrivate
{
public:
QRhiShaderResourceBindingPrivate()
: ref(1)
{
}
QRhiShaderResourceBindingPrivate(const QRhiShaderResourceBindingPrivate *other)
: ref(1),
binding(other->binding),
stage(other->stage),
type(other->type),
u(other->u)
{
}
static QRhiShaderResourceBindingPrivate *get(QRhiShaderResourceBinding *s) { return s->d; }
static const QRhiShaderResourceBindingPrivate *get(const QRhiShaderResourceBinding *s) { return s->d; }
QAtomicInt ref;
int binding;
QRhiShaderResourceBinding::StageFlags stage;
QRhiShaderResourceBinding::Type type;
struct UniformBufferData {
QRhiBuffer *buf;
int offset;
int maybeSize;
};
struct SampledTextureData {
QRhiTexture *tex;
QRhiSampler *sampler;
};
union {
UniformBufferData ubuf;
SampledTextureData stex;
} u;
};
template<typename T>
struct QRhiBatchedBindings
{
......
......@@ -394,12 +394,12 @@ void QRhiD3D11::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline
bool srbUpdate = false;
for (int i = 0, ie = srbD->sortedBindings.count(); i != ie; ++i) {
const QRhiShaderResourceBinding &b(srbD->sortedBindings[i]);
const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&srbD->sortedBindings[i]);
QD3D11ShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[i]);
switch (b.type) {
switch (b->type) {
case QRhiShaderResourceBinding::UniformBuffer:
{
QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, b.ubuf.buf);
QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, b->u.ubuf.buf);
if (bufD->m_type == QRhiBuffer::Dynamic)
executeBufferHostWritesForCurrentFrame(bufD);
......@@ -411,8 +411,8 @@ void QRhiD3D11::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline
break;
case QRhiShaderResourceBinding::SampledTexture:
{
QD3D11Texture *texD = QRHI_RES(QD3D11Texture, b.stex.tex);
QD3D11Sampler *samplerD = QRHI_RES(QD3D11Sampler, b.stex.sampler);
QD3D11Texture *texD = QRHI_RES(QD3D11Texture, b->u.stex.tex);
QD3D11Sampler *samplerD = QRHI_RES(QD3D11Sampler, b->u.stex.sampler);
if (texD->generation != bd.stex.texGeneration
|| samplerD->generation != bd.stex.samplerGeneration)
{
......@@ -1314,28 +1314,28 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD)
srbD->fsshaderresources.clear();
for (int i = 0, ie = srbD->sortedBindings.count(); i != ie; ++i) {
const QRhiShaderResourceBinding &b(srbD->sortedBindings[i]);
const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&srbD->sortedBindings[i]);
QD3D11ShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[i]);
switch (b.type) {
switch (b->type) {
case QRhiShaderResourceBinding::UniformBuffer:
{
QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, b.ubuf.buf);
Q_ASSERT(aligned(b.ubuf.offset, 256) == b.ubuf.offset);
QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, b->u.ubuf.buf);
Q_ASSERT(aligned(b->u.ubuf.offset, 256) == b->u.ubuf.offset);
bd.ubuf.generation = bufD->generation;
const uint offsetInConstants = b.ubuf.offset / 16;
const uint offsetInConstants = b->u.ubuf.offset / 16;
// size must be 16 mult. (in constants, i.e. multiple of 256 bytes).
// We can round up if needed since the buffers's actual size
// (ByteWidth) is always a multiple of 256.
const uint sizeInConstants = aligned(b.ubuf.maybeSize ? b.ubuf.maybeSize : bufD->m_size, 256) / 16;
if (b.stage.testFlag(QRhiShaderResourceBinding::VertexStage)) {
srbD->vsubufs.feed(b.binding, bufD->buffer);
srbD->vsubufoffsets.feed(b.binding, offsetInConstants);
srbD->vsubufsizes.feed(b.binding, sizeInConstants);
const uint sizeInConstants = aligned(b->u.ubuf.maybeSize ? b->u.ubuf.maybeSize : bufD->m_size, 256) / 16;
if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) {
srbD->vsubufs.feed(b->binding, bufD->buffer);
srbD->vsubufoffsets.feed(b->binding, offsetInConstants);
srbD->vsubufsizes.feed(b->binding, sizeInConstants);
}
if (b.stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
srbD->fsubufs.feed(b.binding, bufD->buffer);
srbD->fsubufoffsets.feed(b.binding, offsetInConstants);
srbD->fsubufsizes.feed(b.binding, sizeInConstants);
if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
srbD->fsubufs.feed(b->binding, bufD->buffer);
srbD->fsubufoffsets.feed(b->binding, offsetInConstants);
srbD->fsubufsizes.feed(b->binding, sizeInConstants);
}
}
break;
......@@ -1343,17 +1343,17 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD)
{
// A sampler with binding N is mapped to a HLSL sampler and texture
// with registers sN and tN by SPIRV-Cross.
QD3D11Texture *texD = QRHI_RES(QD3D11Texture, b.stex.tex);
QD3D11Sampler *samplerD = QRHI_RES(QD3D11Sampler, b.stex.sampler);
QD3D11Texture *texD = QRHI_RES(QD3D11Texture, b->u.stex.tex);
QD3D11Sampler *samplerD = QRHI_RES(QD3D11Sampler, b->u.stex.sampler);
bd.stex.texGeneration = texD->generation;
bd.stex.samplerGeneration = samplerD->generation;
if (b.stage.testFlag(QRhiShaderResourceBinding::VertexStage)) {
srbD->vssamplers.feed(b.binding, samplerD->samplerState);
srbD->vsshaderresources.feed(b.binding, texD->srv);
if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) {
srbD->vssamplers.feed(b->binding, samplerD->samplerState);
srbD->vsshaderresources.feed(b->binding, texD->srv);
}
if (b.stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
srbD->fssamplers.feed(b.binding, samplerD->samplerState);
srbD->fsshaderresources.feed(b.binding, texD->srv);
if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
srbD->fssamplers.feed(b->binding, samplerD->samplerState);
srbD->fsshaderresources.feed(b->binding, texD->srv);
}
}
break;
......@@ -2269,7 +2269,7 @@ bool QD3D11ShaderResourceBindings::build()
std::sort(sortedBindings.begin(), sortedBindings.end(),
[](const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b)
{
return a.binding < b.binding;
return QRhiShaderResourceBindingPrivate::get(&a)->binding < QRhiShaderResourceBindingPrivate::get(&b)->binding;
});
boundResourceData.resize(sortedBindings.count());
......
......@@ -1378,19 +1378,19 @@ void QRhiGles2::setChangedUniforms(QGles2GraphicsPipeline *psD, QRhiShaderResour
QGles2ShaderResourceBindings *srbD = QRHI_RES(QGles2ShaderResourceBindings, srb);
for (int i = 0, ie = srbD->m_bindings.count(); i != ie; ++i) {
const QRhiShaderResourceBinding &b(srbD->m_bindings[i]);
const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&srbD->m_bindings[i]);
QGles2ShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[i]);
switch (b.type) {
switch (b->type) {
case QRhiShaderResourceBinding::UniformBuffer:
{
QGles2Buffer *bufD = QRHI_RES(QGles2Buffer, b.ubuf.buf);
QGles2Buffer *bufD = QRHI_RES(QGles2Buffer, b->u.ubuf.buf);
if (changedOnly && bufD->ubufChangeRange.isNull()) // do not set again when nothing changed
break;
const QByteArray bufView = QByteArray::fromRawData(bufD->ubuf.constData() + b.ubuf.offset,
b.ubuf.maybeSize ? b.ubuf.maybeSize : bufD->m_size);
const QByteArray bufView = QByteArray::fromRawData(bufD->ubuf.constData() + b->u.ubuf.offset,
b->u.ubuf.maybeSize ? b->u.ubuf.maybeSize : bufD->m_size);
for (QGles2GraphicsPipeline::Uniform &uniform : psD->uniforms) {
if (uniform.binding == b.binding
if (uniform.binding == b->binding
&& (!changedOnly ||
(uniform.offset >= uint(bufD->ubufChangeRange.changeBegin)
&& uniform.offset < uint(bufD->ubufChangeRange.changeEnd))))
......@@ -1443,19 +1443,19 @@ void QRhiGles2::setChangedUniforms(QGles2GraphicsPipeline *psD, QRhiShaderResour
break;
case QRhiShaderResourceBinding::SampledTexture:
{
QGles2Texture *texD = QRHI_RES(QGles2Texture, b.stex.tex);
QGles2Sampler *samplerD = QRHI_RES(QGles2Sampler, b.stex.sampler);
QGles2Texture *texD = QRHI_RES(QGles2Texture, b->u.stex.tex);
QGles2Sampler *samplerD = QRHI_RES(QGles2Sampler, b->u.stex.sampler);
const bool textureChanged = QRHI_RES(QGles2Texture, b.stex.tex)->generation != bd.stex.texGeneration;
const bool textureChanged = QRHI_RES(QGles2Texture, b->u.stex.tex)->generation != bd.stex.texGeneration;
if (textureChanged)
bd.stex.texGeneration = QRHI_RES(QGles2Texture, b.stex.tex)->generation;
const bool samplerChanged = QRHI_RES(QGles2Sampler, b.stex.sampler)->generation != bd.stex.samplerGeneration;
bd.stex.texGeneration = QRHI_RES(QGles2Texture, b->u.stex.tex)->generation;
const bool samplerChanged = QRHI_RES(QGles2Sampler, b->u.stex.sampler)->generation != bd.stex.samplerGeneration;
if (samplerChanged)
bd.stex.samplerGeneration = QRHI_RES(QGles2Sampler, b.stex.sampler)->generation;
bd.stex.samplerGeneration = QRHI_RES(QGles2Sampler, b->u.stex.sampler)->generation;
int texUnit = 0;
for (QGles2GraphicsPipeline::Sampler &sampler : psD->samplers) {
if (sampler.binding == b.binding) {
if (sampler.binding == b->binding) {
f->glActiveTexture(GL_TEXTURE0 + texUnit);
f->glBindTexture(texD->target, texD->texture);
......@@ -2053,9 +2053,9 @@ bool QGles2ShaderResourceBindings::build()
boundResourceData.resize(m_bindings.count());
for (int i = 0, ie = m_bindings.count(); i != ie; ++i) {
const QRhiShaderResourceBinding &b(m_bindings[i]);
const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&m_bindings[i]);
BoundResourceData &bd(boundResourceData[i]);
switch (b.type) {
switch (b->type) {
case QRhiShaderResourceBinding::UniformBuffer:
// nothing, we do not track buffer generations
break;
......
......@@ -2209,7 +2209,7 @@ bool QMetalShaderResourceBindings::build()
std::sort(sortedBindings.begin(), sortedBindings.end(),
[](const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b)
{
return a.binding < b.binding;
return QRhiShaderResourceBindingPrivate::get(&a)->binding < QRhiShaderResourceBindingPrivate::get(&b)->binding;
});
if (!sortedBindings.isEmpty())
maxBinding = sortedBindings.last().binding;
......
......@@ -1971,27 +1971,27 @@ void QRhiVulkan::updateShaderResourceBindings(QRhiShaderResourceBindings *srb, i
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 QRhiShaderResourceBinding &b(srbD->m_bindings[i]);
const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&srbD->m_bindings[i]);
QVkShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[frameSlot][i]);
VkWriteDescriptorSet writeInfo;
memset(&writeInfo, 0, sizeof(writeInfo));
writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writeInfo.dstSet = srbD->descSets[frameSlot];
writeInfo.dstBinding = b.binding;
writeInfo.dstBinding = b->binding;
writeInfo.descriptorCount = 1;
switch (b.type) {
switch (b->type) {
case QRhiShaderResourceBinding::UniformBuffer:
{
writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
QRhiBuffer *buf = b.ubuf.buf;
QRhiBuffer *buf = b->u.ubuf.buf;
QVkBuffer *bufD = QRHI_RES(QVkBuffer, buf);
bd.ubuf.generation = bufD->generation;
VkDescriptorBufferInfo bufInfo;
bufInfo.buffer = bufD->m_type == QRhiBuffer::Dynamic ? bufD->buffers[frameSlot] : bufD->buffers[0];
bufInfo.offset = b.ubuf.offset;
bufInfo.range = b.ubuf.maybeSize ? b.ubuf.maybeSize : bufD->m_size;
bufInfo.offset = b->u.ubuf.offset;
bufInfo.range = b->u.ubuf.maybeSize ? b->u.ubuf.maybeSize : bufD->m_size;
// be nice and assert when we know the vulkan device would die a horrible death due to non-aligned reads
Q_ASSERT(aligned(bufInfo.offset, ubufAlign) == bufInfo.offset);
bufferInfos.append(bufInfo);
......@@ -2000,8 +2000,8 @@ void QRhiVulkan::updateShaderResourceBindings(QRhiShaderResourceBindings *srb, i
break;
case QRhiShaderResourceBinding::SampledTexture:
{
QVkTexture *texD = QRHI_RES(QVkTexture, b.stex.tex);
QVkSampler *samplerD = QRHI_RES(QVkSampler, b.stex.sampler);
QVkTexture *texD = QRHI_RES(QVkTexture, b->u.stex.tex);
QVkSampler *samplerD = QRHI_RES(QVkSampler, b->u.stex.sampler);
writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
bd.stex.texGeneration = texD->generation;
bd.stex.samplerGeneration = samplerD->generation;
......@@ -2949,10 +2949,11 @@ void QRhiVulkan::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline
QVkShaderResourceBindings *srbD = QRHI_RES(QVkShaderResourceBindings, srb);
bool hasSlottedResourceInSrb = false;
for (const QRhiShaderResourceBinding &b : qAsConst(srbD->m_bindings)) {
switch (b.type) {
for (const QRhiShaderResourceBinding &binding : qAsConst(srbD->m_bindings)) {
const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&binding);
switch (b->type) {
case QRhiShaderResourceBinding::UniformBuffer:
if (QRHI_RES(QVkBuffer, b.ubuf.buf)->m_type == QRhiBuffer::Dynamic)
if (QRHI_RES(QVkBuffer, b->u.ubuf.buf)->m_type == QRhiBuffer::Dynamic)
hasSlottedResourceInSrb = true;
break;
default:
......@@ -2966,12 +2967,12 @@ void QRhiVulkan::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline
// Do host writes and mark referenced shader resources as in-use.
// Also prepare to ensure the descriptor set we are going to bind refers to up-to-date Vk objects.
for (int i = 0, ie = srbD->m_bindings.count(); i != ie; ++i) {
const QRhiShaderResourceBinding &b(srbD->m_bindings[i]);
const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&srbD->m_bindings[i]);
QVkShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[descSetIdx][i]);
switch (b.type) {
switch (b->type) {
case QRhiShaderResourceBinding::UniformBuffer:
{
QVkBuffer *bufD = QRHI_RES(QVkBuffer, b.ubuf.buf);
QVkBuffer *bufD = QRHI_RES(QVkBuffer, b->u.ubuf.buf);
Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer));
bufD->lastActiveFrameSlot = currentFrameSlot;
......@@ -2986,8 +2987,8 @@ void QRhiVulkan::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline
break;
case QRhiShaderResourceBinding::SampledTexture:
{
QVkTexture *texD = QRHI_RES(QVkTexture, b.stex.tex);
QVkSampler *samplerD = QRHI_RES(QVkSampler, b.stex.sampler);
QVkTexture *texD = QRHI_RES(QVkTexture, b->u.stex.tex);
QVkSampler *samplerD = QRHI_RES(QVkSampler, b->u.stex.sampler);
texD->lastActiveFrameSlot = currentFrameSlot;
samplerD->lastActiveFrameSlot = currentFrameSlot;
......@@ -4270,14 +4271,15 @@ bool QVkShaderResourceBindings::build()
descSets[i] = VK_NULL_HANDLE;
QVarLengthArray<VkDescriptorSetLayoutBinding, 4> vkbindings;
for (const QRhiShaderResourceBinding &b : qAsConst(m_bindings)) {
VkDescriptorSetLayoutBinding binding;
memset(&binding, 0, sizeof(binding));
binding.binding = b.binding;
binding.descriptorType = toVkDescriptorType(b.type);
binding.descriptorCount = 1; // no array support yet
binding.stageFlags = toVkShaderStageFlags(b.stage);
vkbindings.append(binding);
for (const QRhiShaderResourceBinding &binding : qAsConst(m_bindings)) {
const QRhiShaderResourceBindingPrivate *b = QRhiShaderResourceBindingPrivate::get(&binding);
VkDescriptorSetLayoutBinding vkbinding;
memset(&vkbinding, 0, sizeof(vkbinding));
vkbinding.binding = b->binding;
vkbinding.descriptorType = toVkDescriptorType(b->type);
vkbinding.descriptorCount = 1; // no array support yet
vkbinding.stageFlags = toVkShaderStageFlags(b->stage);
vkbindings.append(vkbinding);
}
VkDescriptorSetLayoutCreateInfo layoutInfo;
......
......@@ -97,7 +97,8 @@ QT_BEGIN_NAMESPACE
included in it.
QBakedShader uses implicit sharing similarly to many core Qt types, and so
can be returned or passed by value.
can be returned or passed by value. Detach happens implicitly when calling
a setter.
For reference, QRhi expects that a QBakedShader suitable for all its
backends contains at least the following:
......
......@@ -72,6 +72,7 @@ struct Q_SHADERTOOLS_PRIVATE_EXPORT QBakedShaderPrivate
}
static QBakedShaderPrivate *get(QBakedShader *s) { return s->d; }
static const QBakedShaderPrivate *get(const QBakedShader *s) { return s->d; }
QAtomicInt ref;
QBakedShader::ShaderStage stage = QBakedShader::VertexStage;
......
......@@ -65,9 +65,6 @@ QT_BEGIN_NAMESPACE
automatically generated by QShaderBaker and is provided as a
QShaderDescription object for each and every QBakedShader.
Like QBakedShader, QShaderDescription is implicitly shared so its instances
can safely be returned or passed by value.
\section2 Example
Take the following vertex shader:
......