rhi: Add compute api and implement for Vulkan and Metal
D3D11 and GL (4.3+, ES 3.1+) will come separately at a later time. Change-Id: If30f2f3d062fa27e57e9912674669225b82a7b93 Reviewed-by: Lars Knoll <lars.knoll@qt.io>
This commit is contained in:
parent
4c297bdca8
commit
6f4aa54131
@ -266,6 +266,18 @@ QT_BEGIN_NAMESPACE
|
|||||||
transitions. Such synchronization is done implicitly by the backends, where
|
transitions. Such synchronization is done implicitly by the backends, where
|
||||||
applicable (for example, Vulkan), by tracking resource usage as necessary.
|
applicable (for example, Vulkan), by tracking resource usage as necessary.
|
||||||
|
|
||||||
|
\note Resources within a render or compute pass are expected to be bound to
|
||||||
|
a single usage during that pass. For example, a buffer can be used as
|
||||||
|
vertex, index, uniform, or storage buffer, but not a combination of them
|
||||||
|
within a single pass. However, it is perfectly fine to use a buffer as a
|
||||||
|
storage buffer in a compute pass, and then as a vertex buffer in a render
|
||||||
|
pass, for example, assuming the buffer declared both usages upon creation.
|
||||||
|
|
||||||
|
\note Textures have this rule relaxed in certain cases, because using two
|
||||||
|
subresources (typically two different mip levels) of the same texture for
|
||||||
|
different access (one for load, one for store) is supported even within the
|
||||||
|
same pass.
|
||||||
|
|
||||||
\section3 Resource reuse
|
\section3 Resource reuse
|
||||||
|
|
||||||
From the user's point of view a QRhiResource is reusable immediately after
|
From the user's point of view a QRhiResource is reusable immediately after
|
||||||
@ -481,6 +493,8 @@ QT_BEGIN_NAMESPACE
|
|||||||
when running on plain OpenGL ES 2.0 implementations without the necessary
|
when running on plain OpenGL ES 2.0 implementations without the necessary
|
||||||
extension. When false, only 16-bit unsigned elements are supported in the
|
extension. When false, only 16-bit unsigned elements are supported in the
|
||||||
index buffer.
|
index buffer.
|
||||||
|
|
||||||
|
\value Compute Indicates that compute shaders are supported.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -1131,21 +1145,22 @@ QDebug operator<<(QDebug dbg, const QRhiVertexInputLayout &v)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\class QRhiGraphicsShaderStage
|
\class QRhiShaderStage
|
||||||
\inmodule QtRhi
|
\inmodule QtRhi
|
||||||
\brief Specifies the type and the shader code for a shader stage in the graphics pipeline.
|
\brief Specifies the type and the shader code for a shader stage in the pipeline.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\enum QRhiGraphicsShaderStage::Type
|
\enum QRhiShaderStage::Type
|
||||||
Specifies the type of the shader stage.
|
Specifies the type of the shader stage.
|
||||||
|
|
||||||
\value Vertex Vertex stage
|
\value Vertex Vertex stage
|
||||||
\value Fragment Fragment (pixel) stage
|
\value Fragment Fragment (pixel) stage
|
||||||
|
\value Compute Compute stage (this may not always be supported at run time)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\fn QRhiGraphicsShaderStage::QRhiGraphicsShaderStage()
|
\fn QRhiShaderStage::QRhiShaderStage()
|
||||||
|
|
||||||
Constructs a shader stage description for the vertex stage with an empty
|
Constructs a shader stage description for the vertex stage with an empty
|
||||||
QShader.
|
QShader.
|
||||||
@ -1160,7 +1175,7 @@ QDebug operator<<(QDebug dbg, const QRhiVertexInputLayout &v)
|
|||||||
In addition, it can also contain variants of the shader with slightly
|
In addition, it can also contain variants of the shader with slightly
|
||||||
modified code. \a v can then be used to select the desired variant.
|
modified code. \a v can then be used to select the desired variant.
|
||||||
*/
|
*/
|
||||||
QRhiGraphicsShaderStage::QRhiGraphicsShaderStage(Type type, const QShader &shader, QShader::Variant v)
|
QRhiShaderStage::QRhiShaderStage(Type type, const QShader &shader, QShader::Variant v)
|
||||||
: m_type(type),
|
: m_type(type),
|
||||||
m_shader(shader),
|
m_shader(shader),
|
||||||
m_shaderVariant(v)
|
m_shaderVariant(v)
|
||||||
@ -1168,12 +1183,12 @@ QRhiGraphicsShaderStage::QRhiGraphicsShaderStage(Type type, const QShader &shade
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\return \c true if the values in the two QRhiGraphicsShaderStage objects
|
\return \c true if the values in the two QRhiShaderStage objects
|
||||||
\a a and \a b are equal.
|
\a a and \a b are equal.
|
||||||
|
|
||||||
\relates QRhiGraphicsShaderStage
|
\relates QRhiShaderStage
|
||||||
*/
|
*/
|
||||||
bool operator==(const QRhiGraphicsShaderStage &a, const QRhiGraphicsShaderStage &b) Q_DECL_NOTHROW
|
bool operator==(const QRhiShaderStage &a, const QRhiShaderStage &b) Q_DECL_NOTHROW
|
||||||
{
|
{
|
||||||
return a.type() == b.type()
|
return a.type() == b.type()
|
||||||
&& a.shader() == b.shader()
|
&& a.shader() == b.shader()
|
||||||
@ -1181,12 +1196,12 @@ bool operator==(const QRhiGraphicsShaderStage &a, const QRhiGraphicsShaderStage
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\return \c false if the values in the two QRhiGraphicsShaderStage
|
\return \c false if the values in the two QRhiShaderStage
|
||||||
objects \a a and \a b are equal; otherwise returns \c true.
|
objects \a a and \a b are equal; otherwise returns \c true.
|
||||||
|
|
||||||
\relates QRhiGraphicsShaderStage
|
\relates QRhiShaderStage
|
||||||
*/
|
*/
|
||||||
bool operator!=(const QRhiGraphicsShaderStage &a, const QRhiGraphicsShaderStage &b) Q_DECL_NOTHROW
|
bool operator!=(const QRhiShaderStage &a, const QRhiShaderStage &b) Q_DECL_NOTHROW
|
||||||
{
|
{
|
||||||
return !(a == b);
|
return !(a == b);
|
||||||
}
|
}
|
||||||
@ -1194,18 +1209,18 @@ bool operator!=(const QRhiGraphicsShaderStage &a, const QRhiGraphicsShaderStage
|
|||||||
/*!
|
/*!
|
||||||
\return the hash value for \a v, using \a seed to seed the calculation.
|
\return the hash value for \a v, using \a seed to seed the calculation.
|
||||||
|
|
||||||
\relates QRhiGraphicsShaderStage
|
\relates QRhiShaderStage
|
||||||
*/
|
*/
|
||||||
uint qHash(const QRhiGraphicsShaderStage &v, uint seed) Q_DECL_NOTHROW
|
uint qHash(const QRhiShaderStage &v, uint seed) Q_DECL_NOTHROW
|
||||||
{
|
{
|
||||||
return v.type() + qHash(v.shader(), seed) + v.shaderVariant();
|
return v.type() + qHash(v.shader(), seed) + v.shaderVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef QT_NO_DEBUG_STREAM
|
#ifndef QT_NO_DEBUG_STREAM
|
||||||
QDebug operator<<(QDebug dbg, const QRhiGraphicsShaderStage &s)
|
QDebug operator<<(QDebug dbg, const QRhiShaderStage &s)
|
||||||
{
|
{
|
||||||
QDebugStateSaver saver(dbg);
|
QDebugStateSaver saver(dbg);
|
||||||
dbg.nospace() << "QRhiGraphicsShaderStage(type=" << s.type()
|
dbg.nospace() << "QRhiShaderStage(type=" << s.type()
|
||||||
<< " shader=" << s.shader()
|
<< " shader=" << s.shader()
|
||||||
<< " variant=" << s.shaderVariant()
|
<< " variant=" << s.shaderVariant()
|
||||||
<< ')';
|
<< ')';
|
||||||
@ -1781,9 +1796,25 @@ quint64 QRhiResource::globalResourceId() const
|
|||||||
\enum QRhiBuffer::UsageFlag
|
\enum QRhiBuffer::UsageFlag
|
||||||
Flag values to specify how the buffer is going to be used.
|
Flag values to specify how the buffer is going to be used.
|
||||||
|
|
||||||
\value VertexBuffer Vertex buffer
|
\value VertexBuffer Vertex buffer. This allows the QRhiBuffer to be used in
|
||||||
\value IndexBuffer Index buffer
|
\l{setVertexInput()}{QRhiCommandBuffer::setVertexInput()}.
|
||||||
\value UniformBuffer Uniform (constant) buffer
|
|
||||||
|
\value IndexBuffer Index buffer. This allows the QRhiBuffer to be used in
|
||||||
|
\l{setVertexInput()}{QRhiCommandBuffer::setVertexInput()}.
|
||||||
|
|
||||||
|
\value UniformBuffer Uniform buffer (also called constant buffer). This
|
||||||
|
allows the QRhiBuffer to be used in combination with
|
||||||
|
\l{UniformBuffer}{QRhiShaderResourceBinding::UniformBuffer}. When
|
||||||
|
\l{QRhi::NonDynamicUniformBuffers}{NonDynamicUniformBuffers} is reported as
|
||||||
|
not supported, this usage can only be combined with the type Dynamic.
|
||||||
|
|
||||||
|
\value StorageBuffer Storage buffer. This allows the QRhiBuffer to be used
|
||||||
|
in combination with \l{BufferLoad}{QRhiShaderResourceBinding::BufferLoad},
|
||||||
|
\l{BufferStore}{QRhiShaderResourceBinding::BufferStore}, or
|
||||||
|
\l{BufferLoadStore}{QRhiShaderResourceBinding::BufferLoadStore}. This usage
|
||||||
|
can only be combined with the types Immutable or Static, and is only
|
||||||
|
available when the \l{QRhi::Compute}{Compute feature} is reported as
|
||||||
|
supported.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -1941,6 +1972,9 @@ QRhiResource::Type QRhiRenderBuffer::resourceType() const
|
|||||||
|
|
||||||
\value UsedWithGenerateMips The texture is going to be used with
|
\value UsedWithGenerateMips The texture is going to be used with
|
||||||
QRhiResourceUpdateBatch::generateMips().
|
QRhiResourceUpdateBatch::generateMips().
|
||||||
|
|
||||||
|
\value UsedWithLoadStore The texture is going to be used with image
|
||||||
|
load/store operations, for example, in a compute shader.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -2438,7 +2472,26 @@ bool QRhiShaderResourceBindings::isLayoutCompatible(const QRhiShaderResourceBind
|
|||||||
Specifies type of the shader resource bound to a binding point
|
Specifies type of the shader resource bound to a binding point
|
||||||
|
|
||||||
\value UniformBuffer Uniform buffer
|
\value UniformBuffer Uniform buffer
|
||||||
|
|
||||||
\value SampledTexture Combined image sampler
|
\value SampledTexture Combined image sampler
|
||||||
|
|
||||||
|
\value ImageLoad Image load (with GLSL this maps to doing imageLoad() on a
|
||||||
|
single level - and either one or all layers - of a texture exposed to the
|
||||||
|
shader as an image object)
|
||||||
|
|
||||||
|
\value ImageStore Image store (with GLSL this maps to doing imageStore() or
|
||||||
|
imageAtomic*() on a single level - and either one or all layers - of a
|
||||||
|
texture exposed to the shader as an image object)
|
||||||
|
|
||||||
|
\value ImageLoadStore Image load and store
|
||||||
|
|
||||||
|
\value BufferLoad Storage buffer store (with GLSL this maps to reading from
|
||||||
|
a shader storage buffer)
|
||||||
|
|
||||||
|
\value BufferStore Storage buffer store (with GLSL this maps to writing to
|
||||||
|
a shader storage buffer)
|
||||||
|
|
||||||
|
\value BufferLoadStore Storage buffer load and store
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -2447,6 +2500,7 @@ bool QRhiShaderResourceBindings::isLayoutCompatible(const QRhiShaderResourceBind
|
|||||||
|
|
||||||
\value VertexStage Vertex stage
|
\value VertexStage Vertex stage
|
||||||
\value FragmentStage Fragment (pixel) stage
|
\value FragmentStage Fragment (pixel) stage
|
||||||
|
\value ComputeStage Compute stage
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -2513,6 +2567,8 @@ bool QRhiShaderResourceBinding::isLayoutCompatible(const QRhiShaderResourceBindi
|
|||||||
/*!
|
/*!
|
||||||
\return a shader resource binding for the given binding number, pipeline
|
\return a shader resource binding for the given binding number, pipeline
|
||||||
stages, and buffer specified by \a binding, \a stage, and \a buf.
|
stages, and buffer specified by \a binding, \a stage, and \a buf.
|
||||||
|
|
||||||
|
\note \a buf must have been created with QRhiBuffer::UniformBuffer.
|
||||||
*/
|
*/
|
||||||
QRhiShaderResourceBinding QRhiShaderResourceBinding::uniformBuffer(
|
QRhiShaderResourceBinding QRhiShaderResourceBinding::uniformBuffer(
|
||||||
int binding, StageFlags stage, QRhiBuffer *buf)
|
int binding, StageFlags stage, QRhiBuffer *buf)
|
||||||
@ -2539,21 +2595,17 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::uniformBuffer(
|
|||||||
QRhi::ubufAlignment().
|
QRhi::ubufAlignment().
|
||||||
|
|
||||||
\note \a size must be greater than 0.
|
\note \a size must be greater than 0.
|
||||||
|
|
||||||
|
\note \a buf must have been created with QRhiBuffer::UniformBuffer.
|
||||||
*/
|
*/
|
||||||
QRhiShaderResourceBinding QRhiShaderResourceBinding::uniformBuffer(
|
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;
|
QRhiShaderResourceBinding b = uniformBuffer(binding, stage, buf);
|
||||||
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
|
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.offset = offset;
|
||||||
d->u.ubuf.maybeSize = size;
|
d->u.ubuf.maybeSize = size;
|
||||||
d->u.ubuf.hasDynamicOffset = false;
|
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2565,19 +2617,14 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::uniformBuffer(
|
|||||||
varying offset values without creating new bindings for the buffer. The
|
varying offset values without creating new bindings for the buffer. The
|
||||||
size of the bound region is specified by \a size. Like with non-dynamic
|
size of the bound region is specified by \a size. Like with non-dynamic
|
||||||
offsets, \c{offset + size} cannot exceed the size of \a buf.
|
offsets, \c{offset + size} cannot exceed the size of \a buf.
|
||||||
|
|
||||||
|
\note \a buf must have been created with QRhiBuffer::UniformBuffer.
|
||||||
*/
|
*/
|
||||||
QRhiShaderResourceBinding QRhiShaderResourceBinding::uniformBufferWithDynamicOffset(
|
QRhiShaderResourceBinding QRhiShaderResourceBinding::uniformBufferWithDynamicOffset(
|
||||||
int binding, StageFlags stage, QRhiBuffer *buf, int size)
|
int binding, StageFlags stage, QRhiBuffer *buf, int size)
|
||||||
{
|
{
|
||||||
QRhiShaderResourceBinding b;
|
QRhiShaderResourceBinding b = uniformBuffer(binding, stage, buf, 0, size);
|
||||||
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
|
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 = size;
|
|
||||||
d->u.ubuf.hasDynamicOffset = true;
|
d->u.ubuf.hasDynamicOffset = true;
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
@ -2601,6 +2648,167 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::sampledTexture(
|
|||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return a shader resource binding for a read-only storage image with the
|
||||||
|
given \a binding number and pipeline \a stage. The image load operations
|
||||||
|
will have access to all layers of the specified \a level. (so if the texture
|
||||||
|
is a cubemap, the shader must use imageCube instead of image2D)
|
||||||
|
|
||||||
|
\note \a tex must have been created with QRhiTexture::UsedWithLoadStore.
|
||||||
|
*/
|
||||||
|
QRhiShaderResourceBinding QRhiShaderResourceBinding::imageLoad(
|
||||||
|
int binding, StageFlags stage, QRhiTexture *tex, int level)
|
||||||
|
{
|
||||||
|
QRhiShaderResourceBinding b;
|
||||||
|
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
|
||||||
|
Q_ASSERT(d->ref.load() == 1);
|
||||||
|
d->binding = binding;
|
||||||
|
d->stage = stage;
|
||||||
|
d->type = ImageLoad;
|
||||||
|
d->u.simage.tex = tex;
|
||||||
|
d->u.simage.level = level;
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return a shader resource binding for a write-only storage image with the
|
||||||
|
given \a binding number and pipeline \a stage. The image store operations
|
||||||
|
will have access to all layers of the specified \a level. (so if the texture
|
||||||
|
is a cubemap, the shader must use imageCube instead of image2D)
|
||||||
|
|
||||||
|
\note \a tex must have been created with QRhiTexture::UsedWithLoadStore.
|
||||||
|
*/
|
||||||
|
QRhiShaderResourceBinding QRhiShaderResourceBinding::imageStore(
|
||||||
|
int binding, StageFlags stage, QRhiTexture *tex, int level)
|
||||||
|
{
|
||||||
|
QRhiShaderResourceBinding b = imageLoad(binding, stage, tex, level);
|
||||||
|
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
|
||||||
|
d->type = ImageStore;
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return a shader resource binding for a read/write storage image with the
|
||||||
|
given \a binding number and pipeline \a stage. The image load/store operations
|
||||||
|
will have access to all layers of the specified \a level. (so if the texture
|
||||||
|
is a cubemap, the shader must use imageCube instead of image2D)
|
||||||
|
|
||||||
|
\note \a tex must have been created with QRhiTexture::UsedWithLoadStore.
|
||||||
|
*/
|
||||||
|
QRhiShaderResourceBinding QRhiShaderResourceBinding::imageLoadStore(
|
||||||
|
int binding, StageFlags stage, QRhiTexture *tex, int level)
|
||||||
|
{
|
||||||
|
QRhiShaderResourceBinding b = imageLoad(binding, stage, tex, level);
|
||||||
|
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
|
||||||
|
d->type = ImageLoadStore;
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return a shader resource binding for a read-only storage buffer with the
|
||||||
|
given \a binding number and pipeline \a stage.
|
||||||
|
|
||||||
|
\note \a buf must have been created with QRhiBuffer::StorageBuffer.
|
||||||
|
*/
|
||||||
|
QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoad(
|
||||||
|
int binding, StageFlags stage, QRhiBuffer *buf)
|
||||||
|
{
|
||||||
|
QRhiShaderResourceBinding b;
|
||||||
|
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
|
||||||
|
Q_ASSERT(d->ref.load() == 1);
|
||||||
|
d->binding = binding;
|
||||||
|
d->stage = stage;
|
||||||
|
d->type = BufferLoad;
|
||||||
|
d->u.sbuf.buf = buf;
|
||||||
|
d->u.sbuf.offset = 0;
|
||||||
|
d->u.sbuf.maybeSize = 0; // entire buffer
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return a shader resource binding for a read-only storage buffer with the
|
||||||
|
given \a binding number and pipeline \a stage. This overload binds a region
|
||||||
|
only, as specified by \a offset and \a size.
|
||||||
|
|
||||||
|
\note \a buf must have been created with QRhiBuffer::StorageBuffer.
|
||||||
|
*/
|
||||||
|
QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoad(
|
||||||
|
int binding, StageFlags stage, QRhiBuffer *buf, int offset, int size)
|
||||||
|
{
|
||||||
|
Q_ASSERT(size > 0);
|
||||||
|
QRhiShaderResourceBinding b = bufferLoad(binding, stage, buf);
|
||||||
|
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
|
||||||
|
d->u.sbuf.offset = offset;
|
||||||
|
d->u.sbuf.maybeSize = size;
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return a shader resource binding for a write-only storage buffer with the
|
||||||
|
given \a binding number and pipeline \a stage.
|
||||||
|
|
||||||
|
\note \a buf must have been created with QRhiBuffer::StorageBuffer.
|
||||||
|
*/
|
||||||
|
QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferStore(
|
||||||
|
int binding, StageFlags stage, QRhiBuffer *buf)
|
||||||
|
{
|
||||||
|
QRhiShaderResourceBinding b = bufferLoad(binding, stage, buf);
|
||||||
|
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
|
||||||
|
d->type = BufferStore;
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return a shader resource binding for a write-only storage buffer with the
|
||||||
|
given \a binding number and pipeline \a stage. This overload binds a region
|
||||||
|
only, as specified by \a offset and \a size.
|
||||||
|
|
||||||
|
\note \a buf must have been created with QRhiBuffer::StorageBuffer.
|
||||||
|
*/
|
||||||
|
QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferStore(
|
||||||
|
int binding, StageFlags stage, QRhiBuffer *buf, int offset, int size)
|
||||||
|
{
|
||||||
|
Q_ASSERT(size > 0);
|
||||||
|
QRhiShaderResourceBinding b = bufferStore(binding, stage, buf);
|
||||||
|
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
|
||||||
|
d->u.sbuf.offset = offset;
|
||||||
|
d->u.sbuf.maybeSize = size;
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return a shader resource binding for a read-write storage buffer with the
|
||||||
|
given \a binding number and pipeline \a stage.
|
||||||
|
|
||||||
|
\note \a buf must have been created with QRhiBuffer::StorageBuffer.
|
||||||
|
*/
|
||||||
|
QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoadStore(
|
||||||
|
int binding, StageFlags stage, QRhiBuffer *buf)
|
||||||
|
{
|
||||||
|
QRhiShaderResourceBinding b = bufferLoad(binding, stage, buf);
|
||||||
|
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
|
||||||
|
d->type = BufferLoadStore;
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return a shader resource binding for a read-write storage buffer with the
|
||||||
|
given \a binding number and pipeline \a stage. This overload binds a region
|
||||||
|
only, as specified by \a offset and \a size.
|
||||||
|
|
||||||
|
\note \a buf must have been created with QRhiBuffer::StorageBuffer.
|
||||||
|
*/
|
||||||
|
QRhiShaderResourceBinding QRhiShaderResourceBinding::bufferLoadStore(
|
||||||
|
int binding, StageFlags stage, QRhiBuffer *buf, int offset, int size)
|
||||||
|
{
|
||||||
|
Q_ASSERT(size > 0);
|
||||||
|
QRhiShaderResourceBinding b = bufferLoadStore(binding, stage, buf);
|
||||||
|
QRhiShaderResourceBindingPrivate *d = QRhiShaderResourceBindingPrivate::get(&b);
|
||||||
|
d->u.sbuf.offset = offset;
|
||||||
|
d->u.sbuf.maybeSize = size;
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\return \c true if the contents of the two QRhiShaderResourceBinding
|
\return \c true if the contents of the two QRhiShaderResourceBinding
|
||||||
objects \a a and \a b are equal. This includes the resources (buffer,
|
objects \a a and \a b are equal. This includes the resources (buffer,
|
||||||
@ -2639,6 +2847,29 @@ bool operator==(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBind
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case QRhiShaderResourceBinding::ImageLoad:
|
||||||
|
Q_FALLTHROUGH();
|
||||||
|
case QRhiShaderResourceBinding::ImageStore:
|
||||||
|
Q_FALLTHROUGH();
|
||||||
|
case QRhiShaderResourceBinding::ImageLoadStore:
|
||||||
|
if (a.d->u.simage.tex != b.d->u.simage.tex
|
||||||
|
|| a.d->u.simage.level != b.d->u.simage.level)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case QRhiShaderResourceBinding::BufferLoad:
|
||||||
|
Q_FALLTHROUGH();
|
||||||
|
case QRhiShaderResourceBinding::BufferStore:
|
||||||
|
Q_FALLTHROUGH();
|
||||||
|
case QRhiShaderResourceBinding::BufferLoadStore:
|
||||||
|
if (a.d->u.sbuf.buf != b.d->u.sbuf.buf
|
||||||
|
|| a.d->u.sbuf.offset != b.d->u.sbuf.offset
|
||||||
|
|| a.d->u.sbuf.maybeSize != b.d->u.sbuf.maybeSize)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
Q_UNREACHABLE();
|
Q_UNREACHABLE();
|
||||||
return false;
|
return false;
|
||||||
@ -2693,6 +2924,45 @@ QDebug operator<<(QDebug dbg, const QRhiShaderResourceBinding &b)
|
|||||||
<< " sampler=" << d->u.stex.sampler
|
<< " sampler=" << d->u.stex.sampler
|
||||||
<< ')';
|
<< ')';
|
||||||
break;
|
break;
|
||||||
|
case QRhiShaderResourceBinding::ImageLoad:
|
||||||
|
dbg.nospace() << " ImageLoad("
|
||||||
|
<< "texture=" << d->u.simage.tex
|
||||||
|
<< " level=" << d->u.simage.level
|
||||||
|
<< ')';
|
||||||
|
break;
|
||||||
|
case QRhiShaderResourceBinding::ImageStore:
|
||||||
|
dbg.nospace() << " ImageStore("
|
||||||
|
<< "texture=" << d->u.simage.tex
|
||||||
|
<< " level=" << d->u.simage.level
|
||||||
|
<< ')';
|
||||||
|
break;
|
||||||
|
case QRhiShaderResourceBinding::ImageLoadStore:
|
||||||
|
dbg.nospace() << " ImageLoadStore("
|
||||||
|
<< "texture=" << d->u.simage.tex
|
||||||
|
<< " level=" << d->u.simage.level
|
||||||
|
<< ')';
|
||||||
|
break;
|
||||||
|
case QRhiShaderResourceBinding::BufferLoad:
|
||||||
|
dbg.nospace() << " BufferLoad("
|
||||||
|
<< "buffer=" << d->u.sbuf.buf
|
||||||
|
<< " offset=" << d->u.sbuf.offset
|
||||||
|
<< " maybeSize=" << d->u.sbuf.maybeSize
|
||||||
|
<< ')';
|
||||||
|
break;
|
||||||
|
case QRhiShaderResourceBinding::BufferStore:
|
||||||
|
dbg.nospace() << " BufferStore("
|
||||||
|
<< "buffer=" << d->u.sbuf.buf
|
||||||
|
<< " offset=" << d->u.sbuf.offset
|
||||||
|
<< " maybeSize=" << d->u.sbuf.maybeSize
|
||||||
|
<< ')';
|
||||||
|
break;
|
||||||
|
case QRhiShaderResourceBinding::BufferLoadStore:
|
||||||
|
dbg.nospace() << " BufferLoadStore("
|
||||||
|
<< "buffer=" << d->u.sbuf.buf
|
||||||
|
<< " offset=" << d->u.sbuf.offset
|
||||||
|
<< " maybeSize=" << d->u.sbuf.maybeSize
|
||||||
|
<< ')';
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
Q_UNREACHABLE();
|
Q_UNREACHABLE();
|
||||||
break;
|
break;
|
||||||
@ -3195,6 +3465,34 @@ QRhiResource::Type QRhiSwapChain::resourceType() const
|
|||||||
Regardless of the return value, calling release() is always safe.
|
Regardless of the return value, calling release() is always safe.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\class QRhiComputePipeline
|
||||||
|
\inmodule QtRhi
|
||||||
|
\brief Compute pipeline state resource.
|
||||||
|
|
||||||
|
\note Setting the shader resource bindings is mandatory. The referenced
|
||||||
|
QRhiShaderResourceBindings must already be built by the time build() is
|
||||||
|
called.
|
||||||
|
|
||||||
|
\note Setting the shader is mandatory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return the resource type.
|
||||||
|
*/
|
||||||
|
QRhiResource::Type QRhiComputePipeline::resourceType() const
|
||||||
|
{
|
||||||
|
return ComputePipeline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\internal
|
||||||
|
*/
|
||||||
|
QRhiComputePipeline::QRhiComputePipeline(QRhiImplementation *rhi)
|
||||||
|
: QRhiResource(rhi)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\class QRhiCommandBuffer
|
\class QRhiCommandBuffer
|
||||||
\inmodule QtRhi
|
\inmodule QtRhi
|
||||||
@ -3982,8 +4280,8 @@ void QRhiCommandBuffer::endPass(QRhiResourceUpdateBatch *resourceUpdates)
|
|||||||
therefore overoptimizing to avoid calls to this function is not necessary
|
therefore overoptimizing to avoid calls to this function is not necessary
|
||||||
on the applications' side.
|
on the applications' side.
|
||||||
|
|
||||||
\note This function can only be called inside a pass, meaning between a
|
\note This function can only be called inside a render pass, meaning
|
||||||
beginPass() end endPass() call.
|
between a beginPass() and endPass() call.
|
||||||
*/
|
*/
|
||||||
void QRhiCommandBuffer::setGraphicsPipeline(QRhiGraphicsPipeline *ps)
|
void QRhiCommandBuffer::setGraphicsPipeline(QRhiGraphicsPipeline *ps)
|
||||||
{
|
{
|
||||||
@ -3994,14 +4292,13 @@ void QRhiCommandBuffer::setGraphicsPipeline(QRhiGraphicsPipeline *ps)
|
|||||||
Records binding a set of shader resources, such as, uniform buffers or
|
Records binding a set of shader resources, such as, uniform buffers or
|
||||||
textures, that are made visible to one or more shader stages.
|
textures, that are made visible to one or more shader stages.
|
||||||
|
|
||||||
\a srb can be null in which case the current graphics pipeline's associated
|
\a srb can be null in which case the current graphics or compute pipeline's
|
||||||
QRhiGraphicsPipeline::shaderResourceBindings() is used. When \a srb is
|
associated QRhiShaderResourceBindings is used. When \a srb is non-null, it
|
||||||
non-null, it must be
|
must be
|
||||||
\l{QRhiShaderResourceBindings::isLayoutCompatible()}{layout-compatible},
|
\l{QRhiShaderResourceBindings::isLayoutCompatible()}{layout-compatible},
|
||||||
meaning the layout (number of bindings, the type and binding number of each
|
meaning the layout (number of bindings, the type and binding number of each
|
||||||
binding) must fully match the QRhiShaderResourceBindings that was
|
binding) must fully match the QRhiShaderResourceBindings that was
|
||||||
associated with the pipeline at the time of calling
|
associated with the pipeline at the time of calling the pipeline's build().
|
||||||
QRhiGraphicsPipeline::build().
|
|
||||||
|
|
||||||
There are cases when a seemingly unnecessary setShaderResources() call is
|
There are cases when a seemingly unnecessary setShaderResources() call is
|
||||||
mandatory: when rebuilding a resource referenced from \a srb, for example
|
mandatory: when rebuilding a resource referenced from \a srb, for example
|
||||||
@ -4029,8 +4326,9 @@ void QRhiCommandBuffer::setGraphicsPipeline(QRhiGraphicsPipeline *ps)
|
|||||||
the conditions described above into account), so therefore overoptimizing
|
the conditions described above into account), so therefore overoptimizing
|
||||||
to avoid calls to this function is not necessary on the applications' side.
|
to avoid calls to this function is not necessary on the applications' side.
|
||||||
|
|
||||||
\note This function can only be called inside a pass, meaning between a
|
\note This function can only be called inside a render or compute pass,
|
||||||
beginPass() end endPass() call.
|
meaning between a beginPass() and endPass(), or beginComputePass() and
|
||||||
|
endComputePass().
|
||||||
*/
|
*/
|
||||||
void QRhiCommandBuffer::setShaderResources(QRhiShaderResourceBindings *srb,
|
void QRhiCommandBuffer::setShaderResources(QRhiShaderResourceBindings *srb,
|
||||||
int dynamicOffsetCount,
|
int dynamicOffsetCount,
|
||||||
@ -4056,8 +4354,8 @@ void QRhiCommandBuffer::setShaderResources(QRhiShaderResourceBindings *srb,
|
|||||||
automatically with most backends and therefore applications do not need to
|
automatically with most backends and therefore applications do not need to
|
||||||
overoptimize to avoid calls to this function.
|
overoptimize to avoid calls to this function.
|
||||||
|
|
||||||
\note This function can only be called inside a pass, meaning between a
|
\note This function can only be called inside a render pass, meaning
|
||||||
beginPass() end endPass() call.
|
between a beginPass() and endPass() call.
|
||||||
|
|
||||||
As a simple example, take a vertex shader with two inputs:
|
As a simple example, take a vertex shader with two inputs:
|
||||||
|
|
||||||
@ -4110,8 +4408,8 @@ void QRhiCommandBuffer::setVertexInput(int startBinding, int bindingCount, const
|
|||||||
\note QRhi assumes OpenGL-style viewport coordinates, meaning x and y are
|
\note QRhi assumes OpenGL-style viewport coordinates, meaning x and y are
|
||||||
bottom-left.
|
bottom-left.
|
||||||
|
|
||||||
\note This function can only be called inside a pass, meaning between a
|
\note This function can only be called inside a render pass, meaning
|
||||||
beginPass() end endPass() call.
|
between a beginPass() and endPass() call.
|
||||||
*/
|
*/
|
||||||
void QRhiCommandBuffer::setViewport(const QRhiViewport &viewport)
|
void QRhiCommandBuffer::setViewport(const QRhiViewport &viewport)
|
||||||
{
|
{
|
||||||
@ -4129,8 +4427,8 @@ void QRhiCommandBuffer::setViewport(const QRhiViewport &viewport)
|
|||||||
\note QRhi assumes OpenGL-style viewport coordinates, meaning x and y are
|
\note QRhi assumes OpenGL-style viewport coordinates, meaning x and y are
|
||||||
bottom-left.
|
bottom-left.
|
||||||
|
|
||||||
\note This function can only be called inside a pass, meaning between a
|
\note This function can only be called inside a render pass, meaning
|
||||||
beginPass() end endPass() call.
|
between a beginPass() and endPass() call.
|
||||||
*/
|
*/
|
||||||
void QRhiCommandBuffer::setScissor(const QRhiScissor &scissor)
|
void QRhiCommandBuffer::setScissor(const QRhiScissor &scissor)
|
||||||
{
|
{
|
||||||
@ -4143,8 +4441,8 @@ void QRhiCommandBuffer::setScissor(const QRhiScissor &scissor)
|
|||||||
This can only be called when the bound pipeline has
|
This can only be called when the bound pipeline has
|
||||||
QRhiGraphicsPipeline::UsesBlendConstants set.
|
QRhiGraphicsPipeline::UsesBlendConstants set.
|
||||||
|
|
||||||
\note This function can only be called inside a pass, meaning between a
|
\note This function can only be called inside a render pass, meaning
|
||||||
beginPass() end endPass() call.
|
between a beginPass() and endPass() call.
|
||||||
*/
|
*/
|
||||||
void QRhiCommandBuffer::setBlendConstants(const QColor &c)
|
void QRhiCommandBuffer::setBlendConstants(const QColor &c)
|
||||||
{
|
{
|
||||||
@ -4157,8 +4455,8 @@ void QRhiCommandBuffer::setBlendConstants(const QColor &c)
|
|||||||
This can only be called when the bound pipeline has
|
This can only be called when the bound pipeline has
|
||||||
QRhiGraphicsPipeline::UsesStencilRef set.
|
QRhiGraphicsPipeline::UsesStencilRef set.
|
||||||
|
|
||||||
\note This function can only be called inside a pass, meaning between a
|
\note This function can only be called inside a render pass, meaning between
|
||||||
beginPass() end endPass() call.
|
a beginPass() and endPass() call.
|
||||||
*/
|
*/
|
||||||
void QRhiCommandBuffer::setStencilRef(quint32 refValue)
|
void QRhiCommandBuffer::setStencilRef(quint32 refValue)
|
||||||
{
|
{
|
||||||
@ -4173,8 +4471,8 @@ void QRhiCommandBuffer::setStencilRef(quint32 refValue)
|
|||||||
the index of the first vertex to draw. \a firstInstance is the instance ID
|
the index of the first vertex to draw. \a firstInstance is the instance ID
|
||||||
of the first instance to draw.
|
of the first instance to draw.
|
||||||
|
|
||||||
\note This function can only be called inside a pass, meaning between a
|
\note This function can only be called inside a render pass, meaning
|
||||||
beginPass() end 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)
|
||||||
@ -4200,8 +4498,8 @@ void QRhiCommandBuffer::draw(quint32 vertexCount,
|
|||||||
|
|
||||||
\a vertexOffset is added to the vertex index.
|
\a vertexOffset is added to the vertex index.
|
||||||
|
|
||||||
\note This function can only be called inside a pass, meaning between a
|
\note This function can only be called inside a render pass, meaning
|
||||||
beginPass() end endPass() call.
|
between a beginPass() and endPass() call.
|
||||||
*/
|
*/
|
||||||
void QRhiCommandBuffer::drawIndexed(quint32 indexCount,
|
void QRhiCommandBuffer::drawIndexed(quint32 indexCount,
|
||||||
quint32 instanceCount, quint32 firstIndex,
|
quint32 instanceCount, quint32 firstIndex,
|
||||||
@ -4254,6 +4552,69 @@ void QRhiCommandBuffer::debugMarkMsg(const QByteArray &msg)
|
|||||||
m_rhi->debugMarkMsg(this, msg);
|
m_rhi->debugMarkMsg(this, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Records starting a new compute pass.
|
||||||
|
|
||||||
|
\a resourceUpdates, when not null, specifies a resource update batch that
|
||||||
|
is to be committed and then released.
|
||||||
|
|
||||||
|
\note Do not assume that any state or resource bindings persist between
|
||||||
|
passes.
|
||||||
|
|
||||||
|
\note A compute pass can record setComputePipeline(), setShaderResources(),
|
||||||
|
and dispatch() calls, not graphics ones. General functionality, such as,
|
||||||
|
debug markers and beginExternal() is available both in render and compute
|
||||||
|
passes.
|
||||||
|
|
||||||
|
\note Compute is only available when the \l{QRhi::Compute}{Compute} feature
|
||||||
|
is reported as supported.
|
||||||
|
*/
|
||||||
|
void QRhiCommandBuffer::beginComputePass(QRhiResourceUpdateBatch *resourceUpdates)
|
||||||
|
{
|
||||||
|
m_rhi->beginComputePass(this, resourceUpdates);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Records ending the current compute pass.
|
||||||
|
|
||||||
|
\a resourceUpdates, when not null, specifies a resource update batch that
|
||||||
|
is to be committed and then released.
|
||||||
|
*/
|
||||||
|
void QRhiCommandBuffer::endComputePass(QRhiResourceUpdateBatch *resourceUpdates)
|
||||||
|
{
|
||||||
|
m_rhi->endComputePass(this, resourceUpdates);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Records setting a new compute pipeline \a ps.
|
||||||
|
|
||||||
|
\note This function must be called before recording setShaderResources() or
|
||||||
|
dispatch() commands on the command buffer.
|
||||||
|
|
||||||
|
\note QRhi will optimize out unnecessary invocations within a pass, so
|
||||||
|
therefore overoptimizing to avoid calls to this function is not necessary
|
||||||
|
on the applications' side.
|
||||||
|
|
||||||
|
\note This function can only be called inside a compute pass, meaning
|
||||||
|
between a beginComputePass() and endComputePass() call.
|
||||||
|
*/
|
||||||
|
void QRhiCommandBuffer::setComputePipeline(QRhiComputePipeline *ps)
|
||||||
|
{
|
||||||
|
m_rhi->setComputePipeline(this, ps);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Records dispatching compute work items, with \a x, \a y, and \a z
|
||||||
|
specifying the number of local workgroups in the corresponding dimension.
|
||||||
|
|
||||||
|
\note This function can only be called inside a compute pass, meaning
|
||||||
|
between a beginComputePass() and endComputePass() call.
|
||||||
|
*/
|
||||||
|
void QRhiCommandBuffer::dispatch(int x, int y, int z)
|
||||||
|
{
|
||||||
|
m_rhi->dispatch(this, x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\return a pointer to a backend-specific QRhiNativeHandles subclass, such as
|
\return a pointer to a backend-specific QRhiNativeHandles subclass, such as
|
||||||
QRhiVulkanCommandBufferNativeHandles. The returned value is null when
|
QRhiVulkanCommandBufferNativeHandles. The returned value is null when
|
||||||
@ -4479,6 +4840,19 @@ QRhiGraphicsPipeline *QRhi::newGraphicsPipeline()
|
|||||||
return d->createGraphicsPipeline();
|
return d->createGraphicsPipeline();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\return a new compute pipeline resource.
|
||||||
|
|
||||||
|
\note Compute is only available when the \l{QRhi::Compute}{Compute} feature
|
||||||
|
is reported as supported.
|
||||||
|
|
||||||
|
\sa QRhiResource::release()
|
||||||
|
*/
|
||||||
|
QRhiComputePipeline *QRhi::newComputePipeline()
|
||||||
|
{
|
||||||
|
return d->createComputePipeline();
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\return a new shader resource binding collection resource.
|
\return a new shader resource binding collection resource.
|
||||||
|
|
||||||
@ -4493,7 +4867,8 @@ QRhiShaderResourceBindings *QRhi::newShaderResourceBindings()
|
|||||||
\return a new buffer with the specified \a type, \a usage, and \a size.
|
\return a new buffer with the specified \a type, \a usage, and \a size.
|
||||||
|
|
||||||
\note Some \a usage and \a type combinations may not be supported by all
|
\note Some \a usage and \a type combinations may not be supported by all
|
||||||
backends. See \l{QRhi::NonDynamicUniformBuffers}{the feature flags}.
|
backends. See \l{QRhiBuffer::UsageFlag}{UsageFlags} and
|
||||||
|
\l{QRhi::NonDynamicUniformBuffers}{the feature flags}.
|
||||||
|
|
||||||
\sa QRhiResource::release()
|
\sa QRhiResource::release()
|
||||||
*/
|
*/
|
||||||
@ -4840,32 +5215,30 @@ static inline QRhiPassResourceTracker::BufferStage earlierStage(QRhiPassResource
|
|||||||
return QRhiPassResourceTracker::BufferStage(qMin(int(a), int(b)));
|
return QRhiPassResourceTracker::BufferStage(qMin(int(a), int(b)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void QRhiPassResourceTracker::registerBufferOnce(QRhiBuffer *buf, int slot, BufferAccess access, BufferStage stage,
|
void QRhiPassResourceTracker::registerBuffer(QRhiBuffer *buf, int slot, BufferAccess *access, BufferStage *stage,
|
||||||
const UsageState &stateAtPassBegin)
|
const UsageState &state)
|
||||||
{
|
{
|
||||||
auto it = std::find_if(m_buffers.begin(), m_buffers.end(), [buf](const Buffer &b) { return b.buf == buf; });
|
auto it = std::find_if(m_buffers.begin(), m_buffers.end(), [buf](const Buffer &b) { return b.buf == buf; });
|
||||||
if (it != m_buffers.end()) {
|
if (it != m_buffers.end()) {
|
||||||
if (it->access != access) {
|
if (it->access != *access) {
|
||||||
const QByteArray name = buf->name();
|
const QByteArray name = buf->name();
|
||||||
qWarning("Buffer %p (%s) used with different accesses within the same pass, this is not allowed.",
|
qWarning("Buffer %p (%s) used with different accesses within the same pass, this is not allowed.",
|
||||||
buf, name.constData());
|
buf, name.constData());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (it->stage != stage)
|
if (it->stage != *stage) {
|
||||||
it->stage = earlierStage(it->stage, stage);
|
it->stage = earlierStage(it->stage, *stage);
|
||||||
// Multiple registrations of the same buffer is fine as long is it is
|
*stage = it->stage;
|
||||||
// a compatible usage. stateAtPassBegin is not actually the state at
|
}
|
||||||
// pass begin in the second, third, etc. invocation but that's fine
|
|
||||||
// since we'll just return here.
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Buffer b;
|
Buffer b;
|
||||||
b.buf = buf;
|
b.buf = buf;
|
||||||
b.slot = slot;
|
b.slot = slot;
|
||||||
b.access = access;
|
b.access = *access;
|
||||||
b.stage = stage;
|
b.stage = *stage;
|
||||||
b.stateAtPassBegin = stateAtPassBegin;
|
b.stateAtPassBegin = state; // first use -> initial state
|
||||||
m_buffers.append(b);
|
m_buffers.append(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4875,30 +5248,44 @@ static inline QRhiPassResourceTracker::TextureStage earlierStage(QRhiPassResourc
|
|||||||
return QRhiPassResourceTracker::TextureStage(qMin(int(a), int(b)));
|
return QRhiPassResourceTracker::TextureStage(qMin(int(a), int(b)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void QRhiPassResourceTracker::registerTextureOnce(QRhiTexture *tex, TextureAccess access, TextureStage stage,
|
static inline bool isImageLoadStore(QRhiPassResourceTracker::TextureAccess access)
|
||||||
const UsageState &stateAtPassBegin)
|
{
|
||||||
|
return access == QRhiPassResourceTracker::TexStorageLoad
|
||||||
|
|| access == QRhiPassResourceTracker::TexStorageStore
|
||||||
|
|| access == QRhiPassResourceTracker::TexStorageLoadStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QRhiPassResourceTracker::registerTexture(QRhiTexture *tex, TextureAccess *access, TextureStage *stage,
|
||||||
|
const UsageState &state)
|
||||||
{
|
{
|
||||||
auto it = std::find_if(m_textures.begin(), m_textures.end(), [tex](const Texture &t) { return t.tex == tex; });
|
auto it = std::find_if(m_textures.begin(), m_textures.end(), [tex](const Texture &t) { return t.tex == tex; });
|
||||||
if (it != m_textures.end()) {
|
if (it != m_textures.end()) {
|
||||||
if (it->access != access) {
|
if (it->access != *access) {
|
||||||
|
// Different subresources of a texture may be used for both load
|
||||||
|
// and store in the same pass. (think reading from one mip level
|
||||||
|
// and writing to another one in a compute shader) This we can
|
||||||
|
// handle by treating the entire resource as read-write.
|
||||||
|
if (isImageLoadStore(it->access) && isImageLoadStore(*access)) {
|
||||||
|
it->access = QRhiPassResourceTracker::TexStorageLoadStore;
|
||||||
|
*access = it->access;
|
||||||
|
} else {
|
||||||
const QByteArray name = tex->name();
|
const QByteArray name = tex->name();
|
||||||
qWarning("Texture %p (%s) used with different accesses within the same pass, this is not allowed.",
|
qWarning("Texture %p (%s) used with different accesses within the same pass, this is not allowed.",
|
||||||
tex, name.constData());
|
tex, name.constData());
|
||||||
}
|
}
|
||||||
if (it->stage != stage)
|
}
|
||||||
it->stage = earlierStage(it->stage, stage);
|
if (it->stage != *stage) {
|
||||||
// Multiple registrations of the same texture is fine as long is it is
|
it->stage = earlierStage(it->stage, *stage);
|
||||||
// a compatible usage. stateAtPassBegin is not actually the state at
|
*stage = it->stage;
|
||||||
// pass begin in the second, third, etc. invocation but that's fine
|
}
|
||||||
// since we'll just return here.
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Texture t;
|
Texture t;
|
||||||
t.tex = tex;
|
t.tex = tex;
|
||||||
t.access = access;
|
t.access = *access;
|
||||||
t.stage = stage;
|
t.stage = *stage;
|
||||||
t.stateAtPassBegin = stateAtPassBegin;
|
t.stateAtPassBegin = state; // first use -> initial state
|
||||||
m_textures.append(t);
|
m_textures.append(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -259,16 +259,17 @@ Q_GUI_EXPORT uint qHash(const QRhiVertexInputLayout &v, uint seed = 0) Q_DECL_NO
|
|||||||
Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiVertexInputLayout &);
|
Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiVertexInputLayout &);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
class Q_GUI_EXPORT QRhiGraphicsShaderStage
|
class Q_GUI_EXPORT QRhiShaderStage
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum Type {
|
enum Type {
|
||||||
Vertex,
|
Vertex,
|
||||||
Fragment
|
Fragment,
|
||||||
|
Compute
|
||||||
};
|
};
|
||||||
|
|
||||||
QRhiGraphicsShaderStage() = default;
|
QRhiShaderStage() = default;
|
||||||
QRhiGraphicsShaderStage(Type type, const QShader &shader,
|
QRhiShaderStage(Type type, const QShader &shader,
|
||||||
QShader::Variant v = QShader::StandardShader);
|
QShader::Variant v = QShader::StandardShader);
|
||||||
|
|
||||||
Type type() const { return m_type; }
|
Type type() const { return m_type; }
|
||||||
@ -286,26 +287,35 @@ private:
|
|||||||
QShader::Variant m_shaderVariant = QShader::StandardShader;
|
QShader::Variant m_shaderVariant = QShader::StandardShader;
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_DECLARE_TYPEINFO(QRhiGraphicsShaderStage, Q_MOVABLE_TYPE);
|
Q_DECLARE_TYPEINFO(QRhiShaderStage, Q_MOVABLE_TYPE);
|
||||||
|
|
||||||
Q_GUI_EXPORT bool operator==(const QRhiGraphicsShaderStage &a, const QRhiGraphicsShaderStage &b) Q_DECL_NOTHROW;
|
Q_GUI_EXPORT bool operator==(const QRhiShaderStage &a, const QRhiShaderStage &b) Q_DECL_NOTHROW;
|
||||||
Q_GUI_EXPORT bool operator!=(const QRhiGraphicsShaderStage &a, const QRhiGraphicsShaderStage &b) Q_DECL_NOTHROW;
|
Q_GUI_EXPORT bool operator!=(const QRhiShaderStage &a, const QRhiShaderStage &b) Q_DECL_NOTHROW;
|
||||||
Q_GUI_EXPORT uint qHash(const QRhiGraphicsShaderStage &s, uint seed = 0) Q_DECL_NOTHROW;
|
Q_GUI_EXPORT uint qHash(const QRhiShaderStage &s, uint seed = 0) Q_DECL_NOTHROW;
|
||||||
#ifndef QT_NO_DEBUG_STREAM
|
#ifndef QT_NO_DEBUG_STREAM
|
||||||
Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiGraphicsShaderStage &);
|
Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiShaderStage &);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
using QRhiGraphicsShaderStage = QRhiShaderStage;
|
||||||
|
|
||||||
class Q_GUI_EXPORT QRhiShaderResourceBinding
|
class Q_GUI_EXPORT QRhiShaderResourceBinding
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum Type {
|
enum Type {
|
||||||
UniformBuffer,
|
UniformBuffer,
|
||||||
SampledTexture
|
SampledTexture,
|
||||||
|
ImageLoad,
|
||||||
|
ImageStore,
|
||||||
|
ImageLoadStore,
|
||||||
|
BufferLoad,
|
||||||
|
BufferStore,
|
||||||
|
BufferLoadStore
|
||||||
};
|
};
|
||||||
|
|
||||||
enum StageFlag {
|
enum StageFlag {
|
||||||
VertexStage = 1 << 0,
|
VertexStage = 1 << 0,
|
||||||
FragmentStage = 1 << 1
|
FragmentStage = 1 << 1,
|
||||||
|
ComputeStage = 1 << 2
|
||||||
};
|
};
|
||||||
Q_DECLARE_FLAGS(StageFlags, StageFlag)
|
Q_DECLARE_FLAGS(StageFlags, StageFlag)
|
||||||
|
|
||||||
@ -320,8 +330,20 @@ public:
|
|||||||
static QRhiShaderResourceBinding uniformBuffer(int binding, StageFlags stage, QRhiBuffer *buf);
|
static QRhiShaderResourceBinding uniformBuffer(int binding, StageFlags stage, QRhiBuffer *buf);
|
||||||
static QRhiShaderResourceBinding uniformBuffer(int binding, StageFlags stage, QRhiBuffer *buf, int offset, int size);
|
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 uniformBufferWithDynamicOffset(int binding, StageFlags stage, QRhiBuffer *buf, int size);
|
||||||
|
|
||||||
static QRhiShaderResourceBinding sampledTexture(int binding, StageFlags stage, QRhiTexture *tex, QRhiSampler *sampler);
|
static QRhiShaderResourceBinding sampledTexture(int binding, StageFlags stage, QRhiTexture *tex, QRhiSampler *sampler);
|
||||||
|
|
||||||
|
static QRhiShaderResourceBinding imageLoad(int binding, StageFlags stage, QRhiTexture *tex, int level);
|
||||||
|
static QRhiShaderResourceBinding imageStore(int binding, StageFlags stage, QRhiTexture *tex, int level);
|
||||||
|
static QRhiShaderResourceBinding imageLoadStore(int binding, StageFlags stage, QRhiTexture *tex, int level);
|
||||||
|
|
||||||
|
static QRhiShaderResourceBinding bufferLoad(int binding, StageFlags stage, QRhiBuffer *buf);
|
||||||
|
static QRhiShaderResourceBinding bufferLoad(int binding, StageFlags stage, QRhiBuffer *buf, int offset, int size);
|
||||||
|
static QRhiShaderResourceBinding bufferStore(int binding, StageFlags stage, QRhiBuffer *buf);
|
||||||
|
static QRhiShaderResourceBinding bufferStore(int binding, StageFlags stage, QRhiBuffer *buf, int offset, int size);
|
||||||
|
static QRhiShaderResourceBinding bufferLoadStore(int binding, StageFlags stage, QRhiBuffer *buf);
|
||||||
|
static QRhiShaderResourceBinding bufferLoadStore(int binding, StageFlags stage, QRhiBuffer *buf, int offset, int size);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QRhiShaderResourceBindingPrivate *d;
|
QRhiShaderResourceBindingPrivate *d;
|
||||||
friend class QRhiShaderResourceBindingPrivate;
|
friend class QRhiShaderResourceBindingPrivate;
|
||||||
@ -558,6 +580,7 @@ public:
|
|||||||
ShaderResourceBindings,
|
ShaderResourceBindings,
|
||||||
GraphicsPipeline,
|
GraphicsPipeline,
|
||||||
SwapChain,
|
SwapChain,
|
||||||
|
ComputePipeline,
|
||||||
CommandBuffer
|
CommandBuffer
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -594,7 +617,8 @@ public:
|
|||||||
enum UsageFlag {
|
enum UsageFlag {
|
||||||
VertexBuffer = 1 << 0,
|
VertexBuffer = 1 << 0,
|
||||||
IndexBuffer = 1 << 1,
|
IndexBuffer = 1 << 1,
|
||||||
UniformBuffer = 1 << 2
|
UniformBuffer = 1 << 2,
|
||||||
|
StorageBuffer = 1 << 3
|
||||||
};
|
};
|
||||||
Q_DECLARE_FLAGS(UsageFlags, UsageFlag)
|
Q_DECLARE_FLAGS(UsageFlags, UsageFlag)
|
||||||
|
|
||||||
@ -629,7 +653,8 @@ public:
|
|||||||
MipMapped = 1 << 3,
|
MipMapped = 1 << 3,
|
||||||
sRGB = 1 << 4,
|
sRGB = 1 << 4,
|
||||||
UsedAsTransferSource = 1 << 5,
|
UsedAsTransferSource = 1 << 5,
|
||||||
UsedWithGenerateMips = 1 << 6
|
UsedWithGenerateMips = 1 << 6,
|
||||||
|
UsedWithLoadStore = 1 << 7
|
||||||
};
|
};
|
||||||
Q_DECLARE_FLAGS(Flags, Flag)
|
Q_DECLARE_FLAGS(Flags, Flag)
|
||||||
|
|
||||||
@ -1043,8 +1068,8 @@ public:
|
|||||||
int sampleCount() const { return m_sampleCount; }
|
int sampleCount() const { return m_sampleCount; }
|
||||||
void setSampleCount(int s) { m_sampleCount = s; }
|
void setSampleCount(int s) { m_sampleCount = s; }
|
||||||
|
|
||||||
QVector<QRhiGraphicsShaderStage> shaderStages() const { return m_shaderStages; }
|
QVector<QRhiShaderStage> shaderStages() const { return m_shaderStages; }
|
||||||
void setShaderStages(const QVector<QRhiGraphicsShaderStage> &stages) { m_shaderStages = stages; }
|
void setShaderStages(const QVector<QRhiShaderStage> &stages) { m_shaderStages = stages; }
|
||||||
|
|
||||||
QRhiVertexInputLayout vertexInputLayout() const { return m_vertexInputLayout; }
|
QRhiVertexInputLayout vertexInputLayout() const { return m_vertexInputLayout; }
|
||||||
void setVertexInputLayout(const QRhiVertexInputLayout &layout) { m_vertexInputLayout = layout; }
|
void setVertexInputLayout(const QRhiVertexInputLayout &layout) { m_vertexInputLayout = layout; }
|
||||||
@ -1073,7 +1098,7 @@ protected:
|
|||||||
quint32 m_stencilReadMask = 0xFF;
|
quint32 m_stencilReadMask = 0xFF;
|
||||||
quint32 m_stencilWriteMask = 0xFF;
|
quint32 m_stencilWriteMask = 0xFF;
|
||||||
int m_sampleCount = 1;
|
int m_sampleCount = 1;
|
||||||
QVector<QRhiGraphicsShaderStage> m_shaderStages;
|
QVector<QRhiShaderStage> m_shaderStages;
|
||||||
QRhiVertexInputLayout m_vertexInputLayout;
|
QRhiVertexInputLayout m_vertexInputLayout;
|
||||||
QRhiShaderResourceBindings *m_shaderResourceBindings = nullptr;
|
QRhiShaderResourceBindings *m_shaderResourceBindings = nullptr;
|
||||||
QRhiRenderPassDescriptor *m_renderPassDesc = nullptr;
|
QRhiRenderPassDescriptor *m_renderPassDesc = nullptr;
|
||||||
@ -1133,6 +1158,24 @@ protected:
|
|||||||
|
|
||||||
Q_DECLARE_OPERATORS_FOR_FLAGS(QRhiSwapChain::Flags)
|
Q_DECLARE_OPERATORS_FOR_FLAGS(QRhiSwapChain::Flags)
|
||||||
|
|
||||||
|
class Q_GUI_EXPORT QRhiComputePipeline : public QRhiResource
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QRhiResource::Type resourceType() const override;
|
||||||
|
virtual bool build() = 0;
|
||||||
|
|
||||||
|
QRhiShaderStage shaderStage() const { return m_shaderStage; }
|
||||||
|
void setShaderStage(const QRhiShaderStage &stage) { m_shaderStage = stage; }
|
||||||
|
|
||||||
|
QRhiShaderResourceBindings *shaderResourceBindings() const { return m_shaderResourceBindings; }
|
||||||
|
void setShaderResourceBindings(QRhiShaderResourceBindings *srb) { m_shaderResourceBindings = srb; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
QRhiComputePipeline(QRhiImplementation *rhi);
|
||||||
|
QRhiShaderStage m_shaderStage;
|
||||||
|
QRhiShaderResourceBindings *m_shaderResourceBindings = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
class Q_GUI_EXPORT QRhiCommandBuffer : public QRhiResource
|
class Q_GUI_EXPORT QRhiCommandBuffer : public QRhiResource
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -1181,6 +1224,11 @@ public:
|
|||||||
void debugMarkEnd();
|
void debugMarkEnd();
|
||||||
void debugMarkMsg(const QByteArray &msg);
|
void debugMarkMsg(const QByteArray &msg);
|
||||||
|
|
||||||
|
void beginComputePass(QRhiResourceUpdateBatch *resourceUpdates = nullptr);
|
||||||
|
void endComputePass(QRhiResourceUpdateBatch *resourceUpdates = nullptr);
|
||||||
|
void setComputePipeline(QRhiComputePipeline *ps);
|
||||||
|
void dispatch(int x, int y, int z);
|
||||||
|
|
||||||
const QRhiNativeHandles *nativeHandles();
|
const QRhiNativeHandles *nativeHandles();
|
||||||
void beginExternal();
|
void beginExternal();
|
||||||
void endExternal();
|
void endExternal();
|
||||||
@ -1263,7 +1311,8 @@ public:
|
|||||||
NonFourAlignedEffectiveIndexBufferOffset,
|
NonFourAlignedEffectiveIndexBufferOffset,
|
||||||
NPOTTextureRepeat,
|
NPOTTextureRepeat,
|
||||||
RedOrAlpha8IsRed,
|
RedOrAlpha8IsRed,
|
||||||
ElementIndexUint
|
ElementIndexUint,
|
||||||
|
Compute
|
||||||
};
|
};
|
||||||
|
|
||||||
enum BeginFrameFlag {
|
enum BeginFrameFlag {
|
||||||
@ -1297,6 +1346,7 @@ public:
|
|||||||
void runCleanup();
|
void runCleanup();
|
||||||
|
|
||||||
QRhiGraphicsPipeline *newGraphicsPipeline();
|
QRhiGraphicsPipeline *newGraphicsPipeline();
|
||||||
|
QRhiComputePipeline *newComputePipeline();
|
||||||
QRhiShaderResourceBindings *newShaderResourceBindings();
|
QRhiShaderResourceBindings *newShaderResourceBindings();
|
||||||
|
|
||||||
QRhiBuffer *newBuffer(QRhiBuffer::Type type,
|
QRhiBuffer *newBuffer(QRhiBuffer::Type type,
|
||||||
|
@ -70,6 +70,7 @@ public:
|
|||||||
virtual void destroy() = 0;
|
virtual void destroy() = 0;
|
||||||
|
|
||||||
virtual QRhiGraphicsPipeline *createGraphicsPipeline() = 0;
|
virtual QRhiGraphicsPipeline *createGraphicsPipeline() = 0;
|
||||||
|
virtual QRhiComputePipeline *createComputePipeline() = 0;
|
||||||
virtual QRhiShaderResourceBindings *createShaderResourceBindings() = 0;
|
virtual QRhiShaderResourceBindings *createShaderResourceBindings() = 0;
|
||||||
virtual QRhiBuffer *createBuffer(QRhiBuffer::Type type,
|
virtual QRhiBuffer *createBuffer(QRhiBuffer::Type type,
|
||||||
QRhiBuffer::UsageFlags usage,
|
QRhiBuffer::UsageFlags usage,
|
||||||
@ -133,6 +134,11 @@ public:
|
|||||||
virtual void debugMarkEnd(QRhiCommandBuffer *cb) = 0;
|
virtual void debugMarkEnd(QRhiCommandBuffer *cb) = 0;
|
||||||
virtual void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) = 0;
|
virtual void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) = 0;
|
||||||
|
|
||||||
|
virtual void beginComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) = 0;
|
||||||
|
virtual void endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) = 0;
|
||||||
|
virtual void setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps) = 0;
|
||||||
|
virtual void dispatch(QRhiCommandBuffer *cb, int x, int y, int z) = 0;
|
||||||
|
|
||||||
virtual const QRhiNativeHandles *nativeHandles(QRhiCommandBuffer *cb) = 0;
|
virtual const QRhiNativeHandles *nativeHandles(QRhiCommandBuffer *cb) = 0;
|
||||||
virtual void beginExternal(QRhiCommandBuffer *cb) = 0;
|
virtual void beginExternal(QRhiCommandBuffer *cb) = 0;
|
||||||
virtual void endExternal(QRhiCommandBuffer *cb) = 0;
|
virtual void endExternal(QRhiCommandBuffer *cb) = 0;
|
||||||
@ -200,6 +206,7 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
bool debugMarkers = false;
|
bool debugMarkers = false;
|
||||||
int currentFrameSlot = 0; // for vk, mtl, and similar. unused by gl and d3d11.
|
int currentFrameSlot = 0; // for vk, mtl, and similar. unused by gl and d3d11.
|
||||||
|
bool inFrame = false;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QRhi::Implementation implType;
|
QRhi::Implementation implType;
|
||||||
@ -210,7 +217,6 @@ private:
|
|||||||
QSet<QRhiResource *> resources;
|
QSet<QRhiResource *> resources;
|
||||||
QSet<QRhiResource *> pendingReleaseAndDestroyResources;
|
QSet<QRhiResource *> pendingReleaseAndDestroyResources;
|
||||||
QVector<QRhi::CleanupCallback> cleanupCallbacks;
|
QVector<QRhi::CleanupCallback> cleanupCallbacks;
|
||||||
bool inFrame = false;
|
|
||||||
|
|
||||||
friend class QRhi;
|
friend class QRhi;
|
||||||
friend class QRhiResourceUpdateBatchPrivate;
|
friend class QRhiResourceUpdateBatchPrivate;
|
||||||
@ -393,9 +399,20 @@ public:
|
|||||||
QRhiTexture *tex;
|
QRhiTexture *tex;
|
||||||
QRhiSampler *sampler;
|
QRhiSampler *sampler;
|
||||||
};
|
};
|
||||||
|
struct StorageImageData {
|
||||||
|
QRhiTexture *tex;
|
||||||
|
int level;
|
||||||
|
};
|
||||||
|
struct StorageBufferData {
|
||||||
|
QRhiBuffer *buf;
|
||||||
|
int offset;
|
||||||
|
int maybeSize;
|
||||||
|
};
|
||||||
union {
|
union {
|
||||||
UniformBufferData ubuf;
|
UniformBufferData ubuf;
|
||||||
SampledTextureData stex;
|
SampledTextureData stex;
|
||||||
|
StorageImageData simage;
|
||||||
|
StorageBufferData sbuf;
|
||||||
} u;
|
} u;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -487,33 +504,41 @@ public:
|
|||||||
enum BufferStage {
|
enum BufferStage {
|
||||||
BufVertexInputStage,
|
BufVertexInputStage,
|
||||||
BufVertexStage,
|
BufVertexStage,
|
||||||
BufFragmentStage
|
BufFragmentStage,
|
||||||
|
BufComputeStage
|
||||||
};
|
};
|
||||||
|
|
||||||
enum BufferAccess {
|
enum BufferAccess {
|
||||||
BufVertexInput,
|
BufVertexInput,
|
||||||
BufIndexRead,
|
BufIndexRead,
|
||||||
BufUniformRead
|
BufUniformRead,
|
||||||
|
BufStorageLoad,
|
||||||
|
BufStorageStore,
|
||||||
|
BufStorageLoadStore
|
||||||
};
|
};
|
||||||
|
|
||||||
void registerBufferOnce(QRhiBuffer *buf, int slot, BufferAccess access, BufferStage stage,
|
void registerBuffer(QRhiBuffer *buf, int slot, BufferAccess *access, BufferStage *stage,
|
||||||
const UsageState &stateAtPassBegin);
|
const UsageState &state);
|
||||||
|
|
||||||
enum TextureStage {
|
enum TextureStage {
|
||||||
TexVertexStage,
|
TexVertexStage,
|
||||||
TexFragmentStage,
|
TexFragmentStage,
|
||||||
TexColorOutputStage,
|
TexColorOutputStage,
|
||||||
TexDepthOutputStage
|
TexDepthOutputStage,
|
||||||
|
TexComputeStage
|
||||||
};
|
};
|
||||||
|
|
||||||
enum TextureAccess {
|
enum TextureAccess {
|
||||||
TexSample,
|
TexSample,
|
||||||
TexColorOutput,
|
TexColorOutput,
|
||||||
TexDepthOutput
|
TexDepthOutput,
|
||||||
|
TexStorageLoad,
|
||||||
|
TexStorageStore,
|
||||||
|
TexStorageLoadStore
|
||||||
};
|
};
|
||||||
|
|
||||||
void registerTextureOnce(QRhiTexture *tex, TextureAccess access, TextureStage stage,
|
void registerTexture(QRhiTexture *tex, TextureAccess *access, TextureStage *stage,
|
||||||
const UsageState &stateAtPassBegin);
|
const UsageState &state);
|
||||||
|
|
||||||
struct Buffer {
|
struct Buffer {
|
||||||
QRhiBuffer *buf;
|
QRhiBuffer *buf;
|
||||||
|
@ -375,6 +375,8 @@ bool QRhiD3D11::isFeatureSupported(QRhi::Feature feature) const
|
|||||||
return true;
|
return true;
|
||||||
case QRhi::ElementIndexUint:
|
case QRhi::ElementIndexUint:
|
||||||
return true;
|
return true;
|
||||||
|
case QRhi::Compute:
|
||||||
|
return false;
|
||||||
default:
|
default:
|
||||||
Q_UNREACHABLE();
|
Q_UNREACHABLE();
|
||||||
return false;
|
return false;
|
||||||
@ -443,6 +445,11 @@ QRhiGraphicsPipeline *QRhiD3D11::createGraphicsPipeline()
|
|||||||
return new QD3D11GraphicsPipeline(this);
|
return new QD3D11GraphicsPipeline(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QRhiComputePipeline *QRhiD3D11::createComputePipeline()
|
||||||
|
{
|
||||||
|
return new QD3D11ComputePipeline(this);
|
||||||
|
}
|
||||||
|
|
||||||
QRhiShaderResourceBindings *QRhiD3D11::createShaderResourceBindings()
|
QRhiShaderResourceBindings *QRhiD3D11::createShaderResourceBindings()
|
||||||
{
|
{
|
||||||
return new QD3D11ShaderResourceBindings(this);
|
return new QD3D11ShaderResourceBindings(this);
|
||||||
@ -450,9 +457,8 @@ QRhiShaderResourceBindings *QRhiD3D11::createShaderResourceBindings()
|
|||||||
|
|
||||||
void QRhiD3D11::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline *ps)
|
void QRhiD3D11::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline *ps)
|
||||||
{
|
{
|
||||||
Q_ASSERT(inPass);
|
|
||||||
|
|
||||||
QD3D11CommandBuffer *cbD = QRHI_RES(QD3D11CommandBuffer, cb);
|
QD3D11CommandBuffer *cbD = QRHI_RES(QD3D11CommandBuffer, cb);
|
||||||
|
Q_ASSERT(cbD->recordingPass == QD3D11CommandBuffer::RenderPass);
|
||||||
QD3D11GraphicsPipeline *psD = QRHI_RES(QD3D11GraphicsPipeline, ps);
|
QD3D11GraphicsPipeline *psD = QRHI_RES(QD3D11GraphicsPipeline, ps);
|
||||||
const bool pipelineChanged = cbD->currentPipeline != ps || cbD->currentPipelineGeneration != psD->generation;
|
const bool pipelineChanged = cbD->currentPipeline != ps || cbD->currentPipelineGeneration != psD->generation;
|
||||||
|
|
||||||
@ -471,9 +477,8 @@ void QRhiD3D11::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind
|
|||||||
int dynamicOffsetCount,
|
int dynamicOffsetCount,
|
||||||
const QRhiCommandBuffer::DynamicOffset *dynamicOffsets)
|
const QRhiCommandBuffer::DynamicOffset *dynamicOffsets)
|
||||||
{
|
{
|
||||||
Q_ASSERT(inPass);
|
|
||||||
|
|
||||||
QD3D11CommandBuffer *cbD = QRHI_RES(QD3D11CommandBuffer, cb);
|
QD3D11CommandBuffer *cbD = QRHI_RES(QD3D11CommandBuffer, cb);
|
||||||
|
Q_ASSERT(cbD->recordingPass == QD3D11CommandBuffer::RenderPass);
|
||||||
Q_ASSERT(cbD->currentPipeline);
|
Q_ASSERT(cbD->currentPipeline);
|
||||||
|
|
||||||
if (!srb)
|
if (!srb)
|
||||||
@ -568,8 +573,8 @@ void QRhiD3D11::setVertexInput(QRhiCommandBuffer *cb,
|
|||||||
int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings,
|
int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings,
|
||||||
QRhiBuffer *indexBuf, quint32 indexOffset, QRhiCommandBuffer::IndexFormat indexFormat)
|
QRhiBuffer *indexBuf, quint32 indexOffset, QRhiCommandBuffer::IndexFormat indexFormat)
|
||||||
{
|
{
|
||||||
Q_ASSERT(inPass);
|
|
||||||
QD3D11CommandBuffer *cbD = QRHI_RES(QD3D11CommandBuffer, cb);
|
QD3D11CommandBuffer *cbD = QRHI_RES(QD3D11CommandBuffer, cb);
|
||||||
|
Q_ASSERT(cbD->recordingPass == QD3D11CommandBuffer::RenderPass);
|
||||||
|
|
||||||
bool needsBindVBuf = false;
|
bool needsBindVBuf = false;
|
||||||
for (int i = 0; i < bindingCount; ++i) {
|
for (int i = 0; i < bindingCount; ++i) {
|
||||||
@ -632,8 +637,8 @@ void QRhiD3D11::setVertexInput(QRhiCommandBuffer *cb,
|
|||||||
|
|
||||||
void QRhiD3D11::setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport)
|
void QRhiD3D11::setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport)
|
||||||
{
|
{
|
||||||
Q_ASSERT(inPass);
|
|
||||||
QD3D11CommandBuffer *cbD = QRHI_RES(QD3D11CommandBuffer, cb);
|
QD3D11CommandBuffer *cbD = QRHI_RES(QD3D11CommandBuffer, cb);
|
||||||
|
Q_ASSERT(cbD->recordingPass == QD3D11CommandBuffer::RenderPass);
|
||||||
Q_ASSERT(cbD->currentTarget);
|
Q_ASSERT(cbD->currentTarget);
|
||||||
const QSize outputSize = cbD->currentTarget->pixelSize();
|
const QSize outputSize = cbD->currentTarget->pixelSize();
|
||||||
|
|
||||||
@ -656,8 +661,8 @@ void QRhiD3D11::setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport)
|
|||||||
|
|
||||||
void QRhiD3D11::setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor)
|
void QRhiD3D11::setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor)
|
||||||
{
|
{
|
||||||
Q_ASSERT(inPass);
|
|
||||||
QD3D11CommandBuffer *cbD = QRHI_RES(QD3D11CommandBuffer, cb);
|
QD3D11CommandBuffer *cbD = QRHI_RES(QD3D11CommandBuffer, cb);
|
||||||
|
Q_ASSERT(cbD->recordingPass == QD3D11CommandBuffer::RenderPass);
|
||||||
Q_ASSERT(cbD->currentTarget);
|
Q_ASSERT(cbD->currentTarget);
|
||||||
const QSize outputSize = cbD->currentTarget->pixelSize();
|
const QSize outputSize = cbD->currentTarget->pixelSize();
|
||||||
|
|
||||||
@ -678,8 +683,9 @@ void QRhiD3D11::setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor)
|
|||||||
|
|
||||||
void QRhiD3D11::setBlendConstants(QRhiCommandBuffer *cb, const QColor &c)
|
void QRhiD3D11::setBlendConstants(QRhiCommandBuffer *cb, const QColor &c)
|
||||||
{
|
{
|
||||||
Q_ASSERT(inPass);
|
|
||||||
QD3D11CommandBuffer *cbD = QRHI_RES(QD3D11CommandBuffer, cb);
|
QD3D11CommandBuffer *cbD = QRHI_RES(QD3D11CommandBuffer, cb);
|
||||||
|
Q_ASSERT(cbD->recordingPass == QD3D11CommandBuffer::RenderPass);
|
||||||
|
|
||||||
QD3D11CommandBuffer::Command cmd;
|
QD3D11CommandBuffer::Command cmd;
|
||||||
cmd.cmd = QD3D11CommandBuffer::Command::BlendConstants;
|
cmd.cmd = QD3D11CommandBuffer::Command::BlendConstants;
|
||||||
cmd.args.blendConstants.ps = QRHI_RES(QD3D11GraphicsPipeline, cbD->currentPipeline);
|
cmd.args.blendConstants.ps = QRHI_RES(QD3D11GraphicsPipeline, cbD->currentPipeline);
|
||||||
@ -692,8 +698,9 @@ void QRhiD3D11::setBlendConstants(QRhiCommandBuffer *cb, const QColor &c)
|
|||||||
|
|
||||||
void QRhiD3D11::setStencilRef(QRhiCommandBuffer *cb, quint32 refValue)
|
void QRhiD3D11::setStencilRef(QRhiCommandBuffer *cb, quint32 refValue)
|
||||||
{
|
{
|
||||||
Q_ASSERT(inPass);
|
|
||||||
QD3D11CommandBuffer *cbD = QRHI_RES(QD3D11CommandBuffer, cb);
|
QD3D11CommandBuffer *cbD = QRHI_RES(QD3D11CommandBuffer, cb);
|
||||||
|
Q_ASSERT(cbD->recordingPass == QD3D11CommandBuffer::RenderPass);
|
||||||
|
|
||||||
QD3D11CommandBuffer::Command cmd;
|
QD3D11CommandBuffer::Command cmd;
|
||||||
cmd.cmd = QD3D11CommandBuffer::Command::StencilRef;
|
cmd.cmd = QD3D11CommandBuffer::Command::StencilRef;
|
||||||
cmd.args.stencilRef.ps = QRHI_RES(QD3D11GraphicsPipeline, cbD->currentPipeline);
|
cmd.args.stencilRef.ps = QRHI_RES(QD3D11GraphicsPipeline, cbD->currentPipeline);
|
||||||
@ -704,8 +711,9 @@ void QRhiD3D11::setStencilRef(QRhiCommandBuffer *cb, quint32 refValue)
|
|||||||
void QRhiD3D11::draw(QRhiCommandBuffer *cb, quint32 vertexCount,
|
void QRhiD3D11::draw(QRhiCommandBuffer *cb, quint32 vertexCount,
|
||||||
quint32 instanceCount, quint32 firstVertex, quint32 firstInstance)
|
quint32 instanceCount, quint32 firstVertex, quint32 firstInstance)
|
||||||
{
|
{
|
||||||
Q_ASSERT(inPass);
|
|
||||||
QD3D11CommandBuffer *cbD = QRHI_RES(QD3D11CommandBuffer, cb);
|
QD3D11CommandBuffer *cbD = QRHI_RES(QD3D11CommandBuffer, cb);
|
||||||
|
Q_ASSERT(cbD->recordingPass == QD3D11CommandBuffer::RenderPass);
|
||||||
|
|
||||||
QD3D11CommandBuffer::Command cmd;
|
QD3D11CommandBuffer::Command cmd;
|
||||||
cmd.cmd = QD3D11CommandBuffer::Command::Draw;
|
cmd.cmd = QD3D11CommandBuffer::Command::Draw;
|
||||||
cmd.args.draw.ps = QRHI_RES(QD3D11GraphicsPipeline, cbD->currentPipeline);
|
cmd.args.draw.ps = QRHI_RES(QD3D11GraphicsPipeline, cbD->currentPipeline);
|
||||||
@ -719,8 +727,9 @@ void QRhiD3D11::draw(QRhiCommandBuffer *cb, quint32 vertexCount,
|
|||||||
void QRhiD3D11::drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
|
void QRhiD3D11::drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
|
||||||
quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance)
|
quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance)
|
||||||
{
|
{
|
||||||
Q_ASSERT(inPass);
|
|
||||||
QD3D11CommandBuffer *cbD = QRHI_RES(QD3D11CommandBuffer, cb);
|
QD3D11CommandBuffer *cbD = QRHI_RES(QD3D11CommandBuffer, cb);
|
||||||
|
Q_ASSERT(cbD->recordingPass == QD3D11CommandBuffer::RenderPass);
|
||||||
|
|
||||||
QD3D11CommandBuffer::Command cmd;
|
QD3D11CommandBuffer::Command cmd;
|
||||||
cmd.cmd = QD3D11CommandBuffer::Command::DrawIndexed;
|
cmd.cmd = QD3D11CommandBuffer::Command::DrawIndexed;
|
||||||
cmd.args.drawIndexed.ps = QRHI_RES(QD3D11GraphicsPipeline, cbD->currentPipeline);
|
cmd.args.drawIndexed.ps = QRHI_RES(QD3D11GraphicsPipeline, cbD->currentPipeline);
|
||||||
@ -777,18 +786,16 @@ const QRhiNativeHandles *QRhiD3D11::nativeHandles(QRhiCommandBuffer *cb)
|
|||||||
|
|
||||||
void QRhiD3D11::beginExternal(QRhiCommandBuffer *cb)
|
void QRhiD3D11::beginExternal(QRhiCommandBuffer *cb)
|
||||||
{
|
{
|
||||||
Q_ASSERT(inPass);
|
|
||||||
Q_UNUSED(cb);
|
Q_UNUSED(cb);
|
||||||
flushCommandBuffer();
|
flushCommandBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QRhiD3D11::endExternal(QRhiCommandBuffer *cb)
|
void QRhiD3D11::endExternal(QRhiCommandBuffer *cb)
|
||||||
{
|
{
|
||||||
Q_ASSERT(inPass);
|
|
||||||
QD3D11CommandBuffer *cbD = QRHI_RES(QD3D11CommandBuffer, cb);
|
QD3D11CommandBuffer *cbD = QRHI_RES(QD3D11CommandBuffer, cb);
|
||||||
Q_ASSERT(cbD->currentTarget);
|
|
||||||
Q_ASSERT(cbD->commands.isEmpty());
|
Q_ASSERT(cbD->commands.isEmpty());
|
||||||
cbD->resetCachedState();
|
cbD->resetCachedState();
|
||||||
|
if (cbD->currentTarget) // could be compute, no rendertarget then
|
||||||
enqueueSetRenderTarget(cbD, cbD->currentTarget);
|
enqueueSetRenderTarget(cbD, cbD->currentTarget);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -796,9 +803,6 @@ QRhi::FrameOpResult QRhiD3D11::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginF
|
|||||||
{
|
{
|
||||||
Q_UNUSED(flags);
|
Q_UNUSED(flags);
|
||||||
|
|
||||||
Q_ASSERT(!inFrame);
|
|
||||||
inFrame = true;
|
|
||||||
|
|
||||||
QD3D11SwapChain *swapChainD = QRHI_RES(QD3D11SwapChain, swapChain);
|
QD3D11SwapChain *swapChainD = QRHI_RES(QD3D11SwapChain, swapChain);
|
||||||
contextState.currentSwapChain = swapChainD;
|
contextState.currentSwapChain = swapChainD;
|
||||||
const int currentFrameSlot = swapChainD->currentFrameSlot;
|
const int currentFrameSlot = swapChainD->currentFrameSlot;
|
||||||
@ -844,9 +848,6 @@ QRhi::FrameOpResult QRhiD3D11::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginF
|
|||||||
|
|
||||||
QRhi::FrameOpResult QRhiD3D11::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags)
|
QRhi::FrameOpResult QRhiD3D11::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags)
|
||||||
{
|
{
|
||||||
Q_ASSERT(inFrame);
|
|
||||||
inFrame = false;
|
|
||||||
|
|
||||||
QD3D11SwapChain *swapChainD = QRHI_RES(QD3D11SwapChain, swapChain);
|
QD3D11SwapChain *swapChainD = QRHI_RES(QD3D11SwapChain, swapChain);
|
||||||
Q_ASSERT(contextState.currentSwapChain = swapChainD);
|
Q_ASSERT(contextState.currentSwapChain = swapChainD);
|
||||||
const int currentFrameSlot = swapChainD->currentFrameSlot;
|
const int currentFrameSlot = swapChainD->currentFrameSlot;
|
||||||
@ -899,8 +900,6 @@ QRhi::FrameOpResult QRhiD3D11::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrame
|
|||||||
|
|
||||||
QRhi::FrameOpResult QRhiD3D11::beginOffscreenFrame(QRhiCommandBuffer **cb)
|
QRhi::FrameOpResult QRhiD3D11::beginOffscreenFrame(QRhiCommandBuffer **cb)
|
||||||
{
|
{
|
||||||
Q_ASSERT(!inFrame);
|
|
||||||
inFrame = true;
|
|
||||||
ofr.active = true;
|
ofr.active = true;
|
||||||
|
|
||||||
ofr.cbWrapper.resetState();
|
ofr.cbWrapper.resetState();
|
||||||
@ -911,8 +910,6 @@ QRhi::FrameOpResult QRhiD3D11::beginOffscreenFrame(QRhiCommandBuffer **cb)
|
|||||||
|
|
||||||
QRhi::FrameOpResult QRhiD3D11::endOffscreenFrame()
|
QRhi::FrameOpResult QRhiD3D11::endOffscreenFrame()
|
||||||
{
|
{
|
||||||
Q_ASSERT(inFrame && ofr.active);
|
|
||||||
inFrame = false;
|
|
||||||
ofr.active = false;
|
ofr.active = false;
|
||||||
|
|
||||||
executeCommandBuffer(&ofr.cbWrapper);
|
executeCommandBuffer(&ofr.cbWrapper);
|
||||||
@ -1047,8 +1044,6 @@ static inline bool isDepthTextureFormat(QRhiTexture::Format format)
|
|||||||
|
|
||||||
QRhi::FrameOpResult QRhiD3D11::finish()
|
QRhi::FrameOpResult QRhiD3D11::finish()
|
||||||
{
|
{
|
||||||
Q_ASSERT(!inPass);
|
|
||||||
|
|
||||||
if (inFrame)
|
if (inFrame)
|
||||||
flushCommandBuffer();
|
flushCommandBuffer();
|
||||||
|
|
||||||
@ -1379,7 +1374,7 @@ static inline QD3D11RenderTargetData *rtData(QRhiRenderTarget *rt)
|
|||||||
|
|
||||||
void QRhiD3D11::resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
|
void QRhiD3D11::resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
|
||||||
{
|
{
|
||||||
Q_ASSERT(inFrame && !inPass);
|
Q_ASSERT(QRHI_RES(QD3D11CommandBuffer, cb)->recordingPass == QD3D11CommandBuffer::NoPass);
|
||||||
|
|
||||||
enqueueResourceUpdates(cb, resourceUpdates);
|
enqueueResourceUpdates(cb, resourceUpdates);
|
||||||
}
|
}
|
||||||
@ -1398,12 +1393,12 @@ void QRhiD3D11::beginPass(QRhiCommandBuffer *cb,
|
|||||||
const QRhiDepthStencilClearValue &depthStencilClearValue,
|
const QRhiDepthStencilClearValue &depthStencilClearValue,
|
||||||
QRhiResourceUpdateBatch *resourceUpdates)
|
QRhiResourceUpdateBatch *resourceUpdates)
|
||||||
{
|
{
|
||||||
Q_ASSERT(inFrame && !inPass);
|
QD3D11CommandBuffer *cbD = QRHI_RES(QD3D11CommandBuffer, cb);
|
||||||
|
Q_ASSERT(cbD->recordingPass == QD3D11CommandBuffer::NoPass);
|
||||||
|
|
||||||
if (resourceUpdates)
|
if (resourceUpdates)
|
||||||
enqueueResourceUpdates(cb, resourceUpdates);
|
enqueueResourceUpdates(cb, resourceUpdates);
|
||||||
|
|
||||||
QD3D11CommandBuffer *cbD = QRHI_RES(QD3D11CommandBuffer, cb);
|
|
||||||
bool wantsColorClear = true;
|
bool wantsColorClear = true;
|
||||||
bool wantsDsClear = true;
|
bool wantsDsClear = true;
|
||||||
QD3D11RenderTargetData *rtD = rtData(rt);
|
QD3D11RenderTargetData *rtD = rtData(rt);
|
||||||
@ -1431,17 +1426,15 @@ void QRhiD3D11::beginPass(QRhiCommandBuffer *cb,
|
|||||||
clearCmd.args.clear.s = depthStencilClearValue.stencilClearValue();
|
clearCmd.args.clear.s = depthStencilClearValue.stencilClearValue();
|
||||||
cbD->commands.append(clearCmd);
|
cbD->commands.append(clearCmd);
|
||||||
|
|
||||||
|
cbD->recordingPass = QD3D11CommandBuffer::RenderPass;
|
||||||
cbD->currentTarget = rt;
|
cbD->currentTarget = rt;
|
||||||
|
|
||||||
inPass = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QRhiD3D11::endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
|
void QRhiD3D11::endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
|
||||||
{
|
{
|
||||||
Q_ASSERT(inPass);
|
|
||||||
inPass = false;
|
|
||||||
|
|
||||||
QD3D11CommandBuffer *cbD = QRHI_RES(QD3D11CommandBuffer, cb);
|
QD3D11CommandBuffer *cbD = QRHI_RES(QD3D11CommandBuffer, cb);
|
||||||
|
Q_ASSERT(cbD->recordingPass == QD3D11CommandBuffer::RenderPass);
|
||||||
|
|
||||||
if (cbD->currentTarget->resourceType() == QRhiResource::TextureRenderTarget) {
|
if (cbD->currentTarget->resourceType() == QRhiResource::TextureRenderTarget) {
|
||||||
QD3D11TextureRenderTarget *rtTex = QRHI_RES(QD3D11TextureRenderTarget, cbD->currentTarget);
|
QD3D11TextureRenderTarget *rtTex = QRHI_RES(QD3D11TextureRenderTarget, cbD->currentTarget);
|
||||||
const QVector<QRhiColorAttachment> colorAttachments = rtTex->m_desc.colorAttachments();
|
const QVector<QRhiColorAttachment> colorAttachments = rtTex->m_desc.colorAttachments();
|
||||||
@ -1491,12 +1484,49 @@ void QRhiD3D11::endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resource
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cbD->recordingPass = QD3D11CommandBuffer::NoPass;
|
||||||
cbD->currentTarget = nullptr;
|
cbD->currentTarget = nullptr;
|
||||||
|
|
||||||
if (resourceUpdates)
|
if (resourceUpdates)
|
||||||
enqueueResourceUpdates(cb, resourceUpdates);
|
enqueueResourceUpdates(cb, resourceUpdates);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QRhiD3D11::beginComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
|
||||||
|
{
|
||||||
|
QD3D11CommandBuffer *cbD = QRHI_RES(QD3D11CommandBuffer, cb);
|
||||||
|
Q_ASSERT(cbD->recordingPass == QD3D11CommandBuffer::NoPass);
|
||||||
|
|
||||||
|
if (resourceUpdates)
|
||||||
|
enqueueResourceUpdates(cb, resourceUpdates);
|
||||||
|
|
||||||
|
cbD->recordingPass = QD3D11CommandBuffer::ComputePass;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QRhiD3D11::endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
|
||||||
|
{
|
||||||
|
QD3D11CommandBuffer *cbD = QRHI_RES(QD3D11CommandBuffer, cb);
|
||||||
|
Q_ASSERT(cbD->recordingPass == QD3D11CommandBuffer::ComputePass);
|
||||||
|
|
||||||
|
cbD->recordingPass = QD3D11CommandBuffer::NoPass;
|
||||||
|
|
||||||
|
if (resourceUpdates)
|
||||||
|
enqueueResourceUpdates(cb, resourceUpdates);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QRhiD3D11::setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps)
|
||||||
|
{
|
||||||
|
Q_UNUSED(cb);
|
||||||
|
Q_UNUSED(ps);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QRhiD3D11::dispatch(QRhiCommandBuffer *cb, int x, int y, int z)
|
||||||
|
{
|
||||||
|
Q_UNUSED(cb);
|
||||||
|
Q_UNUSED(x);
|
||||||
|
Q_UNUSED(y);
|
||||||
|
Q_UNUSED(z);
|
||||||
|
}
|
||||||
|
|
||||||
void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD)
|
void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD)
|
||||||
{
|
{
|
||||||
srbD->vsubufs.clear();
|
srbD->vsubufs.clear();
|
||||||
@ -1709,6 +1739,8 @@ void QRhiD3D11::setRenderTarget(QRhiRenderTarget *rt)
|
|||||||
|
|
||||||
void QRhiD3D11::executeCommandBuffer(QD3D11CommandBuffer *cbD, QD3D11SwapChain *timestampSwapChain)
|
void QRhiD3D11::executeCommandBuffer(QD3D11CommandBuffer *cbD, QD3D11SwapChain *timestampSwapChain)
|
||||||
{
|
{
|
||||||
|
Q_ASSERT(cbD->recordingPass == QD3D11CommandBuffer::NoPass);
|
||||||
|
|
||||||
quint32 stencilRef = 0;
|
quint32 stencilRef = 0;
|
||||||
float blendConstants[] = { 1, 1, 1, 1 };
|
float blendConstants[] = { 1, 1, 1, 1 };
|
||||||
|
|
||||||
@ -1911,6 +1943,11 @@ bool QD3D11Buffer::build()
|
|||||||
if (buffer)
|
if (buffer)
|
||||||
release();
|
release();
|
||||||
|
|
||||||
|
if (m_usage.testFlag(QRhiBuffer::UniformBuffer) && m_type != Dynamic) {
|
||||||
|
qWarning("UniformBuffer must always be combined with Dynamic on D3D11");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const int nonZeroSize = m_size <= 0 ? 256 : m_size;
|
const int nonZeroSize = m_size <= 0 ? 256 : m_size;
|
||||||
const int roundedSize = m_usage.testFlag(QRhiBuffer::UniformBuffer) ? aligned(nonZeroSize, 256) : nonZeroSize;
|
const int roundedSize = m_usage.testFlag(QRhiBuffer::UniformBuffer) ? aligned(nonZeroSize, 256) : nonZeroSize;
|
||||||
|
|
||||||
@ -3008,7 +3045,7 @@ bool QD3D11GraphicsPipeline::build()
|
|||||||
}
|
}
|
||||||
|
|
||||||
QByteArray vsByteCode;
|
QByteArray vsByteCode;
|
||||||
for (const QRhiGraphicsShaderStage &shaderStage : qAsConst(m_shaderStages)) {
|
for (const QRhiShaderStage &shaderStage : qAsConst(m_shaderStages)) {
|
||||||
QString error;
|
QString error;
|
||||||
QByteArray bytecode = compileHlslShaderSource(shaderStage.shader(), shaderStage.shaderVariant(), &error);
|
QByteArray bytecode = compileHlslShaderSource(shaderStage.shader(), shaderStage.shaderVariant(), &error);
|
||||||
if (bytecode.isEmpty()) {
|
if (bytecode.isEmpty()) {
|
||||||
@ -3016,7 +3053,7 @@ bool QD3D11GraphicsPipeline::build()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
switch (shaderStage.type()) {
|
switch (shaderStage.type()) {
|
||||||
case QRhiGraphicsShaderStage::Vertex:
|
case QRhiShaderStage::Vertex:
|
||||||
hr = rhiD->dev->CreateVertexShader(bytecode.constData(), bytecode.size(), nullptr, &vs);
|
hr = rhiD->dev->CreateVertexShader(bytecode.constData(), bytecode.size(), nullptr, &vs);
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
qWarning("Failed to create vertex shader: %s", qPrintable(comErrorMessage(hr)));
|
qWarning("Failed to create vertex shader: %s", qPrintable(comErrorMessage(hr)));
|
||||||
@ -3024,7 +3061,7 @@ bool QD3D11GraphicsPipeline::build()
|
|||||||
}
|
}
|
||||||
vsByteCode = bytecode;
|
vsByteCode = bytecode;
|
||||||
break;
|
break;
|
||||||
case QRhiGraphicsShaderStage::Fragment:
|
case QRhiShaderStage::Fragment:
|
||||||
hr = rhiD->dev->CreatePixelShader(bytecode.constData(), bytecode.size(), nullptr, &fs);
|
hr = rhiD->dev->CreatePixelShader(bytecode.constData(), bytecode.size(), nullptr, &fs);
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
qWarning("Failed to create pixel shader: %s", qPrintable(comErrorMessage(hr)));
|
qWarning("Failed to create pixel shader: %s", qPrintable(comErrorMessage(hr)));
|
||||||
@ -3072,6 +3109,25 @@ bool QD3D11GraphicsPipeline::build()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QD3D11ComputePipeline::QD3D11ComputePipeline(QRhiImplementation *rhi)
|
||||||
|
: QRhiComputePipeline(rhi)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QD3D11ComputePipeline::~QD3D11ComputePipeline()
|
||||||
|
{
|
||||||
|
release();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QD3D11ComputePipeline::release()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QD3D11ComputePipeline::build()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
QD3D11CommandBuffer::QD3D11CommandBuffer(QRhiImplementation *rhi)
|
QD3D11CommandBuffer::QD3D11CommandBuffer(QRhiImplementation *rhi)
|
||||||
: QRhiCommandBuffer(rhi)
|
: QRhiCommandBuffer(rhi)
|
||||||
{
|
{
|
||||||
|
@ -254,6 +254,14 @@ struct QD3D11GraphicsPipeline : public QRhiGraphicsPipeline
|
|||||||
friend class QRhiD3D11;
|
friend class QRhiD3D11;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct QD3D11ComputePipeline : public QRhiComputePipeline
|
||||||
|
{
|
||||||
|
QD3D11ComputePipeline(QRhiImplementation *rhi);
|
||||||
|
~QD3D11ComputePipeline();
|
||||||
|
void release() override;
|
||||||
|
bool build() override;
|
||||||
|
};
|
||||||
|
|
||||||
struct QD3D11SwapChain;
|
struct QD3D11SwapChain;
|
||||||
|
|
||||||
struct QD3D11CommandBuffer : public QRhiCommandBuffer
|
struct QD3D11CommandBuffer : public QRhiCommandBuffer
|
||||||
@ -387,7 +395,14 @@ struct QD3D11CommandBuffer : public QRhiCommandBuffer
|
|||||||
} args;
|
} args;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum PassType {
|
||||||
|
NoPass,
|
||||||
|
RenderPass,
|
||||||
|
ComputePass
|
||||||
|
};
|
||||||
|
|
||||||
QVector<Command> commands;
|
QVector<Command> commands;
|
||||||
|
PassType recordingPass;
|
||||||
QRhiRenderTarget *currentTarget;
|
QRhiRenderTarget *currentTarget;
|
||||||
QRhiGraphicsPipeline *currentPipeline;
|
QRhiGraphicsPipeline *currentPipeline;
|
||||||
uint currentPipelineGeneration;
|
uint currentPipelineGeneration;
|
||||||
@ -418,6 +433,7 @@ struct QD3D11CommandBuffer : public QRhiCommandBuffer
|
|||||||
}
|
}
|
||||||
void resetState() {
|
void resetState() {
|
||||||
resetCommands();
|
resetCommands();
|
||||||
|
recordingPass = NoPass;
|
||||||
currentTarget = nullptr;
|
currentTarget = nullptr;
|
||||||
resetCachedState();
|
resetCachedState();
|
||||||
}
|
}
|
||||||
@ -484,6 +500,7 @@ public:
|
|||||||
void destroy() override;
|
void destroy() override;
|
||||||
|
|
||||||
QRhiGraphicsPipeline *createGraphicsPipeline() override;
|
QRhiGraphicsPipeline *createGraphicsPipeline() override;
|
||||||
|
QRhiComputePipeline *createComputePipeline() override;
|
||||||
QRhiShaderResourceBindings *createShaderResourceBindings() override;
|
QRhiShaderResourceBindings *createShaderResourceBindings() override;
|
||||||
QRhiBuffer *createBuffer(QRhiBuffer::Type type,
|
QRhiBuffer *createBuffer(QRhiBuffer::Type type,
|
||||||
QRhiBuffer::UsageFlags usage,
|
QRhiBuffer::UsageFlags usage,
|
||||||
@ -548,6 +565,11 @@ public:
|
|||||||
void debugMarkEnd(QRhiCommandBuffer *cb) override;
|
void debugMarkEnd(QRhiCommandBuffer *cb) override;
|
||||||
void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) override;
|
void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) override;
|
||||||
|
|
||||||
|
void beginComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
|
||||||
|
void endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
|
||||||
|
void setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps) override;
|
||||||
|
void dispatch(QRhiCommandBuffer *cb, int x, int y, int z) override;
|
||||||
|
|
||||||
const QRhiNativeHandles *nativeHandles(QRhiCommandBuffer *cb) override;
|
const QRhiNativeHandles *nativeHandles(QRhiCommandBuffer *cb) override;
|
||||||
void beginExternal(QRhiCommandBuffer *cb) override;
|
void beginExternal(QRhiCommandBuffer *cb) override;
|
||||||
void endExternal(QRhiCommandBuffer *cb) override;
|
void endExternal(QRhiCommandBuffer *cb) override;
|
||||||
@ -591,9 +613,6 @@ public:
|
|||||||
bool hasDxgi2 = false;
|
bool hasDxgi2 = false;
|
||||||
QRhiD3D11NativeHandles nativeHandlesStruct;
|
QRhiD3D11NativeHandles nativeHandlesStruct;
|
||||||
|
|
||||||
bool inFrame = false;
|
|
||||||
bool inPass = false;
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
int vsHighestActiveSrvBinding = -1;
|
int vsHighestActiveSrvBinding = -1;
|
||||||
int fsHighestActiveSrvBinding = -1;
|
int fsHighestActiveSrvBinding = -1;
|
||||||
|
@ -616,6 +616,8 @@ bool QRhiGles2::isFeatureSupported(QRhi::Feature feature) const
|
|||||||
return caps.coreProfile;
|
return caps.coreProfile;
|
||||||
case QRhi::ElementIndexUint:
|
case QRhi::ElementIndexUint:
|
||||||
return caps.elementIndexUint;
|
return caps.elementIndexUint;
|
||||||
|
case QRhi::Compute:
|
||||||
|
return false;
|
||||||
default:
|
default:
|
||||||
Q_UNREACHABLE();
|
Q_UNREACHABLE();
|
||||||
return false;
|
return false;
|
||||||
@ -692,11 +694,15 @@ QRhiShaderResourceBindings *QRhiGles2::createShaderResourceBindings()
|
|||||||
return new QGles2ShaderResourceBindings(this);
|
return new QGles2ShaderResourceBindings(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QRhiComputePipeline *QRhiGles2::createComputePipeline()
|
||||||
|
{
|
||||||
|
return new QGles2ComputePipeline(this);
|
||||||
|
}
|
||||||
|
|
||||||
void QRhiGles2::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline *ps)
|
void QRhiGles2::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline *ps)
|
||||||
{
|
{
|
||||||
Q_ASSERT(inPass);
|
|
||||||
|
|
||||||
QGles2CommandBuffer *cbD = QRHI_RES(QGles2CommandBuffer, cb);
|
QGles2CommandBuffer *cbD = QRHI_RES(QGles2CommandBuffer, cb);
|
||||||
|
Q_ASSERT(cbD->recordingPass == QGles2CommandBuffer::RenderPass);
|
||||||
QGles2GraphicsPipeline *psD = QRHI_RES(QGles2GraphicsPipeline, ps);
|
QGles2GraphicsPipeline *psD = QRHI_RES(QGles2GraphicsPipeline, ps);
|
||||||
const bool pipelineChanged = cbD->currentPipeline != ps || cbD->currentPipelineGeneration != psD->generation;
|
const bool pipelineChanged = cbD->currentPipeline != ps || cbD->currentPipelineGeneration != psD->generation;
|
||||||
|
|
||||||
@ -715,9 +721,8 @@ void QRhiGles2::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind
|
|||||||
int dynamicOffsetCount,
|
int dynamicOffsetCount,
|
||||||
const QRhiCommandBuffer::DynamicOffset *dynamicOffsets)
|
const QRhiCommandBuffer::DynamicOffset *dynamicOffsets)
|
||||||
{
|
{
|
||||||
Q_ASSERT(inPass);
|
|
||||||
|
|
||||||
QGles2CommandBuffer *cbD = QRHI_RES(QGles2CommandBuffer, cb);
|
QGles2CommandBuffer *cbD = QRHI_RES(QGles2CommandBuffer, cb);
|
||||||
|
Q_ASSERT(cbD->recordingPass == QGles2CommandBuffer::RenderPass);
|
||||||
Q_ASSERT(cbD->currentPipeline);
|
Q_ASSERT(cbD->currentPipeline);
|
||||||
|
|
||||||
if (!srb)
|
if (!srb)
|
||||||
@ -770,8 +775,8 @@ void QRhiGles2::setVertexInput(QRhiCommandBuffer *cb,
|
|||||||
int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings,
|
int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings,
|
||||||
QRhiBuffer *indexBuf, quint32 indexOffset, QRhiCommandBuffer::IndexFormat indexFormat)
|
QRhiBuffer *indexBuf, quint32 indexOffset, QRhiCommandBuffer::IndexFormat indexFormat)
|
||||||
{
|
{
|
||||||
Q_ASSERT(inPass);
|
|
||||||
QGles2CommandBuffer *cbD = QRHI_RES(QGles2CommandBuffer, cb);
|
QGles2CommandBuffer *cbD = QRHI_RES(QGles2CommandBuffer, cb);
|
||||||
|
Q_ASSERT(cbD->recordingPass == QGles2CommandBuffer::RenderPass);
|
||||||
|
|
||||||
for (int i = 0; i < bindingCount; ++i) {
|
for (int i = 0; i < bindingCount; ++i) {
|
||||||
QRhiBuffer *buf = bindings[i].first;
|
QRhiBuffer *buf = bindings[i].first;
|
||||||
@ -801,7 +806,9 @@ void QRhiGles2::setVertexInput(QRhiCommandBuffer *cb,
|
|||||||
|
|
||||||
void QRhiGles2::setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport)
|
void QRhiGles2::setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport)
|
||||||
{
|
{
|
||||||
Q_ASSERT(inPass);
|
QGles2CommandBuffer *cbD = QRHI_RES(QGles2CommandBuffer, cb);
|
||||||
|
Q_ASSERT(cbD->recordingPass == QGles2CommandBuffer::RenderPass);
|
||||||
|
|
||||||
QGles2CommandBuffer::Command cmd;
|
QGles2CommandBuffer::Command cmd;
|
||||||
cmd.cmd = QGles2CommandBuffer::Command::Viewport;
|
cmd.cmd = QGles2CommandBuffer::Command::Viewport;
|
||||||
const std::array<float, 4> r = viewport.viewport();
|
const std::array<float, 4> r = viewport.viewport();
|
||||||
@ -811,12 +818,14 @@ void QRhiGles2::setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport)
|
|||||||
cmd.args.viewport.h = r[3];
|
cmd.args.viewport.h = r[3];
|
||||||
cmd.args.viewport.d0 = viewport.minDepth();
|
cmd.args.viewport.d0 = viewport.minDepth();
|
||||||
cmd.args.viewport.d1 = viewport.maxDepth();
|
cmd.args.viewport.d1 = viewport.maxDepth();
|
||||||
QRHI_RES(QGles2CommandBuffer, cb)->commands.append(cmd);
|
cbD->commands.append(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QRhiGles2::setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor)
|
void QRhiGles2::setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor)
|
||||||
{
|
{
|
||||||
Q_ASSERT(inPass);
|
QGles2CommandBuffer *cbD = QRHI_RES(QGles2CommandBuffer, cb);
|
||||||
|
Q_ASSERT(cbD->recordingPass == QGles2CommandBuffer::RenderPass);
|
||||||
|
|
||||||
QGles2CommandBuffer::Command cmd;
|
QGles2CommandBuffer::Command cmd;
|
||||||
cmd.cmd = QGles2CommandBuffer::Command::Scissor;
|
cmd.cmd = QGles2CommandBuffer::Command::Scissor;
|
||||||
const std::array<int, 4> r = scissor.scissor();
|
const std::array<int, 4> r = scissor.scissor();
|
||||||
@ -824,25 +833,27 @@ void QRhiGles2::setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor)
|
|||||||
cmd.args.scissor.y = qMax(0, r[1]);
|
cmd.args.scissor.y = qMax(0, r[1]);
|
||||||
cmd.args.scissor.w = r[2];
|
cmd.args.scissor.w = r[2];
|
||||||
cmd.args.scissor.h = r[3];
|
cmd.args.scissor.h = r[3];
|
||||||
QRHI_RES(QGles2CommandBuffer, cb)->commands.append(cmd);
|
cbD->commands.append(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QRhiGles2::setBlendConstants(QRhiCommandBuffer *cb, const QColor &c)
|
void QRhiGles2::setBlendConstants(QRhiCommandBuffer *cb, const QColor &c)
|
||||||
{
|
{
|
||||||
Q_ASSERT(inPass);
|
QGles2CommandBuffer *cbD = QRHI_RES(QGles2CommandBuffer, cb);
|
||||||
|
Q_ASSERT(cbD->recordingPass == QGles2CommandBuffer::RenderPass);
|
||||||
|
|
||||||
QGles2CommandBuffer::Command cmd;
|
QGles2CommandBuffer::Command cmd;
|
||||||
cmd.cmd = QGles2CommandBuffer::Command::BlendConstants;
|
cmd.cmd = QGles2CommandBuffer::Command::BlendConstants;
|
||||||
cmd.args.blendConstants.r = c.redF();
|
cmd.args.blendConstants.r = c.redF();
|
||||||
cmd.args.blendConstants.g = c.greenF();
|
cmd.args.blendConstants.g = c.greenF();
|
||||||
cmd.args.blendConstants.b = c.blueF();
|
cmd.args.blendConstants.b = c.blueF();
|
||||||
cmd.args.blendConstants.a = c.alphaF();
|
cmd.args.blendConstants.a = c.alphaF();
|
||||||
QRHI_RES(QGles2CommandBuffer, cb)->commands.append(cmd);
|
cbD->commands.append(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QRhiGles2::setStencilRef(QRhiCommandBuffer *cb, quint32 refValue)
|
void QRhiGles2::setStencilRef(QRhiCommandBuffer *cb, quint32 refValue)
|
||||||
{
|
{
|
||||||
Q_ASSERT(inPass);
|
|
||||||
QGles2CommandBuffer *cbD = QRHI_RES(QGles2CommandBuffer, cb);
|
QGles2CommandBuffer *cbD = QRHI_RES(QGles2CommandBuffer, cb);
|
||||||
|
Q_ASSERT(cbD->recordingPass == QGles2CommandBuffer::RenderPass);
|
||||||
|
|
||||||
QGles2CommandBuffer::Command cmd;
|
QGles2CommandBuffer::Command cmd;
|
||||||
cmd.cmd = QGles2CommandBuffer::Command::StencilRef;
|
cmd.cmd = QGles2CommandBuffer::Command::StencilRef;
|
||||||
@ -854,10 +865,10 @@ 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_ASSERT(inPass);
|
|
||||||
Q_UNUSED(instanceCount); // no instancing
|
Q_UNUSED(instanceCount); // no instancing
|
||||||
Q_UNUSED(firstInstance);
|
Q_UNUSED(firstInstance);
|
||||||
QGles2CommandBuffer *cbD = QRHI_RES(QGles2CommandBuffer, cb);
|
QGles2CommandBuffer *cbD = QRHI_RES(QGles2CommandBuffer, cb);
|
||||||
|
Q_ASSERT(cbD->recordingPass == QGles2CommandBuffer::RenderPass);
|
||||||
|
|
||||||
QGles2CommandBuffer::Command cmd;
|
QGles2CommandBuffer::Command cmd;
|
||||||
cmd.cmd = QGles2CommandBuffer::Command::Draw;
|
cmd.cmd = QGles2CommandBuffer::Command::Draw;
|
||||||
@ -870,11 +881,11 @@ void QRhiGles2::draw(QRhiCommandBuffer *cb, quint32 vertexCount,
|
|||||||
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_ASSERT(inPass);
|
|
||||||
Q_UNUSED(instanceCount); // no instancing
|
Q_UNUSED(instanceCount); // no instancing
|
||||||
Q_UNUSED(firstInstance);
|
Q_UNUSED(firstInstance);
|
||||||
Q_UNUSED(vertexOffset); // no glDrawElementsBaseVertex
|
Q_UNUSED(vertexOffset); // no glDrawElementsBaseVertex
|
||||||
QGles2CommandBuffer *cbD = QRHI_RES(QGles2CommandBuffer, cb);
|
QGles2CommandBuffer *cbD = QRHI_RES(QGles2CommandBuffer, cb);
|
||||||
|
Q_ASSERT(cbD->recordingPass == QGles2CommandBuffer::RenderPass);
|
||||||
|
|
||||||
QGles2CommandBuffer::Command cmd;
|
QGles2CommandBuffer::Command cmd;
|
||||||
cmd.cmd = QGles2CommandBuffer::Command::DrawIndexed;
|
cmd.cmd = QGles2CommandBuffer::Command::DrawIndexed;
|
||||||
@ -918,18 +929,16 @@ const QRhiNativeHandles *QRhiGles2::nativeHandles(QRhiCommandBuffer *cb)
|
|||||||
|
|
||||||
void QRhiGles2::beginExternal(QRhiCommandBuffer *cb)
|
void QRhiGles2::beginExternal(QRhiCommandBuffer *cb)
|
||||||
{
|
{
|
||||||
Q_ASSERT(inPass);
|
|
||||||
Q_UNUSED(cb);
|
Q_UNUSED(cb);
|
||||||
flushCommandBuffer(); // also ensures the context is current
|
flushCommandBuffer(); // also ensures the context is current
|
||||||
}
|
}
|
||||||
|
|
||||||
void QRhiGles2::endExternal(QRhiCommandBuffer *cb)
|
void QRhiGles2::endExternal(QRhiCommandBuffer *cb)
|
||||||
{
|
{
|
||||||
Q_ASSERT(inPass);
|
|
||||||
QGles2CommandBuffer *cbD = QRHI_RES(QGles2CommandBuffer, cb);
|
QGles2CommandBuffer *cbD = QRHI_RES(QGles2CommandBuffer, cb);
|
||||||
Q_ASSERT(cbD->currentTarget);
|
|
||||||
Q_ASSERT(cbD->commands.isEmpty());
|
Q_ASSERT(cbD->commands.isEmpty());
|
||||||
cbD->resetCachedState();
|
cbD->resetCachedState();
|
||||||
|
if (cbD->currentTarget)
|
||||||
enqueueBindFramebuffer(cbD->currentTarget, cbD);
|
enqueueBindFramebuffer(cbD->currentTarget, cbD);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -943,13 +952,11 @@ static void addBoundaryCommand(QGles2CommandBuffer *cb, QGles2CommandBuffer::Com
|
|||||||
QRhi::FrameOpResult QRhiGles2::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags)
|
QRhi::FrameOpResult QRhiGles2::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags)
|
||||||
{
|
{
|
||||||
Q_UNUSED(flags);
|
Q_UNUSED(flags);
|
||||||
Q_ASSERT(!inFrame);
|
|
||||||
|
|
||||||
QGles2SwapChain *swapChainD = QRHI_RES(QGles2SwapChain, swapChain);
|
QGles2SwapChain *swapChainD = QRHI_RES(QGles2SwapChain, swapChain);
|
||||||
if (!ensureContext(swapChainD->surface))
|
if (!ensureContext(swapChainD->surface))
|
||||||
return QRhi::FrameOpError;
|
return QRhi::FrameOpError;
|
||||||
|
|
||||||
inFrame = true;
|
|
||||||
currentSwapChain = swapChainD;
|
currentSwapChain = swapChainD;
|
||||||
|
|
||||||
QRhiProfilerPrivate *rhiP = profilerPrivateOrNull();
|
QRhiProfilerPrivate *rhiP = profilerPrivateOrNull();
|
||||||
@ -965,9 +972,6 @@ QRhi::FrameOpResult QRhiGles2::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginF
|
|||||||
|
|
||||||
QRhi::FrameOpResult QRhiGles2::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags)
|
QRhi::FrameOpResult QRhiGles2::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags)
|
||||||
{
|
{
|
||||||
Q_ASSERT(inFrame);
|
|
||||||
inFrame = false;
|
|
||||||
|
|
||||||
QGles2SwapChain *swapChainD = QRHI_RES(QGles2SwapChain, swapChain);
|
QGles2SwapChain *swapChainD = QRHI_RES(QGles2SwapChain, swapChain);
|
||||||
Q_ASSERT(currentSwapChain == swapChainD);
|
Q_ASSERT(currentSwapChain == swapChainD);
|
||||||
|
|
||||||
@ -996,12 +1000,9 @@ QRhi::FrameOpResult QRhiGles2::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrame
|
|||||||
|
|
||||||
QRhi::FrameOpResult QRhiGles2::beginOffscreenFrame(QRhiCommandBuffer **cb)
|
QRhi::FrameOpResult QRhiGles2::beginOffscreenFrame(QRhiCommandBuffer **cb)
|
||||||
{
|
{
|
||||||
Q_ASSERT(!inFrame);
|
|
||||||
|
|
||||||
if (!ensureContext())
|
if (!ensureContext())
|
||||||
return QRhi::FrameOpError;
|
return QRhi::FrameOpError;
|
||||||
|
|
||||||
inFrame = true;
|
|
||||||
ofr.active = true;
|
ofr.active = true;
|
||||||
|
|
||||||
executeDeferredReleases();
|
executeDeferredReleases();
|
||||||
@ -1015,8 +1016,7 @@ QRhi::FrameOpResult QRhiGles2::beginOffscreenFrame(QRhiCommandBuffer **cb)
|
|||||||
|
|
||||||
QRhi::FrameOpResult QRhiGles2::endOffscreenFrame()
|
QRhi::FrameOpResult QRhiGles2::endOffscreenFrame()
|
||||||
{
|
{
|
||||||
Q_ASSERT(inFrame && ofr.active);
|
Q_ASSERT(ofr.active);
|
||||||
inFrame = false;
|
|
||||||
ofr.active = false;
|
ofr.active = false;
|
||||||
|
|
||||||
addBoundaryCommand(&ofr.cbWrapper, QGles2CommandBuffer::Command::EndFrame);
|
addBoundaryCommand(&ofr.cbWrapper, QGles2CommandBuffer::Command::EndFrame);
|
||||||
@ -1031,7 +1031,6 @@ QRhi::FrameOpResult QRhiGles2::endOffscreenFrame()
|
|||||||
|
|
||||||
QRhi::FrameOpResult QRhiGles2::finish()
|
QRhi::FrameOpResult QRhiGles2::finish()
|
||||||
{
|
{
|
||||||
Q_ASSERT(!inPass); // because that's what the QRhi docs say, even though not required by this backend
|
|
||||||
return inFrame ? flushCommandBuffer() : QRhi::FrameOpSuccess;
|
return inFrame ? flushCommandBuffer() : QRhi::FrameOpSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1501,6 +1500,8 @@ static inline GLenum toGlTextureCompareFunc(QRhiSampler::CompareOp op)
|
|||||||
void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
|
void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
|
||||||
{
|
{
|
||||||
QGles2CommandBuffer *cbD = QRHI_RES(QGles2CommandBuffer, cb);
|
QGles2CommandBuffer *cbD = QRHI_RES(QGles2CommandBuffer, cb);
|
||||||
|
Q_ASSERT(cbD->recordingPass == QGles2CommandBuffer::NoPass);
|
||||||
|
|
||||||
GLenum indexType = GL_UNSIGNED_SHORT;
|
GLenum indexType = GL_UNSIGNED_SHORT;
|
||||||
quint32 indexStride = sizeof(quint16);
|
quint32 indexStride = sizeof(quint16);
|
||||||
quint32 indexOffset = 0;
|
quint32 indexOffset = 0;
|
||||||
@ -1970,7 +1971,7 @@ void QRhiGles2::bindShaderResources(QRhiGraphicsPipeline *ps, QRhiShaderResource
|
|||||||
|
|
||||||
void QRhiGles2::resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
|
void QRhiGles2::resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
|
||||||
{
|
{
|
||||||
Q_ASSERT(inFrame && !inPass);
|
Q_ASSERT(QRHI_RES(QGles2CommandBuffer, cb)->recordingPass == QGles2CommandBuffer::NoPass);
|
||||||
|
|
||||||
enqueueResourceUpdates(cb, resourceUpdates);
|
enqueueResourceUpdates(cb, resourceUpdates);
|
||||||
}
|
}
|
||||||
@ -2018,12 +2019,12 @@ void QRhiGles2::beginPass(QRhiCommandBuffer *cb,
|
|||||||
const QRhiDepthStencilClearValue &depthStencilClearValue,
|
const QRhiDepthStencilClearValue &depthStencilClearValue,
|
||||||
QRhiResourceUpdateBatch *resourceUpdates)
|
QRhiResourceUpdateBatch *resourceUpdates)
|
||||||
{
|
{
|
||||||
Q_ASSERT(inFrame && !inPass);
|
QGles2CommandBuffer *cbD = QRHI_RES(QGles2CommandBuffer, cb);
|
||||||
|
Q_ASSERT(cbD->recordingPass == QGles2CommandBuffer::NoPass);
|
||||||
|
|
||||||
if (resourceUpdates)
|
if (resourceUpdates)
|
||||||
enqueueResourceUpdates(cb, resourceUpdates);
|
enqueueResourceUpdates(cb, resourceUpdates);
|
||||||
|
|
||||||
QGles2CommandBuffer *cbD = QRHI_RES(QGles2CommandBuffer, cb);
|
|
||||||
bool wantsColorClear, wantsDsClear;
|
bool wantsColorClear, wantsDsClear;
|
||||||
QGles2RenderTargetData *rtD = enqueueBindFramebuffer(rt, cbD, &wantsColorClear, &wantsDsClear);
|
QGles2RenderTargetData *rtD = enqueueBindFramebuffer(rt, cbD, &wantsColorClear, &wantsDsClear);
|
||||||
|
|
||||||
@ -2042,17 +2043,15 @@ void QRhiGles2::beginPass(QRhiCommandBuffer *cb,
|
|||||||
clearCmd.args.clear.s = depthStencilClearValue.stencilClearValue();
|
clearCmd.args.clear.s = depthStencilClearValue.stencilClearValue();
|
||||||
cbD->commands.append(clearCmd);
|
cbD->commands.append(clearCmd);
|
||||||
|
|
||||||
|
cbD->recordingPass = QGles2CommandBuffer::RenderPass;
|
||||||
cbD->currentTarget = rt;
|
cbD->currentTarget = rt;
|
||||||
|
|
||||||
inPass = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QRhiGles2::endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
|
void QRhiGles2::endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
|
||||||
{
|
{
|
||||||
Q_ASSERT(inPass);
|
|
||||||
inPass = false;
|
|
||||||
|
|
||||||
QGles2CommandBuffer *cbD = QRHI_RES(QGles2CommandBuffer, cb);
|
QGles2CommandBuffer *cbD = QRHI_RES(QGles2CommandBuffer, cb);
|
||||||
|
Q_ASSERT(cbD->recordingPass == QGles2CommandBuffer::RenderPass);
|
||||||
|
|
||||||
if (cbD->currentTarget->resourceType() == QRhiResource::TextureRenderTarget) {
|
if (cbD->currentTarget->resourceType() == QRhiResource::TextureRenderTarget) {
|
||||||
QGles2TextureRenderTarget *rtTex = QRHI_RES(QGles2TextureRenderTarget, cbD->currentTarget);
|
QGles2TextureRenderTarget *rtTex = QRHI_RES(QGles2TextureRenderTarget, cbD->currentTarget);
|
||||||
const QVector<QRhiColorAttachment> colorAttachments = rtTex->m_desc.colorAttachments();
|
const QVector<QRhiColorAttachment> colorAttachments = rtTex->m_desc.colorAttachments();
|
||||||
@ -2083,12 +2082,49 @@ void QRhiGles2::endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resource
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cbD->recordingPass = QGles2CommandBuffer::NoPass;
|
||||||
cbD->currentTarget = nullptr;
|
cbD->currentTarget = nullptr;
|
||||||
|
|
||||||
if (resourceUpdates)
|
if (resourceUpdates)
|
||||||
enqueueResourceUpdates(cb, resourceUpdates);
|
enqueueResourceUpdates(cb, resourceUpdates);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QRhiGles2::beginComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
|
||||||
|
{
|
||||||
|
QGles2CommandBuffer *cbD = QRHI_RES(QGles2CommandBuffer, cb);
|
||||||
|
Q_ASSERT(cbD->recordingPass == QGles2CommandBuffer::NoPass);
|
||||||
|
|
||||||
|
if (resourceUpdates)
|
||||||
|
enqueueResourceUpdates(cb, resourceUpdates);
|
||||||
|
|
||||||
|
cbD->recordingPass = QGles2CommandBuffer::ComputePass;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QRhiGles2::endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
|
||||||
|
{
|
||||||
|
QGles2CommandBuffer *cbD = QRHI_RES(QGles2CommandBuffer, cb);
|
||||||
|
Q_ASSERT(cbD->recordingPass == QGles2CommandBuffer::ComputePass);
|
||||||
|
|
||||||
|
cbD->recordingPass = QGles2CommandBuffer::NoPass;
|
||||||
|
|
||||||
|
if (resourceUpdates)
|
||||||
|
enqueueResourceUpdates(cb, resourceUpdates);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QRhiGles2::setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps)
|
||||||
|
{
|
||||||
|
Q_UNUSED(cb);
|
||||||
|
Q_UNUSED(ps);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QRhiGles2::dispatch(QRhiCommandBuffer *cb, int x, int y, int z)
|
||||||
|
{
|
||||||
|
Q_UNUSED(cb);
|
||||||
|
Q_UNUSED(x);
|
||||||
|
Q_UNUSED(y);
|
||||||
|
Q_UNUSED(z);
|
||||||
|
}
|
||||||
|
|
||||||
QGles2Buffer::QGles2Buffer(QRhiImplementation *rhi, Type type, UsageFlags usage, int size)
|
QGles2Buffer::QGles2Buffer(QRhiImplementation *rhi, Type type, UsageFlags usage, int size)
|
||||||
: QRhiBuffer(rhi, type, usage, size)
|
: QRhiBuffer(rhi, type, usage, size)
|
||||||
{
|
{
|
||||||
@ -2742,9 +2778,9 @@ bool QGles2GraphicsPipeline::build()
|
|||||||
program = rhiD->f->glCreateProgram();
|
program = rhiD->f->glCreateProgram();
|
||||||
|
|
||||||
int sourceVer = 0;
|
int sourceVer = 0;
|
||||||
for (const QRhiGraphicsShaderStage &shaderStage : qAsConst(m_shaderStages)) {
|
for (const QRhiShaderStage &shaderStage : qAsConst(m_shaderStages)) {
|
||||||
const bool isVertex = shaderStage.type() == QRhiGraphicsShaderStage::Vertex;
|
const bool isVertex = shaderStage.type() == QRhiShaderStage::Vertex;
|
||||||
const bool isFragment = shaderStage.type() == QRhiGraphicsShaderStage::Fragment;
|
const bool isFragment = shaderStage.type() == QRhiShaderStage::Fragment;
|
||||||
if (!isVertex && !isFragment)
|
if (!isVertex && !isFragment)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -2902,6 +2938,25 @@ bool QGles2GraphicsPipeline::build()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QGles2ComputePipeline::QGles2ComputePipeline(QRhiImplementation *rhi)
|
||||||
|
: QRhiComputePipeline(rhi)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QGles2ComputePipeline::~QGles2ComputePipeline()
|
||||||
|
{
|
||||||
|
release();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QGles2ComputePipeline::release()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QGles2ComputePipeline::build()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
QGles2CommandBuffer::QGles2CommandBuffer(QRhiImplementation *rhi)
|
QGles2CommandBuffer::QGles2CommandBuffer(QRhiImplementation *rhi)
|
||||||
: QRhiCommandBuffer(rhi)
|
: QRhiCommandBuffer(rhi)
|
||||||
{
|
{
|
||||||
|
@ -248,6 +248,14 @@ struct QGles2GraphicsPipeline : public QRhiGraphicsPipeline
|
|||||||
Q_DECLARE_TYPEINFO(QGles2GraphicsPipeline::Uniform, Q_MOVABLE_TYPE);
|
Q_DECLARE_TYPEINFO(QGles2GraphicsPipeline::Uniform, Q_MOVABLE_TYPE);
|
||||||
Q_DECLARE_TYPEINFO(QGles2GraphicsPipeline::Sampler, Q_MOVABLE_TYPE);
|
Q_DECLARE_TYPEINFO(QGles2GraphicsPipeline::Sampler, Q_MOVABLE_TYPE);
|
||||||
|
|
||||||
|
struct QGles2ComputePipeline : public QRhiComputePipeline
|
||||||
|
{
|
||||||
|
QGles2ComputePipeline(QRhiImplementation *rhi);
|
||||||
|
~QGles2ComputePipeline();
|
||||||
|
void release() override;
|
||||||
|
bool build() override;
|
||||||
|
};
|
||||||
|
|
||||||
struct QGles2CommandBuffer : public QRhiCommandBuffer
|
struct QGles2CommandBuffer : public QRhiCommandBuffer
|
||||||
{
|
{
|
||||||
QGles2CommandBuffer(QRhiImplementation *rhi);
|
QGles2CommandBuffer(QRhiImplementation *rhi);
|
||||||
@ -426,7 +434,14 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer
|
|||||||
} args;
|
} args;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum PassType {
|
||||||
|
NoPass,
|
||||||
|
RenderPass,
|
||||||
|
ComputePass
|
||||||
|
};
|
||||||
|
|
||||||
QVector<Command> commands;
|
QVector<Command> commands;
|
||||||
|
PassType recordingPass;
|
||||||
QRhiRenderTarget *currentTarget;
|
QRhiRenderTarget *currentTarget;
|
||||||
QRhiGraphicsPipeline *currentPipeline;
|
QRhiGraphicsPipeline *currentPipeline;
|
||||||
uint currentPipelineGeneration;
|
uint currentPipelineGeneration;
|
||||||
@ -452,6 +467,7 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer
|
|||||||
}
|
}
|
||||||
void resetState() {
|
void resetState() {
|
||||||
resetCommands();
|
resetCommands();
|
||||||
|
recordingPass = NoPass;
|
||||||
currentTarget = nullptr;
|
currentTarget = nullptr;
|
||||||
resetCachedState();
|
resetCachedState();
|
||||||
}
|
}
|
||||||
@ -495,6 +511,7 @@ public:
|
|||||||
void destroy() override;
|
void destroy() override;
|
||||||
|
|
||||||
QRhiGraphicsPipeline *createGraphicsPipeline() override;
|
QRhiGraphicsPipeline *createGraphicsPipeline() override;
|
||||||
|
QRhiComputePipeline *createComputePipeline() override;
|
||||||
QRhiShaderResourceBindings *createShaderResourceBindings() override;
|
QRhiShaderResourceBindings *createShaderResourceBindings() override;
|
||||||
QRhiBuffer *createBuffer(QRhiBuffer::Type type,
|
QRhiBuffer *createBuffer(QRhiBuffer::Type type,
|
||||||
QRhiBuffer::UsageFlags usage,
|
QRhiBuffer::UsageFlags usage,
|
||||||
@ -559,6 +576,11 @@ public:
|
|||||||
void debugMarkEnd(QRhiCommandBuffer *cb) override;
|
void debugMarkEnd(QRhiCommandBuffer *cb) override;
|
||||||
void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) override;
|
void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) override;
|
||||||
|
|
||||||
|
void beginComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
|
||||||
|
void endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
|
||||||
|
void setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps) override;
|
||||||
|
void dispatch(QRhiCommandBuffer *cb, int x, int y, int z) override;
|
||||||
|
|
||||||
const QRhiNativeHandles *nativeHandles(QRhiCommandBuffer *cb) override;
|
const QRhiNativeHandles *nativeHandles(QRhiCommandBuffer *cb) override;
|
||||||
void beginExternal(QRhiCommandBuffer *cb) override;
|
void beginExternal(QRhiCommandBuffer *cb) override;
|
||||||
void endExternal(QRhiCommandBuffer *cb) override;
|
void endExternal(QRhiCommandBuffer *cb) override;
|
||||||
@ -645,8 +667,6 @@ public:
|
|||||||
uint uniformBuffers : 1;
|
uint uniformBuffers : 1;
|
||||||
uint elementIndexUint : 1;
|
uint elementIndexUint : 1;
|
||||||
} caps;
|
} caps;
|
||||||
bool inFrame = false;
|
|
||||||
bool inPass = false;
|
|
||||||
QGles2SwapChain *currentSwapChain = nullptr;
|
QGles2SwapChain *currentSwapChain = nullptr;
|
||||||
QVector<GLint> supportedCompressedFormats;
|
QVector<GLint> supportedCompressedFormats;
|
||||||
mutable QVector<int> supportedSampleCountList;
|
mutable QVector<int> supportedSampleCountList;
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
|
|
||||||
#include "qrhimetal_p_p.h"
|
#include "qrhimetal_p_p.h"
|
||||||
#include "qshader_p.h"
|
#include "qshader_p.h"
|
||||||
|
#include "qshaderdescription_p.h"
|
||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
#include <QWindow>
|
#include <QWindow>
|
||||||
#include <qmath.h>
|
#include <qmath.h>
|
||||||
@ -51,14 +52,12 @@ QT_BEGIN_NAMESPACE
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
Metal backend. Double buffers and throttles to vsync. "Dynamic" buffers are
|
Metal backend. Double buffers and throttles to vsync. "Dynamic" buffers are
|
||||||
Shared (host visible) and duplicated (due to 2 frames in flight), "static"
|
Shared (host visible) and duplicated (to help having 2 frames in flight),
|
||||||
are Managed on macOS and Shared on iOS/tvOS, and still duplicated.
|
"static" and "immutable" are Managed on macOS and Shared on iOS/tvOS.
|
||||||
"Immutable" is like "static" but with only one native buffer underneath.
|
|
||||||
Textures are Private (device local) and a host visible staging buffer is
|
Textures are Private (device local) and a host visible staging buffer is
|
||||||
used to upload data to them. Does not rely on strong objects refs from
|
used to upload data to them. Does not rely on strong objects refs from
|
||||||
command buffers (hence uses commandBufferWithUnretainedReferences), but
|
command buffers but does rely on the automatic resource tracking of the
|
||||||
does rely on automatic dependency tracking between encoders (hence no
|
command encoders.
|
||||||
MTLResourceHazardTrackingModeUntracked atm).
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if __has_feature(objc_arc)
|
#if __has_feature(objc_arc)
|
||||||
@ -173,6 +172,7 @@ struct QRhiMetalData
|
|||||||
struct {
|
struct {
|
||||||
id<MTLTexture> texture;
|
id<MTLTexture> texture;
|
||||||
id<MTLBuffer> stagingBuffers[QMTL_FRAMES_IN_FLIGHT];
|
id<MTLBuffer> stagingBuffers[QMTL_FRAMES_IN_FLIGHT];
|
||||||
|
id<MTLTexture> views[QRhi::MAX_LEVELS];
|
||||||
} texture;
|
} texture;
|
||||||
struct {
|
struct {
|
||||||
id<MTLSamplerState> samplerState;
|
id<MTLSamplerState> samplerState;
|
||||||
@ -213,6 +213,7 @@ Q_DECLARE_TYPEINFO(QRhiMetalData::ActiveReadback, Q_MOVABLE_TYPE);
|
|||||||
struct QMetalBufferData
|
struct QMetalBufferData
|
||||||
{
|
{
|
||||||
bool managed;
|
bool managed;
|
||||||
|
bool slotted;
|
||||||
id<MTLBuffer> buf[QMTL_FRAMES_IN_FLIGHT];
|
id<MTLBuffer> buf[QMTL_FRAMES_IN_FLIGHT];
|
||||||
QVector<QRhiResourceUpdateBatchPrivate::DynamicBufferUpdate> pendingUpdates[QMTL_FRAMES_IN_FLIGHT];
|
QVector<QRhiResourceUpdateBatchPrivate::DynamicBufferUpdate> pendingUpdates[QMTL_FRAMES_IN_FLIGHT];
|
||||||
};
|
};
|
||||||
@ -225,10 +226,16 @@ struct QMetalRenderBufferData
|
|||||||
|
|
||||||
struct QMetalTextureData
|
struct QMetalTextureData
|
||||||
{
|
{
|
||||||
|
QMetalTextureData(QMetalTexture *t) : q(t) { }
|
||||||
|
|
||||||
|
QMetalTexture *q;
|
||||||
MTLPixelFormat format;
|
MTLPixelFormat format;
|
||||||
id<MTLTexture> tex = nil;
|
id<MTLTexture> tex = nil;
|
||||||
id<MTLBuffer> stagingBuf[QMTL_FRAMES_IN_FLIGHT];
|
id<MTLBuffer> stagingBuf[QMTL_FRAMES_IN_FLIGHT];
|
||||||
bool owns = true;
|
bool owns = true;
|
||||||
|
id<MTLTexture> perLevelViews[QRhi::MAX_LEVELS];
|
||||||
|
|
||||||
|
id<MTLTexture> viewForLevel(int level);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct QMetalSamplerData
|
struct QMetalSamplerData
|
||||||
@ -239,7 +246,8 @@ struct QMetalSamplerData
|
|||||||
struct QMetalCommandBufferData
|
struct QMetalCommandBufferData
|
||||||
{
|
{
|
||||||
id<MTLCommandBuffer> cb;
|
id<MTLCommandBuffer> cb;
|
||||||
id<MTLRenderCommandEncoder> currentPassEncoder;
|
id<MTLRenderCommandEncoder> currentRenderPassEncoder;
|
||||||
|
id<MTLComputeCommandEncoder> currentComputePassEncoder;
|
||||||
MTLRenderPassDescriptor *currentPassRpDesc;
|
MTLRenderPassDescriptor *currentPassRpDesc;
|
||||||
int currentFirstVertexBinding;
|
int currentFirstVertexBinding;
|
||||||
QRhiBatchedBindings<id<MTLBuffer> > currentVertexInputsBuffers;
|
QRhiBatchedBindings<id<MTLBuffer> > currentVertexInputsBuffers;
|
||||||
@ -286,6 +294,14 @@ struct QMetalGraphicsPipelineData
|
|||||||
id<MTLFunction> fsFunc = nil;
|
id<MTLFunction> fsFunc = nil;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct QMetalComputePipelineData
|
||||||
|
{
|
||||||
|
id<MTLComputePipelineState> ps = nil;
|
||||||
|
id<MTLLibrary> csLib = nil;
|
||||||
|
id<MTLFunction> csFunc = nil;
|
||||||
|
MTLSize localSize;
|
||||||
|
};
|
||||||
|
|
||||||
struct QMetalSwapChainData
|
struct QMetalSwapChainData
|
||||||
{
|
{
|
||||||
CAMetalLayer *layer = nullptr;
|
CAMetalLayer *layer = nullptr;
|
||||||
@ -505,6 +521,8 @@ bool QRhiMetal::isFeatureSupported(QRhi::Feature feature) const
|
|||||||
return true;
|
return true;
|
||||||
case QRhi::ElementIndexUint:
|
case QRhi::ElementIndexUint:
|
||||||
return true;
|
return true;
|
||||||
|
case QRhi::Compute:
|
||||||
|
return true;
|
||||||
default:
|
default:
|
||||||
Q_UNREACHABLE();
|
Q_UNREACHABLE();
|
||||||
return false;
|
return false;
|
||||||
@ -573,6 +591,11 @@ QRhiGraphicsPipeline *QRhiMetal::createGraphicsPipeline()
|
|||||||
return new QMetalGraphicsPipeline(this);
|
return new QMetalGraphicsPipeline(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QRhiComputePipeline *QRhiMetal::createComputePipeline()
|
||||||
|
{
|
||||||
|
return new QMetalComputePipeline(this);
|
||||||
|
}
|
||||||
|
|
||||||
QRhiShaderResourceBindings *QRhiMetal::createShaderResourceBindings()
|
QRhiShaderResourceBindings *QRhiMetal::createShaderResourceBindings()
|
||||||
{
|
{
|
||||||
return new QMetalShaderResourceBindings(this);
|
return new QMetalShaderResourceBindings(this);
|
||||||
@ -583,7 +606,7 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
|
|||||||
const QRhiCommandBuffer::DynamicOffset *dynamicOffsets,
|
const QRhiCommandBuffer::DynamicOffset *dynamicOffsets,
|
||||||
bool offsetOnlyChange)
|
bool offsetOnlyChange)
|
||||||
{
|
{
|
||||||
static const int KNOWN_STAGES = 2;
|
static const int KNOWN_STAGES = 3;
|
||||||
struct {
|
struct {
|
||||||
QRhiBatchedBindings<id<MTLBuffer> > buffers;
|
QRhiBatchedBindings<id<MTLBuffer> > buffers;
|
||||||
QRhiBatchedBindings<NSUInteger> bufferOffsets;
|
QRhiBatchedBindings<NSUInteger> bufferOffsets;
|
||||||
@ -597,7 +620,7 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
|
|||||||
case QRhiShaderResourceBinding::UniformBuffer:
|
case QRhiShaderResourceBinding::UniformBuffer:
|
||||||
{
|
{
|
||||||
QMetalBuffer *bufD = QRHI_RES(QMetalBuffer, b->u.ubuf.buf);
|
QMetalBuffer *bufD = QRHI_RES(QMetalBuffer, b->u.ubuf.buf);
|
||||||
id<MTLBuffer> mtlbuf = bufD->d->buf[bufD->m_type == QRhiBuffer::Immutable ? 0 : currentFrameSlot];
|
id<MTLBuffer> mtlbuf = bufD->d->buf[bufD->d->slotted ? currentFrameSlot : 0];
|
||||||
uint offset = b->u.ubuf.offset;
|
uint offset = b->u.ubuf.offset;
|
||||||
for (int i = 0; i < dynamicOffsetCount; ++i) {
|
for (int i = 0; i < dynamicOffsetCount; ++i) {
|
||||||
const QRhiCommandBuffer::DynamicOffset &dynOfs(dynamicOffsets[i]);
|
const QRhiCommandBuffer::DynamicOffset &dynOfs(dynamicOffsets[i]);
|
||||||
@ -614,6 +637,10 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
|
|||||||
res[1].buffers.feed(b->binding, mtlbuf);
|
res[1].buffers.feed(b->binding, mtlbuf);
|
||||||
res[1].bufferOffsets.feed(b->binding, offset);
|
res[1].bufferOffsets.feed(b->binding, offset);
|
||||||
}
|
}
|
||||||
|
if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
|
||||||
|
res[2].buffers.feed(b->binding, mtlbuf);
|
||||||
|
res[2].bufferOffsets.feed(b->binding, offset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case QRhiShaderResourceBinding::SampledTexture:
|
case QRhiShaderResourceBinding::SampledTexture:
|
||||||
@ -628,6 +655,49 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
|
|||||||
res[1].textures.feed(b->binding, texD->d->tex);
|
res[1].textures.feed(b->binding, texD->d->tex);
|
||||||
res[1].samplers.feed(b->binding, samplerD->d->samplerState);
|
res[1].samplers.feed(b->binding, samplerD->d->samplerState);
|
||||||
}
|
}
|
||||||
|
if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
|
||||||
|
res[2].textures.feed(b->binding, texD->d->tex);
|
||||||
|
res[2].samplers.feed(b->binding, samplerD->d->samplerState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case QRhiShaderResourceBinding::ImageLoad:
|
||||||
|
Q_FALLTHROUGH();
|
||||||
|
case QRhiShaderResourceBinding::ImageStore:
|
||||||
|
Q_FALLTHROUGH();
|
||||||
|
case QRhiShaderResourceBinding::ImageLoadStore:
|
||||||
|
{
|
||||||
|
QMetalTexture *texD = QRHI_RES(QMetalTexture, b->u.simage.tex);
|
||||||
|
id<MTLTexture> t = texD->d->viewForLevel(b->u.simage.level);
|
||||||
|
if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage))
|
||||||
|
res[0].textures.feed(b->binding, t);
|
||||||
|
if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage))
|
||||||
|
res[1].textures.feed(b->binding, t);
|
||||||
|
if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage))
|
||||||
|
res[2].textures.feed(b->binding, t);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case QRhiShaderResourceBinding::BufferLoad:
|
||||||
|
Q_FALLTHROUGH();
|
||||||
|
case QRhiShaderResourceBinding::BufferStore:
|
||||||
|
Q_FALLTHROUGH();
|
||||||
|
case QRhiShaderResourceBinding::BufferLoadStore:
|
||||||
|
{
|
||||||
|
QMetalBuffer *bufD = QRHI_RES(QMetalBuffer, b->u.sbuf.buf);
|
||||||
|
id<MTLBuffer> mtlbuf = bufD->d->buf[0];
|
||||||
|
uint offset = b->u.sbuf.offset;
|
||||||
|
if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) {
|
||||||
|
res[0].buffers.feed(b->binding, mtlbuf);
|
||||||
|
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, offset);
|
||||||
|
}
|
||||||
|
if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
|
||||||
|
res[2].buffers.feed(b->binding, mtlbuf);
|
||||||
|
res[2].bufferOffsets.feed(b->binding, offset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -645,12 +715,17 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
|
|||||||
const auto &offsetBatch(res[idx].bufferOffsets.batches[i]);
|
const auto &offsetBatch(res[idx].bufferOffsets.batches[i]);
|
||||||
switch (idx) {
|
switch (idx) {
|
||||||
case 0:
|
case 0:
|
||||||
[cbD->d->currentPassEncoder setVertexBuffers: bufferBatch.resources.constData()
|
[cbD->d->currentRenderPassEncoder setVertexBuffers: bufferBatch.resources.constData()
|
||||||
offsets: offsetBatch.resources.constData()
|
offsets: offsetBatch.resources.constData()
|
||||||
withRange: NSMakeRange(bufferBatch.startBinding, bufferBatch.resources.count())];
|
withRange: NSMakeRange(bufferBatch.startBinding, bufferBatch.resources.count())];
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
[cbD->d->currentPassEncoder setFragmentBuffers: bufferBatch.resources.constData()
|
[cbD->d->currentRenderPassEncoder setFragmentBuffers: bufferBatch.resources.constData()
|
||||||
|
offsets: offsetBatch.resources.constData()
|
||||||
|
withRange: NSMakeRange(bufferBatch.startBinding, bufferBatch.resources.count())];
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
[cbD->d->currentComputePassEncoder setBuffers: bufferBatch.resources.constData()
|
||||||
offsets: offsetBatch.resources.constData()
|
offsets: offsetBatch.resources.constData()
|
||||||
withRange: NSMakeRange(bufferBatch.startBinding, bufferBatch.resources.count())];
|
withRange: NSMakeRange(bufferBatch.startBinding, bufferBatch.resources.count())];
|
||||||
break;
|
break;
|
||||||
@ -670,11 +745,15 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
|
|||||||
const auto &batch(res[idx].textures.batches[i]);
|
const auto &batch(res[idx].textures.batches[i]);
|
||||||
switch (idx) {
|
switch (idx) {
|
||||||
case 0:
|
case 0:
|
||||||
[cbD->d->currentPassEncoder setVertexTextures: batch.resources.constData()
|
[cbD->d->currentRenderPassEncoder setVertexTextures: batch.resources.constData()
|
||||||
withRange: NSMakeRange(batch.startBinding, batch.resources.count())];
|
withRange: NSMakeRange(batch.startBinding, batch.resources.count())];
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
[cbD->d->currentPassEncoder setFragmentTextures: batch.resources.constData()
|
[cbD->d->currentRenderPassEncoder setFragmentTextures: batch.resources.constData()
|
||||||
|
withRange: NSMakeRange(batch.startBinding, batch.resources.count())];
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
[cbD->d->currentComputePassEncoder setTextures: batch.resources.constData()
|
||||||
withRange: NSMakeRange(batch.startBinding, batch.resources.count())];
|
withRange: NSMakeRange(batch.startBinding, batch.resources.count())];
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -686,11 +765,15 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
|
|||||||
const auto &batch(res[idx].samplers.batches[i]);
|
const auto &batch(res[idx].samplers.batches[i]);
|
||||||
switch (idx) {
|
switch (idx) {
|
||||||
case 0:
|
case 0:
|
||||||
[cbD->d->currentPassEncoder setVertexSamplerStates: batch.resources.constData()
|
[cbD->d->currentRenderPassEncoder setVertexSamplerStates: batch.resources.constData()
|
||||||
withRange: NSMakeRange(batch.startBinding, batch.resources.count())];
|
withRange: NSMakeRange(batch.startBinding, batch.resources.count())];
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
[cbD->d->currentPassEncoder setFragmentSamplerStates: batch.resources.constData()
|
[cbD->d->currentRenderPassEncoder setFragmentSamplerStates: batch.resources.constData()
|
||||||
|
withRange: NSMakeRange(batch.startBinding, batch.resources.count())];
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
[cbD->d->currentComputePassEncoder setSamplerStates: batch.resources.constData()
|
||||||
withRange: NSMakeRange(batch.startBinding, batch.resources.count())];
|
withRange: NSMakeRange(batch.startBinding, batch.resources.count())];
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -703,19 +786,19 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
|
|||||||
|
|
||||||
void QRhiMetal::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline *ps)
|
void QRhiMetal::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline *ps)
|
||||||
{
|
{
|
||||||
Q_ASSERT(inPass);
|
|
||||||
|
|
||||||
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
|
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
|
||||||
|
Q_ASSERT(cbD->recordingPass == QMetalCommandBuffer::RenderPass);
|
||||||
QMetalGraphicsPipeline *psD = QRHI_RES(QMetalGraphicsPipeline, ps);
|
QMetalGraphicsPipeline *psD = QRHI_RES(QMetalGraphicsPipeline, ps);
|
||||||
|
|
||||||
if (cbD->currentPipeline != ps || cbD->currentPipelineGeneration != psD->generation) {
|
if (cbD->currentGraphicsPipeline != ps || cbD->currentPipelineGeneration != psD->generation) {
|
||||||
cbD->currentPipeline = ps;
|
cbD->currentGraphicsPipeline = ps;
|
||||||
|
cbD->currentComputePipeline = nullptr;
|
||||||
cbD->currentPipelineGeneration = psD->generation;
|
cbD->currentPipelineGeneration = psD->generation;
|
||||||
|
|
||||||
[cbD->d->currentPassEncoder setRenderPipelineState: psD->d->ps];
|
[cbD->d->currentRenderPassEncoder setRenderPipelineState: psD->d->ps];
|
||||||
[cbD->d->currentPassEncoder setDepthStencilState: psD->d->ds];
|
[cbD->d->currentRenderPassEncoder setDepthStencilState: psD->d->ds];
|
||||||
[cbD->d->currentPassEncoder setCullMode: psD->d->cullMode];
|
[cbD->d->currentRenderPassEncoder setCullMode: psD->d->cullMode];
|
||||||
[cbD->d->currentPassEncoder setFrontFacingWinding: psD->d->winding];
|
[cbD->d->currentRenderPassEncoder setFrontFacingWinding: psD->d->winding];
|
||||||
}
|
}
|
||||||
|
|
||||||
psD->lastActiveFrameSlot = currentFrameSlot;
|
psD->lastActiveFrameSlot = currentFrameSlot;
|
||||||
@ -725,12 +808,17 @@ void QRhiMetal::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind
|
|||||||
int dynamicOffsetCount,
|
int dynamicOffsetCount,
|
||||||
const QRhiCommandBuffer::DynamicOffset *dynamicOffsets)
|
const QRhiCommandBuffer::DynamicOffset *dynamicOffsets)
|
||||||
{
|
{
|
||||||
Q_ASSERT(inPass);
|
|
||||||
|
|
||||||
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
|
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
|
||||||
Q_ASSERT(cbD->currentPipeline);
|
Q_ASSERT(cbD->recordingPass != QMetalCommandBuffer::NoPass);
|
||||||
if (!srb)
|
QMetalGraphicsPipeline *gfxPsD = QRHI_RES(QMetalGraphicsPipeline, cbD->currentGraphicsPipeline);
|
||||||
srb = QRHI_RES(QMetalGraphicsPipeline, cbD->currentPipeline)->m_shaderResourceBindings;
|
QMetalComputePipeline *compPsD = QRHI_RES(QMetalComputePipeline, cbD->currentComputePipeline);
|
||||||
|
|
||||||
|
if (!srb) {
|
||||||
|
if (gfxPsD)
|
||||||
|
srb = gfxPsD->m_shaderResourceBindings;
|
||||||
|
else
|
||||||
|
srb = compPsD->m_shaderResourceBindings;
|
||||||
|
}
|
||||||
|
|
||||||
QMetalShaderResourceBindings *srbD = QRHI_RES(QMetalShaderResourceBindings, srb);
|
QMetalShaderResourceBindings *srbD = QRHI_RES(QMetalShaderResourceBindings, srb);
|
||||||
bool hasSlottedResourceInSrb = false;
|
bool hasSlottedResourceInSrb = false;
|
||||||
@ -747,7 +835,7 @@ void QRhiMetal::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind
|
|||||||
QMetalBuffer *bufD = QRHI_RES(QMetalBuffer, b->u.ubuf.buf);
|
QMetalBuffer *bufD = QRHI_RES(QMetalBuffer, b->u.ubuf.buf);
|
||||||
Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer));
|
Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer));
|
||||||
executeBufferHostWritesForCurrentFrame(bufD);
|
executeBufferHostWritesForCurrentFrame(bufD);
|
||||||
if (bufD->m_type != QRhiBuffer::Immutable)
|
if (bufD->d->slotted)
|
||||||
hasSlottedResourceInSrb = true;
|
hasSlottedResourceInSrb = true;
|
||||||
if (b->u.ubuf.hasDynamicOffset)
|
if (b->u.ubuf.hasDynamicOffset)
|
||||||
hasDynamicOffsetInSrb = true;
|
hasDynamicOffsetInSrb = true;
|
||||||
@ -778,6 +866,38 @@ void QRhiMetal::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind
|
|||||||
samplerD->lastActiveFrameSlot = currentFrameSlot;
|
samplerD->lastActiveFrameSlot = currentFrameSlot;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case QRhiShaderResourceBinding::ImageLoad:
|
||||||
|
Q_FALLTHROUGH();
|
||||||
|
case QRhiShaderResourceBinding::ImageStore:
|
||||||
|
Q_FALLTHROUGH();
|
||||||
|
case QRhiShaderResourceBinding::ImageLoadStore:
|
||||||
|
{
|
||||||
|
QMetalTexture *texD = QRHI_RES(QMetalTexture, b->u.simage.tex);
|
||||||
|
if (texD->generation != bd.simage.generation || texD->m_id != bd.simage.id) {
|
||||||
|
resNeedsRebind = true;
|
||||||
|
bd.simage.id = texD->m_id;
|
||||||
|
bd.simage.generation = texD->generation;
|
||||||
|
}
|
||||||
|
texD->lastActiveFrameSlot = currentFrameSlot;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case QRhiShaderResourceBinding::BufferLoad:
|
||||||
|
Q_FALLTHROUGH();
|
||||||
|
case QRhiShaderResourceBinding::BufferStore:
|
||||||
|
Q_FALLTHROUGH();
|
||||||
|
case QRhiShaderResourceBinding::BufferLoadStore:
|
||||||
|
{
|
||||||
|
QMetalBuffer *bufD = QRHI_RES(QMetalBuffer, b->u.sbuf.buf);
|
||||||
|
Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::StorageBuffer));
|
||||||
|
executeBufferHostWritesForCurrentFrame(bufD);
|
||||||
|
if (bufD->generation != bd.sbuf.generation || bufD->m_id != bd.sbuf.id) {
|
||||||
|
resNeedsRebind = true;
|
||||||
|
bd.sbuf.id = bufD->m_id;
|
||||||
|
bd.sbuf.generation = bufD->generation;
|
||||||
|
}
|
||||||
|
bufD->lastActiveFrameSlot = currentFrameSlot;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
Q_UNREACHABLE();
|
Q_UNREACHABLE();
|
||||||
break;
|
break;
|
||||||
@ -789,15 +909,22 @@ void QRhiMetal::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind
|
|||||||
if (hasSlottedResourceInSrb && cbD->currentResSlot != resSlot)
|
if (hasSlottedResourceInSrb && cbD->currentResSlot != resSlot)
|
||||||
resNeedsRebind = true;
|
resNeedsRebind = true;
|
||||||
|
|
||||||
const bool srbChange = cbD->currentSrb != srb || cbD->currentSrbGeneration != srbD->generation;
|
const bool srbChanged = gfxPsD ? (cbD->currentGraphicsSrb != srb) : (cbD->currentComputeSrb != srb);
|
||||||
|
const bool srbRebuilt = cbD->currentSrbGeneration != srbD->generation;
|
||||||
|
|
||||||
// dynamic uniform buffer offsets always trigger a rebind
|
// dynamic uniform buffer offsets always trigger a rebind
|
||||||
if (hasDynamicOffsetInSrb || resNeedsRebind || srbChange) {
|
if (hasDynamicOffsetInSrb || resNeedsRebind || srbChanged || srbRebuilt) {
|
||||||
cbD->currentSrb = srb;
|
if (gfxPsD) {
|
||||||
|
cbD->currentGraphicsSrb = srb;
|
||||||
|
cbD->currentComputeSrb = nullptr;
|
||||||
|
} else {
|
||||||
|
cbD->currentGraphicsSrb = nullptr;
|
||||||
|
cbD->currentComputeSrb = srb;
|
||||||
|
}
|
||||||
cbD->currentSrbGeneration = srbD->generation;
|
cbD->currentSrbGeneration = srbD->generation;
|
||||||
cbD->currentResSlot = resSlot;
|
cbD->currentResSlot = resSlot;
|
||||||
|
|
||||||
const bool offsetOnlyChange = hasDynamicOffsetInSrb && !resNeedsRebind && !srbChange;
|
const bool offsetOnlyChange = hasDynamicOffsetInSrb && !resNeedsRebind && !srbChanged && !srbRebuilt;
|
||||||
enqueueShaderResourceBindings(srbD, cbD, dynamicOffsetCount, dynamicOffsets, offsetOnlyChange);
|
enqueueShaderResourceBindings(srbD, cbD, dynamicOffsetCount, dynamicOffsets, offsetOnlyChange);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -806,9 +933,8 @@ void QRhiMetal::setVertexInput(QRhiCommandBuffer *cb,
|
|||||||
int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings,
|
int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings,
|
||||||
QRhiBuffer *indexBuf, quint32 indexOffset, QRhiCommandBuffer::IndexFormat indexFormat)
|
QRhiBuffer *indexBuf, quint32 indexOffset, QRhiCommandBuffer::IndexFormat indexFormat)
|
||||||
{
|
{
|
||||||
Q_ASSERT(inPass);
|
|
||||||
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
|
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
|
||||||
Q_ASSERT(cbD->currentPipeline);
|
Q_ASSERT(cbD->recordingPass == QMetalCommandBuffer::RenderPass);
|
||||||
|
|
||||||
QRhiBatchedBindings<id<MTLBuffer> > buffers;
|
QRhiBatchedBindings<id<MTLBuffer> > buffers;
|
||||||
QRhiBatchedBindings<NSUInteger> offsets;
|
QRhiBatchedBindings<NSUInteger> offsets;
|
||||||
@ -816,7 +942,7 @@ void QRhiMetal::setVertexInput(QRhiCommandBuffer *cb,
|
|||||||
QMetalBuffer *bufD = QRHI_RES(QMetalBuffer, bindings[i].first);
|
QMetalBuffer *bufD = QRHI_RES(QMetalBuffer, bindings[i].first);
|
||||||
executeBufferHostWritesForCurrentFrame(bufD);
|
executeBufferHostWritesForCurrentFrame(bufD);
|
||||||
bufD->lastActiveFrameSlot = currentFrameSlot;
|
bufD->lastActiveFrameSlot = currentFrameSlot;
|
||||||
id<MTLBuffer> mtlbuf = bufD->d->buf[bufD->m_type == QRhiBuffer::Immutable ? 0 : currentFrameSlot];
|
id<MTLBuffer> mtlbuf = bufD->d->buf[bufD->d->slotted ? currentFrameSlot : 0];
|
||||||
buffers.feed(startBinding + i, mtlbuf);
|
buffers.feed(startBinding + i, mtlbuf);
|
||||||
offsets.feed(startBinding + i, bindings[i].second);
|
offsets.feed(startBinding + i, bindings[i].second);
|
||||||
}
|
}
|
||||||
@ -824,12 +950,12 @@ void QRhiMetal::setVertexInput(QRhiCommandBuffer *cb,
|
|||||||
offsets.finish();
|
offsets.finish();
|
||||||
|
|
||||||
// same binding space for vertex and constant buffers - work it around
|
// same binding space for vertex and constant buffers - work it around
|
||||||
QRhiShaderResourceBindings *srb = cbD->currentSrb;
|
QRhiShaderResourceBindings *srb = cbD->currentGraphicsSrb;
|
||||||
// There's nothing guaranteeing setShaderResources() was called before
|
// There's nothing guaranteeing setShaderResources() was called before
|
||||||
// setVertexInput()... but whatever srb will get bound will have to be
|
// setVertexInput()... but whatever srb will get bound will have to be
|
||||||
// layout-compatible anyways so maxBinding is the same.
|
// layout-compatible anyways so maxBinding is the same.
|
||||||
if (!srb)
|
if (!srb)
|
||||||
srb = cbD->currentPipeline->shaderResourceBindings();
|
srb = cbD->currentGraphicsPipeline->shaderResourceBindings();
|
||||||
const int firstVertexBinding = QRHI_RES(QMetalShaderResourceBindings, srb)->maxBinding + 1;
|
const int firstVertexBinding = QRHI_RES(QMetalShaderResourceBindings, srb)->maxBinding + 1;
|
||||||
|
|
||||||
if (firstVertexBinding != cbD->d->currentFirstVertexBinding
|
if (firstVertexBinding != cbD->d->currentFirstVertexBinding
|
||||||
@ -843,7 +969,7 @@ void QRhiMetal::setVertexInput(QRhiCommandBuffer *cb,
|
|||||||
for (int i = 0, ie = buffers.batches.count(); i != ie; ++i) {
|
for (int i = 0, ie = buffers.batches.count(); i != ie; ++i) {
|
||||||
const auto &bufferBatch(buffers.batches[i]);
|
const auto &bufferBatch(buffers.batches[i]);
|
||||||
const auto &offsetBatch(offsets.batches[i]);
|
const auto &offsetBatch(offsets.batches[i]);
|
||||||
[cbD->d->currentPassEncoder setVertexBuffers:
|
[cbD->d->currentRenderPassEncoder setVertexBuffers:
|
||||||
bufferBatch.resources.constData()
|
bufferBatch.resources.constData()
|
||||||
offsets: offsetBatch.resources.constData()
|
offsets: offsetBatch.resources.constData()
|
||||||
withRange: NSMakeRange(firstVertexBinding + bufferBatch.startBinding, bufferBatch.resources.count())];
|
withRange: NSMakeRange(firstVertexBinding + bufferBatch.startBinding, bufferBatch.resources.count())];
|
||||||
@ -864,9 +990,8 @@ void QRhiMetal::setVertexInput(QRhiCommandBuffer *cb,
|
|||||||
|
|
||||||
void QRhiMetal::setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport)
|
void QRhiMetal::setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport)
|
||||||
{
|
{
|
||||||
Q_ASSERT(inPass);
|
|
||||||
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
|
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
|
||||||
Q_ASSERT(cbD->currentPipeline && cbD->currentTarget);
|
Q_ASSERT(cbD->recordingPass == QMetalCommandBuffer::RenderPass);
|
||||||
const QSize outputSize = cbD->currentTarget->pixelSize();
|
const QSize outputSize = cbD->currentTarget->pixelSize();
|
||||||
|
|
||||||
// x,y is top-left in MTLViewportRect but bottom-left in QRhiViewport
|
// x,y is top-left in MTLViewportRect but bottom-left in QRhiViewport
|
||||||
@ -882,24 +1007,23 @@ void QRhiMetal::setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport)
|
|||||||
vp.znear = viewport.minDepth();
|
vp.znear = viewport.minDepth();
|
||||||
vp.zfar = viewport.maxDepth();
|
vp.zfar = viewport.maxDepth();
|
||||||
|
|
||||||
[cbD->d->currentPassEncoder setViewport: vp];
|
[cbD->d->currentRenderPassEncoder setViewport: vp];
|
||||||
|
|
||||||
if (!QRHI_RES(QMetalGraphicsPipeline, cbD->currentPipeline)->m_flags.testFlag(QRhiGraphicsPipeline::UsesScissor)) {
|
if (!QRHI_RES(QMetalGraphicsPipeline, cbD->currentGraphicsPipeline)->m_flags.testFlag(QRhiGraphicsPipeline::UsesScissor)) {
|
||||||
MTLScissorRect s;
|
MTLScissorRect s;
|
||||||
s.x = x;
|
s.x = x;
|
||||||
s.y = y;
|
s.y = y;
|
||||||
s.width = w;
|
s.width = w;
|
||||||
s.height = h;
|
s.height = h;
|
||||||
[cbD->d->currentPassEncoder setScissorRect: s];
|
[cbD->d->currentRenderPassEncoder setScissorRect: s];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QRhiMetal::setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor)
|
void QRhiMetal::setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor)
|
||||||
{
|
{
|
||||||
Q_ASSERT(inPass);
|
|
||||||
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
|
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
|
||||||
Q_ASSERT(cbD->currentPipeline && cbD->currentTarget);
|
Q_ASSERT(cbD->recordingPass == QMetalCommandBuffer::RenderPass);
|
||||||
Q_ASSERT(QRHI_RES(QMetalGraphicsPipeline, cbD->currentPipeline)->m_flags.testFlag(QRhiGraphicsPipeline::UsesScissor));
|
Q_ASSERT(QRHI_RES(QMetalGraphicsPipeline, cbD->currentGraphicsPipeline)->m_flags.testFlag(QRhiGraphicsPipeline::UsesScissor));
|
||||||
const QSize outputSize = cbD->currentTarget->pixelSize();
|
const QSize outputSize = cbD->currentTarget->pixelSize();
|
||||||
|
|
||||||
// x,y is top-left in MTLScissorRect but bottom-left in QRhiScissor
|
// x,y is top-left in MTLScissorRect but bottom-left in QRhiScissor
|
||||||
@ -913,38 +1037,42 @@ void QRhiMetal::setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor)
|
|||||||
s.width = w;
|
s.width = w;
|
||||||
s.height = h;
|
s.height = h;
|
||||||
|
|
||||||
[cbD->d->currentPassEncoder setScissorRect: s];
|
[cbD->d->currentRenderPassEncoder setScissorRect: s];
|
||||||
}
|
}
|
||||||
|
|
||||||
void QRhiMetal::setBlendConstants(QRhiCommandBuffer *cb, const QColor &c)
|
void QRhiMetal::setBlendConstants(QRhiCommandBuffer *cb, const QColor &c)
|
||||||
{
|
{
|
||||||
Q_ASSERT(inPass);
|
|
||||||
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
|
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
|
||||||
[cbD->d->currentPassEncoder setBlendColorRed: c.redF() green: c.greenF() blue: c.blueF() alpha: c.alphaF()];
|
Q_ASSERT(cbD->recordingPass == QMetalCommandBuffer::RenderPass);
|
||||||
|
|
||||||
|
[cbD->d->currentRenderPassEncoder setBlendColorRed: c.redF() green: c.greenF() blue: c.blueF() alpha: c.alphaF()];
|
||||||
}
|
}
|
||||||
|
|
||||||
void QRhiMetal::setStencilRef(QRhiCommandBuffer *cb, quint32 refValue)
|
void QRhiMetal::setStencilRef(QRhiCommandBuffer *cb, quint32 refValue)
|
||||||
{
|
{
|
||||||
Q_ASSERT(inPass);
|
|
||||||
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
|
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
|
||||||
[cbD->d->currentPassEncoder setStencilReferenceValue: refValue];
|
Q_ASSERT(cbD->recordingPass == QMetalCommandBuffer::RenderPass);
|
||||||
|
|
||||||
|
[cbD->d->currentRenderPassEncoder setStencilReferenceValue: refValue];
|
||||||
}
|
}
|
||||||
|
|
||||||
void QRhiMetal::draw(QRhiCommandBuffer *cb, quint32 vertexCount,
|
void QRhiMetal::draw(QRhiCommandBuffer *cb, quint32 vertexCount,
|
||||||
quint32 instanceCount, quint32 firstVertex, quint32 firstInstance)
|
quint32 instanceCount, quint32 firstVertex, quint32 firstInstance)
|
||||||
{
|
{
|
||||||
Q_ASSERT(inPass);
|
|
||||||
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
|
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
|
||||||
[cbD->d->currentPassEncoder drawPrimitives:
|
Q_ASSERT(cbD->recordingPass == QMetalCommandBuffer::RenderPass);
|
||||||
QRHI_RES(QMetalGraphicsPipeline, cbD->currentPipeline)->d->primitiveType
|
|
||||||
|
[cbD->d->currentRenderPassEncoder drawPrimitives:
|
||||||
|
QRHI_RES(QMetalGraphicsPipeline, cbD->currentGraphicsPipeline)->d->primitiveType
|
||||||
vertexStart: firstVertex vertexCount: vertexCount instanceCount: instanceCount baseInstance: firstInstance];
|
vertexStart: firstVertex vertexCount: vertexCount instanceCount: instanceCount baseInstance: firstInstance];
|
||||||
}
|
}
|
||||||
|
|
||||||
void QRhiMetal::drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
|
void QRhiMetal::drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
|
||||||
quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance)
|
quint32 instanceCount, quint32 firstIndex, qint32 vertexOffset, quint32 firstInstance)
|
||||||
{
|
{
|
||||||
Q_ASSERT(inPass);
|
|
||||||
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
|
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
|
||||||
|
Q_ASSERT(cbD->recordingPass == QMetalCommandBuffer::RenderPass);
|
||||||
|
|
||||||
if (!cbD->currentIndexBuffer)
|
if (!cbD->currentIndexBuffer)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -952,9 +1080,9 @@ void QRhiMetal::drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
|
|||||||
Q_ASSERT(indexOffset == aligned(indexOffset, 4));
|
Q_ASSERT(indexOffset == aligned(indexOffset, 4));
|
||||||
|
|
||||||
QMetalBuffer *ibufD = QRHI_RES(QMetalBuffer, cbD->currentIndexBuffer);
|
QMetalBuffer *ibufD = QRHI_RES(QMetalBuffer, cbD->currentIndexBuffer);
|
||||||
id<MTLBuffer> mtlbuf = ibufD->d->buf[ibufD->m_type == QRhiBuffer::Immutable ? 0 : currentFrameSlot];
|
id<MTLBuffer> mtlbuf = ibufD->d->buf[ibufD->d->slotted ? currentFrameSlot : 0];
|
||||||
|
|
||||||
[cbD->d->currentPassEncoder drawIndexedPrimitives: QRHI_RES(QMetalGraphicsPipeline, cbD->currentPipeline)->d->primitiveType
|
[cbD->d->currentRenderPassEncoder drawIndexedPrimitives: QRHI_RES(QMetalGraphicsPipeline, cbD->currentGraphicsPipeline)->d->primitiveType
|
||||||
indexCount: indexCount
|
indexCount: indexCount
|
||||||
indexType: cbD->currentIndexFormat == QRhiCommandBuffer::IndexUInt16 ? MTLIndexTypeUInt16 : MTLIndexTypeUInt32
|
indexType: cbD->currentIndexFormat == QRhiCommandBuffer::IndexUInt16 ? MTLIndexTypeUInt16 : MTLIndexTypeUInt32
|
||||||
indexBuffer: mtlbuf
|
indexBuffer: mtlbuf
|
||||||
@ -971,8 +1099,8 @@ void QRhiMetal::debugMarkBegin(QRhiCommandBuffer *cb, const QByteArray &name)
|
|||||||
|
|
||||||
NSString *str = [NSString stringWithUTF8String: name.constData()];
|
NSString *str = [NSString stringWithUTF8String: name.constData()];
|
||||||
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
|
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
|
||||||
if (inPass) {
|
if (cbD->recordingPass != QMetalCommandBuffer::NoPass) {
|
||||||
[cbD->d->currentPassEncoder pushDebugGroup: str];
|
[cbD->d->currentRenderPassEncoder pushDebugGroup: str];
|
||||||
} else {
|
} else {
|
||||||
if (@available(macOS 10.13, iOS 11.0, *))
|
if (@available(macOS 10.13, iOS 11.0, *))
|
||||||
[cbD->d->cb pushDebugGroup: str];
|
[cbD->d->cb pushDebugGroup: str];
|
||||||
@ -985,8 +1113,8 @@ void QRhiMetal::debugMarkEnd(QRhiCommandBuffer *cb)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
|
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
|
||||||
if (inPass) {
|
if (cbD->recordingPass != QMetalCommandBuffer::NoPass) {
|
||||||
[cbD->d->currentPassEncoder popDebugGroup];
|
[cbD->d->currentRenderPassEncoder popDebugGroup];
|
||||||
} else {
|
} else {
|
||||||
if (@available(macOS 10.13, iOS 11.0, *))
|
if (@available(macOS 10.13, iOS 11.0, *))
|
||||||
[cbD->d->cb popDebugGroup];
|
[cbD->d->cb popDebugGroup];
|
||||||
@ -998,10 +1126,9 @@ void QRhiMetal::debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg)
|
|||||||
if (!debugMarkers)
|
if (!debugMarkers)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (inPass) {
|
|
||||||
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
|
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
|
||||||
[cbD->d->currentPassEncoder insertDebugSignpost: [NSString stringWithUTF8String: msg.constData()]];
|
if (cbD->recordingPass != QMetalCommandBuffer::NoPass)
|
||||||
}
|
[cbD->d->currentRenderPassEncoder insertDebugSignpost: [NSString stringWithUTF8String: msg.constData()]];
|
||||||
}
|
}
|
||||||
|
|
||||||
const QRhiNativeHandles *QRhiMetal::nativeHandles(QRhiCommandBuffer *cb)
|
const QRhiNativeHandles *QRhiMetal::nativeHandles(QRhiCommandBuffer *cb)
|
||||||
@ -1023,8 +1150,6 @@ void QRhiMetal::endExternal(QRhiCommandBuffer *cb)
|
|||||||
QRhi::FrameOpResult QRhiMetal::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags)
|
QRhi::FrameOpResult QRhiMetal::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags)
|
||||||
{
|
{
|
||||||
Q_UNUSED(flags);
|
Q_UNUSED(flags);
|
||||||
Q_ASSERT(!inFrame);
|
|
||||||
inFrame = true;
|
|
||||||
|
|
||||||
QMetalSwapChain *swapChainD = QRHI_RES(QMetalSwapChain, swapChain);
|
QMetalSwapChain *swapChainD = QRHI_RES(QMetalSwapChain, swapChain);
|
||||||
|
|
||||||
@ -1077,9 +1202,6 @@ QRhi::FrameOpResult QRhiMetal::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginF
|
|||||||
|
|
||||||
QRhi::FrameOpResult QRhiMetal::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags)
|
QRhi::FrameOpResult QRhiMetal::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags)
|
||||||
{
|
{
|
||||||
Q_ASSERT(inFrame);
|
|
||||||
inFrame = false;
|
|
||||||
|
|
||||||
QMetalSwapChain *swapChainD = QRHI_RES(QMetalSwapChain, swapChain);
|
QMetalSwapChain *swapChainD = QRHI_RES(QMetalSwapChain, swapChain);
|
||||||
Q_ASSERT(currentSwapChain == swapChainD);
|
Q_ASSERT(currentSwapChain == swapChainD);
|
||||||
|
|
||||||
@ -1110,9 +1232,6 @@ QRhi::FrameOpResult QRhiMetal::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrame
|
|||||||
|
|
||||||
QRhi::FrameOpResult QRhiMetal::beginOffscreenFrame(QRhiCommandBuffer **cb)
|
QRhi::FrameOpResult QRhiMetal::beginOffscreenFrame(QRhiCommandBuffer **cb)
|
||||||
{
|
{
|
||||||
Q_ASSERT(!inFrame);
|
|
||||||
inFrame = true;
|
|
||||||
|
|
||||||
currentFrameSlot = (currentFrameSlot + 1) % QMTL_FRAMES_IN_FLIGHT;
|
currentFrameSlot = (currentFrameSlot + 1) % QMTL_FRAMES_IN_FLIGHT;
|
||||||
if (swapchains.count() > 1) {
|
if (swapchains.count() > 1) {
|
||||||
for (QMetalSwapChain *sc : qAsConst(swapchains)) {
|
for (QMetalSwapChain *sc : qAsConst(swapchains)) {
|
||||||
@ -1140,8 +1259,6 @@ QRhi::FrameOpResult QRhiMetal::endOffscreenFrame()
|
|||||||
{
|
{
|
||||||
Q_ASSERT(d->ofr.active);
|
Q_ASSERT(d->ofr.active);
|
||||||
d->ofr.active = false;
|
d->ofr.active = false;
|
||||||
Q_ASSERT(inFrame);
|
|
||||||
inFrame = false;
|
|
||||||
|
|
||||||
[d->ofr.cbWrapper.d->cb commit];
|
[d->ofr.cbWrapper.d->cb commit];
|
||||||
|
|
||||||
@ -1155,17 +1272,17 @@ QRhi::FrameOpResult QRhiMetal::endOffscreenFrame()
|
|||||||
|
|
||||||
QRhi::FrameOpResult QRhiMetal::finish()
|
QRhi::FrameOpResult QRhiMetal::finish()
|
||||||
{
|
{
|
||||||
Q_ASSERT(!inPass);
|
|
||||||
|
|
||||||
id<MTLCommandBuffer> cb = nil;
|
id<MTLCommandBuffer> cb = nil;
|
||||||
QMetalSwapChain *swapChainD = nullptr;
|
QMetalSwapChain *swapChainD = nullptr;
|
||||||
if (inFrame) {
|
if (inFrame) {
|
||||||
if (d->ofr.active) {
|
if (d->ofr.active) {
|
||||||
Q_ASSERT(!currentSwapChain);
|
Q_ASSERT(!currentSwapChain);
|
||||||
|
Q_ASSERT(d->ofr.cbWrapper.recordingPass == QMetalCommandBuffer::NoPass);
|
||||||
cb = d->ofr.cbWrapper.d->cb;
|
cb = d->ofr.cbWrapper.d->cb;
|
||||||
} else {
|
} else {
|
||||||
Q_ASSERT(currentSwapChain);
|
Q_ASSERT(currentSwapChain);
|
||||||
swapChainD = currentSwapChain;
|
swapChainD = currentSwapChain;
|
||||||
|
Q_ASSERT(swapChainD->cbWrapper.recordingPass == QMetalCommandBuffer::NoPass);
|
||||||
cb = swapChainD->cbWrapper.d->cb;
|
cb = swapChainD->cbWrapper.d->cb;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1373,11 +1490,13 @@ void QRhiMetal::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
|
|||||||
bufD->d->pendingUpdates[i].append(u);
|
bufD->d->pendingUpdates[i].append(u);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Due to the Metal API the handling of static and dynamic buffers is
|
||||||
|
// basically the same. So go through the same pendingUpdates machinery.
|
||||||
for (const QRhiResourceUpdateBatchPrivate::StaticBufferUpload &u : ud->staticBufferUploads) {
|
for (const QRhiResourceUpdateBatchPrivate::StaticBufferUpload &u : ud->staticBufferUploads) {
|
||||||
QMetalBuffer *bufD = QRHI_RES(QMetalBuffer, u.buf);
|
QMetalBuffer *bufD = QRHI_RES(QMetalBuffer, u.buf);
|
||||||
Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
|
Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
|
||||||
Q_ASSERT(u.offset + u.data.size() <= bufD->m_size);
|
Q_ASSERT(u.offset + u.data.size() <= bufD->m_size);
|
||||||
for (int i = 0, ie = bufD->m_type == QRhiBuffer::Immutable ? 1 : QMTL_FRAMES_IN_FLIGHT; i != ie; ++i)
|
for (int i = 0, ie = bufD->d->slotted ? QMTL_FRAMES_IN_FLIGHT : 1; i != ie; ++i)
|
||||||
bufD->d->pendingUpdates[i].append({ u.buf, u.offset, u.data.size(), u.data.constData() });
|
bufD->d->pendingUpdates[i].append({ u.buf, u.offset, u.data.size(), u.data.constData() });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1516,9 +1635,10 @@ void QRhiMetal::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
|
|||||||
ud->free();
|
ud->free();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this handles all types of buffers, not just Dynamic
|
||||||
void QRhiMetal::executeBufferHostWritesForCurrentFrame(QMetalBuffer *bufD)
|
void QRhiMetal::executeBufferHostWritesForCurrentFrame(QMetalBuffer *bufD)
|
||||||
{
|
{
|
||||||
const int idx = bufD->m_type == QRhiBuffer::Immutable ? 0 : currentFrameSlot;
|
const int idx = bufD->d->slotted ? currentFrameSlot : 0;
|
||||||
QVector<QRhiResourceUpdateBatchPrivate::DynamicBufferUpdate> &updates(bufD->d->pendingUpdates[idx]);
|
QVector<QRhiResourceUpdateBatchPrivate::DynamicBufferUpdate> &updates(bufD->d->pendingUpdates[idx]);
|
||||||
if (updates.isEmpty())
|
if (updates.isEmpty())
|
||||||
return;
|
return;
|
||||||
@ -1542,7 +1662,7 @@ void QRhiMetal::executeBufferHostWritesForCurrentFrame(QMetalBuffer *bufD)
|
|||||||
|
|
||||||
void QRhiMetal::resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
|
void QRhiMetal::resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
|
||||||
{
|
{
|
||||||
Q_ASSERT(inFrame && !inPass);
|
Q_ASSERT(QRHI_RES(QMetalCommandBuffer, cb)->recordingPass == QMetalCommandBuffer::NoPass);
|
||||||
|
|
||||||
enqueueResourceUpdates(cb, resourceUpdates);
|
enqueueResourceUpdates(cb, resourceUpdates);
|
||||||
}
|
}
|
||||||
@ -1553,13 +1673,12 @@ void QRhiMetal::beginPass(QRhiCommandBuffer *cb,
|
|||||||
const QRhiDepthStencilClearValue &depthStencilClearValue,
|
const QRhiDepthStencilClearValue &depthStencilClearValue,
|
||||||
QRhiResourceUpdateBatch *resourceUpdates)
|
QRhiResourceUpdateBatch *resourceUpdates)
|
||||||
{
|
{
|
||||||
Q_ASSERT(inFrame && !inPass);
|
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
|
||||||
|
Q_ASSERT(cbD->recordingPass == QMetalCommandBuffer::NoPass);
|
||||||
|
|
||||||
if (resourceUpdates)
|
if (resourceUpdates)
|
||||||
enqueueResourceUpdates(cb, resourceUpdates);
|
enqueueResourceUpdates(cb, resourceUpdates);
|
||||||
|
|
||||||
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
|
|
||||||
|
|
||||||
QMetalRenderTargetData *rtD = nullptr;
|
QMetalRenderTargetData *rtD = nullptr;
|
||||||
switch (rt->resourceType()) {
|
switch (rt->resourceType()) {
|
||||||
case QRhiResource::RenderTarget:
|
case QRhiResource::RenderTarget:
|
||||||
@ -1639,28 +1758,80 @@ void QRhiMetal::beginPass(QRhiCommandBuffer *cb,
|
|||||||
cbD->d->currentPassRpDesc.depthAttachment.storeAction = MTLStoreActionStore;
|
cbD->d->currentPassRpDesc.depthAttachment.storeAction = MTLStoreActionStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
cbD->d->currentPassEncoder = [cbD->d->cb renderCommandEncoderWithDescriptor: cbD->d->currentPassRpDesc];
|
cbD->d->currentRenderPassEncoder = [cbD->d->cb renderCommandEncoderWithDescriptor: cbD->d->currentPassRpDesc];
|
||||||
|
|
||||||
cbD->resetPerPassState();
|
cbD->resetPerPassState();
|
||||||
|
|
||||||
|
cbD->recordingPass = QMetalCommandBuffer::RenderPass;
|
||||||
cbD->currentTarget = rt;
|
cbD->currentTarget = rt;
|
||||||
inPass = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QRhiMetal::endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
|
void QRhiMetal::endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
|
||||||
{
|
{
|
||||||
Q_ASSERT(inPass);
|
|
||||||
inPass = false;
|
|
||||||
|
|
||||||
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
|
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
|
||||||
[cbD->d->currentPassEncoder endEncoding];
|
Q_ASSERT(cbD->recordingPass == QMetalCommandBuffer::RenderPass);
|
||||||
|
|
||||||
|
[cbD->d->currentRenderPassEncoder endEncoding];
|
||||||
|
|
||||||
|
cbD->recordingPass = QMetalCommandBuffer::NoPass;
|
||||||
cbD->currentTarget = nullptr;
|
cbD->currentTarget = nullptr;
|
||||||
|
|
||||||
if (resourceUpdates)
|
if (resourceUpdates)
|
||||||
enqueueResourceUpdates(cb, resourceUpdates);
|
enqueueResourceUpdates(cb, resourceUpdates);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QRhiMetal::beginComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
|
||||||
|
{
|
||||||
|
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
|
||||||
|
Q_ASSERT(cbD->recordingPass == QMetalCommandBuffer::NoPass);
|
||||||
|
|
||||||
|
if (resourceUpdates)
|
||||||
|
enqueueResourceUpdates(cb, resourceUpdates);
|
||||||
|
|
||||||
|
cbD->d->currentComputePassEncoder = [cbD->d->cb computeCommandEncoder];
|
||||||
|
cbD->resetPerPassState();
|
||||||
|
cbD->recordingPass = QMetalCommandBuffer::ComputePass;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QRhiMetal::endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
|
||||||
|
{
|
||||||
|
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
|
||||||
|
Q_ASSERT(cbD->recordingPass == QMetalCommandBuffer::ComputePass);
|
||||||
|
|
||||||
|
[cbD->d->currentComputePassEncoder endEncoding];
|
||||||
|
cbD->recordingPass = QMetalCommandBuffer::NoPass;
|
||||||
|
|
||||||
|
if (resourceUpdates)
|
||||||
|
enqueueResourceUpdates(cb, resourceUpdates);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QRhiMetal::setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps)
|
||||||
|
{
|
||||||
|
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
|
||||||
|
Q_ASSERT(cbD->recordingPass == QMetalCommandBuffer::ComputePass);
|
||||||
|
QMetalComputePipeline *psD = QRHI_RES(QMetalComputePipeline, ps);
|
||||||
|
|
||||||
|
if (cbD->currentComputePipeline != ps || cbD->currentPipelineGeneration != psD->generation) {
|
||||||
|
cbD->currentGraphicsPipeline = nullptr;
|
||||||
|
cbD->currentComputePipeline = ps;
|
||||||
|
cbD->currentPipelineGeneration = psD->generation;
|
||||||
|
|
||||||
|
[cbD->d->currentComputePassEncoder setComputePipelineState: psD->d->ps];
|
||||||
|
}
|
||||||
|
|
||||||
|
psD->lastActiveFrameSlot = currentFrameSlot;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QRhiMetal::dispatch(QRhiCommandBuffer *cb, int x, int y, int z)
|
||||||
|
{
|
||||||
|
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
|
||||||
|
Q_ASSERT(cbD->recordingPass == QMetalCommandBuffer::ComputePass);
|
||||||
|
QMetalComputePipeline *psD = QRHI_RES(QMetalComputePipeline, cbD->currentComputePipeline);
|
||||||
|
|
||||||
|
[cbD->d->currentComputePassEncoder dispatchThreadgroups: MTLSizeMake(x, y, z)
|
||||||
|
threadsPerThreadgroup: psD->d->localSize];
|
||||||
|
}
|
||||||
|
|
||||||
static void qrhimtl_releaseBuffer(const QRhiMetalData::DeferredReleaseEntry &e)
|
static void qrhimtl_releaseBuffer(const QRhiMetalData::DeferredReleaseEntry &e)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < QMTL_FRAMES_IN_FLIGHT; ++i)
|
for (int i = 0; i < QMTL_FRAMES_IN_FLIGHT; ++i)
|
||||||
@ -1677,6 +1848,8 @@ static void qrhimtl_releaseTexture(const QRhiMetalData::DeferredReleaseEntry &e)
|
|||||||
[e.texture.texture release];
|
[e.texture.texture release];
|
||||||
for (int i = 0; i < QMTL_FRAMES_IN_FLIGHT; ++i)
|
for (int i = 0; i < QMTL_FRAMES_IN_FLIGHT; ++i)
|
||||||
[e.texture.stagingBuffers[i] release];
|
[e.texture.stagingBuffers[i] release];
|
||||||
|
for (int i = 0; i < QRhi::MAX_LEVELS; ++i)
|
||||||
|
[e.texture.views[i] release];
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qrhimtl_releaseSampler(const QRhiMetalData::DeferredReleaseEntry &e)
|
static void qrhimtl_releaseSampler(const QRhiMetalData::DeferredReleaseEntry &e)
|
||||||
@ -1782,6 +1955,11 @@ bool QMetalBuffer::build()
|
|||||||
if (d->buf[0])
|
if (d->buf[0])
|
||||||
release();
|
release();
|
||||||
|
|
||||||
|
if (m_usage.testFlag(QRhiBuffer::StorageBuffer) && m_type == Dynamic) {
|
||||||
|
qWarning("StorageBuffer cannot be combined with Dynamic");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const int nonZeroSize = m_size <= 0 ? 256 : m_size;
|
const int nonZeroSize = m_size <= 0 ? 256 : m_size;
|
||||||
const int roundedSize = m_usage.testFlag(QRhiBuffer::UniformBuffer) ? aligned(nonZeroSize, 256) : nonZeroSize;
|
const int roundedSize = m_usage.testFlag(QRhiBuffer::UniformBuffer) ? aligned(nonZeroSize, 256) : nonZeroSize;
|
||||||
|
|
||||||
@ -1794,15 +1972,17 @@ bool QMetalBuffer::build()
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Immutable and Static only has buf[0] and pendingUpdates[0] in use.
|
||||||
|
// Dynamic uses all.
|
||||||
|
d->slotted = m_type == Dynamic;
|
||||||
|
|
||||||
QRHI_RES_RHI(QRhiMetal);
|
QRHI_RES_RHI(QRhiMetal);
|
||||||
for (int i = 0; i < QMTL_FRAMES_IN_FLIGHT; ++i) {
|
for (int i = 0; i < QMTL_FRAMES_IN_FLIGHT; ++i) {
|
||||||
// Immutable only has buf[0] and pendingUpdates[0] in use.
|
if (i == 0 || d->slotted) {
|
||||||
// Static and Dynamic use all.
|
|
||||||
if (i == 0 || m_type != Immutable) {
|
|
||||||
d->buf[i] = [rhiD->d->dev newBufferWithLength: roundedSize options: opts];
|
d->buf[i] = [rhiD->d->dev newBufferWithLength: roundedSize options: opts];
|
||||||
d->pendingUpdates[i].reserve(16);
|
d->pendingUpdates[i].reserve(16);
|
||||||
if (!m_objectName.isEmpty()) {
|
if (!m_objectName.isEmpty()) {
|
||||||
if (m_type == Immutable) {
|
if (!d->slotted) {
|
||||||
d->buf[i].label = [NSString stringWithUTF8String: m_objectName.constData()];
|
d->buf[i].label = [NSString stringWithUTF8String: m_objectName.constData()];
|
||||||
} else {
|
} else {
|
||||||
const QByteArray name = m_objectName + '/' + QByteArray::number(i);
|
const QByteArray name = m_objectName + '/' + QByteArray::number(i);
|
||||||
@ -1813,7 +1993,7 @@ bool QMetalBuffer::build()
|
|||||||
}
|
}
|
||||||
|
|
||||||
QRHI_PROF;
|
QRHI_PROF;
|
||||||
QRHI_PROF_F(newBuffer(this, roundedSize, m_type == Immutable ? 1 : QMTL_FRAMES_IN_FLIGHT, 0));
|
QRHI_PROF_F(newBuffer(this, roundedSize, d->slotted ? QMTL_FRAMES_IN_FLIGHT : 1, 0));
|
||||||
|
|
||||||
lastActiveFrameSlot = -1;
|
lastActiveFrameSlot = -1;
|
||||||
generation += 1;
|
generation += 1;
|
||||||
@ -1919,10 +2099,13 @@ QRhiTexture::Format QMetalRenderBuffer::backingFormat() const
|
|||||||
QMetalTexture::QMetalTexture(QRhiImplementation *rhi, Format format, const QSize &pixelSize,
|
QMetalTexture::QMetalTexture(QRhiImplementation *rhi, Format format, const QSize &pixelSize,
|
||||||
int sampleCount, Flags flags)
|
int sampleCount, Flags flags)
|
||||||
: QRhiTexture(rhi, format, pixelSize, sampleCount, flags),
|
: QRhiTexture(rhi, format, pixelSize, sampleCount, flags),
|
||||||
d(new QMetalTextureData)
|
d(new QMetalTextureData(this))
|
||||||
{
|
{
|
||||||
for (int i = 0; i < QMTL_FRAMES_IN_FLIGHT; ++i)
|
for (int i = 0; i < QMTL_FRAMES_IN_FLIGHT; ++i)
|
||||||
d->stagingBuf[i] = nil;
|
d->stagingBuf[i] = nil;
|
||||||
|
|
||||||
|
for (int i = 0; i < QRhi::MAX_LEVELS; ++i)
|
||||||
|
d->perLevelViews[i] = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
QMetalTexture::~QMetalTexture()
|
QMetalTexture::~QMetalTexture()
|
||||||
@ -1949,6 +2132,11 @@ void QMetalTexture::release()
|
|||||||
d->stagingBuf[i] = nil;
|
d->stagingBuf[i] = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < QRhi::MAX_LEVELS; ++i) {
|
||||||
|
e.texture.views[i] = d->perLevelViews[i];
|
||||||
|
d->perLevelViews[i] = nil;
|
||||||
|
}
|
||||||
|
|
||||||
QRHI_RES_RHI(QRhiMetal);
|
QRHI_RES_RHI(QRhiMetal);
|
||||||
rhiD->d->releaseQueue.append(e);
|
rhiD->d->releaseQueue.append(e);
|
||||||
QRHI_PROF;
|
QRHI_PROF;
|
||||||
@ -2138,6 +2326,8 @@ bool QMetalTexture::build()
|
|||||||
desc.usage = MTLTextureUsageShaderRead;
|
desc.usage = MTLTextureUsageShaderRead;
|
||||||
if (m_flags.testFlag(RenderTarget))
|
if (m_flags.testFlag(RenderTarget))
|
||||||
desc.usage |= MTLTextureUsageRenderTarget;
|
desc.usage |= MTLTextureUsageRenderTarget;
|
||||||
|
if (m_flags.testFlag(UsedWithLoadStore))
|
||||||
|
desc.usage |= MTLTextureUsageShaderWrite;
|
||||||
|
|
||||||
QRHI_RES_RHI(QRhiMetal);
|
QRHI_RES_RHI(QRhiMetal);
|
||||||
d->tex = [rhiD->d->dev newTextureWithDescriptor: desc];
|
d->tex = [rhiD->d->dev newTextureWithDescriptor: desc];
|
||||||
@ -2187,6 +2377,21 @@ const QRhiNativeHandles *QMetalTexture::nativeHandles()
|
|||||||
return &nativeHandlesStruct;
|
return &nativeHandlesStruct;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
id<MTLTexture> QMetalTextureData::viewForLevel(int level)
|
||||||
|
{
|
||||||
|
Q_ASSERT(level >= 0 && level < int(q->mipLevelCount));
|
||||||
|
if (perLevelViews[level])
|
||||||
|
return perLevelViews[level];
|
||||||
|
|
||||||
|
const MTLTextureType type = [tex textureType];
|
||||||
|
const bool isCube = q->m_flags.testFlag(QRhiTexture::CubeMap);
|
||||||
|
id<MTLTexture> view = [tex newTextureViewWithPixelFormat: format textureType: type
|
||||||
|
levels: NSMakeRange(level, 1) slices: NSMakeRange(0, isCube ? 6 : 1)];
|
||||||
|
|
||||||
|
perLevelViews[level] = view;
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
QMetalSampler::QMetalSampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
|
QMetalSampler::QMetalSampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
|
||||||
AddressMode u, AddressMode v)
|
AddressMode u, AddressMode v)
|
||||||
: QRhiSampler(rhi, magFilter, minFilter, mipmapMode, u, v),
|
: QRhiSampler(rhi, magFilter, minFilter, mipmapMode, u, v),
|
||||||
@ -2538,6 +2743,28 @@ bool QMetalShaderResourceBindings::build()
|
|||||||
bd.stex.samplerGeneration = samplerD->generation;
|
bd.stex.samplerGeneration = samplerD->generation;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case QRhiShaderResourceBinding::ImageLoad:
|
||||||
|
Q_FALLTHROUGH();
|
||||||
|
case QRhiShaderResourceBinding::ImageStore:
|
||||||
|
Q_FALLTHROUGH();
|
||||||
|
case QRhiShaderResourceBinding::ImageLoadStore:
|
||||||
|
{
|
||||||
|
QMetalTexture *texD = QRHI_RES(QMetalTexture, b->u.simage.tex);
|
||||||
|
bd.simage.id = texD->m_id;
|
||||||
|
bd.simage.generation = texD->generation;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case QRhiShaderResourceBinding::BufferLoad:
|
||||||
|
Q_FALLTHROUGH();
|
||||||
|
case QRhiShaderResourceBinding::BufferStore:
|
||||||
|
Q_FALLTHROUGH();
|
||||||
|
case QRhiShaderResourceBinding::BufferLoadStore:
|
||||||
|
{
|
||||||
|
QMetalBuffer *bufD = QRHI_RES(QMetalBuffer, b->u.sbuf.buf);
|
||||||
|
bd.sbuf.id = bufD->m_id;
|
||||||
|
bd.sbuf.generation = bufD->generation;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
Q_UNREACHABLE();
|
Q_UNREACHABLE();
|
||||||
break;
|
break;
|
||||||
@ -2874,21 +3101,12 @@ bool QMetalGraphicsPipeline::build()
|
|||||||
|
|
||||||
rpDesc.vertexDescriptor = inputLayout;
|
rpDesc.vertexDescriptor = inputLayout;
|
||||||
|
|
||||||
if (@available(macOS 10.13, iOS 11.0, *)) {
|
// mutability cannot be determined (slotted buffers could be set as
|
||||||
// Everything is immutable because we can guarantee that "neither the
|
// MTLMutabilityImmutable, but then we potentially need a different
|
||||||
// CPU nor the GPU will modify a buffer's contents between the time the
|
// descriptor for each buffer combination as this depends on the actual
|
||||||
// buffer is set in a function's argument table and the time its
|
// buffers not just the resource binding layout) so leave it at the default
|
||||||
// associated command buffer completes execution" (as that's the point
|
|
||||||
// of our Vulkan-style buffer juggling in the first place).
|
|
||||||
const int vertexBufferCount = firstVertexBinding + bindings.count(); // cbuf + vbuf
|
|
||||||
const int fragmentBufferCount = firstVertexBinding; // cbuf
|
|
||||||
for (int i = 0; i < vertexBufferCount; ++i)
|
|
||||||
rpDesc.vertexBuffers[i].mutability = MTLMutabilityImmutable;
|
|
||||||
for (int i = 0; i < fragmentBufferCount; ++i)
|
|
||||||
rpDesc.fragmentBuffers[i].mutability = MTLMutabilityImmutable;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const QRhiGraphicsShaderStage &shaderStage : qAsConst(m_shaderStages)) {
|
for (const QRhiShaderStage &shaderStage : qAsConst(m_shaderStages)) {
|
||||||
QString error;
|
QString error;
|
||||||
QByteArray entryPoint;
|
QByteArray entryPoint;
|
||||||
id<MTLLibrary> lib = rhiD->d->createMetalLib(shaderStage.shader(), shaderStage.shaderVariant(), &error, &entryPoint);
|
id<MTLLibrary> lib = rhiD->d->createMetalLib(shaderStage.shader(), shaderStage.shaderVariant(), &error, &entryPoint);
|
||||||
@ -2903,12 +3121,12 @@ bool QMetalGraphicsPipeline::build()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
switch (shaderStage.type()) {
|
switch (shaderStage.type()) {
|
||||||
case QRhiGraphicsShaderStage::Vertex:
|
case QRhiShaderStage::Vertex:
|
||||||
rpDesc.vertexFunction = func;
|
rpDesc.vertexFunction = func;
|
||||||
d->vsLib = lib;
|
d->vsLib = lib;
|
||||||
d->vsFunc = func;
|
d->vsFunc = func;
|
||||||
break;
|
break;
|
||||||
case QRhiGraphicsShaderStage::Fragment:
|
case QRhiShaderStage::Fragment:
|
||||||
rpDesc.fragmentFunction = func;
|
rpDesc.fragmentFunction = func;
|
||||||
d->fsLib = lib;
|
d->fsLib = lib;
|
||||||
d->fsFunc = func;
|
d->fsFunc = func;
|
||||||
@ -3000,6 +3218,83 @@ bool QMetalGraphicsPipeline::build()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QMetalComputePipeline::QMetalComputePipeline(QRhiImplementation *rhi)
|
||||||
|
: QRhiComputePipeline(rhi),
|
||||||
|
d(new QMetalComputePipelineData)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QMetalComputePipeline::~QMetalComputePipeline()
|
||||||
|
{
|
||||||
|
release();
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QMetalComputePipeline::release()
|
||||||
|
{
|
||||||
|
QRHI_RES_RHI(QRhiMetal);
|
||||||
|
|
||||||
|
if (d->csFunc) {
|
||||||
|
[d->csFunc release];
|
||||||
|
d->csFunc = nil;
|
||||||
|
}
|
||||||
|
if (d->csLib) {
|
||||||
|
[d->csLib release];
|
||||||
|
d->csLib = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!d->ps)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (d->ps) {
|
||||||
|
[d->ps release];
|
||||||
|
d->ps = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
rhiD->unregisterResource(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QMetalComputePipeline::build()
|
||||||
|
{
|
||||||
|
if (d->ps)
|
||||||
|
release();
|
||||||
|
|
||||||
|
QRHI_RES_RHI(QRhiMetal);
|
||||||
|
|
||||||
|
const QShader shader = m_shaderStage.shader();
|
||||||
|
QString error;
|
||||||
|
QByteArray entryPoint;
|
||||||
|
id<MTLLibrary> lib = rhiD->d->createMetalLib(shader, m_shaderStage.shaderVariant(),
|
||||||
|
&error, &entryPoint);
|
||||||
|
if (!lib) {
|
||||||
|
qWarning("MSL shader compilation failed: %s", qPrintable(error));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
id<MTLFunction> func = rhiD->d->createMSLShaderFunction(lib, entryPoint);
|
||||||
|
if (!func) {
|
||||||
|
qWarning("MSL function for entry point %s not found", entryPoint.constData());
|
||||||
|
[lib release];
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
d->csLib = lib;
|
||||||
|
d->csFunc = func;
|
||||||
|
std::array<uint, 3> localSize = shader.description().computeShaderLocalSize();
|
||||||
|
d->localSize = MTLSizeMake(localSize[0], localSize[1], localSize[2]);
|
||||||
|
|
||||||
|
NSError *err = nil;
|
||||||
|
d->ps = [rhiD->d->dev newComputePipelineStateWithFunction: d->csFunc error: &err];
|
||||||
|
if (!d->ps) {
|
||||||
|
const QString msg = QString::fromNSString(err.localizedDescription);
|
||||||
|
qWarning("Failed to create render pipeline state: %s", qPrintable(msg));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastActiveFrameSlot = -1;
|
||||||
|
generation += 1;
|
||||||
|
rhiD->registerResource(this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
QMetalCommandBuffer::QMetalCommandBuffer(QRhiImplementation *rhi)
|
QMetalCommandBuffer::QMetalCommandBuffer(QRhiImplementation *rhi)
|
||||||
: QRhiCommandBuffer(rhi),
|
: QRhiCommandBuffer(rhi),
|
||||||
d(new QMetalCommandBufferData)
|
d(new QMetalCommandBufferData)
|
||||||
@ -3021,28 +3316,32 @@ void QMetalCommandBuffer::release()
|
|||||||
const QRhiNativeHandles *QMetalCommandBuffer::nativeHandles()
|
const QRhiNativeHandles *QMetalCommandBuffer::nativeHandles()
|
||||||
{
|
{
|
||||||
nativeHandlesStruct.commandBuffer = d->cb;
|
nativeHandlesStruct.commandBuffer = d->cb;
|
||||||
nativeHandlesStruct.encoder = d->currentPassEncoder;
|
nativeHandlesStruct.encoder = d->currentRenderPassEncoder;
|
||||||
return &nativeHandlesStruct;
|
return &nativeHandlesStruct;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QMetalCommandBuffer::resetState()
|
void QMetalCommandBuffer::resetState()
|
||||||
{
|
{
|
||||||
d->currentPassEncoder = nil;
|
d->currentRenderPassEncoder = nil;
|
||||||
|
d->currentComputePassEncoder = nil;
|
||||||
d->currentPassRpDesc = nil;
|
d->currentPassRpDesc = nil;
|
||||||
resetPerPassState();
|
resetPerPassState();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QMetalCommandBuffer::resetPerPassState()
|
void QMetalCommandBuffer::resetPerPassState()
|
||||||
{
|
{
|
||||||
|
recordingPass = NoPass;
|
||||||
currentTarget = nullptr;
|
currentTarget = nullptr;
|
||||||
resetPerPassCachedState();
|
resetPerPassCachedState();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QMetalCommandBuffer::resetPerPassCachedState()
|
void QMetalCommandBuffer::resetPerPassCachedState()
|
||||||
{
|
{
|
||||||
currentPipeline = nullptr;
|
currentGraphicsPipeline = nullptr;
|
||||||
|
currentComputePipeline = nullptr;
|
||||||
currentPipelineGeneration = 0;
|
currentPipelineGeneration = 0;
|
||||||
currentSrb = nullptr;
|
currentGraphicsSrb = nullptr;
|
||||||
|
currentComputeSrb = nullptr;
|
||||||
currentSrbGeneration = 0;
|
currentSrbGeneration = 0;
|
||||||
currentResSlot = -1;
|
currentResSlot = -1;
|
||||||
currentIndexBuffer = nullptr;
|
currentIndexBuffer = nullptr;
|
||||||
|
@ -113,6 +113,7 @@ struct QMetalTexture : public QRhiTexture
|
|||||||
int lastActiveFrameSlot = -1;
|
int lastActiveFrameSlot = -1;
|
||||||
friend class QRhiMetal;
|
friend class QRhiMetal;
|
||||||
friend struct QMetalShaderResourceBindings;
|
friend struct QMetalShaderResourceBindings;
|
||||||
|
friend struct QMetalTextureData;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct QMetalSamplerData;
|
struct QMetalSamplerData;
|
||||||
@ -200,10 +201,20 @@ struct QMetalShaderResourceBindings : public QRhiShaderResourceBindings
|
|||||||
quint64 samplerId;
|
quint64 samplerId;
|
||||||
uint samplerGeneration;
|
uint samplerGeneration;
|
||||||
};
|
};
|
||||||
|
struct BoundStorageImageData {
|
||||||
|
quint64 id;
|
||||||
|
uint generation;
|
||||||
|
};
|
||||||
|
struct BoundStorageBufferData {
|
||||||
|
quint64 id;
|
||||||
|
uint generation;
|
||||||
|
};
|
||||||
struct BoundResourceData {
|
struct BoundResourceData {
|
||||||
union {
|
union {
|
||||||
BoundUniformBufferData ubuf;
|
BoundUniformBufferData ubuf;
|
||||||
BoundSampledTextureData stex;
|
BoundSampledTextureData stex;
|
||||||
|
BoundStorageImageData simage;
|
||||||
|
BoundStorageBufferData sbuf;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
QVector<BoundResourceData> boundResourceData;
|
QVector<BoundResourceData> boundResourceData;
|
||||||
@ -227,6 +238,21 @@ struct QMetalGraphicsPipeline : public QRhiGraphicsPipeline
|
|||||||
friend class QRhiMetal;
|
friend class QRhiMetal;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct QMetalComputePipelineData;
|
||||||
|
|
||||||
|
struct QMetalComputePipeline : public QRhiComputePipeline
|
||||||
|
{
|
||||||
|
QMetalComputePipeline(QRhiImplementation *rhi);
|
||||||
|
~QMetalComputePipeline();
|
||||||
|
void release() override;
|
||||||
|
bool build() override;
|
||||||
|
|
||||||
|
QMetalComputePipelineData *d;
|
||||||
|
uint generation = 0;
|
||||||
|
int lastActiveFrameSlot = -1;
|
||||||
|
friend class QRhiMetal;
|
||||||
|
};
|
||||||
|
|
||||||
struct QMetalCommandBufferData;
|
struct QMetalCommandBufferData;
|
||||||
struct QMetalSwapChain;
|
struct QMetalSwapChain;
|
||||||
|
|
||||||
@ -239,10 +265,19 @@ struct QMetalCommandBuffer : public QRhiCommandBuffer
|
|||||||
QMetalCommandBufferData *d = nullptr;
|
QMetalCommandBufferData *d = nullptr;
|
||||||
QRhiMetalCommandBufferNativeHandles nativeHandlesStruct;
|
QRhiMetalCommandBufferNativeHandles nativeHandlesStruct;
|
||||||
|
|
||||||
|
enum PassType {
|
||||||
|
NoPass,
|
||||||
|
RenderPass,
|
||||||
|
ComputePass
|
||||||
|
};
|
||||||
|
|
||||||
|
PassType recordingPass;
|
||||||
QRhiRenderTarget *currentTarget;
|
QRhiRenderTarget *currentTarget;
|
||||||
QRhiGraphicsPipeline *currentPipeline;
|
QRhiGraphicsPipeline *currentGraphicsPipeline;
|
||||||
|
QRhiComputePipeline *currentComputePipeline;
|
||||||
uint currentPipelineGeneration;
|
uint currentPipelineGeneration;
|
||||||
QRhiShaderResourceBindings *currentSrb;
|
QRhiShaderResourceBindings *currentGraphicsSrb;
|
||||||
|
QRhiShaderResourceBindings *currentComputeSrb;
|
||||||
uint currentSrbGeneration;
|
uint currentSrbGeneration;
|
||||||
int currentResSlot;
|
int currentResSlot;
|
||||||
QRhiBuffer *currentIndexBuffer;
|
QRhiBuffer *currentIndexBuffer;
|
||||||
@ -296,6 +331,7 @@ public:
|
|||||||
void destroy() override;
|
void destroy() override;
|
||||||
|
|
||||||
QRhiGraphicsPipeline *createGraphicsPipeline() override;
|
QRhiGraphicsPipeline *createGraphicsPipeline() override;
|
||||||
|
QRhiComputePipeline *createComputePipeline() override;
|
||||||
QRhiShaderResourceBindings *createShaderResourceBindings() override;
|
QRhiShaderResourceBindings *createShaderResourceBindings() override;
|
||||||
QRhiBuffer *createBuffer(QRhiBuffer::Type type,
|
QRhiBuffer *createBuffer(QRhiBuffer::Type type,
|
||||||
QRhiBuffer::UsageFlags usage,
|
QRhiBuffer::UsageFlags usage,
|
||||||
@ -360,6 +396,11 @@ public:
|
|||||||
void debugMarkEnd(QRhiCommandBuffer *cb) override;
|
void debugMarkEnd(QRhiCommandBuffer *cb) override;
|
||||||
void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) override;
|
void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) override;
|
||||||
|
|
||||||
|
void beginComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
|
||||||
|
void endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
|
||||||
|
void setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps) override;
|
||||||
|
void dispatch(QRhiCommandBuffer *cb, int x, int y, int z) override;
|
||||||
|
|
||||||
const QRhiNativeHandles *nativeHandles(QRhiCommandBuffer *cb) override;
|
const QRhiNativeHandles *nativeHandles(QRhiCommandBuffer *cb) override;
|
||||||
void beginExternal(QRhiCommandBuffer *cb) override;
|
void beginExternal(QRhiCommandBuffer *cb) override;
|
||||||
void endExternal(QRhiCommandBuffer *cb) override;
|
void endExternal(QRhiCommandBuffer *cb) override;
|
||||||
@ -393,8 +434,6 @@ public:
|
|||||||
|
|
||||||
bool importedDevice = false;
|
bool importedDevice = false;
|
||||||
bool importedCmdQueue = false;
|
bool importedCmdQueue = false;
|
||||||
bool inFrame = false;
|
|
||||||
bool inPass = false;
|
|
||||||
QMetalSwapChain *currentSwapChain = nullptr;
|
QMetalSwapChain *currentSwapChain = nullptr;
|
||||||
QSet<QMetalSwapChain *> swapchains;
|
QSet<QMetalSwapChain *> swapchains;
|
||||||
QRhiMetalNativeHandles nativeHandlesStruct;
|
QRhiMetalNativeHandles nativeHandlesStruct;
|
||||||
|
@ -201,6 +201,11 @@ QRhiGraphicsPipeline *QRhiNull::createGraphicsPipeline()
|
|||||||
return new QNullGraphicsPipeline(this);
|
return new QNullGraphicsPipeline(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QRhiComputePipeline *QRhiNull::createComputePipeline()
|
||||||
|
{
|
||||||
|
return new QNullComputePipeline(this);
|
||||||
|
}
|
||||||
|
|
||||||
QRhiShaderResourceBindings *QRhiNull::createShaderResourceBindings()
|
QRhiShaderResourceBindings *QRhiNull::createShaderResourceBindings()
|
||||||
{
|
{
|
||||||
return new QNullShaderResourceBindings(this);
|
return new QNullShaderResourceBindings(this);
|
||||||
@ -297,6 +302,20 @@ void QRhiNull::debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg)
|
|||||||
Q_UNUSED(msg);
|
Q_UNUSED(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QRhiNull::setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps)
|
||||||
|
{
|
||||||
|
Q_UNUSED(cb);
|
||||||
|
Q_UNUSED(ps);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QRhiNull::dispatch(QRhiCommandBuffer *cb, int x, int y, int z)
|
||||||
|
{
|
||||||
|
Q_UNUSED(cb);
|
||||||
|
Q_UNUSED(x);
|
||||||
|
Q_UNUSED(y);
|
||||||
|
Q_UNUSED(z);
|
||||||
|
}
|
||||||
|
|
||||||
const QRhiNativeHandles *QRhiNull::nativeHandles(QRhiCommandBuffer *cb)
|
const QRhiNativeHandles *QRhiNull::nativeHandles(QRhiCommandBuffer *cb)
|
||||||
{
|
{
|
||||||
Q_UNUSED(cb);
|
Q_UNUSED(cb);
|
||||||
@ -395,6 +414,18 @@ void QRhiNull::endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceU
|
|||||||
resourceUpdate(cb, resourceUpdates);
|
resourceUpdate(cb, resourceUpdates);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QRhiNull::beginComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
|
||||||
|
{
|
||||||
|
if (resourceUpdates)
|
||||||
|
resourceUpdate(cb, resourceUpdates);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QRhiNull::endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
|
||||||
|
{
|
||||||
|
if (resourceUpdates)
|
||||||
|
resourceUpdate(cb, resourceUpdates);
|
||||||
|
}
|
||||||
|
|
||||||
QNullBuffer::QNullBuffer(QRhiImplementation *rhi, Type type, UsageFlags usage, int size)
|
QNullBuffer::QNullBuffer(QRhiImplementation *rhi, Type type, UsageFlags usage, int size)
|
||||||
: QRhiBuffer(rhi, type, usage, size)
|
: QRhiBuffer(rhi, type, usage, size)
|
||||||
{
|
{
|
||||||
@ -647,6 +678,25 @@ bool QNullGraphicsPipeline::build()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QNullComputePipeline::QNullComputePipeline(QRhiImplementation *rhi)
|
||||||
|
: QRhiComputePipeline(rhi)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QNullComputePipeline::~QNullComputePipeline()
|
||||||
|
{
|
||||||
|
release();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QNullComputePipeline::release()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QNullComputePipeline::build()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
QNullCommandBuffer::QNullCommandBuffer(QRhiImplementation *rhi)
|
QNullCommandBuffer::QNullCommandBuffer(QRhiImplementation *rhi)
|
||||||
: QRhiCommandBuffer(rhi)
|
: QRhiCommandBuffer(rhi)
|
||||||
{
|
{
|
||||||
|
@ -154,6 +154,14 @@ struct QNullGraphicsPipeline : public QRhiGraphicsPipeline
|
|||||||
bool build() override;
|
bool build() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct QNullComputePipeline : public QRhiComputePipeline
|
||||||
|
{
|
||||||
|
QNullComputePipeline(QRhiImplementation *rhi);
|
||||||
|
~QNullComputePipeline();
|
||||||
|
void release() override;
|
||||||
|
bool build() override;
|
||||||
|
};
|
||||||
|
|
||||||
struct QNullCommandBuffer : public QRhiCommandBuffer
|
struct QNullCommandBuffer : public QRhiCommandBuffer
|
||||||
{
|
{
|
||||||
QNullCommandBuffer(QRhiImplementation *rhi);
|
QNullCommandBuffer(QRhiImplementation *rhi);
|
||||||
@ -189,6 +197,7 @@ public:
|
|||||||
void destroy() override;
|
void destroy() override;
|
||||||
|
|
||||||
QRhiGraphicsPipeline *createGraphicsPipeline() override;
|
QRhiGraphicsPipeline *createGraphicsPipeline() override;
|
||||||
|
QRhiComputePipeline *createComputePipeline() override;
|
||||||
QRhiShaderResourceBindings *createShaderResourceBindings() override;
|
QRhiShaderResourceBindings *createShaderResourceBindings() override;
|
||||||
QRhiBuffer *createBuffer(QRhiBuffer::Type type,
|
QRhiBuffer *createBuffer(QRhiBuffer::Type type,
|
||||||
QRhiBuffer::UsageFlags usage,
|
QRhiBuffer::UsageFlags usage,
|
||||||
@ -253,6 +262,11 @@ public:
|
|||||||
void debugMarkEnd(QRhiCommandBuffer *cb) override;
|
void debugMarkEnd(QRhiCommandBuffer *cb) override;
|
||||||
void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) override;
|
void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) override;
|
||||||
|
|
||||||
|
void beginComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
|
||||||
|
void endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
|
||||||
|
void setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps) override;
|
||||||
|
void dispatch(QRhiCommandBuffer *cb, int x, int y, int z) override;
|
||||||
|
|
||||||
const QRhiNativeHandles *nativeHandles(QRhiCommandBuffer *cb) override;
|
const QRhiNativeHandles *nativeHandles(QRhiCommandBuffer *cb) override;
|
||||||
void beginExternal(QRhiCommandBuffer *cb) override;
|
void beginExternal(QRhiCommandBuffer *cb) override;
|
||||||
void endExternal(QRhiCommandBuffer *cb) override;
|
void endExternal(QRhiCommandBuffer *cb) override;
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -61,6 +61,8 @@ static const int QVK_FRAMES_IN_FLIGHT = 2;
|
|||||||
static const int QVK_DESC_SETS_PER_POOL = 128;
|
static const int QVK_DESC_SETS_PER_POOL = 128;
|
||||||
static const int QVK_UNIFORM_BUFFERS_PER_POOL = 256;
|
static const int QVK_UNIFORM_BUFFERS_PER_POOL = 256;
|
||||||
static const int QVK_COMBINED_IMAGE_SAMPLERS_PER_POOL = 256;
|
static const int QVK_COMBINED_IMAGE_SAMPLERS_PER_POOL = 256;
|
||||||
|
static const int QVK_STORAGE_BUFFERS_PER_POOL = 128;
|
||||||
|
static const int QVK_STORAGE_IMAGES_PER_POOL = 128;
|
||||||
|
|
||||||
static const int QVK_MAX_ACTIVE_TIMESTAMP_PAIRS = 16;
|
static const int QVK_MAX_ACTIVE_TIMESTAMP_PAIRS = 16;
|
||||||
|
|
||||||
@ -123,12 +125,14 @@ struct QVkTexture : public QRhiTexture
|
|||||||
|
|
||||||
bool prepareBuild(QSize *adjustedSize = nullptr);
|
bool prepareBuild(QSize *adjustedSize = nullptr);
|
||||||
bool finishBuild();
|
bool finishBuild();
|
||||||
|
VkImageView imageViewForLevel(int level);
|
||||||
|
|
||||||
VkImage image = VK_NULL_HANDLE;
|
VkImage image = VK_NULL_HANDLE;
|
||||||
VkImageView imageView = VK_NULL_HANDLE;
|
VkImageView imageView = VK_NULL_HANDLE;
|
||||||
QVkAlloc imageAlloc = nullptr;
|
QVkAlloc imageAlloc = nullptr;
|
||||||
VkBuffer stagingBuffers[QVK_FRAMES_IN_FLIGHT];
|
VkBuffer stagingBuffers[QVK_FRAMES_IN_FLIGHT];
|
||||||
QVkAlloc stagingAllocations[QVK_FRAMES_IN_FLIGHT];
|
QVkAlloc stagingAllocations[QVK_FRAMES_IN_FLIGHT];
|
||||||
|
VkImageView perLevelImageViews[QRhi::MAX_LEVELS];
|
||||||
bool owns = true;
|
bool owns = true;
|
||||||
QRhiVulkanTextureNativeHandles nativeHandlesStruct;
|
QRhiVulkanTextureNativeHandles nativeHandlesStruct;
|
||||||
struct UsageState {
|
struct UsageState {
|
||||||
@ -246,10 +250,20 @@ struct QVkShaderResourceBindings : public QRhiShaderResourceBindings
|
|||||||
quint64 samplerId;
|
quint64 samplerId;
|
||||||
uint samplerGeneration;
|
uint samplerGeneration;
|
||||||
};
|
};
|
||||||
|
struct BoundStorageImageData {
|
||||||
|
quint64 id;
|
||||||
|
uint generation;
|
||||||
|
};
|
||||||
|
struct BoundStorageBufferData {
|
||||||
|
quint64 id;
|
||||||
|
uint generation;
|
||||||
|
};
|
||||||
struct BoundResourceData {
|
struct BoundResourceData {
|
||||||
union {
|
union {
|
||||||
BoundUniformBufferData ubuf;
|
BoundUniformBufferData ubuf;
|
||||||
BoundSampledTextureData stex;
|
BoundSampledTextureData stex;
|
||||||
|
BoundStorageImageData simage;
|
||||||
|
BoundStorageBufferData sbuf;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
QVector<BoundResourceData> boundResourceData[QVK_FRAMES_IN_FLIGHT];
|
QVector<BoundResourceData> boundResourceData[QVK_FRAMES_IN_FLIGHT];
|
||||||
@ -273,6 +287,20 @@ struct QVkGraphicsPipeline : public QRhiGraphicsPipeline
|
|||||||
friend class QRhiVulkan;
|
friend class QRhiVulkan;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct QVkComputePipeline : public QRhiComputePipeline
|
||||||
|
{
|
||||||
|
QVkComputePipeline(QRhiImplementation *rhi);
|
||||||
|
~QVkComputePipeline();
|
||||||
|
void release() override;
|
||||||
|
bool build() override;
|
||||||
|
|
||||||
|
VkPipelineLayout layout = VK_NULL_HANDLE;
|
||||||
|
VkPipeline pipeline = VK_NULL_HANDLE;
|
||||||
|
int lastActiveFrameSlot = -1;
|
||||||
|
uint generation = 0;
|
||||||
|
friend class QRhiVulkan;
|
||||||
|
};
|
||||||
|
|
||||||
struct QVkCommandBuffer : public QRhiCommandBuffer
|
struct QVkCommandBuffer : public QRhiCommandBuffer
|
||||||
{
|
{
|
||||||
QVkCommandBuffer(QRhiImplementation *rhi);
|
QVkCommandBuffer(QRhiImplementation *rhi);
|
||||||
@ -287,16 +315,25 @@ struct QVkCommandBuffer : public QRhiCommandBuffer
|
|||||||
return &nativeHandlesStruct;
|
return &nativeHandlesStruct;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum PassType {
|
||||||
|
NoPass,
|
||||||
|
RenderPass,
|
||||||
|
ComputePass
|
||||||
|
};
|
||||||
|
|
||||||
void resetState() {
|
void resetState() {
|
||||||
resetCommands();
|
resetCommands();
|
||||||
|
recordingPass = NoPass;
|
||||||
currentTarget = nullptr;
|
currentTarget = nullptr;
|
||||||
resetCachedState();
|
resetCachedState();
|
||||||
}
|
}
|
||||||
|
|
||||||
void resetCachedState() {
|
void resetCachedState() {
|
||||||
currentPipeline = nullptr;
|
currentGraphicsPipeline = nullptr;
|
||||||
|
currentComputePipeline = nullptr;
|
||||||
currentPipelineGeneration = 0;
|
currentPipelineGeneration = 0;
|
||||||
currentSrb = nullptr;
|
currentGraphicsSrb = nullptr;
|
||||||
|
currentComputeSrb = nullptr;
|
||||||
currentSrbGeneration = 0;
|
currentSrbGeneration = 0;
|
||||||
currentDescSetSlot = -1;
|
currentDescSetSlot = -1;
|
||||||
currentIndexBuffer = VK_NULL_HANDLE;
|
currentIndexBuffer = VK_NULL_HANDLE;
|
||||||
@ -306,10 +343,13 @@ struct QVkCommandBuffer : public QRhiCommandBuffer
|
|||||||
memset(currentVertexOffsets, 0, sizeof(currentVertexOffsets));
|
memset(currentVertexOffsets, 0, sizeof(currentVertexOffsets));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PassType recordingPass;
|
||||||
QRhiRenderTarget *currentTarget;
|
QRhiRenderTarget *currentTarget;
|
||||||
QRhiGraphicsPipeline *currentPipeline;
|
QRhiGraphicsPipeline *currentGraphicsPipeline;
|
||||||
|
QRhiComputePipeline *currentComputePipeline;
|
||||||
uint currentPipelineGeneration;
|
uint currentPipelineGeneration;
|
||||||
QRhiShaderResourceBindings *currentSrb;
|
QRhiShaderResourceBindings *currentGraphicsSrb;
|
||||||
|
QRhiShaderResourceBindings *currentComputeSrb;
|
||||||
uint currentSrbGeneration;
|
uint currentSrbGeneration;
|
||||||
int currentDescSetSlot;
|
int currentDescSetSlot;
|
||||||
VkBuffer currentIndexBuffer;
|
VkBuffer currentIndexBuffer;
|
||||||
@ -343,7 +383,8 @@ struct QVkCommandBuffer : public QRhiCommandBuffer
|
|||||||
DebugMarkerBegin,
|
DebugMarkerBegin,
|
||||||
DebugMarkerEnd,
|
DebugMarkerEnd,
|
||||||
DebugMarkerInsert,
|
DebugMarkerInsert,
|
||||||
TransitionPassResources
|
TransitionPassResources,
|
||||||
|
Dispatch
|
||||||
};
|
};
|
||||||
Cmd cmd;
|
Cmd cmd;
|
||||||
|
|
||||||
@ -456,6 +497,9 @@ struct QVkCommandBuffer : public QRhiCommandBuffer
|
|||||||
struct {
|
struct {
|
||||||
int trackerIndex;
|
int trackerIndex;
|
||||||
} transitionResources;
|
} transitionResources;
|
||||||
|
struct {
|
||||||
|
int x, y, z;
|
||||||
|
} dispatch;
|
||||||
} args;
|
} args;
|
||||||
};
|
};
|
||||||
QVector<Command> commands;
|
QVector<Command> commands;
|
||||||
@ -532,7 +576,12 @@ struct QVkSwapChain : public QRhiSwapChain
|
|||||||
VkFramebuffer fb = VK_NULL_HANDLE;
|
VkFramebuffer fb = VK_NULL_HANDLE;
|
||||||
VkImage msaaImage = VK_NULL_HANDLE;
|
VkImage msaaImage = VK_NULL_HANDLE;
|
||||||
VkImageView msaaImageView = VK_NULL_HANDLE;
|
VkImageView msaaImageView = VK_NULL_HANDLE;
|
||||||
bool transferSource = false;
|
enum LastUse {
|
||||||
|
ScImageUseNone,
|
||||||
|
ScImageUseRender,
|
||||||
|
ScImageUseTransferSource
|
||||||
|
};
|
||||||
|
LastUse lastUse = ScImageUseNone;
|
||||||
} imageRes[MAX_BUFFER_COUNT];
|
} imageRes[MAX_BUFFER_COUNT];
|
||||||
|
|
||||||
struct FrameResources {
|
struct FrameResources {
|
||||||
@ -565,6 +614,7 @@ public:
|
|||||||
void destroy() override;
|
void destroy() override;
|
||||||
|
|
||||||
QRhiGraphicsPipeline *createGraphicsPipeline() override;
|
QRhiGraphicsPipeline *createGraphicsPipeline() override;
|
||||||
|
QRhiComputePipeline *createComputePipeline() override;
|
||||||
QRhiShaderResourceBindings *createShaderResourceBindings() override;
|
QRhiShaderResourceBindings *createShaderResourceBindings() override;
|
||||||
QRhiBuffer *createBuffer(QRhiBuffer::Type type,
|
QRhiBuffer *createBuffer(QRhiBuffer::Type type,
|
||||||
QRhiBuffer::UsageFlags usage,
|
QRhiBuffer::UsageFlags usage,
|
||||||
@ -629,6 +679,11 @@ public:
|
|||||||
void debugMarkEnd(QRhiCommandBuffer *cb) override;
|
void debugMarkEnd(QRhiCommandBuffer *cb) override;
|
||||||
void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) override;
|
void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) override;
|
||||||
|
|
||||||
|
void beginComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
|
||||||
|
void endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
|
||||||
|
void setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps) override;
|
||||||
|
void dispatch(QRhiCommandBuffer *cb, int x, int y, int z) override;
|
||||||
|
|
||||||
const QRhiNativeHandles *nativeHandles(QRhiCommandBuffer *cb) override;
|
const QRhiNativeHandles *nativeHandles(QRhiCommandBuffer *cb) override;
|
||||||
void beginExternal(QRhiCommandBuffer *cb) override;
|
void beginExternal(QRhiCommandBuffer *cb) override;
|
||||||
void endExternal(QRhiCommandBuffer *cb) override;
|
void endExternal(QRhiCommandBuffer *cb) override;
|
||||||
@ -722,6 +777,7 @@ public:
|
|||||||
VkCommandPool cmdPool = VK_NULL_HANDLE;
|
VkCommandPool cmdPool = VK_NULL_HANDLE;
|
||||||
int gfxQueueFamilyIdx = -1;
|
int gfxQueueFamilyIdx = -1;
|
||||||
VkQueue gfxQueue = VK_NULL_HANDLE;
|
VkQueue gfxQueue = VK_NULL_HANDLE;
|
||||||
|
bool hasCompute = false;
|
||||||
quint32 timestampValidBits = 0;
|
quint32 timestampValidBits = 0;
|
||||||
bool importedAllocator = false;
|
bool importedAllocator = false;
|
||||||
QVkAllocator allocator = nullptr;
|
QVkAllocator allocator = nullptr;
|
||||||
@ -765,8 +821,6 @@ public:
|
|||||||
VkFormat optimalDsFormat = VK_FORMAT_UNDEFINED;
|
VkFormat optimalDsFormat = VK_FORMAT_UNDEFINED;
|
||||||
QMatrix4x4 clipCorrectMatrix;
|
QMatrix4x4 clipCorrectMatrix;
|
||||||
|
|
||||||
bool inFrame = false;
|
|
||||||
bool inPass = false;
|
|
||||||
QVkSwapChain *currentSwapChain = nullptr;
|
QVkSwapChain *currentSwapChain = nullptr;
|
||||||
QSet<QVkSwapChain *> swapchains;
|
QSet<QVkSwapChain *> swapchains;
|
||||||
QRhiVulkanNativeHandles nativeHandlesStruct;
|
QRhiVulkanNativeHandles nativeHandlesStruct;
|
||||||
@ -830,6 +884,7 @@ public:
|
|||||||
QVkAlloc allocation;
|
QVkAlloc allocation;
|
||||||
VkBuffer stagingBuffers[QVK_FRAMES_IN_FLIGHT];
|
VkBuffer stagingBuffers[QVK_FRAMES_IN_FLIGHT];
|
||||||
QVkAlloc stagingAllocations[QVK_FRAMES_IN_FLIGHT];
|
QVkAlloc stagingAllocations[QVK_FRAMES_IN_FLIGHT];
|
||||||
|
VkImageView extraImageViews[QRhi::MAX_LEVELS];
|
||||||
} texture;
|
} texture;
|
||||||
struct {
|
struct {
|
||||||
VkSampler sampler;
|
VkSampler sampler;
|
||||||
|
@ -522,6 +522,21 @@ QVector<QShaderDescription::InOutVariable> QShaderDescription::storageImages() c
|
|||||||
return d->storageImages;
|
return d->storageImages;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the local size of a compute shader.
|
||||||
|
|
||||||
|
For example, for a compute shader with the following declaration the
|
||||||
|
function returns { 256, 16, 1}.
|
||||||
|
|
||||||
|
\badcode
|
||||||
|
layout(local_size_x = 256, local_size_y = 16, local_size_z = 1) in;
|
||||||
|
\endcode
|
||||||
|
*/
|
||||||
|
std::array<uint, 3> QShaderDescription::computeShaderLocalSize() const
|
||||||
|
{
|
||||||
|
return d->localSize;
|
||||||
|
}
|
||||||
|
|
||||||
static struct TypeTab {
|
static struct TypeTab {
|
||||||
QString k;
|
QString k;
|
||||||
QShaderDescription::VariableType v;
|
QShaderDescription::VariableType v;
|
||||||
@ -799,6 +814,7 @@ static const QString pushConstantBlocksKey = QLatin1String("pushConstantBlocks")
|
|||||||
static const QString storageBlocksKey = QLatin1String("storageBlocks");
|
static const QString storageBlocksKey = QLatin1String("storageBlocks");
|
||||||
static const QString combinedImageSamplersKey = QLatin1String("combinedImageSamplers");
|
static const QString combinedImageSamplersKey = QLatin1String("combinedImageSamplers");
|
||||||
static const QString storageImagesKey = QLatin1String("storageImages");
|
static const QString storageImagesKey = QLatin1String("storageImages");
|
||||||
|
static const QString localSizeKey = QLatin1String("localSize");
|
||||||
|
|
||||||
static void addDeco(QJsonObject *obj, const QShaderDescription::InOutVariable &v)
|
static void addDeco(QJsonObject *obj, const QShaderDescription::InOutVariable &v)
|
||||||
{
|
{
|
||||||
@ -941,6 +957,11 @@ QJsonDocument QShaderDescriptionPrivate::makeDoc()
|
|||||||
if (!jstorageImages.isEmpty())
|
if (!jstorageImages.isEmpty())
|
||||||
root[storageImagesKey] = jstorageImages;
|
root[storageImagesKey] = jstorageImages;
|
||||||
|
|
||||||
|
QJsonArray jlocalSize;
|
||||||
|
for (int i = 0; i < 3; ++i)
|
||||||
|
jlocalSize.append(QJsonValue(int(localSize[i])));
|
||||||
|
root[localSizeKey] = jlocalSize;
|
||||||
|
|
||||||
return QJsonDocument(root);
|
return QJsonDocument(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1082,6 +1103,14 @@ void QShaderDescriptionPrivate::loadDoc(const QJsonDocument &doc)
|
|||||||
for (int i = 0; i < images.count(); ++i)
|
for (int i = 0; i < images.count(); ++i)
|
||||||
storageImages.append(inOutVar(images[i].toObject()));
|
storageImages.append(inOutVar(images[i].toObject()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (root.contains(localSizeKey)) {
|
||||||
|
QJsonArray localSizeArr = root[localSizeKey].toArray();
|
||||||
|
if (localSizeArr.count() == 3) {
|
||||||
|
for (int i = 0; i < 3; ++i)
|
||||||
|
localSize[i] = localSizeArr[i].toInt();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
@ -51,6 +51,7 @@
|
|||||||
#include <QtGui/qtguiglobal.h>
|
#include <QtGui/qtguiglobal.h>
|
||||||
#include <QtCore/QString>
|
#include <QtCore/QString>
|
||||||
#include <QtCore/QVector>
|
#include <QtCore/QVector>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
@ -254,6 +255,8 @@ public:
|
|||||||
QVector<InOutVariable> combinedImageSamplers() const;
|
QVector<InOutVariable> combinedImageSamplers() const;
|
||||||
QVector<InOutVariable> storageImages() const;
|
QVector<InOutVariable> storageImages() const;
|
||||||
|
|
||||||
|
std::array<uint, 3> computeShaderLocalSize() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QShaderDescriptionPrivate *d;
|
QShaderDescriptionPrivate *d;
|
||||||
friend struct QShaderDescriptionPrivate;
|
friend struct QShaderDescriptionPrivate;
|
||||||
|
@ -60,6 +60,7 @@ struct Q_GUI_EXPORT QShaderDescriptionPrivate
|
|||||||
QShaderDescriptionPrivate()
|
QShaderDescriptionPrivate()
|
||||||
: ref(1)
|
: ref(1)
|
||||||
{
|
{
|
||||||
|
localSize[0] = localSize[1] = localSize[2] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
QShaderDescriptionPrivate(const QShaderDescriptionPrivate *other)
|
QShaderDescriptionPrivate(const QShaderDescriptionPrivate *other)
|
||||||
@ -70,7 +71,8 @@ struct Q_GUI_EXPORT QShaderDescriptionPrivate
|
|||||||
pushConstantBlocks(other->pushConstantBlocks),
|
pushConstantBlocks(other->pushConstantBlocks),
|
||||||
storageBlocks(other->storageBlocks),
|
storageBlocks(other->storageBlocks),
|
||||||
combinedImageSamplers(other->combinedImageSamplers),
|
combinedImageSamplers(other->combinedImageSamplers),
|
||||||
storageImages(other->storageImages)
|
storageImages(other->storageImages),
|
||||||
|
localSize(other->localSize)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,6 +90,7 @@ struct Q_GUI_EXPORT QShaderDescriptionPrivate
|
|||||||
QVector<QShaderDescription::StorageBlock> storageBlocks;
|
QVector<QShaderDescription::StorageBlock> storageBlocks;
|
||||||
QVector<QShaderDescription::InOutVariable> combinedImageSamplers;
|
QVector<QShaderDescription::InOutVariable> combinedImageSamplers;
|
||||||
QVector<QShaderDescription::InOutVariable> storageImages;
|
QVector<QShaderDescription::InOutVariable> storageImages;
|
||||||
|
std::array<uint, 3> localSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
@ -113,8 +113,8 @@ void Window::customInit()
|
|||||||
qFatal("Failed to load shader pack (fragment)");
|
qFatal("Failed to load shader pack (fragment)");
|
||||||
|
|
||||||
d.ps->setShaderStages({
|
d.ps->setShaderStages({
|
||||||
{ QRhiGraphicsShaderStage::Vertex, vs },
|
{ QRhiShaderStage::Vertex, vs },
|
||||||
{ QRhiGraphicsShaderStage::Fragment, fs }
|
{ QRhiShaderStage::Fragment, fs }
|
||||||
});
|
});
|
||||||
|
|
||||||
QRhiVertexInputLayout inputLayout;
|
QRhiVertexInputLayout inputLayout;
|
||||||
|
@ -117,8 +117,8 @@ void Window::customInit()
|
|||||||
qFatal("Failed to load shader pack (fragment)");
|
qFatal("Failed to load shader pack (fragment)");
|
||||||
|
|
||||||
d.ps->setShaderStages({
|
d.ps->setShaderStages({
|
||||||
{ QRhiGraphicsShaderStage::Vertex, vs },
|
{ QRhiShaderStage::Vertex, vs },
|
||||||
{ QRhiGraphicsShaderStage::Fragment, fs }
|
{ QRhiShaderStage::Fragment, fs }
|
||||||
});
|
});
|
||||||
|
|
||||||
QRhiVertexInputLayout inputLayout;
|
QRhiVertexInputLayout inputLayout;
|
||||||
|
41
tests/manual/rhi/computebuffer/buffer.comp
Normal file
41
tests/manual/rhi/computebuffer/buffer.comp
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#version 440
|
||||||
|
|
||||||
|
layout (local_size_x = 256) in;
|
||||||
|
|
||||||
|
struct Data
|
||||||
|
{
|
||||||
|
vec2 pos;
|
||||||
|
float dir;
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(std140, binding = 0) buffer StorageBuffer
|
||||||
|
{
|
||||||
|
Data d[];
|
||||||
|
} buf;
|
||||||
|
|
||||||
|
layout(std140, binding = 1) uniform UniformBuffer
|
||||||
|
{
|
||||||
|
float step;
|
||||||
|
uint count;
|
||||||
|
} ubuf;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
uint index = gl_GlobalInvocationID.x;
|
||||||
|
if (index < ubuf.count) {
|
||||||
|
vec2 p = buf.d[index].pos;
|
||||||
|
float dir = buf.d[index].dir;
|
||||||
|
|
||||||
|
p.x += dir * ubuf.step * 0.01;
|
||||||
|
if (p.x > 1.0) {
|
||||||
|
p.x = 1.0;
|
||||||
|
buf.d[index].dir *= -1.0;
|
||||||
|
}
|
||||||
|
if (p.x < -1.0) {
|
||||||
|
p.x = -1.0;
|
||||||
|
buf.d[index].dir *= -1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.d[index].pos = p;
|
||||||
|
}
|
||||||
|
}
|
BIN
tests/manual/rhi/computebuffer/buffer.comp.qsb
Normal file
BIN
tests/manual/rhi/computebuffer/buffer.comp.qsb
Normal file
Binary file not shown.
3
tests/manual/rhi/computebuffer/buildshaders.bat
Executable file
3
tests/manual/rhi/computebuffer/buildshaders.bat
Executable file
@ -0,0 +1,3 @@
|
|||||||
|
qsb --glsl "310 es,430" --hlsl 50 --msl 12 buffer.comp -o buffer.comp.qsb
|
||||||
|
qsb --glsl "310 es,430" --hlsl 50 --msl 12 main.vert -o main.vert.qsb
|
||||||
|
qsb --glsl "310 es,430" --hlsl 50 --msl 12 main.frag -o main.frag.qsb
|
202
tests/manual/rhi/computebuffer/computebuffer.cpp
Normal file
202
tests/manual/rhi/computebuffer/computebuffer.cpp
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2019 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of the examples of the Qt Toolkit.
|
||||||
|
**
|
||||||
|
** $QT_BEGIN_LICENSE:BSD$
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** BSD License Usage
|
||||||
|
** Alternatively, you may use this file under the terms of the BSD license
|
||||||
|
** as follows:
|
||||||
|
**
|
||||||
|
** "Redistribution and use in source and binary forms, with or without
|
||||||
|
** modification, are permitted provided that the following conditions are
|
||||||
|
** met:
|
||||||
|
** * Redistributions of source code must retain the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer.
|
||||||
|
** * Redistributions in binary form must reproduce the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer in
|
||||||
|
** the documentation and/or other materials provided with the
|
||||||
|
** distribution.
|
||||||
|
** * Neither the name of The Qt Company Ltd nor the names of its
|
||||||
|
** contributors may be used to endorse or promote products derived
|
||||||
|
** from this software without specific prior written permission.
|
||||||
|
**
|
||||||
|
**
|
||||||
|
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||||
|
**
|
||||||
|
** $QT_END_LICENSE$
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "../shared/examplefw.h"
|
||||||
|
#include <QRandomGenerator>
|
||||||
|
|
||||||
|
// Compute shader example. Writes to a storage buffer from a compute shader,
|
||||||
|
// then uses the same buffer as vertex buffer in the vertex stage. This would
|
||||||
|
// be typical when implementing particles for example. Here we just simply move
|
||||||
|
// the positions back and forth along the X axis.
|
||||||
|
|
||||||
|
// Note that the example relies on gl_PointSize which is not supported
|
||||||
|
// everywhere. So in some cases the points will be of size 1.
|
||||||
|
|
||||||
|
struct {
|
||||||
|
QVector<QRhiResource *> releasePool;
|
||||||
|
QRhiBuffer *sbuf = nullptr;
|
||||||
|
QRhiBuffer *computeUniBuf = nullptr;
|
||||||
|
QRhiShaderResourceBindings *computeBindings = nullptr;
|
||||||
|
QRhiComputePipeline *computePipeline = nullptr;
|
||||||
|
QRhiShaderResourceBindings *graphicsBindings = nullptr;
|
||||||
|
QRhiGraphicsPipeline *graphicsPipeline = nullptr;
|
||||||
|
QRhiResourceUpdateBatch *initialUpdates = nullptr;
|
||||||
|
float step = 0.2f;
|
||||||
|
} d;
|
||||||
|
|
||||||
|
// these struct must match the std140 packing rules
|
||||||
|
struct Data {
|
||||||
|
float pos[2];
|
||||||
|
float dir;
|
||||||
|
quint32 pad[1];
|
||||||
|
};
|
||||||
|
struct ComputeUBuf {
|
||||||
|
float step;
|
||||||
|
quint32 count;
|
||||||
|
};
|
||||||
|
|
||||||
|
const int DATA_COUNT = 256 * 128;
|
||||||
|
|
||||||
|
const int COMPUTE_UBUF_SIZE = 8;
|
||||||
|
|
||||||
|
void Window::customInit()
|
||||||
|
{
|
||||||
|
if (!m_r->isFeatureSupported(QRhi::Compute))
|
||||||
|
qFatal("Compute is not supported");
|
||||||
|
|
||||||
|
// compute pass
|
||||||
|
|
||||||
|
d.sbuf = m_r->newBuffer(QRhiBuffer::Immutable,
|
||||||
|
QRhiBuffer::StorageBuffer | QRhiBuffer::VertexBuffer,
|
||||||
|
sizeof(Data) * DATA_COUNT);
|
||||||
|
d.sbuf->build();
|
||||||
|
d.releasePool << d.sbuf;
|
||||||
|
|
||||||
|
d.computeUniBuf = m_r->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, COMPUTE_UBUF_SIZE);
|
||||||
|
d.computeUniBuf->build();
|
||||||
|
d.releasePool << d.computeUniBuf;
|
||||||
|
|
||||||
|
d.initialUpdates = m_r->nextResourceUpdateBatch();
|
||||||
|
|
||||||
|
QByteArray data;
|
||||||
|
data.resize(sizeof(Data) * DATA_COUNT);
|
||||||
|
Data *p = reinterpret_cast<Data *>(data.data());
|
||||||
|
QRandomGenerator *rgen = QRandomGenerator::global();
|
||||||
|
for (int i = 0; i < DATA_COUNT; ++i) {
|
||||||
|
p->pos[0] = rgen->bounded(1000) / 500.0f - 1.0f;
|
||||||
|
p->pos[1] = rgen->bounded(1000) / 500.0f - 1.0f;
|
||||||
|
p->dir = rgen->bounded(2) ? 1 : -1;
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
d.initialUpdates->uploadStaticBuffer(d.sbuf, data.constData());
|
||||||
|
|
||||||
|
ComputeUBuf ud;
|
||||||
|
ud.step = d.step;
|
||||||
|
ud.count = DATA_COUNT;
|
||||||
|
d.initialUpdates->updateDynamicBuffer(d.computeUniBuf, 0, COMPUTE_UBUF_SIZE, &ud);
|
||||||
|
|
||||||
|
d.computeBindings = m_r->newShaderResourceBindings();
|
||||||
|
d.computeBindings->setBindings({
|
||||||
|
QRhiShaderResourceBinding::bufferLoadStore(0, QRhiShaderResourceBinding::ComputeStage, d.sbuf),
|
||||||
|
QRhiShaderResourceBinding::uniformBuffer(1, QRhiShaderResourceBinding::ComputeStage, d.computeUniBuf)
|
||||||
|
});
|
||||||
|
d.computeBindings->build();
|
||||||
|
d.releasePool << d.computeBindings;
|
||||||
|
|
||||||
|
d.computePipeline = m_r->newComputePipeline();
|
||||||
|
d.computePipeline->setShaderResourceBindings(d.computeBindings);
|
||||||
|
d.computePipeline->setShaderStage({ QRhiShaderStage::Compute, getShader(QLatin1String(":/buffer.comp.qsb")) });
|
||||||
|
d.computePipeline->build();
|
||||||
|
d.releasePool << d.computePipeline;
|
||||||
|
|
||||||
|
// graphics pass
|
||||||
|
|
||||||
|
d.graphicsBindings = m_r->newShaderResourceBindings();
|
||||||
|
d.graphicsBindings->build();
|
||||||
|
d.releasePool << d.graphicsBindings;
|
||||||
|
|
||||||
|
d.graphicsPipeline = m_r->newGraphicsPipeline();
|
||||||
|
d.graphicsPipeline->setTopology(QRhiGraphicsPipeline::Points);
|
||||||
|
d.graphicsPipeline->setShaderStages({
|
||||||
|
{ QRhiShaderStage::Vertex, getShader(QLatin1String(":/main.vert.qsb")) },
|
||||||
|
{ QRhiShaderStage::Fragment, getShader(QLatin1String(":/main.frag.qsb")) }
|
||||||
|
});
|
||||||
|
QRhiVertexInputLayout inputLayout;
|
||||||
|
inputLayout.setBindings({
|
||||||
|
{ 2 * sizeof(float) }
|
||||||
|
});
|
||||||
|
inputLayout.setAttributes({
|
||||||
|
{ 0, 0, QRhiVertexInputAttribute::Float2, 0 },
|
||||||
|
});
|
||||||
|
d.graphicsPipeline->setVertexInputLayout(inputLayout);
|
||||||
|
d.graphicsPipeline->setShaderResourceBindings(d.graphicsBindings);
|
||||||
|
d.graphicsPipeline->setRenderPassDescriptor(m_rp);
|
||||||
|
d.graphicsPipeline->build();
|
||||||
|
d.releasePool << d.graphicsPipeline;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::customRelease()
|
||||||
|
{
|
||||||
|
qDeleteAll(d.releasePool);
|
||||||
|
d.releasePool.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::customRender()
|
||||||
|
{
|
||||||
|
const QSize outputSizeInPixels = m_sc->currentPixelSize();
|
||||||
|
QRhiCommandBuffer *cb = m_sc->currentFrameCommandBuffer();
|
||||||
|
QRhiResourceUpdateBatch *u = m_r->nextResourceUpdateBatch();
|
||||||
|
if (d.initialUpdates) {
|
||||||
|
u->merge(d.initialUpdates);
|
||||||
|
d.initialUpdates->release();
|
||||||
|
d.initialUpdates = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
u->updateDynamicBuffer(d.computeUniBuf, 0, sizeof(float), &d.step);
|
||||||
|
d.step += 0.01f;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// compute pass
|
||||||
|
cb->beginComputePass(u);
|
||||||
|
cb->setComputePipeline(d.computePipeline);
|
||||||
|
cb->setShaderResources();
|
||||||
|
cb->dispatch(DATA_COUNT / 256, 1, 1);
|
||||||
|
cb->endComputePass();
|
||||||
|
|
||||||
|
// graphics pass
|
||||||
|
cb->beginPass(m_sc->currentFrameRenderTarget(), QColor::fromRgbF(0.4f, 0.7f, 0.0f, 1.0f), { 1.0f, 0 });
|
||||||
|
cb->setGraphicsPipeline(d.graphicsPipeline);
|
||||||
|
cb->setViewport({ 0, 0, float(outputSizeInPixels.width()), float(outputSizeInPixels.height()) });
|
||||||
|
QRhiCommandBuffer::VertexInput vbufBinding(d.sbuf, 0);
|
||||||
|
cb->setVertexInput(0, 1, &vbufBinding);
|
||||||
|
cb->draw(DATA_COUNT);
|
||||||
|
cb->endPass();
|
||||||
|
}
|
8
tests/manual/rhi/computebuffer/computebuffer.pro
Normal file
8
tests/manual/rhi/computebuffer/computebuffer.pro
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
TEMPLATE = app
|
||||||
|
|
||||||
|
QT += gui-private
|
||||||
|
|
||||||
|
SOURCES = \
|
||||||
|
computebuffer.cpp
|
||||||
|
|
||||||
|
RESOURCES = computebuffer.qrc
|
7
tests/manual/rhi/computebuffer/computebuffer.qrc
Normal file
7
tests/manual/rhi/computebuffer/computebuffer.qrc
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<!DOCTYPE RCC><RCC version="1.0">
|
||||||
|
<qresource>
|
||||||
|
<file>buffer.comp.qsb</file>
|
||||||
|
<file>main.vert.qsb</file>
|
||||||
|
<file>main.frag.qsb</file>
|
||||||
|
</qresource>
|
||||||
|
</RCC>
|
8
tests/manual/rhi/computebuffer/main.frag
Normal file
8
tests/manual/rhi/computebuffer/main.frag
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#version 440
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 fragColor;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
fragColor = vec4(1.0);
|
||||||
|
}
|
BIN
tests/manual/rhi/computebuffer/main.frag.qsb
Normal file
BIN
tests/manual/rhi/computebuffer/main.frag.qsb
Normal file
Binary file not shown.
11
tests/manual/rhi/computebuffer/main.vert
Normal file
11
tests/manual/rhi/computebuffer/main.vert
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#version 440
|
||||||
|
|
||||||
|
layout(location = 0) in vec4 position;
|
||||||
|
|
||||||
|
out gl_PerVertex { vec4 gl_Position; float gl_PointSize; };
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gl_PointSize = 4.0; // required with Vulkan when drawing points
|
||||||
|
gl_Position = position;
|
||||||
|
}
|
BIN
tests/manual/rhi/computebuffer/main.vert.qsb
Normal file
BIN
tests/manual/rhi/computebuffer/main.vert.qsb
Normal file
Binary file not shown.
1
tests/manual/rhi/computeimage/buildshaders.bat
Executable file
1
tests/manual/rhi/computeimage/buildshaders.bat
Executable file
@ -0,0 +1 @@
|
|||||||
|
qsb --glsl "310 es,430" --hlsl 50 --msl 12 image.comp -o image.comp.qsb
|
228
tests/manual/rhi/computeimage/computeimage.cpp
Normal file
228
tests/manual/rhi/computeimage/computeimage.cpp
Normal file
@ -0,0 +1,228 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2019 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of the examples of the Qt Toolkit.
|
||||||
|
**
|
||||||
|
** $QT_BEGIN_LICENSE:BSD$
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** BSD License Usage
|
||||||
|
** Alternatively, you may use this file under the terms of the BSD license
|
||||||
|
** as follows:
|
||||||
|
**
|
||||||
|
** "Redistribution and use in source and binary forms, with or without
|
||||||
|
** modification, are permitted provided that the following conditions are
|
||||||
|
** met:
|
||||||
|
** * Redistributions of source code must retain the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer.
|
||||||
|
** * Redistributions in binary form must reproduce the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer in
|
||||||
|
** the documentation and/or other materials provided with the
|
||||||
|
** distribution.
|
||||||
|
** * Neither the name of The Qt Company Ltd nor the names of its
|
||||||
|
** contributors may be used to endorse or promote products derived
|
||||||
|
** from this software without specific prior written permission.
|
||||||
|
**
|
||||||
|
**
|
||||||
|
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||||
|
**
|
||||||
|
** $QT_END_LICENSE$
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "../shared/examplefw.h"
|
||||||
|
|
||||||
|
// Compute shader example with image load/store. The texture sampled in the
|
||||||
|
// fragment shader is generated by the compute shader.
|
||||||
|
|
||||||
|
struct {
|
||||||
|
QVector<QRhiResource *> releasePool;
|
||||||
|
|
||||||
|
QRhiTexture *texIn = nullptr;
|
||||||
|
QRhiTexture *texOut = nullptr;
|
||||||
|
QRhiBuffer *computeUBuf = nullptr;
|
||||||
|
QRhiShaderResourceBindings *computeBindings = nullptr;
|
||||||
|
QRhiComputePipeline *computePipeline = nullptr;
|
||||||
|
|
||||||
|
QRhiBuffer *vbuf = nullptr;
|
||||||
|
QRhiBuffer *ibuf = nullptr;
|
||||||
|
QRhiBuffer *ubuf = nullptr;
|
||||||
|
QRhiSampler *sampler = nullptr;
|
||||||
|
QRhiShaderResourceBindings *srb = nullptr;
|
||||||
|
QRhiGraphicsPipeline *ps = nullptr;
|
||||||
|
|
||||||
|
QRhiResourceUpdateBatch *initialUpdates = nullptr;
|
||||||
|
QSize imageSize;
|
||||||
|
QMatrix4x4 winProj;
|
||||||
|
float factor = 1.0f;
|
||||||
|
} d;
|
||||||
|
|
||||||
|
static float quadVertexData[] =
|
||||||
|
{ // Y up, CCW
|
||||||
|
-0.5f, 0.5f, 0.0f, 0.0f,
|
||||||
|
-0.5f, -0.5f, 0.0f, 1.0f,
|
||||||
|
0.5f, -0.5f, 1.0f, 1.0f,
|
||||||
|
0.5f, 0.5f, 1.0f, 0.0f
|
||||||
|
};
|
||||||
|
|
||||||
|
static quint16 quadIndexData[] =
|
||||||
|
{
|
||||||
|
0, 1, 2, 0, 2, 3
|
||||||
|
};
|
||||||
|
|
||||||
|
void Window::customInit()
|
||||||
|
{
|
||||||
|
if (!m_r->isFeatureSupported(QRhi::Compute))
|
||||||
|
qFatal("Compute is not supported");
|
||||||
|
|
||||||
|
d.initialUpdates = m_r->nextResourceUpdateBatch();
|
||||||
|
|
||||||
|
// compute pass
|
||||||
|
|
||||||
|
const QImage image = QImage(QLatin1String(":/qt256.png")).convertToFormat(QImage::Format_RGBA8888);
|
||||||
|
d.imageSize = image.size();
|
||||||
|
d.texIn = m_r->newTexture(QRhiTexture::RGBA8, d.imageSize, 1, QRhiTexture::UsedWithLoadStore);
|
||||||
|
d.texIn->build();
|
||||||
|
d.releasePool << d.texIn;
|
||||||
|
|
||||||
|
d.texOut = m_r->newTexture(QRhiTexture::RGBA8, d.imageSize, 1, QRhiTexture::UsedWithLoadStore);
|
||||||
|
d.texOut->build();
|
||||||
|
d.releasePool << d.texOut;
|
||||||
|
|
||||||
|
d.initialUpdates->uploadTexture(d.texIn, image);
|
||||||
|
|
||||||
|
d.computeUBuf = m_r->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 4);
|
||||||
|
d.computeUBuf->build();
|
||||||
|
d.releasePool << d.computeUBuf;
|
||||||
|
|
||||||
|
d.computeBindings = m_r->newShaderResourceBindings();
|
||||||
|
d.computeBindings->setBindings({
|
||||||
|
QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::ComputeStage, d.computeUBuf),
|
||||||
|
QRhiShaderResourceBinding::imageLoad(1, QRhiShaderResourceBinding::ComputeStage, d.texIn, 0),
|
||||||
|
QRhiShaderResourceBinding::imageStore(2, QRhiShaderResourceBinding::ComputeStage, d.texOut, 0)
|
||||||
|
});
|
||||||
|
d.computeBindings->build();
|
||||||
|
d.releasePool << d.computeBindings;
|
||||||
|
|
||||||
|
d.computePipeline = m_r->newComputePipeline();
|
||||||
|
d.computePipeline->setShaderResourceBindings(d.computeBindings);
|
||||||
|
d.computePipeline->setShaderStage({ QRhiShaderStage::Compute, getShader(QLatin1String(":/image.comp.qsb")) });
|
||||||
|
d.computePipeline->build();
|
||||||
|
d.releasePool << d.computePipeline;
|
||||||
|
|
||||||
|
// graphics pass
|
||||||
|
|
||||||
|
d.vbuf = m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(quadVertexData));
|
||||||
|
d.vbuf->build();
|
||||||
|
d.releasePool << d.vbuf;
|
||||||
|
|
||||||
|
d.initialUpdates->uploadStaticBuffer(d.vbuf, quadVertexData);
|
||||||
|
|
||||||
|
d.ibuf = m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::IndexBuffer, sizeof(quadIndexData));
|
||||||
|
d.ibuf->build();
|
||||||
|
d.releasePool << d.ibuf;
|
||||||
|
|
||||||
|
d.initialUpdates->uploadStaticBuffer(d.ibuf, quadIndexData);
|
||||||
|
|
||||||
|
d.ubuf = m_r->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 68);
|
||||||
|
d.ubuf->build();
|
||||||
|
d.releasePool << d.ubuf;
|
||||||
|
|
||||||
|
qint32 flip = m_r->isYUpInFramebuffer() ? 1 : 0;
|
||||||
|
d.initialUpdates->updateDynamicBuffer(d.ubuf, 64, 4, &flip);
|
||||||
|
|
||||||
|
d.sampler = m_r->newSampler(QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
|
||||||
|
QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge);
|
||||||
|
d.releasePool << d.sampler;
|
||||||
|
d.sampler->build();
|
||||||
|
|
||||||
|
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.texOut, d.sampler)
|
||||||
|
});
|
||||||
|
d.srb->build();
|
||||||
|
|
||||||
|
d.ps = m_r->newGraphicsPipeline();
|
||||||
|
d.releasePool << d.ps;
|
||||||
|
d.ps->setShaderStages({
|
||||||
|
{ QRhiShaderStage::Vertex, getShader(QLatin1String(":/texture.vert.qsb")) },
|
||||||
|
{ QRhiShaderStage::Fragment, getShader(QLatin1String(":/texture.frag.qsb")) }
|
||||||
|
});
|
||||||
|
QRhiVertexInputLayout inputLayout;
|
||||||
|
inputLayout.setBindings({
|
||||||
|
{ 4 * sizeof(float) }
|
||||||
|
});
|
||||||
|
inputLayout.setAttributes({
|
||||||
|
{ 0, 0, QRhiVertexInputAttribute::Float2, 0 },
|
||||||
|
{ 0, 1, QRhiVertexInputAttribute::Float2, 2 * sizeof(float) }
|
||||||
|
});
|
||||||
|
d.ps->setVertexInputLayout(inputLayout);
|
||||||
|
d.ps->setShaderResourceBindings(d.srb);
|
||||||
|
d.ps->setRenderPassDescriptor(m_rp);
|
||||||
|
d.ps->build();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::customRelease()
|
||||||
|
{
|
||||||
|
qDeleteAll(d.releasePool);
|
||||||
|
d.releasePool.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::customRender()
|
||||||
|
{
|
||||||
|
const QSize outputSizeInPixels = m_sc->currentPixelSize();
|
||||||
|
QRhiCommandBuffer *cb = m_sc->currentFrameCommandBuffer();
|
||||||
|
QRhiResourceUpdateBatch *u = m_r->nextResourceUpdateBatch();
|
||||||
|
if (d.initialUpdates) {
|
||||||
|
u->merge(d.initialUpdates);
|
||||||
|
d.initialUpdates->release();
|
||||||
|
d.initialUpdates = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d.winProj != m_proj) {
|
||||||
|
d.winProj = m_proj;
|
||||||
|
QMatrix4x4 mvp = m_proj;
|
||||||
|
mvp.scale(2.5f);
|
||||||
|
u->updateDynamicBuffer(d.ubuf, 0, 64, mvp.constData());
|
||||||
|
}
|
||||||
|
|
||||||
|
u->updateDynamicBuffer(d.computeUBuf, 0, 4, &d.factor);
|
||||||
|
d.factor += 0.1f;
|
||||||
|
if (d.factor >= 50.0f)
|
||||||
|
d.factor = 1.0f;
|
||||||
|
|
||||||
|
cb->beginComputePass(u);
|
||||||
|
cb->setComputePipeline(d.computePipeline);
|
||||||
|
cb->setShaderResources();
|
||||||
|
cb->dispatch(d.imageSize.width() / 16, d.imageSize.height() / 16, 1);
|
||||||
|
cb->endComputePass();
|
||||||
|
|
||||||
|
cb->beginPass(m_sc->currentFrameRenderTarget(), QColor::fromRgbF(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();
|
||||||
|
QRhiCommandBuffer::VertexInput vbufBinding(d.vbuf, 0);
|
||||||
|
cb->setVertexInput(0, 1, &vbufBinding, d.ibuf, 0, QRhiCommandBuffer::IndexUInt16);
|
||||||
|
cb->drawIndexed(6);
|
||||||
|
cb->endPass();
|
||||||
|
}
|
8
tests/manual/rhi/computeimage/computeimage.pro
Normal file
8
tests/manual/rhi/computeimage/computeimage.pro
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
TEMPLATE = app
|
||||||
|
|
||||||
|
QT += gui-private
|
||||||
|
|
||||||
|
SOURCES = \
|
||||||
|
computeimage.cpp
|
||||||
|
|
||||||
|
RESOURCES = computeimage.qrc
|
8
tests/manual/rhi/computeimage/computeimage.qrc
Normal file
8
tests/manual/rhi/computeimage/computeimage.qrc
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<!DOCTYPE RCC><RCC version="1.0">
|
||||||
|
<qresource>
|
||||||
|
<file>image.comp.qsb</file>
|
||||||
|
<file alias="texture.vert.qsb">../shared/texture.vert.qsb</file>
|
||||||
|
<file alias="texture.frag.qsb">../shared/texture.frag.qsb</file>
|
||||||
|
<file alias="qt256.png">../shared/qt256.png</file>
|
||||||
|
</qresource>
|
||||||
|
</RCC>
|
20
tests/manual/rhi/computeimage/image.comp
Normal file
20
tests/manual/rhi/computeimage/image.comp
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#version 440
|
||||||
|
|
||||||
|
layout (local_size_x = 16, local_size_y = 16) in;
|
||||||
|
|
||||||
|
layout(std140, binding = 0) uniform UniformBuffer
|
||||||
|
{
|
||||||
|
float factor;
|
||||||
|
} ubuf;
|
||||||
|
|
||||||
|
layout (binding = 1, rgba8) uniform readonly image2D texIn;
|
||||||
|
layout (binding = 2, rgba8) uniform writeonly image2D texOut;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
ivec2 pos = ivec2(gl_GlobalInvocationID.xy);
|
||||||
|
ivec2 d = ivec2(1, 1);
|
||||||
|
vec4 diff = imageLoad(texIn, pos + d) - imageLoad(texIn, pos - d);
|
||||||
|
float c = (diff.x + diff.y + diff.z) / ubuf.factor + 0.5f;
|
||||||
|
imageStore(texOut, pos, vec4(c, c, c, 1.0));
|
||||||
|
}
|
BIN
tests/manual/rhi/computeimage/image.comp.qsb
Normal file
BIN
tests/manual/rhi/computeimage/image.comp.qsb
Normal file
Binary file not shown.
@ -121,8 +121,8 @@ void Window::customInit()
|
|||||||
QShader fs = getShader(QLatin1String(":/cubemap.frag.qsb"));
|
QShader fs = getShader(QLatin1String(":/cubemap.frag.qsb"));
|
||||||
Q_ASSERT(fs.isValid());
|
Q_ASSERT(fs.isValid());
|
||||||
d.ps->setShaderStages({
|
d.ps->setShaderStages({
|
||||||
{ QRhiGraphicsShaderStage::Vertex, vs },
|
{ QRhiShaderStage::Vertex, vs },
|
||||||
{ QRhiGraphicsShaderStage::Fragment, fs }
|
{ QRhiShaderStage::Fragment, fs }
|
||||||
});
|
});
|
||||||
|
|
||||||
QRhiVertexInputLayout inputLayout;
|
QRhiVertexInputLayout inputLayout;
|
||||||
|
@ -266,8 +266,8 @@ void Window::customInit()
|
|||||||
d.ps = m_r->newGraphicsPipeline();
|
d.ps = m_r->newGraphicsPipeline();
|
||||||
d.releasePool << d.ps;
|
d.releasePool << d.ps;
|
||||||
d.ps->setShaderStages({
|
d.ps->setShaderStages({
|
||||||
{ QRhiGraphicsShaderStage::Vertex, getShader(QLatin1String(":/texture.vert.qsb")) },
|
{ QRhiShaderStage::Vertex, getShader(QLatin1String(":/texture.vert.qsb")) },
|
||||||
{ QRhiGraphicsShaderStage::Fragment, getShader(QLatin1String(":/texture.frag.qsb")) }
|
{ QRhiShaderStage::Fragment, getShader(QLatin1String(":/texture.frag.qsb")) }
|
||||||
});
|
});
|
||||||
QRhiVertexInputLayout inputLayout;
|
QRhiVertexInputLayout inputLayout;
|
||||||
inputLayout.setBindings({
|
inputLayout.setBindings({
|
||||||
|
@ -339,8 +339,8 @@ void Window::init()
|
|||||||
qFatal("Failed to load shader pack (fragment)");
|
qFatal("Failed to load shader pack (fragment)");
|
||||||
|
|
||||||
m_ps->setShaderStages({
|
m_ps->setShaderStages({
|
||||||
{ QRhiGraphicsShaderStage::Vertex, vs },
|
{ QRhiShaderStage::Vertex, vs },
|
||||||
{ QRhiGraphicsShaderStage::Fragment, fs }
|
{ QRhiShaderStage::Fragment, fs }
|
||||||
});
|
});
|
||||||
|
|
||||||
QRhiVertexInputLayout inputLayout;
|
QRhiVertexInputLayout inputLayout;
|
||||||
|
@ -157,8 +157,8 @@ void Window::customInit()
|
|||||||
d.ps = m_r->newGraphicsPipeline();
|
d.ps = m_r->newGraphicsPipeline();
|
||||||
d.releasePool << d.ps;
|
d.releasePool << d.ps;
|
||||||
d.ps->setShaderStages({
|
d.ps->setShaderStages({
|
||||||
{ QRhiGraphicsShaderStage::Vertex, getShader(QLatin1String(":/texture.vert.qsb")) },
|
{ QRhiShaderStage::Vertex, getShader(QLatin1String(":/texture.vert.qsb")) },
|
||||||
{ QRhiGraphicsShaderStage::Fragment, getShader(QLatin1String(":/texture.frag.qsb")) }
|
{ QRhiShaderStage::Fragment, getShader(QLatin1String(":/texture.frag.qsb")) }
|
||||||
});
|
});
|
||||||
QRhiVertexInputLayout inputLayout;
|
QRhiVertexInputLayout inputLayout;
|
||||||
inputLayout.setBindings({
|
inputLayout.setBindings({
|
||||||
@ -197,8 +197,8 @@ void Window::customInit()
|
|||||||
d.triPs = m_r->newGraphicsPipeline();
|
d.triPs = m_r->newGraphicsPipeline();
|
||||||
d.releasePool << d.triPs;
|
d.releasePool << d.triPs;
|
||||||
d.triPs->setShaderStages({
|
d.triPs->setShaderStages({
|
||||||
{ QRhiGraphicsShaderStage::Vertex, getShader(QLatin1String(":/mrt.vert.qsb")) },
|
{ QRhiShaderStage::Vertex, getShader(QLatin1String(":/mrt.vert.qsb")) },
|
||||||
{ QRhiGraphicsShaderStage::Fragment, getShader(QLatin1String(":/mrt.frag.qsb")) }
|
{ QRhiShaderStage::Fragment, getShader(QLatin1String(":/mrt.frag.qsb")) }
|
||||||
});
|
});
|
||||||
QVector<QRhiGraphicsPipeline::TargetBlend> blends;
|
QVector<QRhiGraphicsPipeline::TargetBlend> blends;
|
||||||
for (int i = 0; i < ATTCOUNT; ++i) {
|
for (int i = 0; i < ATTCOUNT; ++i) {
|
||||||
|
@ -146,8 +146,8 @@ void Window::customInit()
|
|||||||
d.releasePool << d.triPs;
|
d.releasePool << d.triPs;
|
||||||
d.triPs->setSampleCount(4); // must match the render target
|
d.triPs->setSampleCount(4); // must match the render target
|
||||||
d.triPs->setShaderStages({
|
d.triPs->setShaderStages({
|
||||||
{ QRhiGraphicsShaderStage::Vertex, getShader(QLatin1String(":/color.vert.qsb")) },
|
{ QRhiShaderStage::Vertex, getShader(QLatin1String(":/color.vert.qsb")) },
|
||||||
{ QRhiGraphicsShaderStage::Fragment, getShader(QLatin1String(":/color.frag.qsb")) }
|
{ QRhiShaderStage::Fragment, getShader(QLatin1String(":/color.frag.qsb")) }
|
||||||
});
|
});
|
||||||
QRhiVertexInputLayout inputLayout;
|
QRhiVertexInputLayout inputLayout;
|
||||||
inputLayout.setBindings({
|
inputLayout.setBindings({
|
||||||
@ -178,8 +178,8 @@ void Window::customInit()
|
|||||||
d.ps = m_r->newGraphicsPipeline();
|
d.ps = m_r->newGraphicsPipeline();
|
||||||
d.releasePool << d.ps;
|
d.releasePool << d.ps;
|
||||||
d.ps->setShaderStages({
|
d.ps->setShaderStages({
|
||||||
{ QRhiGraphicsShaderStage::Vertex, getShader(QLatin1String(":/texture.vert.qsb")) },
|
{ QRhiShaderStage::Vertex, getShader(QLatin1String(":/texture.vert.qsb")) },
|
||||||
{ QRhiGraphicsShaderStage::Fragment, getShader(QLatin1String(":/texture.frag.qsb")) }
|
{ QRhiShaderStage::Fragment, getShader(QLatin1String(":/texture.frag.qsb")) }
|
||||||
});
|
});
|
||||||
inputLayout.setBindings({
|
inputLayout.setBindings({
|
||||||
{ 4 * sizeof(float) }
|
{ 4 * sizeof(float) }
|
||||||
|
@ -164,8 +164,8 @@ void Window::customInit()
|
|||||||
d.psLeft = m_r->newGraphicsPipeline();
|
d.psLeft = m_r->newGraphicsPipeline();
|
||||||
d.releasePool << d.psLeft;
|
d.releasePool << d.psLeft;
|
||||||
d.psLeft->setShaderStages({
|
d.psLeft->setShaderStages({
|
||||||
{ QRhiGraphicsShaderStage::Vertex, getShader(QLatin1String(":/texture.vert.qsb")) },
|
{ QRhiShaderStage::Vertex, getShader(QLatin1String(":/texture.vert.qsb")) },
|
||||||
{ QRhiGraphicsShaderStage::Fragment, getShader(QLatin1String(":/texture.frag.qsb")) }
|
{ QRhiShaderStage::Fragment, getShader(QLatin1String(":/texture.frag.qsb")) }
|
||||||
});
|
});
|
||||||
QRhiVertexInputLayout inputLayout;
|
QRhiVertexInputLayout inputLayout;
|
||||||
inputLayout.setBindings({ { 4 * sizeof(float) } });
|
inputLayout.setBindings({ { 4 * sizeof(float) } });
|
||||||
@ -181,11 +181,11 @@ void Window::customInit()
|
|||||||
d.psRight = m_r->newGraphicsPipeline();
|
d.psRight = m_r->newGraphicsPipeline();
|
||||||
d.releasePool << d.psRight;
|
d.releasePool << d.psRight;
|
||||||
d.psRight->setShaderStages({
|
d.psRight->setShaderStages({
|
||||||
{ QRhiGraphicsShaderStage::Vertex, getShader(QLatin1String(":/texture.vert.qsb")) },
|
{ QRhiShaderStage::Vertex, getShader(QLatin1String(":/texture.vert.qsb")) },
|
||||||
#ifndef NO_MSAA
|
#ifndef NO_MSAA
|
||||||
{ QRhiGraphicsShaderStage::Fragment, getShader(QLatin1String(":/texture_ms4.frag.qsb")) }
|
{ QRhiShaderStage::Fragment, getShader(QLatin1String(":/texture_ms4.frag.qsb")) }
|
||||||
#else
|
#else
|
||||||
{ QRhiGraphicsShaderStage::Fragment, getShader(QLatin1String(":/texture.frag.qsb")) }
|
{ QRhiShaderStage::Fragment, getShader(QLatin1String(":/texture.frag.qsb")) }
|
||||||
#endif
|
#endif
|
||||||
});
|
});
|
||||||
d.psRight->setVertexInputLayout(d.psLeft->vertexInputLayout());
|
d.psRight->setVertexInputLayout(d.psLeft->vertexInputLayout());
|
||||||
@ -219,8 +219,8 @@ void Window::customInit()
|
|||||||
d.releasePool << d.triPs;
|
d.releasePool << d.triPs;
|
||||||
d.triPs->setSampleCount(1);
|
d.triPs->setSampleCount(1);
|
||||||
d.triPs->setShaderStages({
|
d.triPs->setShaderStages({
|
||||||
{ QRhiGraphicsShaderStage::Vertex, getShader(QLatin1String(":/color.vert.qsb")) },
|
{ QRhiShaderStage::Vertex, getShader(QLatin1String(":/color.vert.qsb")) },
|
||||||
{ QRhiGraphicsShaderStage::Fragment, getShader(QLatin1String(":/color.frag.qsb")) }
|
{ QRhiShaderStage::Fragment, getShader(QLatin1String(":/color.frag.qsb")) }
|
||||||
});
|
});
|
||||||
inputLayout.setBindings({
|
inputLayout.setBindings({
|
||||||
{ 5 * sizeof(float) }
|
{ 5 * sizeof(float) }
|
||||||
|
@ -234,8 +234,8 @@ void ensureSharedResources(QRhiRenderPassDescriptor *rp)
|
|||||||
qFatal("Failed to load shader pack (fragment)");
|
qFatal("Failed to load shader pack (fragment)");
|
||||||
|
|
||||||
d.ps->setShaderStages({
|
d.ps->setShaderStages({
|
||||||
{ QRhiGraphicsShaderStage::Vertex, vs },
|
{ QRhiShaderStage::Vertex, vs },
|
||||||
{ QRhiGraphicsShaderStage::Fragment, fs }
|
{ QRhiShaderStage::Fragment, fs }
|
||||||
});
|
});
|
||||||
|
|
||||||
QRhiVertexInputLayout inputLayout;
|
QRhiVertexInputLayout inputLayout;
|
||||||
|
@ -484,8 +484,8 @@ void Renderer::init()
|
|||||||
m_ps->setFrontFace(QRhiGraphicsPipeline::CCW);
|
m_ps->setFrontFace(QRhiGraphicsPipeline::CCW);
|
||||||
|
|
||||||
m_ps->setShaderStages({
|
m_ps->setShaderStages({
|
||||||
{ QRhiGraphicsShaderStage::Vertex, getShader(QLatin1String(":/texture.vert.qsb")) },
|
{ QRhiShaderStage::Vertex, getShader(QLatin1String(":/texture.vert.qsb")) },
|
||||||
{ QRhiGraphicsShaderStage::Fragment, getShader(QLatin1String(":/texture.frag.qsb")) }
|
{ QRhiShaderStage::Fragment, getShader(QLatin1String(":/texture.frag.qsb")) }
|
||||||
});
|
});
|
||||||
|
|
||||||
QRhiVertexInputLayout inputLayout;
|
QRhiVertexInputLayout inputLayout;
|
||||||
|
@ -264,8 +264,8 @@ int main(int argc, char **argv)
|
|||||||
qFatal("Failed to load shader pack (fragment)");
|
qFatal("Failed to load shader pack (fragment)");
|
||||||
|
|
||||||
ps->setShaderStages({
|
ps->setShaderStages({
|
||||||
{ QRhiGraphicsShaderStage::Vertex, vs },
|
{ QRhiShaderStage::Vertex, vs },
|
||||||
{ QRhiGraphicsShaderStage::Fragment, fs }
|
{ QRhiShaderStage::Fragment, fs }
|
||||||
});
|
});
|
||||||
|
|
||||||
QRhiVertexInputLayout inputLayout;
|
QRhiVertexInputLayout inputLayout;
|
||||||
|
@ -14,7 +14,9 @@ SUBDIRS += \
|
|||||||
offscreen \
|
offscreen \
|
||||||
floattexture \
|
floattexture \
|
||||||
mrt \
|
mrt \
|
||||||
shadowmap
|
shadowmap \
|
||||||
|
computebuffer \
|
||||||
|
computeimage
|
||||||
|
|
||||||
qtConfig(widgets) {
|
qtConfig(widgets) {
|
||||||
SUBDIRS += \
|
SUBDIRS += \
|
||||||
|
@ -128,8 +128,8 @@ void Window::customInit()
|
|||||||
d.ps = m_r->newGraphicsPipeline();
|
d.ps = m_r->newGraphicsPipeline();
|
||||||
d.releasePool << d.ps;
|
d.releasePool << d.ps;
|
||||||
d.ps->setShaderStages({
|
d.ps->setShaderStages({
|
||||||
{ QRhiGraphicsShaderStage::Vertex, getShader(QLatin1String(":/main.vert.qsb")) },
|
{ QRhiShaderStage::Vertex, getShader(QLatin1String(":/main.vert.qsb")) },
|
||||||
{ QRhiGraphicsShaderStage::Fragment, getShader(QLatin1String(":/main.frag.qsb")) }
|
{ QRhiShaderStage::Fragment, getShader(QLatin1String(":/main.frag.qsb")) }
|
||||||
});
|
});
|
||||||
d.ps->setDepthTest(true);
|
d.ps->setDepthTest(true);
|
||||||
d.ps->setDepthWrite(true);
|
d.ps->setDepthWrite(true);
|
||||||
@ -168,8 +168,8 @@ void Window::customInit()
|
|||||||
d.shadowPs = m_r->newGraphicsPipeline();
|
d.shadowPs = m_r->newGraphicsPipeline();
|
||||||
d.releasePool << d.shadowPs;
|
d.releasePool << d.shadowPs;
|
||||||
d.shadowPs->setShaderStages({
|
d.shadowPs->setShaderStages({
|
||||||
{ QRhiGraphicsShaderStage::Vertex, getShader(QLatin1String(":/shadowmap.vert.qsb")) },
|
{ QRhiShaderStage::Vertex, getShader(QLatin1String(":/shadowmap.vert.qsb")) },
|
||||||
{ QRhiGraphicsShaderStage::Fragment, getShader(QLatin1String(":/shadowmap.frag.qsb")) }
|
{ QRhiShaderStage::Fragment, getShader(QLatin1String(":/shadowmap.frag.qsb")) }
|
||||||
});
|
});
|
||||||
d.shadowPs->setDepthTest(true);
|
d.shadowPs->setDepthTest(true);
|
||||||
d.shadowPs->setDepthWrite(true);
|
d.shadowPs->setDepthWrite(true);
|
||||||
|
@ -124,8 +124,8 @@ void Window::customInit()
|
|||||||
qFatal("Failed to load shader pack (fragment)");
|
qFatal("Failed to load shader pack (fragment)");
|
||||||
|
|
||||||
d.ps->setShaderStages({
|
d.ps->setShaderStages({
|
||||||
{ QRhiGraphicsShaderStage::Vertex, vs },
|
{ QRhiShaderStage::Vertex, vs },
|
||||||
{ QRhiGraphicsShaderStage::Fragment, fs }
|
{ QRhiShaderStage::Fragment, fs }
|
||||||
});
|
});
|
||||||
|
|
||||||
QRhiVertexInputLayout inputLayout;
|
QRhiVertexInputLayout inputLayout;
|
||||||
|
@ -121,8 +121,8 @@ void TexturedCubeRenderer::initResources(QRhiRenderPassDescriptor *rp)
|
|||||||
QShader fs = getShader(QLatin1String(":/texture.frag.qsb"));
|
QShader fs = getShader(QLatin1String(":/texture.frag.qsb"));
|
||||||
Q_ASSERT(fs.isValid());
|
Q_ASSERT(fs.isValid());
|
||||||
m_ps->setShaderStages({
|
m_ps->setShaderStages({
|
||||||
{ QRhiGraphicsShaderStage::Vertex, vs },
|
{ QRhiShaderStage::Vertex, vs },
|
||||||
{ QRhiGraphicsShaderStage::Fragment, fs }
|
{ QRhiShaderStage::Fragment, fs }
|
||||||
});
|
});
|
||||||
|
|
||||||
QRhiVertexInputLayout inputLayout;
|
QRhiVertexInputLayout inputLayout;
|
||||||
|
@ -138,8 +138,8 @@ void TriangleOnCubeRenderer::initResources(QRhiRenderPassDescriptor *rp)
|
|||||||
QShader fs = getShader(QLatin1String(":/texture.frag.qsb"));
|
QShader fs = getShader(QLatin1String(":/texture.frag.qsb"));
|
||||||
Q_ASSERT(fs.isValid());
|
Q_ASSERT(fs.isValid());
|
||||||
m_ps->setShaderStages({
|
m_ps->setShaderStages({
|
||||||
{ QRhiGraphicsShaderStage::Vertex, vs },
|
{ QRhiShaderStage::Vertex, vs },
|
||||||
{ QRhiGraphicsShaderStage::Fragment, fs }
|
{ QRhiShaderStage::Fragment, fs }
|
||||||
});
|
});
|
||||||
|
|
||||||
QRhiVertexInputLayout inputLayout;
|
QRhiVertexInputLayout inputLayout;
|
||||||
|
@ -112,8 +112,8 @@ void TriangleRenderer::initResources(QRhiRenderPassDescriptor *rp)
|
|||||||
QShader fs = getShader(QLatin1String(":/color.frag.qsb"));
|
QShader fs = getShader(QLatin1String(":/color.frag.qsb"));
|
||||||
Q_ASSERT(fs.isValid());
|
Q_ASSERT(fs.isValid());
|
||||||
m_ps->setShaderStages({
|
m_ps->setShaderStages({
|
||||||
{ QRhiGraphicsShaderStage::Vertex, vs },
|
{ QRhiShaderStage::Vertex, vs },
|
||||||
{ QRhiGraphicsShaderStage::Fragment, fs }
|
{ QRhiShaderStage::Fragment, fs }
|
||||||
});
|
});
|
||||||
|
|
||||||
QRhiVertexInputLayout inputLayout;
|
QRhiVertexInputLayout inputLayout;
|
||||||
|
@ -171,6 +171,7 @@ void Window::customInit()
|
|||||||
qDebug("isFeatureSupported(NPOTTextureRepeat): %d", m_r->isFeatureSupported(QRhi::NPOTTextureRepeat));
|
qDebug("isFeatureSupported(NPOTTextureRepeat): %d", m_r->isFeatureSupported(QRhi::NPOTTextureRepeat));
|
||||||
qDebug("isFeatureSupported(RedOrAlpha8IsRed): %d", m_r->isFeatureSupported(QRhi::RedOrAlpha8IsRed));
|
qDebug("isFeatureSupported(RedOrAlpha8IsRed): %d", m_r->isFeatureSupported(QRhi::RedOrAlpha8IsRed));
|
||||||
qDebug("isFeatureSupported(ElementIndexUint): %d", m_r->isFeatureSupported(QRhi::ElementIndexUint));
|
qDebug("isFeatureSupported(ElementIndexUint): %d", m_r->isFeatureSupported(QRhi::ElementIndexUint));
|
||||||
|
qDebug("isFeatureSupported(Compute): %d", m_r->isFeatureSupported(QRhi::Compute));
|
||||||
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…
x
Reference in New Issue
Block a user