Remove QVector in the API of QRhiResource subclasses

Forcing users to go through a QVector, when in practice they almost
always want to source the data from an initializer list, a QVarLengthArray,
or a plain C array, is not ideal. Especially since we can reason about
the maximum number of elements in the vast majority of use cases for all
the affected lists. QRhiResource is also not copyable so we do not need
the usual machinery offered by containers. So switch to a
QVarLengthArray.

Note that a resource is not a container. The only operations we are
interested in is to be able to source data either via an initializer
list or by iterating on something, and to be able to extract the data,
in case a user wishes to set up another resource based on the existing
one.

In some cases a QVector overload is kept for source compatibility with
other modules (Qt Quick). These may be removed in the future.

Also do a similar QVector->QVarLengthArray change in the srb-related
data in the backends.

Change-Id: I6f5b2ebd8e75416ce0cca0817bb529446a4cb664
Reviewed-by: Christian Strømme <christian.stromme@qt.io>
This commit is contained in:
Laszlo Agocs 2019-09-28 15:19:09 +02:00
parent d4c17725ab
commit 7000b66f7e
12 changed files with 77 additions and 49 deletions

View File

@ -2534,16 +2534,8 @@ QRhiResource::Type QRhiTextureRenderTarget::resourceType() const
be used with the same pipeline, assuming the pipeline was built with one of
them in the first place.
Creating and then using a new \c srb2 that is very similar to \c srb with
the exception of referencing another texture could be implemented like the
following:
\badcode
srb2 = rhi->newShaderResourceBindings();
QVector<QRhiShaderResourceBinding> bindings = srb->bindings();
bindings[1] = QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, anotherTexture, sampler);
srb2->setBindings(bindings);
srb2->build();
...
cb->setGraphicsPipeline(ps);
cb->setShaderResources(srb2); // binds srb2
@ -3064,6 +3056,11 @@ QDebug operator<<(QDebug dbg, const QRhiShaderResourceBinding &b)
#endif
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug dbg, const QVarLengthArray<QRhiShaderResourceBinding, 8> &bindings)
{
return QtPrivate::printSequentialContainer(dbg, "Bindings", bindings);
}
QDebug operator<<(QDebug dbg, const QRhiShaderResourceBindings &srb)
{
QDebugStateSaver saver(dbg);

View File

@ -52,6 +52,7 @@
#include <QSize>
#include <QMatrix4x4>
#include <QVector>
#include <QVarLengthArray>
#include <QThread>
#include <QColor>
#include <QImage>
@ -926,8 +927,22 @@ class Q_GUI_EXPORT QRhiShaderResourceBindings : public QRhiResource
public:
QRhiResource::Type resourceType() const override;
QVector<QRhiShaderResourceBinding> bindings() const { return m_bindings; }
void setBindings(const QVector<QRhiShaderResourceBinding> &b) { m_bindings = b; }
void setBindings(std::initializer_list<QRhiShaderResourceBinding> list) { m_bindings = list; }
template<typename InputIterator>
void setBindings(InputIterator first, InputIterator last)
{
m_bindings.clear();
std::copy(first, last, std::back_inserter(m_bindings));
}
void setBindings(const QVector<QRhiShaderResourceBinding> &bindings) // compat., to be removed
{
setBindings(bindings.cbegin(), bindings.cend());
}
const QRhiShaderResourceBinding *cbeginBindings() const { return m_bindings.cbegin(); }
const QRhiShaderResourceBinding *cendBindings() const { return m_bindings.cend(); }
bool isLayoutCompatible(const QRhiShaderResourceBindings *other) const;
@ -935,7 +950,7 @@ public:
protected:
QRhiShaderResourceBindings(QRhiImplementation *rhi);
QVector<QRhiShaderResourceBinding> m_bindings;
QVarLengthArray<QRhiShaderResourceBinding, 8> m_bindings;
#ifndef QT_NO_DEBUG_STREAM
friend Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiShaderResourceBindings &);
#endif
@ -1066,8 +1081,15 @@ public:
FrontFace frontFace() const { return m_frontFace; }
void setFrontFace(FrontFace f) { m_frontFace = f; }
QVector<TargetBlend> targetBlends() const { return m_targetBlends; }
void setTargetBlends(const QVector<TargetBlend> &blends) { m_targetBlends = blends; }
void setTargetBlends(std::initializer_list<TargetBlend> list) { m_targetBlends = list; }
template<typename InputIterator>
void setTargetBlends(InputIterator first, InputIterator last)
{
m_targetBlends.clear();
std::copy(first, last, std::back_inserter(m_targetBlends));
}
const TargetBlend *cbeginTargetBlends() const { return m_targetBlends.cbegin(); }
const TargetBlend *cendTargetBlends() const { return m_targetBlends.cend(); }
bool hasDepthTest() const { return m_depthTest; }
void setDepthTest(bool enable) { m_depthTest = enable; }
@ -1099,8 +1121,19 @@ public:
float lineWidth() const { return m_lineWidth; }
void setLineWidth(float width) { m_lineWidth = width; }
QVector<QRhiShaderStage> shaderStages() const { return m_shaderStages; }
void setShaderStages(const QVector<QRhiShaderStage> &stages) { m_shaderStages = stages; }
void setShaderStages(std::initializer_list<QRhiShaderStage> list) { m_shaderStages = list; }
template<typename InputIterator>
void setShaderStages(InputIterator first, InputIterator last)
{
m_shaderStages.clear();
std::copy(first, last, std::back_inserter(m_shaderStages));
}
void setShaderStages(const QVector<QRhiShaderStage> &stages) // compat., to be removed
{
setShaderStages(stages.cbegin(), stages.cend());
}
const QRhiShaderStage *cbeginShaderStages() const { return m_shaderStages.cbegin(); }
const QRhiShaderStage *cendShaderStages() const { return m_shaderStages.cend(); }
QRhiVertexInputLayout vertexInputLayout() const { return m_vertexInputLayout; }
void setVertexInputLayout(const QRhiVertexInputLayout &layout) { m_vertexInputLayout = layout; }
@ -1119,7 +1152,7 @@ protected:
Topology m_topology = Triangles;
CullMode m_cullMode = None;
FrontFace m_frontFace = CCW;
QVector<TargetBlend> m_targetBlends;
QVarLengthArray<TargetBlend, 8> m_targetBlends;
bool m_depthTest = false;
bool m_depthWrite = false;
CompareOp m_depthOp = Less;
@ -1130,7 +1163,7 @@ protected:
quint32 m_stencilWriteMask = 0xFF;
int m_sampleCount = 1;
float m_lineWidth = 1.0f;
QVector<QRhiShaderStage> m_shaderStages;
QVarLengthArray<QRhiShaderStage, 4> m_shaderStages;
QRhiVertexInputLayout m_vertexInputLayout;
QRhiShaderResourceBindings *m_shaderResourceBindings = nullptr;
QRhiRenderPassDescriptor *m_renderPassDesc = nullptr;

View File

@ -3082,7 +3082,7 @@ bool QD3D11ShaderResourceBindings::build()
if (!sortedBindings.isEmpty())
release();
sortedBindings = m_bindings;
std::copy(m_bindings.cbegin(), m_bindings.cend(), std::back_inserter(sortedBindings));
std::sort(sortedBindings.begin(), sortedBindings.end(),
[](const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b)
{

View File

@ -199,7 +199,7 @@ struct QD3D11ShaderResourceBindings : public QRhiShaderResourceBindings
void release() override;
bool build() override;
QVector<QRhiShaderResourceBinding> sortedBindings;
QVarLengthArray<QRhiShaderResourceBinding, 8> sortedBindings;
uint generation = 0;
// Keep track of the generation number of each referenced QRhi* to be able
@ -230,7 +230,7 @@ struct QD3D11ShaderResourceBindings : public QRhiShaderResourceBindings
BoundStorageBufferData sbuf;
};
};
QVector<BoundResourceData> boundResourceData;
QVarLengthArray<BoundResourceData, 8> boundResourceData;
QRhiBatchedBindings<ID3D11Buffer *> vsubufs;
QRhiBatchedBindings<UINT> vsubufoffsets;

View File

@ -2768,7 +2768,7 @@ bool QMetalShaderResourceBindings::build()
if (!sortedBindings.isEmpty())
release();
sortedBindings = m_bindings;
std::copy(m_bindings.cbegin(), m_bindings.cend(), std::back_inserter(sortedBindings));
std::sort(sortedBindings.begin(), sortedBindings.end(),
[](const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b)
{
@ -2782,7 +2782,7 @@ bool QMetalShaderResourceBindings::build()
boundResourceData.resize(sortedBindings.count());
for (int i = 0, ie = sortedBindings.count(); i != ie; ++i) {
const QRhiShaderResourceBinding::Data *b = srbD->sortedBindings.at(i).data();
const QRhiShaderResourceBinding::Data *b = sortedBindings.at(i).data();
QMetalShaderResourceBindings::BoundResourceData &bd(boundResourceData[i]);
switch (b->type) {
case QRhiShaderResourceBinding::UniformBuffer:

View File

@ -188,7 +188,7 @@ struct QMetalShaderResourceBindings : public QRhiShaderResourceBindings
void release() override;
bool build() override;
QVector<QRhiShaderResourceBinding> sortedBindings;
QVarLengthArray<QRhiShaderResourceBinding, 8> sortedBindings;
int maxBinding = -1;
struct BoundUniformBufferData {
@ -217,7 +217,7 @@ struct QMetalShaderResourceBindings : public QRhiShaderResourceBindings
BoundStorageBufferData sbuf;
};
};
QVector<BoundResourceData> boundResourceData;
QVarLengthArray<BoundResourceData, 8> boundResourceData;
uint generation = 0;
friend class QRhiMetal;

View File

@ -5697,7 +5697,8 @@ bool QVkShaderResourceBindings::build()
for (int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
descSets[i] = VK_NULL_HANDLE;
sortedBindings = m_bindings;
sortedBindings.clear();
std::copy(m_bindings.cbegin(), m_bindings.cend(), std::back_inserter(sortedBindings));
std::sort(sortedBindings.begin(), sortedBindings.end(),
[](const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b)
{

View File

@ -232,7 +232,7 @@ struct QVkShaderResourceBindings : public QRhiShaderResourceBindings
void release() override;
bool build() override;
QVector<QRhiShaderResourceBinding> sortedBindings;
QVarLengthArray<QRhiShaderResourceBinding, 8> sortedBindings;
int poolIndex = -1;
VkDescriptorSetLayout layout = VK_NULL_HANDLE;
VkDescriptorSet descSets[QVK_FRAMES_IN_FLIGHT]; // multiple sets to support dynamic buffers
@ -268,7 +268,7 @@ struct QVkShaderResourceBindings : public QRhiShaderResourceBindings
BoundStorageBufferData sbuf;
};
};
QVector<BoundResourceData> boundResourceData[QVK_FRAMES_IN_FLIGHT];
QVarLengthArray<BoundResourceData, 8> boundResourceData[QVK_FRAMES_IN_FLIGHT];
friend class QRhiVulkan;
};

View File

@ -200,12 +200,10 @@ void Window::customInit()
{ QRhiShaderStage::Vertex, getShader(QLatin1String(":/mrt.vert.qsb")) },
{ QRhiShaderStage::Fragment, getShader(QLatin1String(":/mrt.frag.qsb")) }
});
QVector<QRhiGraphicsPipeline::TargetBlend> blends;
for (int i = 0; i < ATTCOUNT; ++i) {
QRhiGraphicsPipeline::TargetBlend blend;
blends.append(blend);
}
d.triPs->setTargetBlends(blends);
QRhiGraphicsPipeline::TargetBlend blends[ATTCOUNT]; // defaults to blending == false
d.triPs->setTargetBlends(blends, blends + ATTCOUNT);
inputLayout.setBindings({
{ 5 * sizeof(float) }
});

View File

@ -240,7 +240,7 @@ void Window::customInit()
#else
d.msaaTriPs->setSampleCount(1);
#endif
d.msaaTriPs->setShaderStages(d.triPs->shaderStages());
d.msaaTriPs->setShaderStages(d.triPs->cbeginShaderStages(), d.triPs->cendShaderStages());
d.msaaTriPs->setVertexInputLayout(d.triPs->vertexInputLayout());
d.msaaTriPs->setShaderResourceBindings(d.triSrb);
d.msaaTriPs->setRenderPassDescriptor(d.msaaRtRp);

View File

@ -68,6 +68,8 @@ struct {
QRhiTexture *newTex = nullptr;
QRhiTexture *importedTex = nullptr;
int testStage = 0;
QRhiShaderResourceBinding bindings[2];
} d;
void Window::customInit()
@ -100,10 +102,10 @@ void Window::customInit()
d.srb = m_r->newShaderResourceBindings();
d.releasePool << d.srb;
d.srb->setBindings({
QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d.ubuf),
QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.tex, d.sampler)
});
d.bindings[0] = QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d.ubuf);
d.bindings[1] = QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.tex, d.sampler);
d.srb->setBindings(d.bindings, d.bindings + 2);
d.srb->build();
d.ps = m_r->newGraphicsPipeline();
@ -211,9 +213,8 @@ void Window::customRender()
u->copyTexture(d.newTex, d.tex, desc);
// Now replace d.tex with d.newTex as the shader resource.
auto bindings = d.srb->bindings();
bindings[1] = QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.newTex, d.sampler);
d.srb->setBindings(bindings);
d.bindings[1] = QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.newTex, d.sampler);
d.srb->setBindings(d.bindings, d.bindings + 2);
// "rebuild", whatever that means for a given backend. This srb is
// already live as the ps in the setGraphicsPipeline references it,
// but that's fine. Changes will be picked up automatically.
@ -259,9 +260,8 @@ void Window::customRender()
// underneath (owned by d.tex)
// switch to showing d.importedTex
auto bindings = d.srb->bindings();
bindings[1] = QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.importedTex, d.sampler);
d.srb->setBindings(bindings);
d.bindings[1] = QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.importedTex, d.sampler);
d.srb->setBindings(d.bindings, d.bindings + 2);
d.srb->build();
} else {
qWarning("Accessing native texture object is not supported");
@ -270,9 +270,8 @@ void Window::customRender()
// Exercise uploading uncompressed data without a QImage.
if (d.testStage == 7) {
auto bindings = d.srb->bindings();
bindings[1] = QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.newTex, d.sampler);
d.srb->setBindings(bindings);
d.bindings[1] = QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.newTex, d.sampler);
d.srb->setBindings(d.bindings, d.bindings + 2);
d.srb->build();
const QSize sz(221, 139);

View File

@ -94,11 +94,11 @@ void TriangleRenderer::initResources(QRhiRenderPassDescriptor *rp)
QRhiGraphicsPipeline::TargetBlend premulAlphaBlend; // convenient defaults...
premulAlphaBlend.enable = true;
QVector<QRhiGraphicsPipeline::TargetBlend> rtblends;
QVarLengthArray<QRhiGraphicsPipeline::TargetBlend, 4> rtblends;
for (int i = 0; i < m_colorAttCount; ++i)
rtblends << premulAlphaBlend;
m_ps->setTargetBlends(rtblends);
m_ps->setTargetBlends(rtblends.cbegin(), rtblends.cend());
m_ps->setSampleCount(m_sampleCount);
if (m_depthWrite) { // TriangleOnCube may want to exercise this