Merge remote-tracking branch 'origin/5.15' into dev
Change-Id: I14f539ccfa4ab6e21188b98c314bdb030f3b9f70
This commit is contained in:
commit
50d41f14ee
@ -141,7 +141,8 @@ bool
|
|||||||
BuildsMetaMakefileGenerator::write()
|
BuildsMetaMakefileGenerator::write()
|
||||||
{
|
{
|
||||||
Build *glue = nullptr;
|
Build *glue = nullptr;
|
||||||
if(!makefiles.isEmpty() && !makefiles.first()->build.isNull()) {
|
if(!makefiles.isEmpty() && !makefiles.first()->build.isNull()
|
||||||
|
&& Option::qmake_mode != Option::QMAKE_GENERATE_PRL) {
|
||||||
glue = new Build;
|
glue = new Build;
|
||||||
glue->name = name;
|
glue->name = name;
|
||||||
glue->makefile = createMakefileGenerator(project, true);
|
glue->makefile = createMakefileGenerator(project, true);
|
||||||
|
@ -118,16 +118,16 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool runIterations(Iterator sequenceBeginIterator, int begin, int end, ReducedResultType *) override
|
bool runIterations(Iterator sequenceBeginIterator, int beginIndex, int endIndex, ReducedResultType *) override
|
||||||
{
|
{
|
||||||
IntermediateResults<typename MapFunctor::result_type> results;
|
IntermediateResults<typename MapFunctor::result_type> results;
|
||||||
results.begin = begin;
|
results.begin = beginIndex;
|
||||||
results.end = end;
|
results.end = endIndex;
|
||||||
results.vector.reserve(end - begin);
|
results.vector.reserve(endIndex - beginIndex);
|
||||||
|
|
||||||
Iterator it = sequenceBeginIterator;
|
Iterator it = sequenceBeginIterator;
|
||||||
std::advance(it, begin);
|
std::advance(it, beginIndex);
|
||||||
for (int i = begin; i < end; ++i) {
|
for (int i = beginIndex; i < endIndex; ++i) {
|
||||||
results.vector.append(map(*(it)));
|
results.vector.append(map(*(it)));
|
||||||
std::advance(it, 1);
|
std::advance(it, 1);
|
||||||
}
|
}
|
||||||
@ -176,13 +176,13 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool runIterations(Iterator sequenceBeginIterator, int begin, int end, T *results) override
|
bool runIterations(Iterator sequenceBeginIterator, int beginIndex, int endIndex, T *results) override
|
||||||
{
|
{
|
||||||
|
|
||||||
Iterator it = sequenceBeginIterator;
|
Iterator it = sequenceBeginIterator;
|
||||||
std::advance(it, begin);
|
std::advance(it, beginIndex);
|
||||||
for (int i = begin; i < end; ++i) {
|
for (int i = beginIndex; i < endIndex; ++i) {
|
||||||
runIteration(it, i, results + (i - begin));
|
runIteration(it, i, results + (i - beginIndex));
|
||||||
std::advance(it, 1);
|
std::advance(it, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -727,6 +727,11 @@ QLibraryInfo::rawLocation(LibraryLocation loc, PathGroup group)
|
|||||||
|
|
||||||
#ifndef QT_BUILD_QMAKE_BOOTSTRAP
|
#ifndef QT_BUILD_QMAKE_BOOTSTRAP
|
||||||
if (!fromConf) {
|
if (!fromConf) {
|
||||||
|
// "volatile" here is a hack to prevent compilers from doing a
|
||||||
|
// compile-time strlen() on "path". The issue is that Qt installers
|
||||||
|
// will binary-patch the Qt installation paths -- in such scenarios, Qt
|
||||||
|
// will be built with a dummy path, thus the compile-time result of
|
||||||
|
// strlen is meaningless.
|
||||||
const char * volatile path = 0;
|
const char * volatile path = 0;
|
||||||
if (loc == PrefixPath) {
|
if (loc == PrefixPath) {
|
||||||
path = getPrefix(
|
path = getPrefix(
|
||||||
|
@ -566,7 +566,19 @@ Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general")
|
|||||||
|
|
||||||
\value TriangleFanTopology Indicates that QRhiGraphicsPipeline::setTopology()
|
\value TriangleFanTopology Indicates that QRhiGraphicsPipeline::setTopology()
|
||||||
supports QRhiGraphicsPipeline::TriangleFan.
|
supports QRhiGraphicsPipeline::TriangleFan.
|
||||||
*/
|
|
||||||
|
\value ReadBackNonUniformBuffer Indicates that
|
||||||
|
\l{QRhiResourceUpdateBatch::readBackBuffer()}{reading buffer contents} is
|
||||||
|
supported for QRhiBuffer instances with a usage different than
|
||||||
|
UniformBuffer. While this is supported in the majority of cases, it will be
|
||||||
|
unsupported with OpenGL ES older than 3.0.
|
||||||
|
|
||||||
|
\value ReadBackNonBaseMipLevel Indicates that specifying a mip level other
|
||||||
|
than 0 is supported when reading back texture contents. When not supported,
|
||||||
|
specifying a non-zero level in QRhiReadbackDescription leads to returning
|
||||||
|
an all-zero image. In practice this feature will be unsupported with OpenGL
|
||||||
|
ES 2.0, while it will likely be supported everywhere else.
|
||||||
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\enum QRhi::BeginFrameFlag
|
\enum QRhi::BeginFrameFlag
|
||||||
@ -3072,9 +3084,13 @@ QDebug operator<<(QDebug dbg, const QRhiShaderResourceBindings &srb)
|
|||||||
\inmodule QtGui
|
\inmodule QtGui
|
||||||
\brief Graphics pipeline state resource.
|
\brief Graphics pipeline state resource.
|
||||||
|
|
||||||
|
\note Setting the shader stages is mandatory. There must be at least one
|
||||||
|
stage, and there must be a vertex stage.
|
||||||
|
|
||||||
\note Setting the shader resource bindings is mandatory. The referenced
|
\note Setting the shader resource bindings is mandatory. The referenced
|
||||||
QRhiShaderResourceBindings must already be built by the time build() is
|
QRhiShaderResourceBindings must already be built by the time build() is
|
||||||
called.
|
called. Associating with a QRhiShaderResourceBindings that has no bindings
|
||||||
|
is also valid, as long as no shader in any stage expects any resources.
|
||||||
|
|
||||||
\note Setting the render pass descriptor is mandatory. To obtain a
|
\note Setting the render pass descriptor is mandatory. To obtain a
|
||||||
QRhiRenderPassDescriptor that can be passed to setRenderPassDescriptor(),
|
QRhiRenderPassDescriptor that can be passed to setRenderPassDescriptor(),
|
||||||
@ -3083,8 +3099,6 @@ QDebug operator<<(QDebug dbg, const QRhiShaderResourceBindings &srb)
|
|||||||
|
|
||||||
\note Setting the vertex input layout is mandatory.
|
\note Setting the vertex input layout is mandatory.
|
||||||
|
|
||||||
\note Setting the shader stages is mandatory.
|
|
||||||
|
|
||||||
\note sampleCount() defaults to 1 and must match the sample count of the
|
\note sampleCount() defaults to 1 and must match the sample count of the
|
||||||
render target's color and depth stencil attachments.
|
render target's color and depth stencil attachments.
|
||||||
|
|
||||||
@ -3900,6 +3914,46 @@ quint32 QRhiImplementation::approxByteSizeForTexture(QRhiTexture::Format format,
|
|||||||
return approxSize;
|
return approxSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool QRhiImplementation::sanityCheckGraphicsPipeline(QRhiGraphicsPipeline *ps)
|
||||||
|
{
|
||||||
|
if (ps->cbeginShaderStages() == ps->cendShaderStages()) {
|
||||||
|
qWarning("Cannot build a graphics pipeline without any stages");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasVertexStage = false;
|
||||||
|
for (auto it = ps->cbeginShaderStages(), itEnd = ps->cendShaderStages(); it != itEnd; ++it) {
|
||||||
|
if (!it->shader().isValid()) {
|
||||||
|
qWarning("Empty shader passed to graphics pipeline");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (it->type() == QRhiShaderStage::Vertex) {
|
||||||
|
hasVertexStage = true;
|
||||||
|
const QRhiVertexInputLayout inputLayout = ps->vertexInputLayout();
|
||||||
|
if (inputLayout.cbeginAttributes() == inputLayout.cendAttributes()) {
|
||||||
|
qWarning("Vertex stage present without any vertex inputs");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!hasVertexStage) {
|
||||||
|
qWarning("Cannot build a graphics pipeline without a vertex stage");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ps->renderPassDescriptor()) {
|
||||||
|
qWarning("Cannot build a graphics pipeline without a QRhiRenderPassDescriptor");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ps->shaderResourceBindings()) {
|
||||||
|
qWarning("Cannot build a graphics pipeline without QRhiShaderResourceBindings");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\internal
|
\internal
|
||||||
*/
|
*/
|
||||||
@ -4175,7 +4229,7 @@ void QRhiResourceUpdateBatch::merge(QRhiResourceUpdateBatch *other)
|
|||||||
void QRhiResourceUpdateBatch::updateDynamicBuffer(QRhiBuffer *buf, int offset, int size, const void *data)
|
void QRhiResourceUpdateBatch::updateDynamicBuffer(QRhiBuffer *buf, int offset, int size, const void *data)
|
||||||
{
|
{
|
||||||
if (size > 0)
|
if (size > 0)
|
||||||
d->dynamicBufferUpdates.append({ buf, offset, size, data });
|
d->bufferOps.append(QRhiResourceUpdateBatchPrivate::BufferOp::dynamicUpdate(buf, offset, size, data));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -4189,7 +4243,7 @@ void QRhiResourceUpdateBatch::updateDynamicBuffer(QRhiBuffer *buf, int offset, i
|
|||||||
void QRhiResourceUpdateBatch::uploadStaticBuffer(QRhiBuffer *buf, int offset, int size, const void *data)
|
void QRhiResourceUpdateBatch::uploadStaticBuffer(QRhiBuffer *buf, int offset, int size, const void *data)
|
||||||
{
|
{
|
||||||
if (size > 0)
|
if (size > 0)
|
||||||
d->staticBufferUploads.append({ buf, offset, size, data });
|
d->bufferOps.append(QRhiResourceUpdateBatchPrivate::BufferOp::staticUpload(buf, offset, size, data));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -4199,7 +4253,28 @@ void QRhiResourceUpdateBatch::uploadStaticBuffer(QRhiBuffer *buf, int offset, in
|
|||||||
void QRhiResourceUpdateBatch::uploadStaticBuffer(QRhiBuffer *buf, const void *data)
|
void QRhiResourceUpdateBatch::uploadStaticBuffer(QRhiBuffer *buf, const void *data)
|
||||||
{
|
{
|
||||||
if (buf->size() > 0)
|
if (buf->size() > 0)
|
||||||
d->staticBufferUploads.append({ buf, 0, 0, data });
|
d->bufferOps.append(QRhiResourceUpdateBatchPrivate::BufferOp::staticUpload(buf, 0, 0, data));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Enqueues reading back a region of the QRhiBuffer \a buf. The size of the
|
||||||
|
region is specified by \a size in bytes, \a offset is the offset in bytes
|
||||||
|
to start reading from.
|
||||||
|
|
||||||
|
A readback is asynchronous. \a result contains a callback that is invoked
|
||||||
|
when the operation has completed. The data is provided in
|
||||||
|
QRhiBufferReadbackResult::data. Upon successful completion that QByteArray
|
||||||
|
will have a size equal to \a size. On failure the QByteArray will be empty.
|
||||||
|
|
||||||
|
\note Reading buffers with a usage different than QRhiBuffer::UniformBuffer
|
||||||
|
is supported only when the QRhi::ReadBackNonUniformBuffer feature is
|
||||||
|
reported as supported.
|
||||||
|
|
||||||
|
\a readBackTexture(), QRhi::isFeatureSupported()
|
||||||
|
*/
|
||||||
|
void QRhiResourceUpdateBatch::readBackBuffer(QRhiBuffer *buf, int offset, int size, QRhiBufferReadbackResult *result)
|
||||||
|
{
|
||||||
|
d->bufferOps.append(QRhiResourceUpdateBatchPrivate::BufferOp::read(buf, offset, size, result));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -4212,7 +4287,7 @@ void QRhiResourceUpdateBatch::uploadStaticBuffer(QRhiBuffer *buf, const void *da
|
|||||||
void QRhiResourceUpdateBatch::uploadTexture(QRhiTexture *tex, const QRhiTextureUploadDescription &desc)
|
void QRhiResourceUpdateBatch::uploadTexture(QRhiTexture *tex, const QRhiTextureUploadDescription &desc)
|
||||||
{
|
{
|
||||||
if (desc.cbeginEntries() != desc.cendEntries())
|
if (desc.cbeginEntries() != desc.cendEntries())
|
||||||
d->textureOps.append(QRhiResourceUpdateBatchPrivate::TextureOp::textureUpload(tex, desc));
|
d->textureOps.append(QRhiResourceUpdateBatchPrivate::TextureOp::upload(tex, desc));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -4237,7 +4312,7 @@ void QRhiResourceUpdateBatch::uploadTexture(QRhiTexture *tex, const QImage &imag
|
|||||||
*/
|
*/
|
||||||
void QRhiResourceUpdateBatch::copyTexture(QRhiTexture *dst, QRhiTexture *src, const QRhiTextureCopyDescription &desc)
|
void QRhiResourceUpdateBatch::copyTexture(QRhiTexture *dst, QRhiTexture *src, const QRhiTextureCopyDescription &desc)
|
||||||
{
|
{
|
||||||
d->textureOps.append(QRhiResourceUpdateBatchPrivate::TextureOp::textureCopy(dst, src, desc));
|
d->textureOps.append(QRhiResourceUpdateBatchPrivate::TextureOp::copy(dst, src, desc));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -4289,7 +4364,7 @@ void QRhiResourceUpdateBatch::copyTexture(QRhiTexture *dst, QRhiTexture *src, co
|
|||||||
*/
|
*/
|
||||||
void QRhiResourceUpdateBatch::readBackTexture(const QRhiReadbackDescription &rb, QRhiReadbackResult *result)
|
void QRhiResourceUpdateBatch::readBackTexture(const QRhiReadbackDescription &rb, QRhiReadbackResult *result)
|
||||||
{
|
{
|
||||||
d->textureOps.append(QRhiResourceUpdateBatchPrivate::TextureOp::textureRead(rb, result));
|
d->textureOps.append(QRhiResourceUpdateBatchPrivate::TextureOp::read(rb, result));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -4301,7 +4376,7 @@ void QRhiResourceUpdateBatch::readBackTexture(const QRhiReadbackDescription &rb,
|
|||||||
*/
|
*/
|
||||||
void QRhiResourceUpdateBatch::generateMips(QRhiTexture *tex, int layer)
|
void QRhiResourceUpdateBatch::generateMips(QRhiTexture *tex, int layer)
|
||||||
{
|
{
|
||||||
d->textureOps.append(QRhiResourceUpdateBatchPrivate::TextureOp::textureMipGen(tex, layer));
|
d->textureOps.append(QRhiResourceUpdateBatchPrivate::TextureOp::genMips(tex, layer));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -4350,8 +4425,7 @@ void QRhiResourceUpdateBatchPrivate::free()
|
|||||||
{
|
{
|
||||||
Q_ASSERT(poolIndex >= 0 && rhi->resUpdPool[poolIndex] == q);
|
Q_ASSERT(poolIndex >= 0 && rhi->resUpdPool[poolIndex] == q);
|
||||||
|
|
||||||
dynamicBufferUpdates.clear();
|
bufferOps.clear();
|
||||||
staticBufferUploads.clear();
|
|
||||||
textureOps.clear();
|
textureOps.clear();
|
||||||
|
|
||||||
rhi->resUpdPoolMap.clearBit(poolIndex);
|
rhi->resUpdPoolMap.clearBit(poolIndex);
|
||||||
@ -4360,9 +4434,13 @@ void QRhiResourceUpdateBatchPrivate::free()
|
|||||||
|
|
||||||
void QRhiResourceUpdateBatchPrivate::merge(QRhiResourceUpdateBatchPrivate *other)
|
void QRhiResourceUpdateBatchPrivate::merge(QRhiResourceUpdateBatchPrivate *other)
|
||||||
{
|
{
|
||||||
dynamicBufferUpdates += other->dynamicBufferUpdates;
|
bufferOps.reserve(bufferOps.size() + other->bufferOps.size());
|
||||||
staticBufferUploads += other->staticBufferUploads;
|
for (const BufferOp &op : qAsConst(other->bufferOps))
|
||||||
textureOps += other->textureOps;
|
bufferOps.append(op);
|
||||||
|
|
||||||
|
textureOps.reserve(textureOps.size() + other->textureOps.size());
|
||||||
|
for (const TextureOp &op : qAsConst(other->textureOps))
|
||||||
|
textureOps.append(op);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -72,7 +72,6 @@ class QRhiCommandBuffer;
|
|||||||
class QRhiResourceUpdateBatch;
|
class QRhiResourceUpdateBatch;
|
||||||
class QRhiResourceUpdateBatchPrivate;
|
class QRhiResourceUpdateBatchPrivate;
|
||||||
class QRhiProfiler;
|
class QRhiProfiler;
|
||||||
class QRhiShaderResourceBindingPrivate;
|
|
||||||
|
|
||||||
class Q_GUI_EXPORT QRhiDepthStencilClearValue
|
class Q_GUI_EXPORT QRhiDepthStencilClearValue
|
||||||
{
|
{
|
||||||
@ -1355,6 +1354,12 @@ struct Q_GUI_EXPORT QRhiReadbackResult
|
|||||||
QByteArray data;
|
QByteArray data;
|
||||||
}; // non-movable due to the std::function
|
}; // non-movable due to the std::function
|
||||||
|
|
||||||
|
struct Q_GUI_EXPORT QRhiBufferReadbackResult
|
||||||
|
{
|
||||||
|
std::function<void()> completed = nullptr;
|
||||||
|
QByteArray data;
|
||||||
|
};
|
||||||
|
|
||||||
class Q_GUI_EXPORT QRhiResourceUpdateBatch
|
class Q_GUI_EXPORT QRhiResourceUpdateBatch
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -1367,6 +1372,7 @@ public:
|
|||||||
void updateDynamicBuffer(QRhiBuffer *buf, int offset, int size, const void *data);
|
void updateDynamicBuffer(QRhiBuffer *buf, int offset, int size, const void *data);
|
||||||
void uploadStaticBuffer(QRhiBuffer *buf, int offset, int size, const void *data);
|
void uploadStaticBuffer(QRhiBuffer *buf, int offset, int size, const void *data);
|
||||||
void uploadStaticBuffer(QRhiBuffer *buf, const void *data);
|
void uploadStaticBuffer(QRhiBuffer *buf, const void *data);
|
||||||
|
void readBackBuffer(QRhiBuffer *buf, int offset, int size, QRhiBufferReadbackResult *result);
|
||||||
void uploadTexture(QRhiTexture *tex, const QRhiTextureUploadDescription &desc);
|
void uploadTexture(QRhiTexture *tex, const QRhiTextureUploadDescription &desc);
|
||||||
void uploadTexture(QRhiTexture *tex, const QImage &image);
|
void uploadTexture(QRhiTexture *tex, const QImage &image);
|
||||||
void copyTexture(QRhiTexture *dst, QRhiTexture *src, const QRhiTextureCopyDescription &desc = QRhiTextureCopyDescription());
|
void copyTexture(QRhiTexture *dst, QRhiTexture *src, const QRhiTextureCopyDescription &desc = QRhiTextureCopyDescription());
|
||||||
@ -1428,7 +1434,9 @@ public:
|
|||||||
VertexShaderPointSize,
|
VertexShaderPointSize,
|
||||||
BaseVertex,
|
BaseVertex,
|
||||||
BaseInstance,
|
BaseInstance,
|
||||||
TriangleFanTopology
|
TriangleFanTopology,
|
||||||
|
ReadBackNonUniformBuffer,
|
||||||
|
ReadBackNonBaseMipLevel
|
||||||
};
|
};
|
||||||
|
|
||||||
enum BeginFrameFlag {
|
enum BeginFrameFlag {
|
||||||
|
@ -205,6 +205,8 @@ public:
|
|||||||
cleanupCallbacks.append(callback);
|
cleanupCallbacks.append(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool sanityCheckGraphicsPipeline(QRhiGraphicsPipeline *ps);
|
||||||
|
|
||||||
QRhi *q;
|
QRhi *q;
|
||||||
|
|
||||||
static const int MAX_SHADER_CACHE_ENTRIES = 128;
|
static const int MAX_SHADER_CACHE_ENTRIES = 128;
|
||||||
@ -218,7 +220,7 @@ private:
|
|||||||
QRhi::Implementation implType;
|
QRhi::Implementation implType;
|
||||||
QThread *implThread;
|
QThread *implThread;
|
||||||
QRhiProfiler profiler;
|
QRhiProfiler profiler;
|
||||||
QVector<QRhiResourceUpdateBatch *> resUpdPool;
|
QVarLengthArray<QRhiResourceUpdateBatch *, 4> resUpdPool;
|
||||||
QBitArray resUpdPoolMap;
|
QBitArray resUpdPoolMap;
|
||||||
QSet<QRhiResource *> resources;
|
QSet<QRhiResource *> resources;
|
||||||
QSet<QRhiResource *> pendingReleaseAndDestroyResources;
|
QSet<QRhiResource *> pendingReleaseAndDestroyResources;
|
||||||
@ -271,26 +273,49 @@ bool qrhi_toTopLeftRenderTargetRect(const QSize &outputSize, const std::array<T,
|
|||||||
class QRhiResourceUpdateBatchPrivate
|
class QRhiResourceUpdateBatchPrivate
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
struct DynamicBufferUpdate {
|
struct BufferOp {
|
||||||
DynamicBufferUpdate() { }
|
enum Type {
|
||||||
DynamicBufferUpdate(QRhiBuffer *buf_, int offset_, int size_, const void *data_)
|
DynamicUpdate,
|
||||||
: buf(buf_), offset(offset_), data(reinterpret_cast<const char *>(data_), size_)
|
StaticUpload,
|
||||||
{ }
|
Read
|
||||||
|
};
|
||||||
QRhiBuffer *buf = nullptr;
|
Type type;
|
||||||
int offset = 0;
|
QRhiBuffer *buf;
|
||||||
|
int offset;
|
||||||
QByteArray data;
|
QByteArray data;
|
||||||
};
|
int readSize;
|
||||||
|
QRhiBufferReadbackResult *result;
|
||||||
|
|
||||||
struct StaticBufferUpload {
|
static BufferOp dynamicUpdate(QRhiBuffer *buf, int offset, int size, const void *data)
|
||||||
StaticBufferUpload() { }
|
{
|
||||||
StaticBufferUpload(QRhiBuffer *buf_, int offset_, int size_, const void *data_)
|
BufferOp op;
|
||||||
: buf(buf_), offset(offset_), data(reinterpret_cast<const char *>(data_), size_ ? size_ : buf_->size())
|
op.type = DynamicUpdate;
|
||||||
{ }
|
op.buf = buf;
|
||||||
|
op.offset = offset;
|
||||||
|
op.data = QByteArray(reinterpret_cast<const char *>(data), size ? size : buf->size());
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
QRhiBuffer *buf = nullptr;
|
static BufferOp staticUpload(QRhiBuffer *buf, int offset, int size, const void *data)
|
||||||
int offset = 0;
|
{
|
||||||
QByteArray data;
|
BufferOp op;
|
||||||
|
op.type = StaticUpload;
|
||||||
|
op.buf = buf;
|
||||||
|
op.offset = offset;
|
||||||
|
op.data = QByteArray(reinterpret_cast<const char *>(data), size ? size : buf->size());
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BufferOp read(QRhiBuffer *buf, int offset, int size, QRhiBufferReadbackResult *result)
|
||||||
|
{
|
||||||
|
BufferOp op;
|
||||||
|
op.type = Read;
|
||||||
|
op.buf = buf;
|
||||||
|
op.offset = offset;
|
||||||
|
op.readSize = size;
|
||||||
|
op.result = result;
|
||||||
|
return op;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TextureOp {
|
struct TextureOp {
|
||||||
@ -298,73 +323,62 @@ public:
|
|||||||
Upload,
|
Upload,
|
||||||
Copy,
|
Copy,
|
||||||
Read,
|
Read,
|
||||||
MipGen
|
GenMips
|
||||||
};
|
};
|
||||||
Type type;
|
Type type;
|
||||||
struct SUpload {
|
QRhiTexture *dst;
|
||||||
QRhiTexture *tex = nullptr;
|
// Specifying multiple uploads for a subresource must be supported.
|
||||||
// Specifying multiple uploads for a subresource must be supported.
|
// In the backend this can then end up, where applicable, as a
|
||||||
// In the backend this can then end up, where applicable, as a
|
// single, batched copy operation with only one set of barriers.
|
||||||
// single, batched copy operation with only one set of barriers.
|
// This helps when doing for example glyph cache fills.
|
||||||
// This helps when doing for example glyph cache fills.
|
QVector<QRhiTextureSubresourceUploadDescription> subresDesc[QRhi::MAX_LAYERS][QRhi::MAX_LEVELS];
|
||||||
QVector<QRhiTextureSubresourceUploadDescription> subresDesc[QRhi::MAX_LAYERS][QRhi::MAX_LEVELS];
|
QRhiTexture *src;
|
||||||
} upload;
|
QRhiTextureCopyDescription desc;
|
||||||
struct SCopy {
|
QRhiReadbackDescription rb;
|
||||||
QRhiTexture *dst = nullptr;
|
QRhiReadbackResult *result;
|
||||||
QRhiTexture *src = nullptr;
|
int layer;
|
||||||
QRhiTextureCopyDescription desc;
|
|
||||||
} copy;
|
|
||||||
struct SRead {
|
|
||||||
QRhiReadbackDescription rb;
|
|
||||||
QRhiReadbackResult *result;
|
|
||||||
} read;
|
|
||||||
struct SMipGen {
|
|
||||||
QRhiTexture *tex = nullptr;
|
|
||||||
int layer = 0;
|
|
||||||
} mipgen;
|
|
||||||
|
|
||||||
static TextureOp textureUpload(QRhiTexture *tex, const QRhiTextureUploadDescription &desc)
|
static TextureOp upload(QRhiTexture *tex, const QRhiTextureUploadDescription &desc)
|
||||||
{
|
{
|
||||||
TextureOp op;
|
TextureOp op;
|
||||||
op.type = Upload;
|
op.type = Upload;
|
||||||
op.upload.tex = tex;
|
op.dst = tex;
|
||||||
for (auto it = desc.cbeginEntries(), itEnd = desc.cendEntries(); it != itEnd; ++it)
|
for (auto it = desc.cbeginEntries(), itEnd = desc.cendEntries(); it != itEnd; ++it)
|
||||||
op.upload.subresDesc[it->layer()][it->level()].append(it->description());
|
op.subresDesc[it->layer()][it->level()].append(it->description());
|
||||||
return op;
|
return op;
|
||||||
}
|
}
|
||||||
|
|
||||||
static TextureOp textureCopy(QRhiTexture *dst, QRhiTexture *src, const QRhiTextureCopyDescription &desc)
|
static TextureOp copy(QRhiTexture *dst, QRhiTexture *src, const QRhiTextureCopyDescription &desc)
|
||||||
{
|
{
|
||||||
TextureOp op;
|
TextureOp op;
|
||||||
op.type = Copy;
|
op.type = Copy;
|
||||||
op.copy.dst = dst;
|
op.dst = dst;
|
||||||
op.copy.src = src;
|
op.src = src;
|
||||||
op.copy.desc = desc;
|
op.desc = desc;
|
||||||
return op;
|
return op;
|
||||||
}
|
}
|
||||||
|
|
||||||
static TextureOp textureRead(const QRhiReadbackDescription &rb, QRhiReadbackResult *result)
|
static TextureOp read(const QRhiReadbackDescription &rb, QRhiReadbackResult *result)
|
||||||
{
|
{
|
||||||
TextureOp op;
|
TextureOp op;
|
||||||
op.type = Read;
|
op.type = Read;
|
||||||
op.read.rb = rb;
|
op.rb = rb;
|
||||||
op.read.result = result;
|
op.result = result;
|
||||||
return op;
|
return op;
|
||||||
}
|
}
|
||||||
|
|
||||||
static TextureOp textureMipGen(QRhiTexture *tex, int layer)
|
static TextureOp genMips(QRhiTexture *tex, int layer)
|
||||||
{
|
{
|
||||||
TextureOp op;
|
TextureOp op;
|
||||||
op.type = MipGen;
|
op.type = GenMips;
|
||||||
op.mipgen.tex = tex;
|
op.dst = tex;
|
||||||
op.mipgen.layer = layer;
|
op.layer = layer;
|
||||||
return op;
|
return op;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
QVector<DynamicBufferUpdate> dynamicBufferUpdates;
|
QVarLengthArray<BufferOp, 1024> bufferOps;
|
||||||
QVector<StaticBufferUpload> staticBufferUploads;
|
QVarLengthArray<TextureOp, 256> textureOps;
|
||||||
QVector<TextureOp> textureOps;
|
|
||||||
|
|
||||||
QRhiResourceUpdateBatch *q = nullptr;
|
QRhiResourceUpdateBatch *q = nullptr;
|
||||||
QRhiImplementation *rhi = nullptr;
|
QRhiImplementation *rhi = nullptr;
|
||||||
@ -376,8 +390,7 @@ public:
|
|||||||
static QRhiResourceUpdateBatchPrivate *get(QRhiResourceUpdateBatch *b) { return b->d; }
|
static QRhiResourceUpdateBatchPrivate *get(QRhiResourceUpdateBatch *b) { return b->d; }
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::DynamicBufferUpdate, Q_MOVABLE_TYPE);
|
Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::BufferOp, Q_MOVABLE_TYPE);
|
||||||
Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::StaticBufferUpload, Q_MOVABLE_TYPE);
|
|
||||||
Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::TextureOp, Q_MOVABLE_TYPE);
|
Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::TextureOp, Q_MOVABLE_TYPE);
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
@ -471,6 +471,10 @@ bool QRhiD3D11::isFeatureSupported(QRhi::Feature feature) const
|
|||||||
return true;
|
return true;
|
||||||
case QRhi::TriangleFanTopology:
|
case QRhi::TriangleFanTopology:
|
||||||
return false;
|
return false;
|
||||||
|
case QRhi::ReadBackNonUniformBuffer:
|
||||||
|
return true;
|
||||||
|
case QRhi::ReadBackNonBaseMipLevel:
|
||||||
|
return true;
|
||||||
default:
|
default:
|
||||||
Q_UNREACHABLE();
|
Q_UNREACHABLE();
|
||||||
return false;
|
return false;
|
||||||
@ -1323,61 +1327,105 @@ void QRhiD3D11::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
|
|||||||
QRhiResourceUpdateBatchPrivate *ud = QRhiResourceUpdateBatchPrivate::get(resourceUpdates);
|
QRhiResourceUpdateBatchPrivate *ud = QRhiResourceUpdateBatchPrivate::get(resourceUpdates);
|
||||||
QRhiProfilerPrivate *rhiP = profilerPrivateOrNull();
|
QRhiProfilerPrivate *rhiP = profilerPrivateOrNull();
|
||||||
|
|
||||||
for (const QRhiResourceUpdateBatchPrivate::DynamicBufferUpdate &u : ud->dynamicBufferUpdates) {
|
for (const QRhiResourceUpdateBatchPrivate::BufferOp &u : ud->bufferOps) {
|
||||||
QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, u.buf);
|
if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::DynamicUpdate) {
|
||||||
Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
|
QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, u.buf);
|
||||||
memcpy(bufD->dynBuf.data() + u.offset, u.data.constData(), size_t(u.data.size()));
|
Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
|
||||||
bufD->hasPendingDynamicUpdates = true;
|
memcpy(bufD->dynBuf.data() + u.offset, u.data.constData(), size_t(u.data.size()));
|
||||||
}
|
bufD->hasPendingDynamicUpdates = true;
|
||||||
|
} else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::StaticUpload) {
|
||||||
|
QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, u.buf);
|
||||||
|
Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
|
||||||
|
Q_ASSERT(u.offset + u.data.size() <= bufD->m_size);
|
||||||
|
QD3D11CommandBuffer::Command cmd;
|
||||||
|
cmd.cmd = QD3D11CommandBuffer::Command::UpdateSubRes;
|
||||||
|
cmd.args.updateSubRes.dst = bufD->buffer;
|
||||||
|
cmd.args.updateSubRes.dstSubRes = 0;
|
||||||
|
cmd.args.updateSubRes.src = cbD->retainData(u.data);
|
||||||
|
cmd.args.updateSubRes.srcRowPitch = 0;
|
||||||
|
// Specify the region (even when offset is 0 and all data is provided)
|
||||||
|
// since the ID3D11Buffer's size is rounded up to be a multiple of 256
|
||||||
|
// while the data we have has the original size.
|
||||||
|
D3D11_BOX box;
|
||||||
|
box.left = UINT(u.offset);
|
||||||
|
box.top = box.front = 0;
|
||||||
|
box.back = box.bottom = 1;
|
||||||
|
box.right = UINT(u.offset + u.data.size()); // no -1: right, bottom, back are exclusive, see D3D11_BOX doc
|
||||||
|
cmd.args.updateSubRes.hasDstBox = true;
|
||||||
|
cmd.args.updateSubRes.dstBox = box;
|
||||||
|
cbD->commands.append(cmd);
|
||||||
|
} else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::Read) {
|
||||||
|
QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, u.buf);
|
||||||
|
if (bufD->m_type == QRhiBuffer::Dynamic) {
|
||||||
|
u.result->data.resize(u.readSize);
|
||||||
|
memcpy(u.result->data.data(), bufD->dynBuf.constData() + u.offset, size_t(u.readSize));
|
||||||
|
} else {
|
||||||
|
BufferReadback readback;
|
||||||
|
readback.result = u.result;
|
||||||
|
readback.byteSize = u.readSize;
|
||||||
|
|
||||||
for (const QRhiResourceUpdateBatchPrivate::StaticBufferUpload &u : ud->staticBufferUploads) {
|
D3D11_BUFFER_DESC desc;
|
||||||
QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, u.buf);
|
memset(&desc, 0, sizeof(desc));
|
||||||
Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
|
desc.ByteWidth = readback.byteSize;
|
||||||
Q_ASSERT(u.offset + u.data.size() <= bufD->m_size);
|
desc.Usage = D3D11_USAGE_STAGING;
|
||||||
QD3D11CommandBuffer::Command cmd;
|
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
||||||
cmd.cmd = QD3D11CommandBuffer::Command::UpdateSubRes;
|
HRESULT hr = dev->CreateBuffer(&desc, nullptr, &readback.stagingBuf);
|
||||||
cmd.args.updateSubRes.dst = bufD->buffer;
|
if (FAILED(hr)) {
|
||||||
cmd.args.updateSubRes.dstSubRes = 0;
|
qWarning("Failed to create buffer: %s", qPrintable(comErrorMessage(hr)));
|
||||||
cmd.args.updateSubRes.src = cbD->retainData(u.data);
|
continue;
|
||||||
cmd.args.updateSubRes.srcRowPitch = 0;
|
}
|
||||||
// Specify the region (even when offset is 0 and all data is provided)
|
QRHI_PROF_F(newReadbackBuffer(qint64(qintptr(readback.stagingBuf)), bufD, readback.byteSize));
|
||||||
// since the ID3D11Buffer's size is rounded up to be a multiple of 256
|
|
||||||
// while the data we have has the original size.
|
QD3D11CommandBuffer::Command cmd;
|
||||||
D3D11_BOX box;
|
cmd.cmd = QD3D11CommandBuffer::Command::CopySubRes;
|
||||||
box.left = UINT(u.offset);
|
cmd.args.copySubRes.dst = readback.stagingBuf;
|
||||||
box.top = box.front = 0;
|
cmd.args.copySubRes.dstSubRes = 0;
|
||||||
box.back = box.bottom = 1;
|
cmd.args.copySubRes.dstX = 0;
|
||||||
box.right = UINT(u.offset + u.data.size()); // no -1: right, bottom, back are exclusive, see D3D11_BOX doc
|
cmd.args.copySubRes.dstY = 0;
|
||||||
cmd.args.updateSubRes.hasDstBox = true;
|
cmd.args.copySubRes.src = bufD->buffer;
|
||||||
cmd.args.updateSubRes.dstBox = box;
|
cmd.args.copySubRes.srcSubRes = 0;
|
||||||
cbD->commands.append(cmd);
|
cmd.args.copySubRes.hasSrcBox = true;
|
||||||
|
D3D11_BOX box;
|
||||||
|
box.left = UINT(u.offset);
|
||||||
|
box.top = box.front = 0;
|
||||||
|
box.back = box.bottom = 1;
|
||||||
|
box.right = UINT(u.offset + u.readSize);
|
||||||
|
cmd.args.copySubRes.srcBox = box;
|
||||||
|
cbD->commands.append(cmd);
|
||||||
|
|
||||||
|
activeBufferReadbacks.append(readback);
|
||||||
|
}
|
||||||
|
if (u.result->completed)
|
||||||
|
u.result->completed();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const QRhiResourceUpdateBatchPrivate::TextureOp &u : ud->textureOps) {
|
for (const QRhiResourceUpdateBatchPrivate::TextureOp &u : ud->textureOps) {
|
||||||
if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Upload) {
|
if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Upload) {
|
||||||
QD3D11Texture *texD = QRHI_RES(QD3D11Texture, u.upload.tex);
|
QD3D11Texture *texD = QRHI_RES(QD3D11Texture, u.dst);
|
||||||
for (int layer = 0; layer < QRhi::MAX_LAYERS; ++layer) {
|
for (int layer = 0; layer < QRhi::MAX_LAYERS; ++layer) {
|
||||||
for (int level = 0; level < QRhi::MAX_LEVELS; ++level) {
|
for (int level = 0; level < QRhi::MAX_LEVELS; ++level) {
|
||||||
for (const QRhiTextureSubresourceUploadDescription &subresDesc : qAsConst(u.upload.subresDesc[layer][level]))
|
for (const QRhiTextureSubresourceUploadDescription &subresDesc : qAsConst(u.subresDesc[layer][level]))
|
||||||
enqueueSubresUpload(texD, cbD, layer, level, subresDesc);
|
enqueueSubresUpload(texD, cbD, layer, level, subresDesc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Copy) {
|
} else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Copy) {
|
||||||
Q_ASSERT(u.copy.src && u.copy.dst);
|
Q_ASSERT(u.src && u.dst);
|
||||||
QD3D11Texture *srcD = QRHI_RES(QD3D11Texture, u.copy.src);
|
QD3D11Texture *srcD = QRHI_RES(QD3D11Texture, u.src);
|
||||||
QD3D11Texture *dstD = QRHI_RES(QD3D11Texture, u.copy.dst);
|
QD3D11Texture *dstD = QRHI_RES(QD3D11Texture, u.dst);
|
||||||
UINT srcSubRes = D3D11CalcSubresource(UINT(u.copy.desc.sourceLevel()), UINT(u.copy.desc.sourceLayer()), srcD->mipLevelCount);
|
UINT srcSubRes = D3D11CalcSubresource(UINT(u.desc.sourceLevel()), UINT(u.desc.sourceLayer()), srcD->mipLevelCount);
|
||||||
UINT dstSubRes = D3D11CalcSubresource(UINT(u.copy.desc.destinationLevel()), UINT(u.copy.desc.destinationLayer()), dstD->mipLevelCount);
|
UINT dstSubRes = D3D11CalcSubresource(UINT(u.desc.destinationLevel()), UINT(u.desc.destinationLayer()), dstD->mipLevelCount);
|
||||||
const QPoint dp = u.copy.desc.destinationTopLeft();
|
const QPoint dp = u.desc.destinationTopLeft();
|
||||||
const QSize size = u.copy.desc.pixelSize().isEmpty() ? srcD->m_pixelSize : u.copy.desc.pixelSize();
|
const QSize mipSize = q->sizeForMipLevel(u.desc.sourceLevel(), srcD->m_pixelSize);
|
||||||
const QPoint sp = u.copy.desc.sourceTopLeft();
|
const QSize copySize = u.desc.pixelSize().isEmpty() ? mipSize : u.desc.pixelSize();
|
||||||
|
const QPoint sp = u.desc.sourceTopLeft();
|
||||||
D3D11_BOX srcBox;
|
D3D11_BOX srcBox;
|
||||||
srcBox.left = UINT(sp.x());
|
srcBox.left = UINT(sp.x());
|
||||||
srcBox.top = UINT(sp.y());
|
srcBox.top = UINT(sp.y());
|
||||||
srcBox.front = 0;
|
srcBox.front = 0;
|
||||||
// back, right, bottom are exclusive
|
// back, right, bottom are exclusive
|
||||||
srcBox.right = srcBox.left + UINT(size.width());
|
srcBox.right = srcBox.left + UINT(copySize.width());
|
||||||
srcBox.bottom = srcBox.top + UINT(size.height());
|
srcBox.bottom = srcBox.top + UINT(copySize.height());
|
||||||
srcBox.back = 1;
|
srcBox.back = 1;
|
||||||
QD3D11CommandBuffer::Command cmd;
|
QD3D11CommandBuffer::Command cmd;
|
||||||
cmd.cmd = QD3D11CommandBuffer::Command::CopySubRes;
|
cmd.cmd = QD3D11CommandBuffer::Command::CopySubRes;
|
||||||
@ -1391,16 +1439,16 @@ void QRhiD3D11::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
|
|||||||
cmd.args.copySubRes.srcBox = srcBox;
|
cmd.args.copySubRes.srcBox = srcBox;
|
||||||
cbD->commands.append(cmd);
|
cbD->commands.append(cmd);
|
||||||
} else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Read) {
|
} else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Read) {
|
||||||
ActiveReadback aRb;
|
TextureReadback readback;
|
||||||
aRb.desc = u.read.rb;
|
readback.desc = u.rb;
|
||||||
aRb.result = u.read.result;
|
readback.result = u.result;
|
||||||
|
|
||||||
ID3D11Resource *src;
|
ID3D11Resource *src;
|
||||||
DXGI_FORMAT dxgiFormat;
|
DXGI_FORMAT dxgiFormat;
|
||||||
QSize pixelSize;
|
QSize pixelSize;
|
||||||
QRhiTexture::Format format;
|
QRhiTexture::Format format;
|
||||||
UINT subres = 0;
|
UINT subres = 0;
|
||||||
QD3D11Texture *texD = QRHI_RES(QD3D11Texture, u.read.rb.texture());
|
QD3D11Texture *texD = QRHI_RES(QD3D11Texture, u.rb.texture());
|
||||||
QD3D11SwapChain *swapChainD = nullptr;
|
QD3D11SwapChain *swapChainD = nullptr;
|
||||||
|
|
||||||
if (texD) {
|
if (texD) {
|
||||||
@ -1410,9 +1458,9 @@ void QRhiD3D11::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
|
|||||||
}
|
}
|
||||||
src = texD->tex;
|
src = texD->tex;
|
||||||
dxgiFormat = texD->dxgiFormat;
|
dxgiFormat = texD->dxgiFormat;
|
||||||
pixelSize = u.read.rb.level() > 0 ? q->sizeForMipLevel(u.read.rb.level(), texD->m_pixelSize) : texD->m_pixelSize;
|
pixelSize = q->sizeForMipLevel(u.rb.level(), texD->m_pixelSize);
|
||||||
format = texD->m_format;
|
format = texD->m_format;
|
||||||
subres = D3D11CalcSubresource(UINT(u.read.rb.level()), UINT(u.read.rb.layer()), texD->mipLevelCount);
|
subres = D3D11CalcSubresource(UINT(u.rb.level()), UINT(u.rb.layer()), texD->mipLevelCount);
|
||||||
} else {
|
} else {
|
||||||
Q_ASSERT(contextState.currentSwapChain);
|
Q_ASSERT(contextState.currentSwapChain);
|
||||||
swapChainD = QRHI_RES(QD3D11SwapChain, contextState.currentSwapChain);
|
swapChainD = QRHI_RES(QD3D11SwapChain, contextState.currentSwapChain);
|
||||||
@ -1435,9 +1483,9 @@ void QRhiD3D11::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
|
|||||||
if (format == QRhiTexture::UnknownFormat)
|
if (format == QRhiTexture::UnknownFormat)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
quint32 bufSize = 0;
|
quint32 byteSize = 0;
|
||||||
quint32 bpl = 0;
|
quint32 bpl = 0;
|
||||||
textureFormatInfo(format, pixelSize, &bpl, &bufSize);
|
textureFormatInfo(format, pixelSize, &bpl, &byteSize);
|
||||||
|
|
||||||
D3D11_TEXTURE2D_DESC desc;
|
D3D11_TEXTURE2D_DESC desc;
|
||||||
memset(&desc, 0, sizeof(desc));
|
memset(&desc, 0, sizeof(desc));
|
||||||
@ -1457,7 +1505,7 @@ void QRhiD3D11::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
|
|||||||
}
|
}
|
||||||
QRHI_PROF_F(newReadbackBuffer(qint64(qintptr(stagingTex)),
|
QRHI_PROF_F(newReadbackBuffer(qint64(qintptr(stagingTex)),
|
||||||
texD ? static_cast<QRhiResource *>(texD) : static_cast<QRhiResource *>(swapChainD),
|
texD ? static_cast<QRhiResource *>(texD) : static_cast<QRhiResource *>(swapChainD),
|
||||||
bufSize));
|
byteSize));
|
||||||
|
|
||||||
QD3D11CommandBuffer::Command cmd;
|
QD3D11CommandBuffer::Command cmd;
|
||||||
cmd.cmd = QD3D11CommandBuffer::Command::CopySubRes;
|
cmd.cmd = QD3D11CommandBuffer::Command::CopySubRes;
|
||||||
@ -1470,18 +1518,18 @@ void QRhiD3D11::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
|
|||||||
cmd.args.copySubRes.hasSrcBox = false;
|
cmd.args.copySubRes.hasSrcBox = false;
|
||||||
cbD->commands.append(cmd);
|
cbD->commands.append(cmd);
|
||||||
|
|
||||||
aRb.stagingTex = stagingTex;
|
readback.stagingTex = stagingTex;
|
||||||
aRb.bufSize = bufSize;
|
readback.byteSize = byteSize;
|
||||||
aRb.bpl = bpl;
|
readback.bpl = bpl;
|
||||||
aRb.pixelSize = pixelSize;
|
readback.pixelSize = pixelSize;
|
||||||
aRb.format = format;
|
readback.format = format;
|
||||||
|
|
||||||
activeReadbacks.append(aRb);
|
activeTextureReadbacks.append(readback);
|
||||||
} else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::MipGen) {
|
} else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::GenMips) {
|
||||||
Q_ASSERT(u.mipgen.tex->flags().testFlag(QRhiTexture::UsedWithGenerateMips));
|
Q_ASSERT(u.dst->flags().testFlag(QRhiTexture::UsedWithGenerateMips));
|
||||||
QD3D11CommandBuffer::Command cmd;
|
QD3D11CommandBuffer::Command cmd;
|
||||||
cmd.cmd = QD3D11CommandBuffer::Command::GenMip;
|
cmd.cmd = QD3D11CommandBuffer::Command::GenMip;
|
||||||
cmd.args.genMip.srv = QRHI_RES(QD3D11Texture, u.mipgen.tex)->srv;
|
cmd.args.genMip.srv = QRHI_RES(QD3D11Texture, u.dst)->srv;
|
||||||
cbD->commands.append(cmd);
|
cbD->commands.append(cmd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1494,37 +1542,58 @@ void QRhiD3D11::finishActiveReadbacks()
|
|||||||
QVarLengthArray<std::function<void()>, 4> completedCallbacks;
|
QVarLengthArray<std::function<void()>, 4> completedCallbacks;
|
||||||
QRhiProfilerPrivate *rhiP = profilerPrivateOrNull();
|
QRhiProfilerPrivate *rhiP = profilerPrivateOrNull();
|
||||||
|
|
||||||
for (int i = activeReadbacks.count() - 1; i >= 0; --i) {
|
for (int i = activeTextureReadbacks.count() - 1; i >= 0; --i) {
|
||||||
const QRhiD3D11::ActiveReadback &aRb(activeReadbacks[i]);
|
const QRhiD3D11::TextureReadback &readback(activeTextureReadbacks[i]);
|
||||||
aRb.result->format = aRb.format;
|
readback.result->format = readback.format;
|
||||||
aRb.result->pixelSize = aRb.pixelSize;
|
readback.result->pixelSize = readback.pixelSize;
|
||||||
aRb.result->data.resize(int(aRb.bufSize));
|
|
||||||
|
|
||||||
D3D11_MAPPED_SUBRESOURCE mp;
|
D3D11_MAPPED_SUBRESOURCE mp;
|
||||||
HRESULT hr = context->Map(aRb.stagingTex, 0, D3D11_MAP_READ, 0, &mp);
|
HRESULT hr = context->Map(readback.stagingTex, 0, D3D11_MAP_READ, 0, &mp);
|
||||||
if (FAILED(hr)) {
|
if (SUCCEEDED(hr)) {
|
||||||
|
readback.result->data.resize(int(readback.byteSize));
|
||||||
|
// nothing says the rows are tightly packed in the texture, must take
|
||||||
|
// the stride into account
|
||||||
|
char *dst = readback.result->data.data();
|
||||||
|
char *src = static_cast<char *>(mp.pData);
|
||||||
|
for (int y = 0, h = readback.pixelSize.height(); y != h; ++y) {
|
||||||
|
memcpy(dst, src, readback.bpl);
|
||||||
|
dst += readback.bpl;
|
||||||
|
src += mp.RowPitch;
|
||||||
|
}
|
||||||
|
context->Unmap(readback.stagingTex, 0);
|
||||||
|
} else {
|
||||||
qWarning("Failed to map readback staging texture: %s", qPrintable(comErrorMessage(hr)));
|
qWarning("Failed to map readback staging texture: %s", qPrintable(comErrorMessage(hr)));
|
||||||
aRb.stagingTex->Release();
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
// nothing says the rows are tightly packed in the texture, must take
|
|
||||||
// the stride into account
|
readback.stagingTex->Release();
|
||||||
char *dst = aRb.result->data.data();
|
QRHI_PROF_F(releaseReadbackBuffer(qint64(qintptr(readback.stagingTex))));
|
||||||
char *src = static_cast<char *>(mp.pData);
|
|
||||||
for (int y = 0, h = aRb.pixelSize.height(); y != h; ++y) {
|
if (readback.result->completed)
|
||||||
memcpy(dst, src, aRb.bpl);
|
completedCallbacks.append(readback.result->completed);
|
||||||
dst += aRb.bpl;
|
|
||||||
src += mp.RowPitch;
|
activeTextureReadbacks.removeAt(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = activeBufferReadbacks.count() - 1; i >= 0; --i) {
|
||||||
|
const QRhiD3D11::BufferReadback &readback(activeBufferReadbacks[i]);
|
||||||
|
|
||||||
|
D3D11_MAPPED_SUBRESOURCE mp;
|
||||||
|
HRESULT hr = context->Map(readback.stagingBuf, 0, D3D11_MAP_READ, 0, &mp);
|
||||||
|
if (SUCCEEDED(hr)) {
|
||||||
|
readback.result->data.resize(int(readback.byteSize));
|
||||||
|
memcpy(readback.result->data.data(), mp.pData, readback.byteSize);
|
||||||
|
context->Unmap(readback.stagingBuf, 0);
|
||||||
|
} else {
|
||||||
|
qWarning("Failed to map readback staging texture: %s", qPrintable(comErrorMessage(hr)));
|
||||||
}
|
}
|
||||||
context->Unmap(aRb.stagingTex, 0);
|
|
||||||
|
|
||||||
aRb.stagingTex->Release();
|
readback.stagingBuf->Release();
|
||||||
QRHI_PROF_F(releaseReadbackBuffer(qint64(qintptr(aRb.stagingTex))));
|
QRHI_PROF_F(releaseReadbackBuffer(qint64(qintptr(readback.stagingBuf))));
|
||||||
|
|
||||||
if (aRb.result->completed)
|
if (readback.result->completed)
|
||||||
completedCallbacks.append(aRb.result->completed);
|
completedCallbacks.append(readback.result->completed);
|
||||||
|
|
||||||
activeReadbacks.removeAt(i);
|
activeBufferReadbacks.removeAt(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto f : completedCallbacks)
|
for (auto f : completedCallbacks)
|
||||||
@ -3423,6 +3492,8 @@ bool QD3D11GraphicsPipeline::build()
|
|||||||
release();
|
release();
|
||||||
|
|
||||||
QRHI_RES_RHI(QRhiD3D11);
|
QRHI_RES_RHI(QRhiD3D11);
|
||||||
|
if (!rhiD->sanityCheckGraphicsPipeline(this))
|
||||||
|
return false;
|
||||||
|
|
||||||
D3D11_RASTERIZER_DESC rastDesc;
|
D3D11_RASTERIZER_DESC rastDesc;
|
||||||
memset(&rastDesc, 0, sizeof(rastDesc));
|
memset(&rastDesc, 0, sizeof(rastDesc));
|
||||||
|
@ -678,16 +678,22 @@ public:
|
|||||||
QD3D11CommandBuffer cbWrapper;
|
QD3D11CommandBuffer cbWrapper;
|
||||||
} ofr;
|
} ofr;
|
||||||
|
|
||||||
struct ActiveReadback {
|
struct TextureReadback {
|
||||||
QRhiReadbackDescription desc;
|
QRhiReadbackDescription desc;
|
||||||
QRhiReadbackResult *result;
|
QRhiReadbackResult *result;
|
||||||
ID3D11Texture2D *stagingTex;
|
ID3D11Texture2D *stagingTex;
|
||||||
quint32 bufSize;
|
quint32 byteSize;
|
||||||
quint32 bpl;
|
quint32 bpl;
|
||||||
QSize pixelSize;
|
QSize pixelSize;
|
||||||
QRhiTexture::Format format;
|
QRhiTexture::Format format;
|
||||||
};
|
};
|
||||||
QVector<ActiveReadback> activeReadbacks;
|
QVector<TextureReadback> activeTextureReadbacks;
|
||||||
|
struct BufferReadback {
|
||||||
|
QRhiBufferReadbackResult *result;
|
||||||
|
quint32 byteSize;
|
||||||
|
ID3D11Buffer *stagingBuf;
|
||||||
|
};
|
||||||
|
QVector<BufferReadback> activeBufferReadbacks;
|
||||||
|
|
||||||
struct Shader {
|
struct Shader {
|
||||||
Shader() = default;
|
Shader() = default;
|
||||||
@ -711,7 +717,8 @@ public:
|
|||||||
} deviceCurse;
|
} deviceCurse;
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_DECLARE_TYPEINFO(QRhiD3D11::ActiveReadback, Q_MOVABLE_TYPE);
|
Q_DECLARE_TYPEINFO(QRhiD3D11::TextureReadback, Q_MOVABLE_TYPE);
|
||||||
|
Q_DECLARE_TYPEINFO(QRhiD3D11::BufferReadback, Q_MOVABLE_TYPE);
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
@ -276,6 +276,10 @@ QT_BEGIN_NAMESPACE
|
|||||||
#define GL_POINT_SPRITE 0x8861
|
#define GL_POINT_SPRITE 0x8861
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef GL_MAP_READ_BIT
|
||||||
|
#define GL_MAP_READ_BIT 0x0001
|
||||||
|
#endif
|
||||||
|
|
||||||
Q_DECLARE_LOGGING_CATEGORY(lcOpenGLProgramDiskCache)
|
Q_DECLARE_LOGGING_CATEGORY(lcOpenGLProgramDiskCache)
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -492,6 +496,15 @@ bool QRhiGles2::create(QRhi::Flags flags)
|
|||||||
else
|
else
|
||||||
caps.textureCompareMode = true;
|
caps.textureCompareMode = true;
|
||||||
|
|
||||||
|
// proper as in ES 3.0 (glMapBufferRange), not the old glMapBuffer
|
||||||
|
// extension(s) (which is not in ES 3.0...messy)
|
||||||
|
caps.properMapBuffer = f->hasOpenGLExtension(QOpenGLExtensions::MapBufferRange);
|
||||||
|
|
||||||
|
if (caps.gles)
|
||||||
|
caps.nonBaseLevelFramebufferTexture = caps.ctxMajor >= 3; // ES 3.0
|
||||||
|
else
|
||||||
|
caps.nonBaseLevelFramebufferTexture = true;
|
||||||
|
|
||||||
if (!caps.gles) {
|
if (!caps.gles) {
|
||||||
f->glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
|
f->glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
|
||||||
f->glEnable(GL_POINT_SPRITE);
|
f->glEnable(GL_POINT_SPRITE);
|
||||||
@ -734,6 +747,10 @@ bool QRhiGles2::isFeatureSupported(QRhi::Feature feature) const
|
|||||||
return false; // not in ES 3.2, so won't bother
|
return false; // not in ES 3.2, so won't bother
|
||||||
case QRhi::TriangleFanTopology:
|
case QRhi::TriangleFanTopology:
|
||||||
return true;
|
return true;
|
||||||
|
case QRhi::ReadBackNonUniformBuffer:
|
||||||
|
return !caps.gles || caps.properMapBuffer;
|
||||||
|
case QRhi::ReadBackNonBaseMipLevel:
|
||||||
|
return caps.nonBaseLevelFramebufferTexture;
|
||||||
default:
|
default:
|
||||||
Q_UNREACHABLE();
|
Q_UNREACHABLE();
|
||||||
return false;
|
return false;
|
||||||
@ -1417,65 +1434,83 @@ void QRhiGles2::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
|
|||||||
QGles2CommandBuffer *cbD = QRHI_RES(QGles2CommandBuffer, cb);
|
QGles2CommandBuffer *cbD = QRHI_RES(QGles2CommandBuffer, cb);
|
||||||
QRhiResourceUpdateBatchPrivate *ud = QRhiResourceUpdateBatchPrivate::get(resourceUpdates);
|
QRhiResourceUpdateBatchPrivate *ud = QRhiResourceUpdateBatchPrivate::get(resourceUpdates);
|
||||||
|
|
||||||
for (const QRhiResourceUpdateBatchPrivate::DynamicBufferUpdate &u : ud->dynamicBufferUpdates) {
|
for (const QRhiResourceUpdateBatchPrivate::BufferOp &u : ud->bufferOps) {
|
||||||
QGles2Buffer *bufD = QRHI_RES(QGles2Buffer, u.buf);
|
if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::DynamicUpdate) {
|
||||||
Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
|
QGles2Buffer *bufD = QRHI_RES(QGles2Buffer, u.buf);
|
||||||
if (bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer)) {
|
Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
|
||||||
memcpy(bufD->ubuf.data() + u.offset, u.data.constData(), size_t(u.data.size()));
|
if (bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer)) {
|
||||||
} else {
|
memcpy(bufD->ubuf.data() + u.offset, u.data.constData(), size_t(u.data.size()));
|
||||||
trackedBufferBarrier(cbD, bufD, QGles2Buffer::AccessUpdate);
|
} else {
|
||||||
QGles2CommandBuffer::Command cmd;
|
trackedBufferBarrier(cbD, bufD, QGles2Buffer::AccessUpdate);
|
||||||
cmd.cmd = QGles2CommandBuffer::Command::BufferSubData;
|
QGles2CommandBuffer::Command cmd;
|
||||||
cmd.args.bufferSubData.target = bufD->targetForDataOps;
|
cmd.cmd = QGles2CommandBuffer::Command::BufferSubData;
|
||||||
cmd.args.bufferSubData.buffer = bufD->buffer;
|
cmd.args.bufferSubData.target = bufD->targetForDataOps;
|
||||||
cmd.args.bufferSubData.offset = u.offset;
|
cmd.args.bufferSubData.buffer = bufD->buffer;
|
||||||
cmd.args.bufferSubData.size = u.data.size();
|
cmd.args.bufferSubData.offset = u.offset;
|
||||||
cmd.args.bufferSubData.data = cbD->retainData(u.data);
|
cmd.args.bufferSubData.size = u.data.size();
|
||||||
cbD->commands.append(cmd);
|
cmd.args.bufferSubData.data = cbD->retainData(u.data);
|
||||||
}
|
cbD->commands.append(cmd);
|
||||||
}
|
}
|
||||||
|
} else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::StaticUpload) {
|
||||||
for (const QRhiResourceUpdateBatchPrivate::StaticBufferUpload &u : ud->staticBufferUploads) {
|
QGles2Buffer *bufD = QRHI_RES(QGles2Buffer, u.buf);
|
||||||
QGles2Buffer *bufD = QRHI_RES(QGles2Buffer, 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);
|
if (bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer)) {
|
||||||
if (bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer)) {
|
memcpy(bufD->ubuf.data() + u.offset, u.data.constData(), size_t(u.data.size()));
|
||||||
memcpy(bufD->ubuf.data() + u.offset, u.data.constData(), size_t(u.data.size()));
|
} else {
|
||||||
} else {
|
trackedBufferBarrier(cbD, bufD, QGles2Buffer::AccessUpdate);
|
||||||
trackedBufferBarrier(cbD, bufD, QGles2Buffer::AccessUpdate);
|
QGles2CommandBuffer::Command cmd;
|
||||||
QGles2CommandBuffer::Command cmd;
|
cmd.cmd = QGles2CommandBuffer::Command::BufferSubData;
|
||||||
cmd.cmd = QGles2CommandBuffer::Command::BufferSubData;
|
cmd.args.bufferSubData.target = bufD->targetForDataOps;
|
||||||
cmd.args.bufferSubData.target = bufD->targetForDataOps;
|
cmd.args.bufferSubData.buffer = bufD->buffer;
|
||||||
cmd.args.bufferSubData.buffer = bufD->buffer;
|
cmd.args.bufferSubData.offset = u.offset;
|
||||||
cmd.args.bufferSubData.offset = u.offset;
|
cmd.args.bufferSubData.size = u.data.size();
|
||||||
cmd.args.bufferSubData.size = u.data.size();
|
cmd.args.bufferSubData.data = cbD->retainData(u.data);
|
||||||
cmd.args.bufferSubData.data = cbD->retainData(u.data);
|
cbD->commands.append(cmd);
|
||||||
cbD->commands.append(cmd);
|
}
|
||||||
|
} else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::Read) {
|
||||||
|
QGles2Buffer *bufD = QRHI_RES(QGles2Buffer, u.buf);
|
||||||
|
if (bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer)) {
|
||||||
|
u.result->data.resize(u.readSize);
|
||||||
|
memcpy(u.result->data.data(), bufD->ubuf.constData() + u.offset, size_t(u.readSize));
|
||||||
|
if (u.result->completed)
|
||||||
|
u.result->completed();
|
||||||
|
} else {
|
||||||
|
QGles2CommandBuffer::Command cmd;
|
||||||
|
cmd.cmd = QGles2CommandBuffer::Command::GetBufferSubData;
|
||||||
|
cmd.args.getBufferSubData.result = u.result;
|
||||||
|
cmd.args.getBufferSubData.target = bufD->targetForDataOps;
|
||||||
|
cmd.args.getBufferSubData.buffer = bufD->buffer;
|
||||||
|
cmd.args.getBufferSubData.offset = u.offset;
|
||||||
|
cmd.args.getBufferSubData.size = u.readSize;
|
||||||
|
cbD->commands.append(cmd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const QRhiResourceUpdateBatchPrivate::TextureOp &u : ud->textureOps) {
|
for (const QRhiResourceUpdateBatchPrivate::TextureOp &u : ud->textureOps) {
|
||||||
if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Upload) {
|
if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Upload) {
|
||||||
QGles2Texture *texD = QRHI_RES(QGles2Texture, u.upload.tex);
|
QGles2Texture *texD = QRHI_RES(QGles2Texture, u.dst);
|
||||||
for (int layer = 0; layer < QRhi::MAX_LAYERS; ++layer) {
|
for (int layer = 0; layer < QRhi::MAX_LAYERS; ++layer) {
|
||||||
for (int level = 0; level < QRhi::MAX_LEVELS; ++level) {
|
for (int level = 0; level < QRhi::MAX_LEVELS; ++level) {
|
||||||
for (const QRhiTextureSubresourceUploadDescription &subresDesc : qAsConst(u.upload.subresDesc[layer][level]))
|
for (const QRhiTextureSubresourceUploadDescription &subresDesc : qAsConst(u.subresDesc[layer][level]))
|
||||||
enqueueSubresUpload(texD, cbD, layer, level, subresDesc);
|
enqueueSubresUpload(texD, cbD, layer, level, subresDesc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
texD->specified = true;
|
texD->specified = true;
|
||||||
} else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Copy) {
|
} else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Copy) {
|
||||||
Q_ASSERT(u.copy.src && u.copy.dst);
|
Q_ASSERT(u.src && u.dst);
|
||||||
QGles2Texture *srcD = QRHI_RES(QGles2Texture, u.copy.src);
|
QGles2Texture *srcD = QRHI_RES(QGles2Texture, u.src);
|
||||||
QGles2Texture *dstD = QRHI_RES(QGles2Texture, u.copy.dst);
|
QGles2Texture *dstD = QRHI_RES(QGles2Texture, u.dst);
|
||||||
|
|
||||||
trackedImageBarrier(cbD, srcD, QGles2Texture::AccessRead);
|
trackedImageBarrier(cbD, srcD, QGles2Texture::AccessRead);
|
||||||
trackedImageBarrier(cbD, dstD, QGles2Texture::AccessUpdate);
|
trackedImageBarrier(cbD, dstD, QGles2Texture::AccessUpdate);
|
||||||
|
|
||||||
const QSize size = u.copy.desc.pixelSize().isEmpty() ? srcD->m_pixelSize : u.copy.desc.pixelSize();
|
const QSize mipSize = q->sizeForMipLevel(u.desc.sourceLevel(), srcD->m_pixelSize);
|
||||||
|
const QSize copySize = u.desc.pixelSize().isEmpty() ? mipSize : u.desc.pixelSize();
|
||||||
// do not translate coordinates, even if sp is bottom-left from gl's pov
|
// do not translate coordinates, even if sp is bottom-left from gl's pov
|
||||||
const QPoint sp = u.copy.desc.sourceTopLeft();
|
const QPoint sp = u.desc.sourceTopLeft();
|
||||||
const QPoint dp = u.copy.desc.destinationTopLeft();
|
const QPoint dp = u.desc.destinationTopLeft();
|
||||||
|
|
||||||
const GLenum srcFaceTargetBase = srcD->m_flags.testFlag(QRhiTexture::CubeMap)
|
const GLenum srcFaceTargetBase = srcD->m_flags.testFlag(QRhiTexture::CubeMap)
|
||||||
? GL_TEXTURE_CUBE_MAP_POSITIVE_X : srcD->target;
|
? GL_TEXTURE_CUBE_MAP_POSITIVE_X : srcD->target;
|
||||||
@ -1485,43 +1520,44 @@ void QRhiGles2::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
|
|||||||
QGles2CommandBuffer::Command cmd;
|
QGles2CommandBuffer::Command cmd;
|
||||||
cmd.cmd = QGles2CommandBuffer::Command::CopyTex;
|
cmd.cmd = QGles2CommandBuffer::Command::CopyTex;
|
||||||
|
|
||||||
cmd.args.copyTex.srcFaceTarget = srcFaceTargetBase + uint(u.copy.desc.sourceLayer());
|
cmd.args.copyTex.srcFaceTarget = srcFaceTargetBase + uint(u.desc.sourceLayer());
|
||||||
cmd.args.copyTex.srcTexture = srcD->texture;
|
cmd.args.copyTex.srcTexture = srcD->texture;
|
||||||
cmd.args.copyTex.srcLevel = u.copy.desc.sourceLevel();
|
cmd.args.copyTex.srcLevel = u.desc.sourceLevel();
|
||||||
cmd.args.copyTex.srcX = sp.x();
|
cmd.args.copyTex.srcX = sp.x();
|
||||||
cmd.args.copyTex.srcY = sp.y();
|
cmd.args.copyTex.srcY = sp.y();
|
||||||
|
|
||||||
cmd.args.copyTex.dstTarget = dstD->target;
|
cmd.args.copyTex.dstTarget = dstD->target;
|
||||||
cmd.args.copyTex.dstTexture = dstD->texture;
|
cmd.args.copyTex.dstTexture = dstD->texture;
|
||||||
cmd.args.copyTex.dstFaceTarget = dstFaceTargetBase + uint(u.copy.desc.destinationLayer());
|
cmd.args.copyTex.dstFaceTarget = dstFaceTargetBase + uint(u.desc.destinationLayer());
|
||||||
cmd.args.copyTex.dstLevel = u.copy.desc.destinationLevel();
|
cmd.args.copyTex.dstLevel = u.desc.destinationLevel();
|
||||||
cmd.args.copyTex.dstX = dp.x();
|
cmd.args.copyTex.dstX = dp.x();
|
||||||
cmd.args.copyTex.dstY = dp.y();
|
cmd.args.copyTex.dstY = dp.y();
|
||||||
|
|
||||||
cmd.args.copyTex.w = size.width();
|
cmd.args.copyTex.w = copySize.width();
|
||||||
cmd.args.copyTex.h = size.height();
|
cmd.args.copyTex.h = copySize.height();
|
||||||
|
|
||||||
cbD->commands.append(cmd);
|
cbD->commands.append(cmd);
|
||||||
} else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Read) {
|
} else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Read) {
|
||||||
QGles2CommandBuffer::Command cmd;
|
QGles2CommandBuffer::Command cmd;
|
||||||
cmd.cmd = QGles2CommandBuffer::Command::ReadPixels;
|
cmd.cmd = QGles2CommandBuffer::Command::ReadPixels;
|
||||||
cmd.args.readPixels.result = u.read.result;
|
cmd.args.readPixels.result = u.result;
|
||||||
QGles2Texture *texD = QRHI_RES(QGles2Texture, u.read.rb.texture());
|
QGles2Texture *texD = QRHI_RES(QGles2Texture, u.rb.texture());
|
||||||
if (texD)
|
if (texD)
|
||||||
trackedImageBarrier(cbD, texD, QGles2Texture::AccessRead);
|
trackedImageBarrier(cbD, texD, QGles2Texture::AccessRead);
|
||||||
cmd.args.readPixels.texture = texD ? texD->texture : 0;
|
cmd.args.readPixels.texture = texD ? texD->texture : 0;
|
||||||
if (texD) {
|
if (texD) {
|
||||||
cmd.args.readPixels.w = texD->m_pixelSize.width();
|
const QSize readImageSize = q->sizeForMipLevel(u.rb.level(), texD->m_pixelSize);
|
||||||
cmd.args.readPixels.h = texD->m_pixelSize.height();
|
cmd.args.readPixels.w = readImageSize.width();
|
||||||
|
cmd.args.readPixels.h = readImageSize.height();
|
||||||
cmd.args.readPixels.format = texD->m_format;
|
cmd.args.readPixels.format = texD->m_format;
|
||||||
const GLenum faceTargetBase = texD->m_flags.testFlag(QRhiTexture::CubeMap)
|
const GLenum faceTargetBase = texD->m_flags.testFlag(QRhiTexture::CubeMap)
|
||||||
? GL_TEXTURE_CUBE_MAP_POSITIVE_X : texD->target;
|
? GL_TEXTURE_CUBE_MAP_POSITIVE_X : texD->target;
|
||||||
cmd.args.readPixels.readTarget = faceTargetBase + uint(u.read.rb.layer());
|
cmd.args.readPixels.readTarget = faceTargetBase + uint(u.rb.layer());
|
||||||
cmd.args.readPixels.level = u.read.rb.level();
|
cmd.args.readPixels.level = u.rb.level();
|
||||||
}
|
}
|
||||||
cbD->commands.append(cmd);
|
cbD->commands.append(cmd);
|
||||||
} else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::MipGen) {
|
} else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::GenMips) {
|
||||||
QGles2Texture *texD = QRHI_RES(QGles2Texture, u.mipgen.tex);
|
QGles2Texture *texD = QRHI_RES(QGles2Texture, u.dst);
|
||||||
trackedImageBarrier(cbD, texD, QGles2Texture::AccessFramebuffer);
|
trackedImageBarrier(cbD, texD, QGles2Texture::AccessFramebuffer);
|
||||||
QGles2CommandBuffer::Command cmd;
|
QGles2CommandBuffer::Command cmd;
|
||||||
cmd.cmd = QGles2CommandBuffer::Command::GenMip;
|
cmd.cmd = QGles2CommandBuffer::Command::GenMip;
|
||||||
@ -2080,6 +2116,33 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
|
|||||||
f->glBufferSubData(cmd.args.bufferSubData.target, cmd.args.bufferSubData.offset, cmd.args.bufferSubData.size,
|
f->glBufferSubData(cmd.args.bufferSubData.target, cmd.args.bufferSubData.offset, cmd.args.bufferSubData.size,
|
||||||
cmd.args.bufferSubData.data);
|
cmd.args.bufferSubData.data);
|
||||||
break;
|
break;
|
||||||
|
case QGles2CommandBuffer::Command::GetBufferSubData:
|
||||||
|
{
|
||||||
|
QRhiBufferReadbackResult *result = cmd.args.getBufferSubData.result;
|
||||||
|
f->glBindBuffer(cmd.args.getBufferSubData.target, cmd.args.getBufferSubData.buffer);
|
||||||
|
if (caps.gles) {
|
||||||
|
if (caps.properMapBuffer) {
|
||||||
|
void *p = f->glMapBufferRange(cmd.args.getBufferSubData.target,
|
||||||
|
cmd.args.getBufferSubData.offset,
|
||||||
|
cmd.args.getBufferSubData.size,
|
||||||
|
GL_MAP_READ_BIT);
|
||||||
|
if (p) {
|
||||||
|
result->data.resize(cmd.args.getBufferSubData.size);
|
||||||
|
memcpy(result->data.data(), p, size_t(cmd.args.getBufferSubData.size));
|
||||||
|
f->glUnmapBuffer(cmd.args.getBufferSubData.target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result->data.resize(cmd.args.getBufferSubData.size);
|
||||||
|
f->glGetBufferSubData(cmd.args.getBufferSubData.target,
|
||||||
|
cmd.args.getBufferSubData.offset,
|
||||||
|
cmd.args.getBufferSubData.size,
|
||||||
|
result->data.data());
|
||||||
|
}
|
||||||
|
if (result->completed)
|
||||||
|
result->completed();
|
||||||
|
}
|
||||||
|
break;
|
||||||
case QGles2CommandBuffer::Command::CopyTex:
|
case QGles2CommandBuffer::Command::CopyTex:
|
||||||
{
|
{
|
||||||
GLuint fbo;
|
GLuint fbo;
|
||||||
@ -2101,23 +2164,31 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
|
|||||||
QRhiReadbackResult *result = cmd.args.readPixels.result;
|
QRhiReadbackResult *result = cmd.args.readPixels.result;
|
||||||
GLuint tex = cmd.args.readPixels.texture;
|
GLuint tex = cmd.args.readPixels.texture;
|
||||||
GLuint fbo = 0;
|
GLuint fbo = 0;
|
||||||
|
int mipLevel = 0;
|
||||||
if (tex) {
|
if (tex) {
|
||||||
result->pixelSize = QSize(cmd.args.readPixels.w, cmd.args.readPixels.h);
|
result->pixelSize = QSize(cmd.args.readPixels.w, cmd.args.readPixels.h);
|
||||||
result->format = cmd.args.readPixels.format;
|
result->format = cmd.args.readPixels.format;
|
||||||
f->glGenFramebuffers(1, &fbo);
|
mipLevel = cmd.args.readPixels.level;
|
||||||
f->glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
if (mipLevel == 0 || caps.nonBaseLevelFramebufferTexture) {
|
||||||
f->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
f->glGenFramebuffers(1, &fbo);
|
||||||
cmd.args.readPixels.readTarget, cmd.args.readPixels.texture, cmd.args.readPixels.level);
|
f->glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||||
|
f->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||||
|
cmd.args.readPixels.readTarget, cmd.args.readPixels.texture, mipLevel);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
result->pixelSize = currentSwapChain->pixelSize;
|
result->pixelSize = currentSwapChain->pixelSize;
|
||||||
result->format = QRhiTexture::RGBA8;
|
result->format = QRhiTexture::RGBA8;
|
||||||
// readPixels handles multisample resolving implicitly
|
// readPixels handles multisample resolving implicitly
|
||||||
}
|
}
|
||||||
result->data.resize(result->pixelSize.width() * result->pixelSize.height() * 4);
|
result->data.resize(result->pixelSize.width() * result->pixelSize.height() * 4);
|
||||||
// With GLES (2.0?) GL_RGBA is the only mandated readback format, so stick with it.
|
if (mipLevel == 0 || caps.nonBaseLevelFramebufferTexture) {
|
||||||
f->glReadPixels(0, 0, result->pixelSize.width(), result->pixelSize.height(),
|
// With GLES (2.0?) GL_RGBA is the only mandated readback format, so stick with it.
|
||||||
GL_RGBA, GL_UNSIGNED_BYTE,
|
f->glReadPixels(0, 0, result->pixelSize.width(), result->pixelSize.height(),
|
||||||
result->data.data());
|
GL_RGBA, GL_UNSIGNED_BYTE,
|
||||||
|
result->data.data());
|
||||||
|
} else {
|
||||||
|
result->data.fill('\0');
|
||||||
|
}
|
||||||
if (fbo) {
|
if (fbo) {
|
||||||
f->glBindFramebuffer(GL_FRAMEBUFFER, ctx->defaultFramebufferObject());
|
f->glBindFramebuffer(GL_FRAMEBUFFER, ctx->defaultFramebufferObject());
|
||||||
f->glDeleteFramebuffers(1, &fbo);
|
f->glDeleteFramebuffers(1, &fbo);
|
||||||
@ -3620,6 +3691,9 @@ bool QGles2GraphicsPipeline::build()
|
|||||||
if (!rhiD->ensureContext())
|
if (!rhiD->ensureContext())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (!rhiD->sanityCheckGraphicsPipeline(this))
|
||||||
|
return false;
|
||||||
|
|
||||||
drawMode = toGlTopology(m_topology);
|
drawMode = toGlTopology(m_topology);
|
||||||
|
|
||||||
program = rhiD->f->glCreateProgram();
|
program = rhiD->f->glCreateProgram();
|
||||||
|
@ -312,8 +312,8 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer
|
|||||||
BindShaderResources,
|
BindShaderResources,
|
||||||
BindFramebuffer,
|
BindFramebuffer,
|
||||||
Clear,
|
Clear,
|
||||||
BufferData,
|
|
||||||
BufferSubData,
|
BufferSubData,
|
||||||
|
GetBufferSubData,
|
||||||
CopyTex,
|
CopyTex,
|
||||||
ReadPixels,
|
ReadPixels,
|
||||||
SubImage,
|
SubImage,
|
||||||
@ -401,6 +401,13 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer
|
|||||||
int size;
|
int size;
|
||||||
const void *data; // must come from retainData()
|
const void *data; // must come from retainData()
|
||||||
} bufferSubData;
|
} bufferSubData;
|
||||||
|
struct {
|
||||||
|
QRhiBufferReadbackResult *result;
|
||||||
|
GLenum target;
|
||||||
|
GLuint buffer;
|
||||||
|
int offset;
|
||||||
|
int size;
|
||||||
|
} getBufferSubData;
|
||||||
struct {
|
struct {
|
||||||
GLenum srcFaceTarget;
|
GLenum srcFaceTarget;
|
||||||
GLuint srcTexture;
|
GLuint srcTexture;
|
||||||
@ -744,7 +751,10 @@ public:
|
|||||||
rgba8Format(false),
|
rgba8Format(false),
|
||||||
instancing(false),
|
instancing(false),
|
||||||
baseVertex(false),
|
baseVertex(false),
|
||||||
compute(false)
|
compute(false),
|
||||||
|
textureCompareMode(false),
|
||||||
|
properMapBuffer(false),
|
||||||
|
nonBaseLevelFramebufferTexture(false)
|
||||||
{ }
|
{ }
|
||||||
int ctxMajor;
|
int ctxMajor;
|
||||||
int ctxMinor;
|
int ctxMinor;
|
||||||
@ -775,6 +785,8 @@ public:
|
|||||||
uint baseVertex : 1;
|
uint baseVertex : 1;
|
||||||
uint compute : 1;
|
uint compute : 1;
|
||||||
uint textureCompareMode : 1;
|
uint textureCompareMode : 1;
|
||||||
|
uint properMapBuffer : 1;
|
||||||
|
uint nonBaseLevelFramebufferTexture : 1;
|
||||||
} caps;
|
} caps;
|
||||||
QGles2SwapChain *currentSwapChain = nullptr;
|
QGles2SwapChain *currentSwapChain = nullptr;
|
||||||
QVector<GLint> supportedCompressedFormats;
|
QVector<GLint> supportedCompressedFormats;
|
||||||
|
@ -205,7 +205,7 @@ struct QRhiMetalData
|
|||||||
QMetalCommandBuffer cbWrapper;
|
QMetalCommandBuffer cbWrapper;
|
||||||
} ofr;
|
} ofr;
|
||||||
|
|
||||||
struct ActiveReadback {
|
struct TextureReadback {
|
||||||
int activeFrameSlot = -1;
|
int activeFrameSlot = -1;
|
||||||
QRhiReadbackDescription desc;
|
QRhiReadbackDescription desc;
|
||||||
QRhiReadbackResult *result;
|
QRhiReadbackResult *result;
|
||||||
@ -214,7 +214,7 @@ struct QRhiMetalData
|
|||||||
QSize pixelSize;
|
QSize pixelSize;
|
||||||
QRhiTexture::Format format;
|
QRhiTexture::Format format;
|
||||||
};
|
};
|
||||||
QVector<ActiveReadback> activeReadbacks;
|
QVector<TextureReadback> activeTextureReadbacks;
|
||||||
|
|
||||||
API_AVAILABLE(macos(10.13), ios(11.0)) MTLCaptureManager *captureMgr;
|
API_AVAILABLE(macos(10.13), ios(11.0)) MTLCaptureManager *captureMgr;
|
||||||
API_AVAILABLE(macos(10.13), ios(11.0)) id<MTLCaptureScope> captureScope = nil;
|
API_AVAILABLE(macos(10.13), ios(11.0)) id<MTLCaptureScope> captureScope = nil;
|
||||||
@ -225,14 +225,14 @@ struct QRhiMetalData
|
|||||||
};
|
};
|
||||||
|
|
||||||
Q_DECLARE_TYPEINFO(QRhiMetalData::DeferredReleaseEntry, Q_MOVABLE_TYPE);
|
Q_DECLARE_TYPEINFO(QRhiMetalData::DeferredReleaseEntry, Q_MOVABLE_TYPE);
|
||||||
Q_DECLARE_TYPEINFO(QRhiMetalData::ActiveReadback, Q_MOVABLE_TYPE);
|
Q_DECLARE_TYPEINFO(QRhiMetalData::TextureReadback, Q_MOVABLE_TYPE);
|
||||||
|
|
||||||
struct QMetalBufferData
|
struct QMetalBufferData
|
||||||
{
|
{
|
||||||
bool managed;
|
bool managed;
|
||||||
bool slotted;
|
bool slotted;
|
||||||
id<MTLBuffer> buf[QMTL_FRAMES_IN_FLIGHT];
|
id<MTLBuffer> buf[QMTL_FRAMES_IN_FLIGHT];
|
||||||
QVector<QRhiResourceUpdateBatchPrivate::DynamicBufferUpdate> pendingUpdates[QMTL_FRAMES_IN_FLIGHT];
|
QVarLengthArray<QRhiResourceUpdateBatchPrivate::BufferOp, 16> pendingUpdates[QMTL_FRAMES_IN_FLIGHT];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct QMetalRenderBufferData
|
struct QMetalRenderBufferData
|
||||||
@ -367,6 +367,11 @@ bool QRhiMetal::create(QRhi::Flags flags)
|
|||||||
else
|
else
|
||||||
d->dev = MTLCreateSystemDefaultDevice();
|
d->dev = MTLCreateSystemDefaultDevice();
|
||||||
|
|
||||||
|
if (!d->dev) {
|
||||||
|
qWarning("No MTLDevice");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
qCDebug(QRHI_LOG_INFO, "Metal device: %s", qPrintable(QString::fromNSString([d->dev name])));
|
qCDebug(QRHI_LOG_INFO, "Metal device: %s", qPrintable(QString::fromNSString([d->dev name])));
|
||||||
|
|
||||||
if (importedCmdQueue)
|
if (importedCmdQueue)
|
||||||
@ -552,6 +557,10 @@ bool QRhiMetal::isFeatureSupported(QRhi::Feature feature) const
|
|||||||
return true;
|
return true;
|
||||||
case QRhi::TriangleFanTopology:
|
case QRhi::TriangleFanTopology:
|
||||||
return false;
|
return false;
|
||||||
|
case QRhi::ReadBackNonUniformBuffer:
|
||||||
|
return true;
|
||||||
|
case QRhi::ReadBackNonBaseMipLevel:
|
||||||
|
return true;
|
||||||
default:
|
default:
|
||||||
Q_UNREACHABLE();
|
Q_UNREACHABLE();
|
||||||
return false;
|
return false;
|
||||||
@ -1541,21 +1550,33 @@ void QRhiMetal::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
|
|||||||
QRhiResourceUpdateBatchPrivate *ud = QRhiResourceUpdateBatchPrivate::get(resourceUpdates);
|
QRhiResourceUpdateBatchPrivate *ud = QRhiResourceUpdateBatchPrivate::get(resourceUpdates);
|
||||||
QRhiProfilerPrivate *rhiP = profilerPrivateOrNull();
|
QRhiProfilerPrivate *rhiP = profilerPrivateOrNull();
|
||||||
|
|
||||||
for (const QRhiResourceUpdateBatchPrivate::DynamicBufferUpdate &u : ud->dynamicBufferUpdates) {
|
for (const QRhiResourceUpdateBatchPrivate::BufferOp &u : ud->bufferOps) {
|
||||||
QMetalBuffer *bufD = QRHI_RES(QMetalBuffer, u.buf);
|
if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::DynamicUpdate) {
|
||||||
Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
|
QMetalBuffer *bufD = QRHI_RES(QMetalBuffer, u.buf);
|
||||||
for (int i = 0; i < QMTL_FRAMES_IN_FLIGHT; ++i)
|
Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
|
||||||
bufD->d->pendingUpdates[i].append(u);
|
for (int i = 0; i < QMTL_FRAMES_IN_FLIGHT; ++i)
|
||||||
}
|
bufD->d->pendingUpdates[i].append(u);
|
||||||
|
} else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::StaticUpload) {
|
||||||
// Due to the Metal API the handling of static and dynamic buffers is
|
// Due to the Metal API the handling of static and dynamic buffers is
|
||||||
// basically the same. So go through the same pendingUpdates machinery.
|
// basically the same. So go through the same pendingUpdates machinery.
|
||||||
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->d->slotted ? QMTL_FRAMES_IN_FLIGHT : 1; i != ie; ++i)
|
||||||
for (int i = 0, ie = bufD->d->slotted ? QMTL_FRAMES_IN_FLIGHT : 1; i != ie; ++i)
|
bufD->d->pendingUpdates[i].append(
|
||||||
bufD->d->pendingUpdates[i].append({ u.buf, u.offset, u.data.size(), u.data.constData() });
|
QRhiResourceUpdateBatchPrivate::BufferOp::dynamicUpdate(u.buf, u.offset, u.data.size(), u.data.constData()));
|
||||||
|
} else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::Read) {
|
||||||
|
QMetalBuffer *bufD = QRHI_RES(QMetalBuffer, u.buf);
|
||||||
|
executeBufferHostWritesForCurrentFrame(bufD);
|
||||||
|
const int idx = bufD->d->slotted ? currentFrameSlot : 0;
|
||||||
|
char *p = reinterpret_cast<char *>([bufD->d->buf[idx] contents]);
|
||||||
|
if (p) {
|
||||||
|
u.result->data.resize(u.readSize);
|
||||||
|
memcpy(u.result->data.data(), p + u.offset, size_t(u.readSize));
|
||||||
|
}
|
||||||
|
if (u.result->completed)
|
||||||
|
u.result->completed();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
id<MTLBlitCommandEncoder> blitEnc = nil;
|
id<MTLBlitCommandEncoder> blitEnc = nil;
|
||||||
@ -1569,11 +1590,11 @@ void QRhiMetal::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
|
|||||||
|
|
||||||
for (const QRhiResourceUpdateBatchPrivate::TextureOp &u : ud->textureOps) {
|
for (const QRhiResourceUpdateBatchPrivate::TextureOp &u : ud->textureOps) {
|
||||||
if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Upload) {
|
if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Upload) {
|
||||||
QMetalTexture *utexD = QRHI_RES(QMetalTexture, u.upload.tex);
|
QMetalTexture *utexD = QRHI_RES(QMetalTexture, u.dst);
|
||||||
qsizetype stagingSize = 0;
|
qsizetype stagingSize = 0;
|
||||||
for (int layer = 0; layer < QRhi::MAX_LAYERS; ++layer) {
|
for (int layer = 0; layer < QRhi::MAX_LAYERS; ++layer) {
|
||||||
for (int level = 0; level < QRhi::MAX_LEVELS; ++level) {
|
for (int level = 0; level < QRhi::MAX_LEVELS; ++level) {
|
||||||
for (const QRhiTextureSubresourceUploadDescription &subresDesc : qAsConst(u.upload.subresDesc[layer][level]))
|
for (const QRhiTextureSubresourceUploadDescription &subresDesc : qAsConst(u.subresDesc[layer][level]))
|
||||||
stagingSize += subresUploadByteSize(subresDesc);
|
stagingSize += subresUploadByteSize(subresDesc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1588,7 +1609,7 @@ void QRhiMetal::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
|
|||||||
qsizetype curOfs = 0;
|
qsizetype curOfs = 0;
|
||||||
for (int layer = 0; layer < QRhi::MAX_LAYERS; ++layer) {
|
for (int layer = 0; layer < QRhi::MAX_LAYERS; ++layer) {
|
||||||
for (int level = 0; level < QRhi::MAX_LEVELS; ++level) {
|
for (int level = 0; level < QRhi::MAX_LEVELS; ++level) {
|
||||||
for (const QRhiTextureSubresourceUploadDescription &subresDesc : qAsConst(u.upload.subresDesc[layer][level]))
|
for (const QRhiTextureSubresourceUploadDescription &subresDesc : qAsConst(u.subresDesc[layer][level]))
|
||||||
enqueueSubresUpload(utexD, mp, blitEnc, layer, level, subresDesc, &curOfs);
|
enqueueSubresUpload(utexD, mp, blitEnc, layer, level, subresDesc, &curOfs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1603,32 +1624,33 @@ void QRhiMetal::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
|
|||||||
d->releaseQueue.append(e);
|
d->releaseQueue.append(e);
|
||||||
QRHI_PROF_F(releaseTextureStagingArea(utexD, currentFrameSlot));
|
QRHI_PROF_F(releaseTextureStagingArea(utexD, currentFrameSlot));
|
||||||
} else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Copy) {
|
} else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Copy) {
|
||||||
Q_ASSERT(u.copy.src && u.copy.dst);
|
Q_ASSERT(u.src && u.dst);
|
||||||
QMetalTexture *srcD = QRHI_RES(QMetalTexture, u.copy.src);
|
QMetalTexture *srcD = QRHI_RES(QMetalTexture, u.src);
|
||||||
QMetalTexture *dstD = QRHI_RES(QMetalTexture, u.copy.dst);
|
QMetalTexture *dstD = QRHI_RES(QMetalTexture, u.dst);
|
||||||
const QPoint dp = u.copy.desc.destinationTopLeft();
|
const QPoint dp = u.desc.destinationTopLeft();
|
||||||
const QSize size = u.copy.desc.pixelSize().isEmpty() ? srcD->m_pixelSize : u.copy.desc.pixelSize();
|
const QSize mipSize = q->sizeForMipLevel(u.desc.sourceLevel(), srcD->m_pixelSize);
|
||||||
const QPoint sp = u.copy.desc.sourceTopLeft();
|
const QSize copySize = u.desc.pixelSize().isEmpty() ? mipSize : u.desc.pixelSize();
|
||||||
|
const QPoint sp = u.desc.sourceTopLeft();
|
||||||
|
|
||||||
ensureBlit();
|
ensureBlit();
|
||||||
[blitEnc copyFromTexture: srcD->d->tex
|
[blitEnc copyFromTexture: srcD->d->tex
|
||||||
sourceSlice: NSUInteger(u.copy.desc.sourceLayer())
|
sourceSlice: NSUInteger(u.desc.sourceLayer())
|
||||||
sourceLevel: NSUInteger(u.copy.desc.sourceLevel())
|
sourceLevel: NSUInteger(u.desc.sourceLevel())
|
||||||
sourceOrigin: MTLOriginMake(NSUInteger(sp.x()), NSUInteger(sp.y()), 0)
|
sourceOrigin: MTLOriginMake(NSUInteger(sp.x()), NSUInteger(sp.y()), 0)
|
||||||
sourceSize: MTLSizeMake(NSUInteger(size.width()), NSUInteger(size.height()), 1)
|
sourceSize: MTLSizeMake(NSUInteger(copySize.width()), NSUInteger(copySize.height()), 1)
|
||||||
toTexture: dstD->d->tex
|
toTexture: dstD->d->tex
|
||||||
destinationSlice: NSUInteger(u.copy.desc.destinationLayer())
|
destinationSlice: NSUInteger(u.desc.destinationLayer())
|
||||||
destinationLevel: NSUInteger(u.copy.desc.destinationLevel())
|
destinationLevel: NSUInteger(u.desc.destinationLevel())
|
||||||
destinationOrigin: MTLOriginMake(NSUInteger(dp.x()), NSUInteger(dp.y()), 0)];
|
destinationOrigin: MTLOriginMake(NSUInteger(dp.x()), NSUInteger(dp.y()), 0)];
|
||||||
|
|
||||||
srcD->lastActiveFrameSlot = dstD->lastActiveFrameSlot = currentFrameSlot;
|
srcD->lastActiveFrameSlot = dstD->lastActiveFrameSlot = currentFrameSlot;
|
||||||
} else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Read) {
|
} else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Read) {
|
||||||
QRhiMetalData::ActiveReadback aRb;
|
QRhiMetalData::TextureReadback readback;
|
||||||
aRb.activeFrameSlot = currentFrameSlot;
|
readback.activeFrameSlot = currentFrameSlot;
|
||||||
aRb.desc = u.read.rb;
|
readback.desc = u.rb;
|
||||||
aRb.result = u.read.result;
|
readback.result = u.result;
|
||||||
|
|
||||||
QMetalTexture *texD = QRHI_RES(QMetalTexture, u.read.rb.texture());
|
QMetalTexture *texD = QRHI_RES(QMetalTexture, u.rb.texture());
|
||||||
QMetalSwapChain *swapChainD = nullptr;
|
QMetalSwapChain *swapChainD = nullptr;
|
||||||
id<MTLTexture> src;
|
id<MTLTexture> src;
|
||||||
QSize srcSize;
|
QSize srcSize;
|
||||||
@ -1637,17 +1659,16 @@ void QRhiMetal::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
|
|||||||
qWarning("Multisample texture cannot be read back");
|
qWarning("Multisample texture cannot be read back");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
aRb.pixelSize = u.read.rb.level() > 0 ? q->sizeForMipLevel(u.read.rb.level(), texD->m_pixelSize)
|
readback.pixelSize = q->sizeForMipLevel(u.rb.level(), texD->m_pixelSize);
|
||||||
: texD->m_pixelSize;
|
readback.format = texD->m_format;
|
||||||
aRb.format = texD->m_format;
|
|
||||||
src = texD->d->tex;
|
src = texD->d->tex;
|
||||||
srcSize = texD->m_pixelSize;
|
srcSize = readback.pixelSize;
|
||||||
texD->lastActiveFrameSlot = currentFrameSlot;
|
texD->lastActiveFrameSlot = currentFrameSlot;
|
||||||
} else {
|
} else {
|
||||||
Q_ASSERT(currentSwapChain);
|
Q_ASSERT(currentSwapChain);
|
||||||
swapChainD = QRHI_RES(QMetalSwapChain, currentSwapChain);
|
swapChainD = QRHI_RES(QMetalSwapChain, currentSwapChain);
|
||||||
aRb.pixelSize = swapChainD->pixelSize;
|
readback.pixelSize = swapChainD->pixelSize;
|
||||||
aRb.format = swapChainD->d->rhiColorFormat;
|
readback.format = swapChainD->d->rhiColorFormat;
|
||||||
// Multisample swapchains need nothing special since resolving
|
// Multisample swapchains need nothing special since resolving
|
||||||
// happens when ending a renderpass.
|
// happens when ending a renderpass.
|
||||||
const QMetalRenderTargetData::ColorAtt &colorAtt(swapChainD->rtWrapper.d->fb.colorAtt[0]);
|
const QMetalRenderTargetData::ColorAtt &colorAtt(swapChainD->rtWrapper.d->fb.colorAtt[0]);
|
||||||
@ -1656,28 +1677,28 @@ void QRhiMetal::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
|
|||||||
}
|
}
|
||||||
|
|
||||||
quint32 bpl = 0;
|
quint32 bpl = 0;
|
||||||
textureFormatInfo(aRb.format, aRb.pixelSize, &bpl, &aRb.bufSize);
|
textureFormatInfo(readback.format, readback.pixelSize, &bpl, &readback.bufSize);
|
||||||
aRb.buf = [d->dev newBufferWithLength: aRb.bufSize options: MTLResourceStorageModeShared];
|
readback.buf = [d->dev newBufferWithLength: readback.bufSize options: MTLResourceStorageModeShared];
|
||||||
|
|
||||||
QRHI_PROF_F(newReadbackBuffer(qint64(qintptr(aRb.buf)),
|
QRHI_PROF_F(newReadbackBuffer(qint64(qintptr(readback.buf)),
|
||||||
texD ? static_cast<QRhiResource *>(texD) : static_cast<QRhiResource *>(swapChainD),
|
texD ? static_cast<QRhiResource *>(texD) : static_cast<QRhiResource *>(swapChainD),
|
||||||
aRb.bufSize));
|
readback.bufSize));
|
||||||
|
|
||||||
ensureBlit();
|
ensureBlit();
|
||||||
[blitEnc copyFromTexture: src
|
[blitEnc copyFromTexture: src
|
||||||
sourceSlice: NSUInteger(u.read.rb.layer())
|
sourceSlice: NSUInteger(u.rb.layer())
|
||||||
sourceLevel: NSUInteger(u.read.rb.level())
|
sourceLevel: NSUInteger(u.rb.level())
|
||||||
sourceOrigin: MTLOriginMake(0, 0, 0)
|
sourceOrigin: MTLOriginMake(0, 0, 0)
|
||||||
sourceSize: MTLSizeMake(NSUInteger(srcSize.width()), NSUInteger(srcSize.height()), 1)
|
sourceSize: MTLSizeMake(NSUInteger(srcSize.width()), NSUInteger(srcSize.height()), 1)
|
||||||
toBuffer: aRb.buf
|
toBuffer: readback.buf
|
||||||
destinationOffset: 0
|
destinationOffset: 0
|
||||||
destinationBytesPerRow: bpl
|
destinationBytesPerRow: bpl
|
||||||
destinationBytesPerImage: 0
|
destinationBytesPerImage: 0
|
||||||
options: MTLBlitOptionNone];
|
options: MTLBlitOptionNone];
|
||||||
|
|
||||||
d->activeReadbacks.append(aRb);
|
d->activeTextureReadbacks.append(readback);
|
||||||
} else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::MipGen) {
|
} else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::GenMips) {
|
||||||
QMetalTexture *utexD = QRHI_RES(QMetalTexture, u.mipgen.tex);
|
QMetalTexture *utexD = QRHI_RES(QMetalTexture, u.dst);
|
||||||
ensureBlit();
|
ensureBlit();
|
||||||
[blitEnc generateMipmapsForTexture: utexD->d->tex];
|
[blitEnc generateMipmapsForTexture: utexD->d->tex];
|
||||||
utexD->lastActiveFrameSlot = currentFrameSlot;
|
utexD->lastActiveFrameSlot = currentFrameSlot;
|
||||||
@ -1697,14 +1718,13 @@ void QRhiMetal::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
|
|||||||
void QRhiMetal::executeBufferHostWritesForCurrentFrame(QMetalBuffer *bufD)
|
void QRhiMetal::executeBufferHostWritesForCurrentFrame(QMetalBuffer *bufD)
|
||||||
{
|
{
|
||||||
const int idx = bufD->d->slotted ? currentFrameSlot : 0;
|
const int idx = bufD->d->slotted ? currentFrameSlot : 0;
|
||||||
QVector<QRhiResourceUpdateBatchPrivate::DynamicBufferUpdate> &updates(bufD->d->pendingUpdates[idx]);
|
if (bufD->d->pendingUpdates[idx].isEmpty())
|
||||||
if (updates.isEmpty())
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
void *p = [bufD->d->buf[idx] contents];
|
void *p = [bufD->d->buf[idx] contents];
|
||||||
int changeBegin = -1;
|
int changeBegin = -1;
|
||||||
int changeEnd = -1;
|
int changeEnd = -1;
|
||||||
for (const QRhiResourceUpdateBatchPrivate::DynamicBufferUpdate &u : updates) {
|
for (const QRhiResourceUpdateBatchPrivate::BufferOp &u : qAsConst(bufD->d->pendingUpdates[idx])) {
|
||||||
Q_ASSERT(bufD == QRHI_RES(QMetalBuffer, u.buf));
|
Q_ASSERT(bufD == QRHI_RES(QMetalBuffer, u.buf));
|
||||||
memcpy(static_cast<char *>(p) + u.offset, u.data.constData(), size_t(u.data.size()));
|
memcpy(static_cast<char *>(p) + u.offset, u.data.constData(), size_t(u.data.size()));
|
||||||
if (changeBegin == -1 || u.offset < changeBegin)
|
if (changeBegin == -1 || u.offset < changeBegin)
|
||||||
@ -1715,7 +1735,7 @@ void QRhiMetal::executeBufferHostWritesForCurrentFrame(QMetalBuffer *bufD)
|
|||||||
if (changeBegin >= 0 && bufD->d->managed)
|
if (changeBegin >= 0 && bufD->d->managed)
|
||||||
[bufD->d->buf[idx] didModifyRange: NSMakeRange(NSUInteger(changeBegin), NSUInteger(changeEnd - changeBegin))];
|
[bufD->d->buf[idx] didModifyRange: NSMakeRange(NSUInteger(changeBegin), NSUInteger(changeEnd - changeBegin))];
|
||||||
|
|
||||||
updates.clear();
|
bufD->d->pendingUpdates[idx].clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QRhiMetal::resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
|
void QRhiMetal::resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
|
||||||
@ -1951,22 +1971,22 @@ void QRhiMetal::finishActiveReadbacks(bool forced)
|
|||||||
QVarLengthArray<std::function<void()>, 4> completedCallbacks;
|
QVarLengthArray<std::function<void()>, 4> completedCallbacks;
|
||||||
QRhiProfilerPrivate *rhiP = profilerPrivateOrNull();
|
QRhiProfilerPrivate *rhiP = profilerPrivateOrNull();
|
||||||
|
|
||||||
for (int i = d->activeReadbacks.count() - 1; i >= 0; --i) {
|
for (int i = d->activeTextureReadbacks.count() - 1; i >= 0; --i) {
|
||||||
const QRhiMetalData::ActiveReadback &aRb(d->activeReadbacks[i]);
|
const QRhiMetalData::TextureReadback &readback(d->activeTextureReadbacks[i]);
|
||||||
if (forced || currentFrameSlot == aRb.activeFrameSlot || aRb.activeFrameSlot < 0) {
|
if (forced || currentFrameSlot == readback.activeFrameSlot || readback.activeFrameSlot < 0) {
|
||||||
aRb.result->format = aRb.format;
|
readback.result->format = readback.format;
|
||||||
aRb.result->pixelSize = aRb.pixelSize;
|
readback.result->pixelSize = readback.pixelSize;
|
||||||
aRb.result->data.resize(int(aRb.bufSize));
|
readback.result->data.resize(int(readback.bufSize));
|
||||||
void *p = [aRb.buf contents];
|
void *p = [readback.buf contents];
|
||||||
memcpy(aRb.result->data.data(), p, aRb.bufSize);
|
memcpy(readback.result->data.data(), p, readback.bufSize);
|
||||||
[aRb.buf release];
|
[readback.buf release];
|
||||||
|
|
||||||
QRHI_PROF_F(releaseReadbackBuffer(qint64(qintptr(aRb.buf))));
|
QRHI_PROF_F(releaseReadbackBuffer(qint64(qintptr(readback.buf))));
|
||||||
|
|
||||||
if (aRb.result->completed)
|
if (readback.result->completed)
|
||||||
completedCallbacks.append(aRb.result->completed);
|
completedCallbacks.append(readback.result->completed);
|
||||||
|
|
||||||
d->activeReadbacks.removeAt(i);
|
d->activeTextureReadbacks.removeAt(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2042,7 +2062,6 @@ bool QMetalBuffer::build()
|
|||||||
for (int i = 0; i < QMTL_FRAMES_IN_FLIGHT; ++i) {
|
for (int i = 0; i < QMTL_FRAMES_IN_FLIGHT; ++i) {
|
||||||
if (i == 0 || d->slotted) {
|
if (i == 0 || d->slotted) {
|
||||||
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);
|
|
||||||
if (!m_objectName.isEmpty()) {
|
if (!m_objectName.isEmpty()) {
|
||||||
if (!d->slotted) {
|
if (!d->slotted) {
|
||||||
d->buf[i].label = [NSString stringWithUTF8String: m_objectName.constData()];
|
d->buf[i].label = [NSString stringWithUTF8String: m_objectName.constData()];
|
||||||
@ -3120,6 +3139,8 @@ bool QMetalGraphicsPipeline::build()
|
|||||||
release();
|
release();
|
||||||
|
|
||||||
QRHI_RES_RHI(QRhiMetal);
|
QRHI_RES_RHI(QRhiMetal);
|
||||||
|
if (!rhiD->sanityCheckGraphicsPipeline(this))
|
||||||
|
return false;
|
||||||
|
|
||||||
// same binding space for vertex and constant buffers - work it around
|
// same binding space for vertex and constant buffers - work it around
|
||||||
const int firstVertexBinding = QRHI_RES(QMetalShaderResourceBindings, m_shaderResourceBindings)->maxBinding + 1;
|
const int firstVertexBinding = QRHI_RES(QMetalShaderResourceBindings, m_shaderResourceBindings)->maxBinding + 1;
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
|
|
||||||
#include "qrhinull_p_p.h"
|
#include "qrhinull_p_p.h"
|
||||||
#include <qmath.h>
|
#include <qmath.h>
|
||||||
|
#include <QPainter>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
@ -385,27 +386,125 @@ QRhi::FrameOpResult QRhiNull::finish()
|
|||||||
return QRhi::FrameOpSuccess;
|
return QRhi::FrameOpSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QRhiNull::simulateTextureUpload(const QRhiResourceUpdateBatchPrivate::TextureOp &u)
|
||||||
|
{
|
||||||
|
QNullTexture *texD = QRHI_RES(QNullTexture, u.dst);
|
||||||
|
for (int layer = 0; layer < QRhi::MAX_LAYERS; ++layer) {
|
||||||
|
for (int level = 0; level < QRhi::MAX_LEVELS; ++level) {
|
||||||
|
for (const QRhiTextureSubresourceUploadDescription &subresDesc : qAsConst(u.subresDesc[layer][level])) {
|
||||||
|
if (!subresDesc.image().isNull()) {
|
||||||
|
const QImage src = subresDesc.image();
|
||||||
|
QPainter painter(&texD->image[layer][level]);
|
||||||
|
const QSize srcSize = subresDesc.sourceSize().isEmpty()
|
||||||
|
? src.size() : subresDesc.sourceSize();
|
||||||
|
painter.setCompositionMode(QPainter::CompositionMode_Source);
|
||||||
|
painter.drawImage(subresDesc.destinationTopLeft(), src,
|
||||||
|
QRect(subresDesc.sourceTopLeft(), srcSize));
|
||||||
|
} else if (!subresDesc.data().isEmpty()) {
|
||||||
|
const QSize subresSize = q->sizeForMipLevel(level, texD->pixelSize());
|
||||||
|
int w = subresSize.width();
|
||||||
|
int h = subresSize.height();
|
||||||
|
if (!subresDesc.sourceSize().isEmpty()) {
|
||||||
|
w = subresDesc.sourceSize().width();
|
||||||
|
h = subresDesc.sourceSize().height();
|
||||||
|
}
|
||||||
|
// sourceTopLeft is not supported on this path as per QRhi docs
|
||||||
|
const char *src = subresDesc.data().constData();
|
||||||
|
const int srcBpl = w * 4;
|
||||||
|
const QPoint dstOffset = subresDesc.destinationTopLeft();
|
||||||
|
uchar *dst = texD->image[layer][level].bits();
|
||||||
|
const int dstBpl = texD->image[layer][level].bytesPerLine();
|
||||||
|
for (int y = 0; y < h; ++y) {
|
||||||
|
memcpy(dst + dstOffset.x() * 4 + (y + dstOffset.y()) * dstBpl,
|
||||||
|
src + y * srcBpl,
|
||||||
|
size_t(srcBpl));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QRhiNull::simulateTextureCopy(const QRhiResourceUpdateBatchPrivate::TextureOp &u)
|
||||||
|
{
|
||||||
|
QNullTexture *srcD = QRHI_RES(QNullTexture, u.src);
|
||||||
|
QNullTexture *dstD = QRHI_RES(QNullTexture, u.dst);
|
||||||
|
const QImage &srcImage(srcD->image[u.desc.sourceLayer()][u.desc.sourceLevel()]);
|
||||||
|
QImage &dstImage(dstD->image[u.desc.destinationLayer()][u.desc.destinationLevel()]);
|
||||||
|
const QPoint dstPos = u.desc.destinationTopLeft();
|
||||||
|
const QSize size = u.desc.pixelSize().isEmpty() ? srcD->pixelSize() : u.desc.pixelSize();
|
||||||
|
const QPoint srcPos = u.desc.sourceTopLeft();
|
||||||
|
|
||||||
|
QPainter painter(&dstImage);
|
||||||
|
painter.setCompositionMode(QPainter::CompositionMode_Source);
|
||||||
|
painter.drawImage(QRect(dstPos, size), srcImage, QRect(srcPos, size));
|
||||||
|
}
|
||||||
|
|
||||||
|
void QRhiNull::simulateTextureGenMips(const QRhiResourceUpdateBatchPrivate::TextureOp &u)
|
||||||
|
{
|
||||||
|
QNullTexture *texD = QRHI_RES(QNullTexture, u.dst);
|
||||||
|
const QSize baseSize = texD->pixelSize();
|
||||||
|
const int levelCount = q->mipLevelsForSize(baseSize);
|
||||||
|
for (int level = 1; level < levelCount; ++level)
|
||||||
|
texD->image[0][level] = texD->image[0][0].scaled(q->sizeForMipLevel(level, baseSize));
|
||||||
|
}
|
||||||
|
|
||||||
void QRhiNull::resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
|
void QRhiNull::resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
|
||||||
{
|
{
|
||||||
Q_UNUSED(cb);
|
Q_UNUSED(cb);
|
||||||
QRhiResourceUpdateBatchPrivate *ud = QRhiResourceUpdateBatchPrivate::get(resourceUpdates);
|
QRhiResourceUpdateBatchPrivate *ud = QRhiResourceUpdateBatchPrivate::get(resourceUpdates);
|
||||||
|
for (const QRhiResourceUpdateBatchPrivate::BufferOp &u : ud->bufferOps) {
|
||||||
|
if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::DynamicUpdate
|
||||||
|
|| u.type == QRhiResourceUpdateBatchPrivate::BufferOp::StaticUpload)
|
||||||
|
{
|
||||||
|
QNullBuffer *bufD = QRHI_RES(QNullBuffer, u.buf);
|
||||||
|
memcpy(bufD->data.data() + u.offset, u.data.constData(), size_t(u.data.size()));
|
||||||
|
} else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::Read) {
|
||||||
|
QRhiBufferReadbackResult *result = u.result;
|
||||||
|
result->data.resize(u.readSize);
|
||||||
|
QNullBuffer *bufD = QRHI_RES(QNullBuffer, u.buf);
|
||||||
|
memcpy(result->data.data(), bufD->data.constData() + u.offset, size_t(u.readSize));
|
||||||
|
if (result->completed)
|
||||||
|
result->completed();
|
||||||
|
}
|
||||||
|
}
|
||||||
for (const QRhiResourceUpdateBatchPrivate::TextureOp &u : ud->textureOps) {
|
for (const QRhiResourceUpdateBatchPrivate::TextureOp &u : ud->textureOps) {
|
||||||
if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Read) {
|
if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Upload) {
|
||||||
QRhiReadbackResult *result = u.read.result;
|
if (u.dst->format() == QRhiTexture::RGBA8)
|
||||||
QRhiTexture *tex = u.read.rb.texture();
|
simulateTextureUpload(u);
|
||||||
if (tex) {
|
} else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Copy) {
|
||||||
result->format = tex->format();
|
if (u.src->format() == QRhiTexture::RGBA8 && u.dst->format() == QRhiTexture::RGBA8)
|
||||||
result->pixelSize = q->sizeForMipLevel(u.read.rb.level(), tex->pixelSize());
|
simulateTextureCopy(u);
|
||||||
|
} else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Read) {
|
||||||
|
QRhiReadbackResult *result = u.result;
|
||||||
|
QNullTexture *texD = QRHI_RES(QNullTexture, u.rb.texture());
|
||||||
|
if (texD) {
|
||||||
|
result->format = texD->format();
|
||||||
|
result->pixelSize = q->sizeForMipLevel(u.rb.level(), texD->pixelSize());
|
||||||
} else {
|
} else {
|
||||||
Q_ASSERT(currentSwapChain);
|
Q_ASSERT(currentSwapChain);
|
||||||
result->format = QRhiTexture::RGBA8;
|
result->format = QRhiTexture::RGBA8;
|
||||||
result->pixelSize = currentSwapChain->currentPixelSize();
|
result->pixelSize = currentSwapChain->currentPixelSize();
|
||||||
}
|
}
|
||||||
|
quint32 bytesPerLine = 0;
|
||||||
quint32 byteSize = 0;
|
quint32 byteSize = 0;
|
||||||
textureFormatInfo(result->format, result->pixelSize, nullptr, &byteSize);
|
textureFormatInfo(result->format, result->pixelSize, &bytesPerLine, &byteSize);
|
||||||
result->data.fill(0, byteSize);
|
if (texD && texD->format() == QRhiTexture::RGBA8) {
|
||||||
|
result->data.resize(int(byteSize));
|
||||||
|
const QImage &src(texD->image[u.rb.layer()][u.rb.level()]);
|
||||||
|
char *dst = result->data.data();
|
||||||
|
for (int y = 0, h = src.height(); y < h; ++y) {
|
||||||
|
memcpy(dst, src.constScanLine(y), bytesPerLine);
|
||||||
|
dst += bytesPerLine;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result->data.fill(0, int(byteSize));
|
||||||
|
}
|
||||||
if (result->completed)
|
if (result->completed)
|
||||||
result->completed();
|
result->completed();
|
||||||
|
} else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::GenMips) {
|
||||||
|
if (u.dst->format() == QRhiTexture::RGBA8)
|
||||||
|
simulateTextureGenMips(u);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ud->free();
|
ud->free();
|
||||||
@ -454,14 +553,18 @@ QNullBuffer::~QNullBuffer()
|
|||||||
|
|
||||||
void QNullBuffer::release()
|
void QNullBuffer::release()
|
||||||
{
|
{
|
||||||
|
data.clear();
|
||||||
|
|
||||||
QRHI_PROF;
|
QRHI_PROF;
|
||||||
QRHI_PROF_F(releaseBuffer(this));
|
QRHI_PROF_F(releaseBuffer(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QNullBuffer::build()
|
bool QNullBuffer::build()
|
||||||
{
|
{
|
||||||
|
data.fill('\0', m_size);
|
||||||
|
|
||||||
QRHI_PROF;
|
QRHI_PROF;
|
||||||
QRHI_PROF_F(newBuffer(this, m_size, 1, 0));
|
QRHI_PROF_F(newBuffer(this, uint(m_size), 1, 0));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -513,22 +616,36 @@ void QNullTexture::release()
|
|||||||
|
|
||||||
bool QNullTexture::build()
|
bool QNullTexture::build()
|
||||||
{
|
{
|
||||||
|
QRHI_RES_RHI(QRhiNull);
|
||||||
const bool isCube = m_flags.testFlag(CubeMap);
|
const bool isCube = m_flags.testFlag(CubeMap);
|
||||||
const bool hasMipMaps = m_flags.testFlag(MipMapped);
|
const bool hasMipMaps = m_flags.testFlag(MipMapped);
|
||||||
QSize size = m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize;
|
QSize size = m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize;
|
||||||
const int mipLevelCount = hasMipMaps ? qCeil(log2(qMax(size.width(), size.height()))) + 1 : 1;
|
const int mipLevelCount = hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1;
|
||||||
|
const int layerCount = isCube ? 6 : 1;
|
||||||
|
|
||||||
|
if (m_format == RGBA8) {
|
||||||
|
for (int layer = 0; layer < layerCount; ++layer) {
|
||||||
|
for (int level = 0; level < mipLevelCount; ++level) {
|
||||||
|
image[layer][level] = QImage(rhiD->q->sizeForMipLevel(level, size),
|
||||||
|
QImage::Format_RGBA8888_Premultiplied);
|
||||||
|
image[layer][level].fill(Qt::yellow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QRHI_PROF;
|
QRHI_PROF;
|
||||||
QRHI_PROF_F(newTexture(this, true, mipLevelCount, isCube ? 6 : 1, 1));
|
QRHI_PROF_F(newTexture(this, true, mipLevelCount, layerCount, 1));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QNullTexture::buildFrom(const QRhiNativeHandles *src)
|
bool QNullTexture::buildFrom(const QRhiNativeHandles *src)
|
||||||
{
|
{
|
||||||
Q_UNUSED(src);
|
Q_UNUSED(src);
|
||||||
|
QRHI_RES_RHI(QRhiNull);
|
||||||
const bool isCube = m_flags.testFlag(CubeMap);
|
const bool isCube = m_flags.testFlag(CubeMap);
|
||||||
const bool hasMipMaps = m_flags.testFlag(MipMapped);
|
const bool hasMipMaps = m_flags.testFlag(MipMapped);
|
||||||
QSize size = m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize;
|
QSize size = m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize;
|
||||||
const int mipLevelCount = hasMipMaps ? qCeil(log2(qMax(size.width(), size.height()))) + 1 : 1;
|
const int mipLevelCount = hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1;
|
||||||
QRHI_PROF;
|
QRHI_PROF;
|
||||||
QRHI_PROF_F(newTexture(this, false, mipLevelCount, isCube ? 6 : 1, 1));
|
QRHI_PROF_F(newTexture(this, false, mipLevelCount, isCube ? 6 : 1, 1));
|
||||||
return true;
|
return true;
|
||||||
@ -690,6 +807,10 @@ void QNullGraphicsPipeline::release()
|
|||||||
|
|
||||||
bool QNullGraphicsPipeline::build()
|
bool QNullGraphicsPipeline::build()
|
||||||
{
|
{
|
||||||
|
QRHI_RES_RHI(QRhiNull);
|
||||||
|
if (!rhiD->sanityCheckGraphicsPipeline(this))
|
||||||
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,6 +59,8 @@ struct QNullBuffer : public QRhiBuffer
|
|||||||
~QNullBuffer();
|
~QNullBuffer();
|
||||||
void release() override;
|
void release() override;
|
||||||
bool build() override;
|
bool build() override;
|
||||||
|
|
||||||
|
QByteArray data;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct QNullRenderBuffer : public QRhiRenderBuffer
|
struct QNullRenderBuffer : public QRhiRenderBuffer
|
||||||
@ -82,6 +84,7 @@ struct QNullTexture : public QRhiTexture
|
|||||||
const QRhiNativeHandles *nativeHandles() override;
|
const QRhiNativeHandles *nativeHandles() override;
|
||||||
|
|
||||||
QRhiNullTextureNativeHandles nativeHandlesStruct;
|
QRhiNullTextureNativeHandles nativeHandlesStruct;
|
||||||
|
QImage image[QRhi::MAX_LAYERS][QRhi::MAX_LEVELS];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct QNullSampler : public QRhiSampler
|
struct QNullSampler : public QRhiSampler
|
||||||
@ -286,6 +289,10 @@ public:
|
|||||||
void releaseCachedResources() override;
|
void releaseCachedResources() override;
|
||||||
bool isDeviceLost() const override;
|
bool isDeviceLost() const override;
|
||||||
|
|
||||||
|
void simulateTextureUpload(const QRhiResourceUpdateBatchPrivate::TextureOp &u);
|
||||||
|
void simulateTextureCopy(const QRhiResourceUpdateBatchPrivate::TextureOp &u);
|
||||||
|
void simulateTextureGenMips(const QRhiResourceUpdateBatchPrivate::TextureOp &u);
|
||||||
|
|
||||||
QRhiNullNativeHandles nativeHandlesStruct;
|
QRhiNullNativeHandles nativeHandlesStruct;
|
||||||
QRhiSwapChain *currentSwapChain = nullptr;
|
QRhiSwapChain *currentSwapChain = nullptr;
|
||||||
QNullCommandBuffer offscreenCommandBuffer;
|
QNullCommandBuffer offscreenCommandBuffer;
|
||||||
|
@ -363,6 +363,11 @@ bool QRhiVulkan::create(QRhi::Flags flags)
|
|||||||
Q_UNUSED(flags);
|
Q_UNUSED(flags);
|
||||||
Q_ASSERT(inst);
|
Q_ASSERT(inst);
|
||||||
|
|
||||||
|
if (!inst->isValid()) {
|
||||||
|
qWarning("Vulkan instance is not valid");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
globalVulkanInstance = inst; // assume this will not change during the lifetime of the entire application
|
globalVulkanInstance = inst; // assume this will not change during the lifetime of the entire application
|
||||||
|
|
||||||
f = inst->functions();
|
f = inst->functions();
|
||||||
@ -2649,100 +2654,164 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat
|
|||||||
QRhiResourceUpdateBatchPrivate *ud = QRhiResourceUpdateBatchPrivate::get(resourceUpdates);
|
QRhiResourceUpdateBatchPrivate *ud = QRhiResourceUpdateBatchPrivate::get(resourceUpdates);
|
||||||
QRhiProfilerPrivate *rhiP = profilerPrivateOrNull();
|
QRhiProfilerPrivate *rhiP = profilerPrivateOrNull();
|
||||||
|
|
||||||
for (const QRhiResourceUpdateBatchPrivate::DynamicBufferUpdate &u : ud->dynamicBufferUpdates) {
|
for (const QRhiResourceUpdateBatchPrivate::BufferOp &u : ud->bufferOps) {
|
||||||
QVkBuffer *bufD = QRHI_RES(QVkBuffer, u.buf);
|
if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::DynamicUpdate) {
|
||||||
Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
|
QVkBuffer *bufD = QRHI_RES(QVkBuffer, u.buf);
|
||||||
for (int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
|
Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
|
||||||
bufD->pendingDynamicUpdates[i].append(u);
|
for (int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
|
||||||
}
|
bufD->pendingDynamicUpdates[i].append(u);
|
||||||
|
} else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::StaticUpload) {
|
||||||
|
QVkBuffer *bufD = QRHI_RES(QVkBuffer, u.buf);
|
||||||
|
Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
|
||||||
|
Q_ASSERT(u.offset + u.data.size() <= bufD->m_size);
|
||||||
|
|
||||||
for (const QRhiResourceUpdateBatchPrivate::StaticBufferUpload &u : ud->staticBufferUploads) {
|
if (!bufD->stagingBuffers[currentFrameSlot]) {
|
||||||
QVkBuffer *bufD = QRHI_RES(QVkBuffer, u.buf);
|
VkBufferCreateInfo bufferInfo;
|
||||||
Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
|
memset(&bufferInfo, 0, sizeof(bufferInfo));
|
||||||
Q_ASSERT(u.offset + u.data.size() <= bufD->m_size);
|
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||||
|
// must cover the entire buffer - this way multiple, partial updates per frame
|
||||||
|
// are supported even when the staging buffer is reused (Static)
|
||||||
|
bufferInfo.size = VkDeviceSize(bufD->m_size);
|
||||||
|
bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
|
||||||
|
|
||||||
if (!bufD->stagingBuffers[currentFrameSlot]) {
|
VmaAllocationCreateInfo allocInfo;
|
||||||
VkBufferCreateInfo bufferInfo;
|
memset(&allocInfo, 0, sizeof(allocInfo));
|
||||||
memset(&bufferInfo, 0, sizeof(bufferInfo));
|
allocInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
|
||||||
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
|
||||||
// must cover the entire buffer - this way multiple, partial updates per frame
|
|
||||||
// are supported even when the staging buffer is reused (Static)
|
|
||||||
bufferInfo.size = VkDeviceSize(bufD->m_size);
|
|
||||||
bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
|
|
||||||
|
|
||||||
VmaAllocationCreateInfo allocInfo;
|
VmaAllocation allocation;
|
||||||
memset(&allocInfo, 0, sizeof(allocInfo));
|
VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo,
|
||||||
allocInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
|
&bufD->stagingBuffers[currentFrameSlot], &allocation, nullptr);
|
||||||
|
if (err == VK_SUCCESS) {
|
||||||
|
bufD->stagingAllocations[currentFrameSlot] = allocation;
|
||||||
|
QRHI_PROF_F(newBufferStagingArea(bufD, currentFrameSlot, quint32(bufD->m_size)));
|
||||||
|
} else {
|
||||||
|
qWarning("Failed to create staging buffer of size %d: %d", bufD->m_size, err);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
VmaAllocation allocation;
|
void *p = nullptr;
|
||||||
VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo,
|
VmaAllocation a = toVmaAllocation(bufD->stagingAllocations[currentFrameSlot]);
|
||||||
&bufD->stagingBuffers[currentFrameSlot], &allocation, nullptr);
|
VkResult err = vmaMapMemory(toVmaAllocator(allocator), a, &p);
|
||||||
if (err == VK_SUCCESS) {
|
if (err != VK_SUCCESS) {
|
||||||
bufD->stagingAllocations[currentFrameSlot] = allocation;
|
qWarning("Failed to map buffer: %d", err);
|
||||||
QRHI_PROF_F(newBufferStagingArea(bufD, currentFrameSlot, quint32(bufD->m_size)));
|
|
||||||
} else {
|
|
||||||
qWarning("Failed to create staging buffer of size %d: %d", bufD->m_size, err);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
memcpy(static_cast<uchar *>(p) + u.offset, u.data.constData(), size_t(u.data.size()));
|
||||||
|
vmaUnmapMemory(toVmaAllocator(allocator), a);
|
||||||
|
vmaFlushAllocation(toVmaAllocator(allocator), a, VkDeviceSize(u.offset), VkDeviceSize(u.data.size()));
|
||||||
|
|
||||||
void *p = nullptr;
|
trackedBufferBarrier(cbD, bufD, 0,
|
||||||
VmaAllocation a = toVmaAllocation(bufD->stagingAllocations[currentFrameSlot]);
|
VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
|
||||||
VkResult err = vmaMapMemory(toVmaAllocator(allocator), a, &p);
|
|
||||||
if (err != VK_SUCCESS) {
|
|
||||||
qWarning("Failed to map buffer: %d", err);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
memcpy(static_cast<uchar *>(p) + u.offset, u.data.constData(), size_t(u.data.size()));
|
|
||||||
vmaUnmapMemory(toVmaAllocator(allocator), a);
|
|
||||||
vmaFlushAllocation(toVmaAllocator(allocator), a, VkDeviceSize(u.offset), VkDeviceSize(u.data.size()));
|
|
||||||
|
|
||||||
trackedBufferBarrier(cbD, bufD, 0,
|
VkBufferCopy copyInfo;
|
||||||
VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
|
memset(©Info, 0, sizeof(copyInfo));
|
||||||
|
copyInfo.srcOffset = VkDeviceSize(u.offset);
|
||||||
|
copyInfo.dstOffset = VkDeviceSize(u.offset);
|
||||||
|
copyInfo.size = VkDeviceSize(u.data.size());
|
||||||
|
|
||||||
VkBufferCopy copyInfo;
|
QVkCommandBuffer::Command cmd;
|
||||||
memset(©Info, 0, sizeof(copyInfo));
|
cmd.cmd = QVkCommandBuffer::Command::CopyBuffer;
|
||||||
copyInfo.srcOffset = VkDeviceSize(u.offset);
|
cmd.args.copyBuffer.src = bufD->stagingBuffers[currentFrameSlot];
|
||||||
copyInfo.dstOffset = VkDeviceSize(u.offset);
|
cmd.args.copyBuffer.dst = bufD->buffers[0];
|
||||||
copyInfo.size = VkDeviceSize(u.data.size());
|
cmd.args.copyBuffer.desc = copyInfo;
|
||||||
|
cbD->commands.append(cmd);
|
||||||
|
|
||||||
QVkCommandBuffer::Command cmd;
|
// Where's the barrier for read-after-write? (assuming the common case
|
||||||
cmd.cmd = QVkCommandBuffer::Command::CopyBuffer;
|
// of binding this buffer as vertex/index, or, less likely, as uniform
|
||||||
cmd.args.copyBuffer.src = bufD->stagingBuffers[currentFrameSlot];
|
// buffer, in a renderpass later on) That is handled by the pass
|
||||||
cmd.args.copyBuffer.dst = bufD->buffers[0];
|
// resource tracking: the appropriate pipeline barrier will be
|
||||||
cmd.args.copyBuffer.desc = copyInfo;
|
// generated and recorded right before the renderpass, that binds this
|
||||||
cbD->commands.append(cmd);
|
// buffer in one of its commands, gets its BeginRenderPass recorded.
|
||||||
|
|
||||||
// Where's the barrier for read-after-write? (assuming the common case
|
bufD->lastActiveFrameSlot = currentFrameSlot;
|
||||||
// of binding this buffer as vertex/index, or, less likely, as uniform
|
|
||||||
// buffer, in a renderpass later on) That is handled by the pass
|
|
||||||
// resource tracking: the appropriate pipeline barrier will be
|
|
||||||
// generated and recorded right before the renderpass, that binds this
|
|
||||||
// buffer in one of its commands, gets its BeginRenderPass recorded.
|
|
||||||
|
|
||||||
bufD->lastActiveFrameSlot = currentFrameSlot;
|
if (bufD->m_type == QRhiBuffer::Immutable) {
|
||||||
|
QRhiVulkan::DeferredReleaseEntry e;
|
||||||
|
e.type = QRhiVulkan::DeferredReleaseEntry::StagingBuffer;
|
||||||
|
e.lastActiveFrameSlot = currentFrameSlot;
|
||||||
|
e.stagingBuffer.stagingBuffer = bufD->stagingBuffers[currentFrameSlot];
|
||||||
|
e.stagingBuffer.stagingAllocation = bufD->stagingAllocations[currentFrameSlot];
|
||||||
|
bufD->stagingBuffers[currentFrameSlot] = VK_NULL_HANDLE;
|
||||||
|
bufD->stagingAllocations[currentFrameSlot] = nullptr;
|
||||||
|
releaseQueue.append(e);
|
||||||
|
QRHI_PROF_F(releaseBufferStagingArea(bufD, currentFrameSlot));
|
||||||
|
}
|
||||||
|
} else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::Read) {
|
||||||
|
QVkBuffer *bufD = QRHI_RES(QVkBuffer, u.buf);
|
||||||
|
if (bufD->m_type == QRhiBuffer::Dynamic) {
|
||||||
|
executeBufferHostWritesForCurrentFrame(bufD);
|
||||||
|
void *p = nullptr;
|
||||||
|
VmaAllocation a = toVmaAllocation(bufD->allocations[currentFrameSlot]);
|
||||||
|
VkResult err = vmaMapMemory(toVmaAllocator(allocator), a, &p);
|
||||||
|
if (err == VK_SUCCESS) {
|
||||||
|
u.result->data.resize(u.readSize);
|
||||||
|
memcpy(u.result->data.data(), reinterpret_cast<char *>(p) + u.offset, size_t(u.readSize));
|
||||||
|
vmaUnmapMemory(toVmaAllocator(allocator), a);
|
||||||
|
}
|
||||||
|
if (u.result->completed)
|
||||||
|
u.result->completed();
|
||||||
|
} else {
|
||||||
|
// Non-Dynamic buffers may not be host visible, so have to
|
||||||
|
// create a readback buffer, enqueue a copy from
|
||||||
|
// bufD->buffers[0] to this buffer, and then once the command
|
||||||
|
// buffer completes, copy the data out of the host visible
|
||||||
|
// readback buffer. Quite similar to what we do for texture
|
||||||
|
// readbacks.
|
||||||
|
BufferReadback readback;
|
||||||
|
readback.activeFrameSlot = currentFrameSlot;
|
||||||
|
readback.result = u.result;
|
||||||
|
readback.byteSize = u.readSize;
|
||||||
|
|
||||||
if (bufD->m_type == QRhiBuffer::Immutable) {
|
VkBufferCreateInfo bufferInfo;
|
||||||
QRhiVulkan::DeferredReleaseEntry e;
|
memset(&bufferInfo, 0, sizeof(bufferInfo));
|
||||||
e.type = QRhiVulkan::DeferredReleaseEntry::StagingBuffer;
|
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||||
e.lastActiveFrameSlot = currentFrameSlot;
|
bufferInfo.size = VkDeviceSize(readback.byteSize);
|
||||||
e.stagingBuffer.stagingBuffer = bufD->stagingBuffers[currentFrameSlot];
|
bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
|
||||||
e.stagingBuffer.stagingAllocation = bufD->stagingAllocations[currentFrameSlot];
|
|
||||||
bufD->stagingBuffers[currentFrameSlot] = VK_NULL_HANDLE;
|
VmaAllocationCreateInfo allocInfo;
|
||||||
bufD->stagingAllocations[currentFrameSlot] = nullptr;
|
memset(&allocInfo, 0, sizeof(allocInfo));
|
||||||
releaseQueue.append(e);
|
allocInfo.usage = VMA_MEMORY_USAGE_GPU_TO_CPU;
|
||||||
QRHI_PROF_F(releaseBufferStagingArea(bufD, currentFrameSlot));
|
|
||||||
|
VmaAllocation allocation;
|
||||||
|
VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo, &readback.stagingBuf, &allocation, nullptr);
|
||||||
|
if (err == VK_SUCCESS) {
|
||||||
|
readback.stagingAlloc = allocation;
|
||||||
|
QRHI_PROF_F(newReadbackBuffer(qint64(readback.stagingBuf), bufD, uint(readback.byteSize)));
|
||||||
|
} else {
|
||||||
|
qWarning("Failed to create readback buffer of size %u: %d", readback.byteSize, err);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
trackedBufferBarrier(cbD, bufD, 0, VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
|
||||||
|
|
||||||
|
VkBufferCopy copyInfo;
|
||||||
|
memset(©Info, 0, sizeof(copyInfo));
|
||||||
|
copyInfo.srcOffset = VkDeviceSize(u.offset);
|
||||||
|
copyInfo.size = VkDeviceSize(u.readSize);
|
||||||
|
|
||||||
|
QVkCommandBuffer::Command cmd;
|
||||||
|
cmd.cmd = QVkCommandBuffer::Command::CopyBuffer;
|
||||||
|
cmd.args.copyBuffer.src = bufD->buffers[0];
|
||||||
|
cmd.args.copyBuffer.dst = readback.stagingBuf;
|
||||||
|
cmd.args.copyBuffer.desc = copyInfo;
|
||||||
|
cbD->commands.append(cmd);
|
||||||
|
|
||||||
|
bufD->lastActiveFrameSlot = currentFrameSlot;
|
||||||
|
|
||||||
|
activeBufferReadbacks.append(readback);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const QRhiResourceUpdateBatchPrivate::TextureOp &u : ud->textureOps) {
|
for (const QRhiResourceUpdateBatchPrivate::TextureOp &u : ud->textureOps) {
|
||||||
if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Upload) {
|
if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Upload) {
|
||||||
QVkTexture *utexD = QRHI_RES(QVkTexture, u.upload.tex);
|
QVkTexture *utexD = QRHI_RES(QVkTexture, u.dst);
|
||||||
// batch into a single staging buffer and a single CopyBufferToImage with multiple copyInfos
|
// batch into a single staging buffer and a single CopyBufferToImage with multiple copyInfos
|
||||||
VkDeviceSize stagingSize = 0;
|
VkDeviceSize stagingSize = 0;
|
||||||
for (int layer = 0; layer < QRhi::MAX_LAYERS; ++layer) {
|
for (int layer = 0; layer < QRhi::MAX_LAYERS; ++layer) {
|
||||||
for (int level = 0; level < QRhi::MAX_LEVELS; ++level) {
|
for (int level = 0; level < QRhi::MAX_LEVELS; ++level) {
|
||||||
for (const QRhiTextureSubresourceUploadDescription &subresDesc : qAsConst(u.upload.subresDesc[layer][level]))
|
for (const QRhiTextureSubresourceUploadDescription &subresDesc : qAsConst(u.subresDesc[layer][level]))
|
||||||
stagingSize += subresUploadByteSize(subresDesc);
|
stagingSize += subresUploadByteSize(subresDesc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2780,7 +2849,7 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat
|
|||||||
|
|
||||||
for (int layer = 0; layer < QRhi::MAX_LAYERS; ++layer) {
|
for (int layer = 0; layer < QRhi::MAX_LAYERS; ++layer) {
|
||||||
for (int level = 0; level < QRhi::MAX_LEVELS; ++level) {
|
for (int level = 0; level < QRhi::MAX_LEVELS; ++level) {
|
||||||
const QVector<QRhiTextureSubresourceUploadDescription> &srd(u.upload.subresDesc[layer][level]);
|
const QVector<QRhiTextureSubresourceUploadDescription> &srd(u.subresDesc[layer][level]);
|
||||||
if (srd.isEmpty())
|
if (srd.isEmpty())
|
||||||
continue;
|
continue;
|
||||||
for (const QRhiTextureSubresourceUploadDescription &subresDesc : qAsConst(srd)) {
|
for (const QRhiTextureSubresourceUploadDescription &subresDesc : qAsConst(srd)) {
|
||||||
@ -2821,36 +2890,37 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat
|
|||||||
|
|
||||||
utexD->lastActiveFrameSlot = currentFrameSlot;
|
utexD->lastActiveFrameSlot = currentFrameSlot;
|
||||||
} else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Copy) {
|
} else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Copy) {
|
||||||
Q_ASSERT(u.copy.src && u.copy.dst);
|
Q_ASSERT(u.src && u.dst);
|
||||||
if (u.copy.src == u.copy.dst) {
|
if (u.src == u.dst) {
|
||||||
qWarning("Texture copy with matching source and destination is not supported");
|
qWarning("Texture copy with matching source and destination is not supported");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
QVkTexture *srcD = QRHI_RES(QVkTexture, u.copy.src);
|
QVkTexture *srcD = QRHI_RES(QVkTexture, u.src);
|
||||||
QVkTexture *dstD = QRHI_RES(QVkTexture, u.copy.dst);
|
QVkTexture *dstD = QRHI_RES(QVkTexture, u.dst);
|
||||||
|
|
||||||
VkImageCopy region;
|
VkImageCopy region;
|
||||||
memset(®ion, 0, sizeof(region));
|
memset(®ion, 0, sizeof(region));
|
||||||
|
|
||||||
region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
region.srcSubresource.mipLevel = uint32_t(u.copy.desc.sourceLevel());
|
region.srcSubresource.mipLevel = uint32_t(u.desc.sourceLevel());
|
||||||
region.srcSubresource.baseArrayLayer = uint32_t(u.copy.desc.sourceLayer());
|
region.srcSubresource.baseArrayLayer = uint32_t(u.desc.sourceLayer());
|
||||||
region.srcSubresource.layerCount = 1;
|
region.srcSubresource.layerCount = 1;
|
||||||
|
|
||||||
region.srcOffset.x = u.copy.desc.sourceTopLeft().x();
|
region.srcOffset.x = u.desc.sourceTopLeft().x();
|
||||||
region.srcOffset.y = u.copy.desc.sourceTopLeft().y();
|
region.srcOffset.y = u.desc.sourceTopLeft().y();
|
||||||
|
|
||||||
region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
region.dstSubresource.mipLevel = uint32_t(u.copy.desc.destinationLevel());
|
region.dstSubresource.mipLevel = uint32_t(u.desc.destinationLevel());
|
||||||
region.dstSubresource.baseArrayLayer = uint32_t(u.copy.desc.destinationLayer());
|
region.dstSubresource.baseArrayLayer = uint32_t(u.desc.destinationLayer());
|
||||||
region.dstSubresource.layerCount = 1;
|
region.dstSubresource.layerCount = 1;
|
||||||
|
|
||||||
region.dstOffset.x = u.copy.desc.destinationTopLeft().x();
|
region.dstOffset.x = u.desc.destinationTopLeft().x();
|
||||||
region.dstOffset.y = u.copy.desc.destinationTopLeft().y();
|
region.dstOffset.y = u.desc.destinationTopLeft().y();
|
||||||
|
|
||||||
const QSize size = u.copy.desc.pixelSize().isEmpty() ? srcD->m_pixelSize : u.copy.desc.pixelSize();
|
const QSize mipSize = q->sizeForMipLevel(u.desc.sourceLevel(), srcD->m_pixelSize);
|
||||||
region.extent.width = uint32_t(size.width());
|
const QSize copySize = u.desc.pixelSize().isEmpty() ? mipSize : u.desc.pixelSize();
|
||||||
region.extent.height = uint32_t(size.height());
|
region.extent.width = uint32_t(copySize.width());
|
||||||
|
region.extent.height = uint32_t(copySize.height());
|
||||||
region.extent.depth = 1;
|
region.extent.depth = 1;
|
||||||
|
|
||||||
trackedImageBarrier(cbD, srcD, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
trackedImageBarrier(cbD, srcD, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||||
@ -2869,21 +2939,20 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat
|
|||||||
|
|
||||||
srcD->lastActiveFrameSlot = dstD->lastActiveFrameSlot = currentFrameSlot;
|
srcD->lastActiveFrameSlot = dstD->lastActiveFrameSlot = currentFrameSlot;
|
||||||
} else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Read) {
|
} else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Read) {
|
||||||
ActiveReadback aRb;
|
TextureReadback readback;
|
||||||
aRb.activeFrameSlot = currentFrameSlot;
|
readback.activeFrameSlot = currentFrameSlot;
|
||||||
aRb.desc = u.read.rb;
|
readback.desc = u.rb;
|
||||||
aRb.result = u.read.result;
|
readback.result = u.result;
|
||||||
|
|
||||||
QVkTexture *texD = QRHI_RES(QVkTexture, u.read.rb.texture());
|
QVkTexture *texD = QRHI_RES(QVkTexture, u.rb.texture());
|
||||||
QVkSwapChain *swapChainD = nullptr;
|
QVkSwapChain *swapChainD = nullptr;
|
||||||
if (texD) {
|
if (texD) {
|
||||||
if (texD->samples > VK_SAMPLE_COUNT_1_BIT) {
|
if (texD->samples > VK_SAMPLE_COUNT_1_BIT) {
|
||||||
qWarning("Multisample texture cannot be read back");
|
qWarning("Multisample texture cannot be read back");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
aRb.pixelSize = u.read.rb.level() > 0 ? q->sizeForMipLevel(u.read.rb.level(), texD->m_pixelSize)
|
readback.pixelSize = q->sizeForMipLevel(u.rb.level(), texD->m_pixelSize);
|
||||||
: texD->m_pixelSize;
|
readback.format = texD->m_format;
|
||||||
aRb.format = texD->m_format;
|
|
||||||
texD->lastActiveFrameSlot = currentFrameSlot;
|
texD->lastActiveFrameSlot = currentFrameSlot;
|
||||||
} else {
|
} else {
|
||||||
Q_ASSERT(currentSwapChain);
|
Q_ASSERT(currentSwapChain);
|
||||||
@ -2892,21 +2961,21 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat
|
|||||||
qWarning("Swapchain does not support readback");
|
qWarning("Swapchain does not support readback");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
aRb.pixelSize = swapChainD->pixelSize;
|
readback.pixelSize = swapChainD->pixelSize;
|
||||||
aRb.format = colorTextureFormatFromVkFormat(swapChainD->colorFormat, nullptr);
|
readback.format = colorTextureFormatFromVkFormat(swapChainD->colorFormat, nullptr);
|
||||||
if (aRb.format == QRhiTexture::UnknownFormat)
|
if (readback.format == QRhiTexture::UnknownFormat)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Multisample swapchains need nothing special since resolving
|
// Multisample swapchains need nothing special since resolving
|
||||||
// happens when ending a renderpass.
|
// happens when ending a renderpass.
|
||||||
}
|
}
|
||||||
textureFormatInfo(aRb.format, aRb.pixelSize, nullptr, &aRb.bufSize);
|
textureFormatInfo(readback.format, readback.pixelSize, nullptr, &readback.byteSize);
|
||||||
|
|
||||||
// Create a host visible buffer.
|
// Create a host visible readback buffer.
|
||||||
VkBufferCreateInfo bufferInfo;
|
VkBufferCreateInfo bufferInfo;
|
||||||
memset(&bufferInfo, 0, sizeof(bufferInfo));
|
memset(&bufferInfo, 0, sizeof(bufferInfo));
|
||||||
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||||
bufferInfo.size = aRb.bufSize;
|
bufferInfo.size = readback.byteSize;
|
||||||
bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
|
bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
|
||||||
|
|
||||||
VmaAllocationCreateInfo allocInfo;
|
VmaAllocationCreateInfo allocInfo;
|
||||||
@ -2914,14 +2983,14 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat
|
|||||||
allocInfo.usage = VMA_MEMORY_USAGE_GPU_TO_CPU;
|
allocInfo.usage = VMA_MEMORY_USAGE_GPU_TO_CPU;
|
||||||
|
|
||||||
VmaAllocation allocation;
|
VmaAllocation allocation;
|
||||||
VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo, &aRb.buf, &allocation, nullptr);
|
VkResult err = vmaCreateBuffer(toVmaAllocator(allocator), &bufferInfo, &allocInfo, &readback.stagingBuf, &allocation, nullptr);
|
||||||
if (err == VK_SUCCESS) {
|
if (err == VK_SUCCESS) {
|
||||||
aRb.bufAlloc = allocation;
|
readback.stagingAlloc = allocation;
|
||||||
QRHI_PROF_F(newReadbackBuffer(qint64(aRb.buf),
|
QRHI_PROF_F(newReadbackBuffer(qint64(readback.stagingBuf),
|
||||||
texD ? static_cast<QRhiResource *>(texD) : static_cast<QRhiResource *>(swapChainD),
|
texD ? static_cast<QRhiResource *>(texD) : static_cast<QRhiResource *>(swapChainD),
|
||||||
aRb.bufSize));
|
readback.byteSize));
|
||||||
} else {
|
} else {
|
||||||
qWarning("Failed to create readback buffer of size %u: %d", aRb.bufSize, err);
|
qWarning("Failed to create readback buffer of size %u: %d", readback.byteSize, err);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2930,11 +2999,11 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat
|
|||||||
memset(©Desc, 0, sizeof(copyDesc));
|
memset(©Desc, 0, sizeof(copyDesc));
|
||||||
copyDesc.bufferOffset = 0;
|
copyDesc.bufferOffset = 0;
|
||||||
copyDesc.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
copyDesc.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
copyDesc.imageSubresource.mipLevel = uint32_t(u.read.rb.level());
|
copyDesc.imageSubresource.mipLevel = uint32_t(u.rb.level());
|
||||||
copyDesc.imageSubresource.baseArrayLayer = uint32_t(u.read.rb.layer());
|
copyDesc.imageSubresource.baseArrayLayer = uint32_t(u.rb.layer());
|
||||||
copyDesc.imageSubresource.layerCount = 1;
|
copyDesc.imageSubresource.layerCount = 1;
|
||||||
copyDesc.imageExtent.width = uint32_t(aRb.pixelSize.width());
|
copyDesc.imageExtent.width = uint32_t(readback.pixelSize.width());
|
||||||
copyDesc.imageExtent.height = uint32_t(aRb.pixelSize.height());
|
copyDesc.imageExtent.height = uint32_t(readback.pixelSize.height());
|
||||||
copyDesc.imageExtent.depth = 1;
|
copyDesc.imageExtent.depth = 1;
|
||||||
|
|
||||||
if (texD) {
|
if (texD) {
|
||||||
@ -2944,7 +3013,7 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat
|
|||||||
cmd.cmd = QVkCommandBuffer::Command::CopyImageToBuffer;
|
cmd.cmd = QVkCommandBuffer::Command::CopyImageToBuffer;
|
||||||
cmd.args.copyImageToBuffer.src = texD->image;
|
cmd.args.copyImageToBuffer.src = texD->image;
|
||||||
cmd.args.copyImageToBuffer.srcLayout = texD->usageState.layout;
|
cmd.args.copyImageToBuffer.srcLayout = texD->usageState.layout;
|
||||||
cmd.args.copyImageToBuffer.dst = aRb.buf;
|
cmd.args.copyImageToBuffer.dst = readback.stagingBuf;
|
||||||
cmd.args.copyImageToBuffer.desc = copyDesc;
|
cmd.args.copyImageToBuffer.desc = copyDesc;
|
||||||
cbD->commands.append(cmd);
|
cbD->commands.append(cmd);
|
||||||
} else {
|
} else {
|
||||||
@ -2969,14 +3038,14 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat
|
|||||||
cmd.cmd = QVkCommandBuffer::Command::CopyImageToBuffer;
|
cmd.cmd = QVkCommandBuffer::Command::CopyImageToBuffer;
|
||||||
cmd.args.copyImageToBuffer.src = image;
|
cmd.args.copyImageToBuffer.src = image;
|
||||||
cmd.args.copyImageToBuffer.srcLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
cmd.args.copyImageToBuffer.srcLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||||
cmd.args.copyImageToBuffer.dst = aRb.buf;
|
cmd.args.copyImageToBuffer.dst = readback.stagingBuf;
|
||||||
cmd.args.copyImageToBuffer.desc = copyDesc;
|
cmd.args.copyImageToBuffer.desc = copyDesc;
|
||||||
cbD->commands.append(cmd);
|
cbD->commands.append(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
activeReadbacks.append(aRb);
|
activeTextureReadbacks.append(readback);
|
||||||
} else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::MipGen) {
|
} else if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::GenMips) {
|
||||||
QVkTexture *utexD = QRHI_RES(QVkTexture, u.mipgen.tex);
|
QVkTexture *utexD = QRHI_RES(QVkTexture, u.dst);
|
||||||
Q_ASSERT(utexD->m_flags.testFlag(QRhiTexture::UsedWithGenerateMips));
|
Q_ASSERT(utexD->m_flags.testFlag(QRhiTexture::UsedWithGenerateMips));
|
||||||
int w = utexD->m_pixelSize.width();
|
int w = utexD->m_pixelSize.width();
|
||||||
int h = utexD->m_pixelSize.height();
|
int h = utexD->m_pixelSize.height();
|
||||||
@ -2993,14 +3062,14 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat
|
|||||||
origLayout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
origLayout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||||
origAccess, VK_ACCESS_TRANSFER_READ_BIT,
|
origAccess, VK_ACCESS_TRANSFER_READ_BIT,
|
||||||
origStage, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
origStage, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||||
u.mipgen.layer, 1,
|
u.layer, 1,
|
||||||
level - 1, 1);
|
level - 1, 1);
|
||||||
} else {
|
} else {
|
||||||
subresourceBarrier(cbD, utexD->image,
|
subresourceBarrier(cbD, utexD->image,
|
||||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||||
VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
|
VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
|
||||||
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||||
u.mipgen.layer, 1,
|
u.layer, 1,
|
||||||
level - 1, 1);
|
level - 1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3008,7 +3077,7 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat
|
|||||||
origLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
origLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||||
origAccess, VK_ACCESS_TRANSFER_WRITE_BIT,
|
origAccess, VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||||
origStage, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
origStage, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||||
u.mipgen.layer, 1,
|
u.layer, 1,
|
||||||
level, 1);
|
level, 1);
|
||||||
|
|
||||||
VkImageBlit region;
|
VkImageBlit region;
|
||||||
@ -3016,7 +3085,7 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat
|
|||||||
|
|
||||||
region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
region.srcSubresource.mipLevel = uint32_t(level) - 1;
|
region.srcSubresource.mipLevel = uint32_t(level) - 1;
|
||||||
region.srcSubresource.baseArrayLayer = uint32_t(u.mipgen.layer);
|
region.srcSubresource.baseArrayLayer = uint32_t(u.layer);
|
||||||
region.srcSubresource.layerCount = 1;
|
region.srcSubresource.layerCount = 1;
|
||||||
|
|
||||||
region.srcOffsets[1].x = qMax(1, w);
|
region.srcOffsets[1].x = qMax(1, w);
|
||||||
@ -3025,7 +3094,7 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat
|
|||||||
|
|
||||||
region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
region.dstSubresource.mipLevel = uint32_t(level);
|
region.dstSubresource.mipLevel = uint32_t(level);
|
||||||
region.dstSubresource.baseArrayLayer = uint32_t(u.mipgen.layer);
|
region.dstSubresource.baseArrayLayer = uint32_t(u.layer);
|
||||||
region.dstSubresource.layerCount = 1;
|
region.dstSubresource.layerCount = 1;
|
||||||
|
|
||||||
region.dstOffsets[1].x = qMax(1, w >> 1);
|
region.dstOffsets[1].x = qMax(1, w >> 1);
|
||||||
@ -3051,13 +3120,13 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat
|
|||||||
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, origLayout,
|
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, origLayout,
|
||||||
VK_ACCESS_TRANSFER_READ_BIT, origAccess,
|
VK_ACCESS_TRANSFER_READ_BIT, origAccess,
|
||||||
VK_PIPELINE_STAGE_TRANSFER_BIT, origStage,
|
VK_PIPELINE_STAGE_TRANSFER_BIT, origStage,
|
||||||
u.mipgen.layer, 1,
|
u.layer, 1,
|
||||||
0, int(utexD->mipLevelCount) - 1);
|
0, int(utexD->mipLevelCount) - 1);
|
||||||
subresourceBarrier(cbD, utexD->image,
|
subresourceBarrier(cbD, utexD->image,
|
||||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, origLayout,
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, origLayout,
|
||||||
VK_ACCESS_TRANSFER_WRITE_BIT, origAccess,
|
VK_ACCESS_TRANSFER_WRITE_BIT, origAccess,
|
||||||
VK_PIPELINE_STAGE_TRANSFER_BIT, origStage,
|
VK_PIPELINE_STAGE_TRANSFER_BIT, origStage,
|
||||||
u.mipgen.layer, 1,
|
u.layer, 1,
|
||||||
int(utexD->mipLevelCount) - 1, 1);
|
int(utexD->mipLevelCount) - 1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3070,8 +3139,7 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat
|
|||||||
|
|
||||||
void QRhiVulkan::executeBufferHostWritesForCurrentFrame(QVkBuffer *bufD)
|
void QRhiVulkan::executeBufferHostWritesForCurrentFrame(QVkBuffer *bufD)
|
||||||
{
|
{
|
||||||
QVector<QRhiResourceUpdateBatchPrivate::DynamicBufferUpdate> &updates(bufD->pendingDynamicUpdates[currentFrameSlot]);
|
if (bufD->pendingDynamicUpdates[currentFrameSlot].isEmpty())
|
||||||
if (updates.isEmpty())
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
|
Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
|
||||||
@ -3087,7 +3155,7 @@ void QRhiVulkan::executeBufferHostWritesForCurrentFrame(QVkBuffer *bufD)
|
|||||||
}
|
}
|
||||||
int changeBegin = -1;
|
int changeBegin = -1;
|
||||||
int changeEnd = -1;
|
int changeEnd = -1;
|
||||||
for (const QRhiResourceUpdateBatchPrivate::DynamicBufferUpdate &u : updates) {
|
for (const QRhiResourceUpdateBatchPrivate::BufferOp &u : qAsConst(bufD->pendingDynamicUpdates[currentFrameSlot])) {
|
||||||
Q_ASSERT(bufD == QRHI_RES(QVkBuffer, u.buf));
|
Q_ASSERT(bufD == QRHI_RES(QVkBuffer, u.buf));
|
||||||
memcpy(static_cast<char *>(p) + u.offset, u.data.constData(), size_t(u.data.size()));
|
memcpy(static_cast<char *>(p) + u.offset, u.data.constData(), size_t(u.data.size()));
|
||||||
if (changeBegin == -1 || u.offset < changeBegin)
|
if (changeBegin == -1 || u.offset < changeBegin)
|
||||||
@ -3099,7 +3167,7 @@ void QRhiVulkan::executeBufferHostWritesForCurrentFrame(QVkBuffer *bufD)
|
|||||||
if (changeBegin >= 0)
|
if (changeBegin >= 0)
|
||||||
vmaFlushAllocation(toVmaAllocator(allocator), a, VkDeviceSize(changeBegin), VkDeviceSize(changeEnd - changeBegin));
|
vmaFlushAllocation(toVmaAllocator(allocator), a, VkDeviceSize(changeBegin), VkDeviceSize(changeEnd - changeBegin));
|
||||||
|
|
||||||
updates.clear();
|
bufD->pendingDynamicUpdates[currentFrameSlot].clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qrhivk_releaseBuffer(const QRhiVulkan::DeferredReleaseEntry &e, void *allocator)
|
static void qrhivk_releaseBuffer(const QRhiVulkan::DeferredReleaseEntry &e, void *allocator)
|
||||||
@ -3193,29 +3261,53 @@ void QRhiVulkan::finishActiveReadbacks(bool forced)
|
|||||||
QVarLengthArray<std::function<void()>, 4> completedCallbacks;
|
QVarLengthArray<std::function<void()>, 4> completedCallbacks;
|
||||||
QRhiProfilerPrivate *rhiP = profilerPrivateOrNull();
|
QRhiProfilerPrivate *rhiP = profilerPrivateOrNull();
|
||||||
|
|
||||||
for (int i = activeReadbacks.count() - 1; i >= 0; --i) {
|
for (int i = activeTextureReadbacks.count() - 1; i >= 0; --i) {
|
||||||
const QRhiVulkan::ActiveReadback &aRb(activeReadbacks[i]);
|
const QRhiVulkan::TextureReadback &readback(activeTextureReadbacks[i]);
|
||||||
if (forced || currentFrameSlot == aRb.activeFrameSlot || aRb.activeFrameSlot < 0) {
|
if (forced || currentFrameSlot == readback.activeFrameSlot || readback.activeFrameSlot < 0) {
|
||||||
aRb.result->format = aRb.format;
|
readback.result->format = readback.format;
|
||||||
aRb.result->pixelSize = aRb.pixelSize;
|
readback.result->pixelSize = readback.pixelSize;
|
||||||
aRb.result->data.resize(int(aRb.bufSize));
|
VmaAllocation a = toVmaAllocation(readback.stagingAlloc);
|
||||||
void *p = nullptr;
|
void *p = nullptr;
|
||||||
VmaAllocation a = toVmaAllocation(aRb.bufAlloc);
|
|
||||||
VkResult err = vmaMapMemory(toVmaAllocator(allocator), a, &p);
|
VkResult err = vmaMapMemory(toVmaAllocator(allocator), a, &p);
|
||||||
if (err != VK_SUCCESS) {
|
if (err == VK_SUCCESS && p) {
|
||||||
qWarning("Failed to map readback buffer: %d", err);
|
readback.result->data.resize(int(readback.byteSize));
|
||||||
continue;
|
memcpy(readback.result->data.data(), p, readback.byteSize);
|
||||||
|
vmaUnmapMemory(toVmaAllocator(allocator), a);
|
||||||
|
} else {
|
||||||
|
qWarning("Failed to map texture readback buffer of size %u: %d", readback.byteSize, err);
|
||||||
}
|
}
|
||||||
memcpy(aRb.result->data.data(), p, aRb.bufSize);
|
|
||||||
vmaUnmapMemory(toVmaAllocator(allocator), a);
|
|
||||||
|
|
||||||
vmaDestroyBuffer(toVmaAllocator(allocator), aRb.buf, a);
|
vmaDestroyBuffer(toVmaAllocator(allocator), readback.stagingBuf, a);
|
||||||
QRHI_PROF_F(releaseReadbackBuffer(qint64(aRb.buf)));
|
QRHI_PROF_F(releaseReadbackBuffer(qint64(readback.stagingBuf)));
|
||||||
|
|
||||||
if (aRb.result->completed)
|
if (readback.result->completed)
|
||||||
completedCallbacks.append(aRb.result->completed);
|
completedCallbacks.append(readback.result->completed);
|
||||||
|
|
||||||
activeReadbacks.removeAt(i);
|
activeTextureReadbacks.removeAt(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = activeBufferReadbacks.count() - 1; i >= 0; --i) {
|
||||||
|
const QRhiVulkan::BufferReadback &readback(activeBufferReadbacks[i]);
|
||||||
|
if (forced || currentFrameSlot == readback.activeFrameSlot || readback.activeFrameSlot < 0) {
|
||||||
|
VmaAllocation a = toVmaAllocation(readback.stagingAlloc);
|
||||||
|
void *p = nullptr;
|
||||||
|
VkResult err = vmaMapMemory(toVmaAllocator(allocator), a, &p);
|
||||||
|
if (err == VK_SUCCESS && p) {
|
||||||
|
readback.result->data.resize(readback.byteSize);
|
||||||
|
memcpy(readback.result->data.data(), p, size_t(readback.byteSize));
|
||||||
|
vmaUnmapMemory(toVmaAllocator(allocator), a);
|
||||||
|
} else {
|
||||||
|
qWarning("Failed to map buffer readback buffer of size %d: %d", readback.byteSize, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
vmaDestroyBuffer(toVmaAllocator(allocator), readback.stagingBuf, a);
|
||||||
|
QRHI_PROF_F(releaseReadbackBuffer(qint64(readback.stagingBuf)));
|
||||||
|
|
||||||
|
if (readback.result->completed)
|
||||||
|
completedCallbacks.append(readback.result->completed);
|
||||||
|
|
||||||
|
activeBufferReadbacks.removeAt(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3733,6 +3825,10 @@ bool QRhiVulkan::isFeatureSupported(QRhi::Feature feature) const
|
|||||||
return true;
|
return true;
|
||||||
case QRhi::TriangleFanTopology:
|
case QRhi::TriangleFanTopology:
|
||||||
return true;
|
return true;
|
||||||
|
case QRhi::ReadBackNonUniformBuffer:
|
||||||
|
return true;
|
||||||
|
case QRhi::ReadBackNonBaseMipLevel:
|
||||||
|
return true;
|
||||||
default:
|
default:
|
||||||
Q_UNREACHABLE();
|
Q_UNREACHABLE();
|
||||||
return false;
|
return false;
|
||||||
@ -4902,7 +4998,7 @@ bool QVkBuffer::build()
|
|||||||
allocInfo.usage = VMA_MEMORY_USAGE_CPU_TO_GPU;
|
allocInfo.usage = VMA_MEMORY_USAGE_CPU_TO_GPU;
|
||||||
} else {
|
} else {
|
||||||
allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
|
allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
|
||||||
bufferInfo.usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT;
|
bufferInfo.usage |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
QRHI_RES_RHI(QRhiVulkan);
|
QRHI_RES_RHI(QRhiVulkan);
|
||||||
@ -4916,11 +5012,7 @@ bool QVkBuffer::build()
|
|||||||
err = vmaCreateBuffer(toVmaAllocator(rhiD->allocator), &bufferInfo, &allocInfo, &buffers[i], &allocation, nullptr);
|
err = vmaCreateBuffer(toVmaAllocator(rhiD->allocator), &bufferInfo, &allocInfo, &buffers[i], &allocation, nullptr);
|
||||||
if (err != VK_SUCCESS)
|
if (err != VK_SUCCESS)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
allocations[i] = allocation;
|
allocations[i] = allocation;
|
||||||
if (m_type == Dynamic)
|
|
||||||
pendingDynamicUpdates[i].reserve(16);
|
|
||||||
|
|
||||||
rhiD->setObjectName(uint64_t(buffers[i]), VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, m_objectName,
|
rhiD->setObjectName(uint64_t(buffers[i]), VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, m_objectName,
|
||||||
m_type == Dynamic ? i : -1);
|
m_type == Dynamic ? i : -1);
|
||||||
}
|
}
|
||||||
@ -5798,6 +5890,9 @@ bool QVkGraphicsPipeline::build()
|
|||||||
release();
|
release();
|
||||||
|
|
||||||
QRHI_RES_RHI(QRhiVulkan);
|
QRHI_RES_RHI(QRhiVulkan);
|
||||||
|
if (!rhiD->sanityCheckGraphicsPipeline(this))
|
||||||
|
return false;
|
||||||
|
|
||||||
if (!rhiD->ensurePipelineCache())
|
if (!rhiD->ensurePipelineCache())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ struct QVkBuffer : public QRhiBuffer
|
|||||||
|
|
||||||
VkBuffer buffers[QVK_FRAMES_IN_FLIGHT];
|
VkBuffer buffers[QVK_FRAMES_IN_FLIGHT];
|
||||||
QVkAlloc allocations[QVK_FRAMES_IN_FLIGHT];
|
QVkAlloc allocations[QVK_FRAMES_IN_FLIGHT];
|
||||||
QVector<QRhiResourceUpdateBatchPrivate::DynamicBufferUpdate> pendingDynamicUpdates[QVK_FRAMES_IN_FLIGHT];
|
QVarLengthArray<QRhiResourceUpdateBatchPrivate::BufferOp, 16> pendingDynamicUpdates[QVK_FRAMES_IN_FLIGHT];
|
||||||
VkBuffer stagingBuffers[QVK_FRAMES_IN_FLIGHT];
|
VkBuffer stagingBuffers[QVK_FRAMES_IN_FLIGHT];
|
||||||
QVkAlloc stagingAllocations[QVK_FRAMES_IN_FLIGHT];
|
QVkAlloc stagingAllocations[QVK_FRAMES_IN_FLIGHT];
|
||||||
struct UsageState {
|
struct UsageState {
|
||||||
@ -853,17 +853,25 @@ public:
|
|||||||
VkFence cmdFence = VK_NULL_HANDLE;
|
VkFence cmdFence = VK_NULL_HANDLE;
|
||||||
} ofr;
|
} ofr;
|
||||||
|
|
||||||
struct ActiveReadback {
|
struct TextureReadback {
|
||||||
int activeFrameSlot = -1;
|
int activeFrameSlot = -1;
|
||||||
QRhiReadbackDescription desc;
|
QRhiReadbackDescription desc;
|
||||||
QRhiReadbackResult *result;
|
QRhiReadbackResult *result;
|
||||||
VkBuffer buf;
|
VkBuffer stagingBuf;
|
||||||
QVkAlloc bufAlloc;
|
QVkAlloc stagingAlloc;
|
||||||
quint32 bufSize;
|
quint32 byteSize;
|
||||||
QSize pixelSize;
|
QSize pixelSize;
|
||||||
QRhiTexture::Format format;
|
QRhiTexture::Format format;
|
||||||
};
|
};
|
||||||
QVector<ActiveReadback> activeReadbacks;
|
QVector<TextureReadback> activeTextureReadbacks;
|
||||||
|
struct BufferReadback {
|
||||||
|
int activeFrameSlot = -1;
|
||||||
|
QRhiBufferReadbackResult *result;
|
||||||
|
int byteSize;
|
||||||
|
VkBuffer stagingBuf;
|
||||||
|
QVkAlloc stagingAlloc;
|
||||||
|
};
|
||||||
|
QVector<BufferReadback> activeBufferReadbacks;
|
||||||
|
|
||||||
struct DeferredReleaseEntry {
|
struct DeferredReleaseEntry {
|
||||||
enum Type {
|
enum Type {
|
||||||
@ -933,7 +941,8 @@ public:
|
|||||||
|
|
||||||
Q_DECLARE_TYPEINFO(QRhiVulkan::DescriptorPoolData, Q_MOVABLE_TYPE);
|
Q_DECLARE_TYPEINFO(QRhiVulkan::DescriptorPoolData, Q_MOVABLE_TYPE);
|
||||||
Q_DECLARE_TYPEINFO(QRhiVulkan::DeferredReleaseEntry, Q_MOVABLE_TYPE);
|
Q_DECLARE_TYPEINFO(QRhiVulkan::DeferredReleaseEntry, Q_MOVABLE_TYPE);
|
||||||
Q_DECLARE_TYPEINFO(QRhiVulkan::ActiveReadback, Q_MOVABLE_TYPE);
|
Q_DECLARE_TYPEINFO(QRhiVulkan::TextureReadback, Q_MOVABLE_TYPE);
|
||||||
|
Q_DECLARE_TYPEINFO(QRhiVulkan::BufferReadback, Q_MOVABLE_TYPE);
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
@ -102,13 +102,23 @@
|
|||||||
"gssapi": {
|
"gssapi": {
|
||||||
"label": "KRB5 GSSAPI Support",
|
"label": "KRB5 GSSAPI Support",
|
||||||
"test": {
|
"test": {
|
||||||
|
"head": [
|
||||||
|
"#if defined(__APPLE__) && (defined(__GNUC__) || defined(__xlC__) || defined(__xlc__))",
|
||||||
|
"# include <TargetConditionals.h>",
|
||||||
|
"# if defined(TARGET_OS_MAC) && TARGET_OS_MAC",
|
||||||
|
"# include <GSS/GSS.h>",
|
||||||
|
"# endif",
|
||||||
|
"#else",
|
||||||
|
"# include <gssapi/gssapi.h>",
|
||||||
|
"#endif"
|
||||||
|
],
|
||||||
"main": [
|
"main": [
|
||||||
"gss_ctx_id_t ctx;",
|
"gss_ctx_id_t ctx;",
|
||||||
"gss_context_time(nullptr, ctx, nullptr);"
|
"gss_context_time(nullptr, ctx, nullptr);"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"headers": [ "gssapi/gssapi.h" ],
|
|
||||||
"sources": [
|
"sources": [
|
||||||
|
{ "libs": "-framework GSS", "condition": "config.darwin" },
|
||||||
{ "type": "pkgConfig", "args": "krb5-gssapi" },
|
{ "type": "pkgConfig", "args": "krb5-gssapi" },
|
||||||
"-lgssapi_krb5"
|
"-lgssapi_krb5"
|
||||||
]
|
]
|
||||||
|
@ -59,8 +59,12 @@
|
|||||||
#define SECURITY_WIN32 1
|
#define SECURITY_WIN32 1
|
||||||
#include <security.h>
|
#include <security.h>
|
||||||
#elif QT_CONFIG(gssapi) // GSSAPI
|
#elif QT_CONFIG(gssapi) // GSSAPI
|
||||||
|
#if defined(Q_OS_DARWIN)
|
||||||
|
#include <GSS/GSS.h>
|
||||||
|
#else
|
||||||
#include <gssapi/gssapi.h>
|
#include <gssapi/gssapi.h>
|
||||||
#endif
|
#endif // Q_OS_DARWIN
|
||||||
|
#endif // Q_CONFIG(sspi)
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
@ -69,6 +69,7 @@ extern "C" {
|
|||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
Q_LOGGING_CATEGORY(qLcEvdevTouch, "qt.qpa.input")
|
Q_LOGGING_CATEGORY(qLcEvdevTouch, "qt.qpa.input")
|
||||||
|
Q_LOGGING_CATEGORY(qLcEvents, "qt.qpa.input.events")
|
||||||
|
|
||||||
/* android (and perhaps some other linux-derived stuff) don't define everything
|
/* android (and perhaps some other linux-derived stuff) don't define everything
|
||||||
* in linux/input.h, so we'll need to do that ourselves.
|
* in linux/input.h, so we'll need to do that ourselves.
|
||||||
@ -539,6 +540,9 @@ void QEvdevTouchScreenData::processInputEvent(input_event *data)
|
|||||||
if (m_typeB)
|
if (m_typeB)
|
||||||
m_contacts[m_currentSlot].maj = m_currentData.maj;
|
m_contacts[m_currentSlot].maj = m_currentData.maj;
|
||||||
} else if (data->code == ABS_PRESSURE || data->code == ABS_MT_PRESSURE) {
|
} else if (data->code == ABS_PRESSURE || data->code == ABS_MT_PRESSURE) {
|
||||||
|
if (Q_UNLIKELY(qLcEvents().isDebugEnabled()))
|
||||||
|
qCDebug(qLcEvents, "EV_ABS code 0x%x: pressure %d; bounding to [%d,%d]",
|
||||||
|
data->code, data->value, hw_pressure_min, hw_pressure_max);
|
||||||
m_currentData.pressure = qBound(hw_pressure_min, data->value, hw_pressure_max);
|
m_currentData.pressure = qBound(hw_pressure_min, data->value, hw_pressure_max);
|
||||||
if (m_typeB || m_singleTouch)
|
if (m_typeB || m_singleTouch)
|
||||||
m_contacts[m_currentSlot].pressure = m_currentData.pressure;
|
m_contacts[m_currentSlot].pressure = m_currentData.pressure;
|
||||||
@ -577,6 +581,7 @@ void QEvdevTouchScreenData::processInputEvent(input_event *data)
|
|||||||
m_lastTouchPoints = m_touchPoints;
|
m_lastTouchPoints = m_touchPoints;
|
||||||
m_touchPoints.clear();
|
m_touchPoints.clear();
|
||||||
Qt::TouchPointStates combinedStates;
|
Qt::TouchPointStates combinedStates;
|
||||||
|
bool hasPressure = false;
|
||||||
|
|
||||||
for (auto i = m_contacts.begin(), end = m_contacts.end(); i != end; /*erasing*/) {
|
for (auto i = m_contacts.begin(), end = m_contacts.end(); i != end; /*erasing*/) {
|
||||||
auto it = i++;
|
auto it = i++;
|
||||||
@ -607,6 +612,9 @@ void QEvdevTouchScreenData::processInputEvent(input_event *data)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (contact.pressure)
|
||||||
|
hasPressure = true;
|
||||||
|
|
||||||
addTouchPoint(contact, &combinedStates);
|
addTouchPoint(contact, &combinedStates);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -651,7 +659,7 @@ void QEvdevTouchScreenData::processInputEvent(input_event *data)
|
|||||||
m_contacts.clear();
|
m_contacts.clear();
|
||||||
|
|
||||||
|
|
||||||
if (!m_touchPoints.isEmpty() && combinedStates != Qt::TouchPointStationary)
|
if (!m_touchPoints.isEmpty() && (hasPressure || combinedStates != Qt::TouchPointStationary))
|
||||||
reportPoints();
|
reportPoints();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -777,6 +785,9 @@ void QEvdevTouchScreenData::reportPoints()
|
|||||||
tp.pressure = tp.state == Qt::TouchPointReleased ? 0 : 1;
|
tp.pressure = tp.state == Qt::TouchPointReleased ? 0 : 1;
|
||||||
else
|
else
|
||||||
tp.pressure = (tp.pressure - hw_pressure_min) / qreal(hw_pressure_max - hw_pressure_min);
|
tp.pressure = (tp.pressure - hw_pressure_min) / qreal(hw_pressure_max - hw_pressure_min);
|
||||||
|
|
||||||
|
if (Q_UNLIKELY(qLcEvents().isDebugEnabled()))
|
||||||
|
qCDebug(qLcEvents) << "reporting" << tp;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Let qguiapp pick the target window.
|
// Let qguiapp pick the target window.
|
||||||
|
@ -9213,9 +9213,11 @@ void QWidget::mouseReleaseEvent(QMouseEvent *event)
|
|||||||
The default implementation calls mousePressEvent().
|
The default implementation calls mousePressEvent().
|
||||||
|
|
||||||
\note The widget will also receive mouse press and mouse release
|
\note The widget will also receive mouse press and mouse release
|
||||||
events in addition to the double click event. It is up to the
|
events in addition to the double click event. And if another widget
|
||||||
developer to ensure that the application interprets these events
|
that overlaps this widget disappears in response to press or
|
||||||
correctly.
|
release events, then this widget will only receive the double click
|
||||||
|
event. It is up to the developer to ensure that the application
|
||||||
|
interprets these events correctly.
|
||||||
|
|
||||||
\sa mousePressEvent(), mouseReleaseEvent(), mouseMoveEvent(),
|
\sa mousePressEvent(), mouseReleaseEvent(), mouseMoveEvent(),
|
||||||
event(), QMouseEvent
|
event(), QMouseEvent
|
||||||
|
@ -4593,6 +4593,8 @@ void tst_QString::fromLatin1()
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if QT_DEPRECATED_SINCE(5, 0)
|
#if QT_DEPRECATED_SINCE(5, 0)
|
||||||
|
QT_WARNING_PUSH
|
||||||
|
QT_WARNING_DISABLE_DEPRECATED
|
||||||
void tst_QString::fromAscii()
|
void tst_QString::fromAscii()
|
||||||
{
|
{
|
||||||
QString a;
|
QString a;
|
||||||
@ -4613,6 +4615,7 @@ void tst_QString::fromAscii()
|
|||||||
a = QString::fromAscii("\0abcd", 5);
|
a = QString::fromAscii("\0abcd", 5);
|
||||||
QVERIFY(a.size() == 5);
|
QVERIFY(a.size() == 5);
|
||||||
}
|
}
|
||||||
|
QT_WARNING_POP
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void tst_QString::fromUcs4()
|
void tst_QString::fromUcs4()
|
||||||
|
48
tests/auto/gui/rhi/qrhi/data/compile.bat
Normal file
48
tests/auto/gui/rhi/qrhi/data/compile.bat
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||||
|
::
|
||||||
|
:: Copyright (C) 2019 The Qt Company Ltd.
|
||||||
|
:: Contact: https://www.qt.io/licensing/
|
||||||
|
::
|
||||||
|
:: This file is part of the QtQuick module of the Qt Toolkit.
|
||||||
|
::
|
||||||
|
:: $QT_BEGIN_LICENSE:LGPL$
|
||||||
|
:: 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.
|
||||||
|
::
|
||||||
|
:: GNU Lesser General Public License Usage
|
||||||
|
:: Alternatively, this file may be used under the terms of the GNU Lesser
|
||||||
|
:: General Public License version 3 as published by the Free Software
|
||||||
|
:: Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||||
|
:: packaging of this file. Please review the following information to
|
||||||
|
:: ensure the GNU Lesser General Public License version 3 requirements
|
||||||
|
:: will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||||
|
::
|
||||||
|
:: GNU General Public License Usage
|
||||||
|
:: Alternatively, this file may be used under the terms of the GNU
|
||||||
|
:: General Public License version 2.0 or (at your option) the GNU General
|
||||||
|
:: Public license version 3 or any later version approved by the KDE Free
|
||||||
|
:: Qt Foundation. The licenses are as published by the Free Software
|
||||||
|
:: Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
||||||
|
:: included in the packaging of this file. Please review the following
|
||||||
|
:: information to ensure the GNU General Public License requirements will
|
||||||
|
:: be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
||||||
|
:: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
::
|
||||||
|
:: $QT_END_LICENSE$
|
||||||
|
::
|
||||||
|
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||||
|
|
||||||
|
:: Note the -c argument: we do not want runtime HLSL compilation since that is
|
||||||
|
:: not an option on UWP (WinRT). This means that running qsb must happen on Windows.
|
||||||
|
|
||||||
|
qsb --glsl "150,120,100 es" --hlsl 50 -c --msl 12 -o simple.vert.qsb simple.vert
|
||||||
|
qsb --glsl "150,120,100 es" --hlsl 50 -c --msl 12 -o simple.frag.qsb simple.frag
|
||||||
|
qsb --glsl "150,120,100 es" --hlsl 50 -c --msl 12 -o simpletextured.vert.qsb simpletextured.vert
|
||||||
|
qsb --glsl "150,120,100 es" --hlsl 50 -c --msl 12 -o simpletextured.frag.qsb simpletextured.frag
|
||||||
|
qsb --glsl "150,120,100 es" --hlsl 50 -c --msl 12 -o textured.vert.qsb textured.vert
|
||||||
|
qsb --glsl "150,120,100 es" --hlsl 50 -c --msl 12 -o textured.frag.qsb textured.frag
|
BIN
tests/auto/gui/rhi/qrhi/data/qt256.png
Normal file
BIN
tests/auto/gui/rhi/qrhi/data/qt256.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.1 KiB |
8
tests/auto/gui/rhi/qrhi/data/simple.frag
Normal file
8
tests/auto/gui/rhi/qrhi/data/simple.frag
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#version 440
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 fragColor;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
fragColor = vec4(1.0, 0.0, 0.0, 1.0);
|
||||||
|
}
|
BIN
tests/auto/gui/rhi/qrhi/data/simple.frag.qsb
Normal file
BIN
tests/auto/gui/rhi/qrhi/data/simple.frag.qsb
Normal file
Binary file not shown.
10
tests/auto/gui/rhi/qrhi/data/simple.vert
Normal file
10
tests/auto/gui/rhi/qrhi/data/simple.vert
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#version 440
|
||||||
|
|
||||||
|
layout(location = 0) in vec4 position;
|
||||||
|
|
||||||
|
out gl_PerVertex { vec4 gl_Position; };
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gl_Position = position;
|
||||||
|
}
|
BIN
tests/auto/gui/rhi/qrhi/data/simple.vert.qsb
Normal file
BIN
tests/auto/gui/rhi/qrhi/data/simple.vert.qsb
Normal file
Binary file not shown.
13
tests/auto/gui/rhi/qrhi/data/simpletextured.frag
Normal file
13
tests/auto/gui/rhi/qrhi/data/simpletextured.frag
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#version 440
|
||||||
|
|
||||||
|
layout(location = 0) in vec2 uv;
|
||||||
|
layout(location = 0) out vec4 fragColor;
|
||||||
|
|
||||||
|
layout(binding = 0) uniform sampler2D tex;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vec4 c = texture(tex, uv);
|
||||||
|
c.rgb *= c.a;
|
||||||
|
fragColor = c;
|
||||||
|
}
|
BIN
tests/auto/gui/rhi/qrhi/data/simpletextured.frag.qsb
Normal file
BIN
tests/auto/gui/rhi/qrhi/data/simpletextured.frag.qsb
Normal file
Binary file not shown.
14
tests/auto/gui/rhi/qrhi/data/simpletextured.vert
Normal file
14
tests/auto/gui/rhi/qrhi/data/simpletextured.vert
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#version 440
|
||||||
|
|
||||||
|
layout(location = 0) in vec4 position;
|
||||||
|
layout(location = 1) in vec2 texcoord;
|
||||||
|
|
||||||
|
layout(location = 0) out vec2 uv;
|
||||||
|
|
||||||
|
out gl_PerVertex { vec4 gl_Position; };
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
uv = texcoord;
|
||||||
|
gl_Position = position;
|
||||||
|
}
|
BIN
tests/auto/gui/rhi/qrhi/data/simpletextured.vert.qsb
Normal file
BIN
tests/auto/gui/rhi/qrhi/data/simpletextured.vert.qsb
Normal file
Binary file not shown.
@ -1,12 +0,0 @@
|
|||||||
#version 440
|
|
||||||
|
|
||||||
layout(location = 0) in vec2 v_texcoord;
|
|
||||||
|
|
||||||
layout(location = 0) out vec4 fragColor;
|
|
||||||
|
|
||||||
layout(binding = 1) uniform sampler2D tex;
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
fragColor = texture(tex, v_texcoord);
|
|
||||||
}
|
|
19
tests/auto/gui/rhi/qrhi/data/textured.frag
Normal file
19
tests/auto/gui/rhi/qrhi/data/textured.frag
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#version 440
|
||||||
|
|
||||||
|
layout(location = 0) in vec2 uv;
|
||||||
|
layout(location = 0) out vec4 fragColor;
|
||||||
|
|
||||||
|
layout(std140, binding = 0) uniform buf {
|
||||||
|
mat4 matrix;
|
||||||
|
float opacity;
|
||||||
|
} ubuf;
|
||||||
|
|
||||||
|
layout(binding = 1) uniform sampler2D tex;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vec4 c = texture(tex, uv);
|
||||||
|
c.a *= ubuf.opacity;
|
||||||
|
c.rgb *= c.a;
|
||||||
|
fragColor = c;
|
||||||
|
}
|
BIN
tests/auto/gui/rhi/qrhi/data/textured.frag.qsb
Normal file
BIN
tests/auto/gui/rhi/qrhi/data/textured.frag.qsb
Normal file
Binary file not shown.
@ -3,16 +3,17 @@
|
|||||||
layout(location = 0) in vec4 position;
|
layout(location = 0) in vec4 position;
|
||||||
layout(location = 1) in vec2 texcoord;
|
layout(location = 1) in vec2 texcoord;
|
||||||
|
|
||||||
layout(location = 0) out vec2 v_texcoord;
|
layout(location = 0) out vec2 uv;
|
||||||
|
|
||||||
layout(std140, binding = 0) uniform buf {
|
layout(std140, binding = 0) uniform buf {
|
||||||
mat4 mvp;
|
mat4 matrix;
|
||||||
|
float opacity;
|
||||||
} ubuf;
|
} ubuf;
|
||||||
|
|
||||||
out gl_PerVertex { vec4 gl_Position; };
|
out gl_PerVertex { vec4 gl_Position; };
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
v_texcoord = texcoord;
|
uv = texcoord;
|
||||||
gl_Position = ubuf.mvp * position;
|
gl_Position = ubuf.matrix * position;
|
||||||
}
|
}
|
BIN
tests/auto/gui/rhi/qrhi/data/textured.vert.qsb
Normal file
BIN
tests/auto/gui/rhi/qrhi/data/textured.vert.qsb
Normal file
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -11,7 +11,7 @@ SUBDIRS=\
|
|||||||
macplist \
|
macplist \
|
||||||
networkselftest \
|
networkselftest \
|
||||||
qaccessibility \
|
qaccessibility \
|
||||||
# qaccessibilitylinux \ # QTBUG-44434
|
# qaccessibilitylinux # QTBUG-44434 \
|
||||||
qaccessibilitymac \
|
qaccessibilitymac \
|
||||||
qcomplextext \
|
qcomplextext \
|
||||||
qfocusevent \
|
qfocusevent \
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
#include <QXmlStreamReader>
|
#include <QXmlStreamReader>
|
||||||
|
|
||||||
extern "C" int LLVMFuzzerTestOneInput(const char *Data, size_t Size) {
|
extern "C" int LLVMFuzzerTestOneInput(const char *Data, size_t Size) {
|
||||||
QXmlStreamReader reader(QByteArray(Data, Size));
|
QXmlStreamReader reader(QByteArray::fromRawData(Data, Size));
|
||||||
while (!reader.atEnd())
|
while (!reader.atEnd())
|
||||||
reader.readNext();
|
reader.readNext();
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -32,6 +32,6 @@
|
|||||||
extern "C" int LLVMFuzzerTestOneInput(const char *data, size_t size) {
|
extern "C" int LLVMFuzzerTestOneInput(const char *data, size_t size) {
|
||||||
static int c = 0;
|
static int c = 0;
|
||||||
static QGuiApplication a(c, nullptr);
|
static QGuiApplication a(c, nullptr);
|
||||||
QColorSpace cs = QColorSpace::fromIccProfile(QByteArray(data, size));
|
QColorSpace cs = QColorSpace::fromIccProfile(QByteArray::fromRawData(data, size));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,6 @@
|
|||||||
extern "C" int LLVMFuzzerTestOneInput(const char *Data, size_t Size) {
|
extern "C" int LLVMFuzzerTestOneInput(const char *Data, size_t Size) {
|
||||||
static int c = 0;
|
static int c = 0;
|
||||||
static QApplication a(c, nullptr);
|
static QApplication a(c, nullptr);
|
||||||
QTextDocument().setHtml(QByteArray(Data, Size));
|
QTextDocument().setHtml(QByteArray::fromRawData(Data, Size));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,6 @@
|
|||||||
#include <QTextDocument>
|
#include <QTextDocument>
|
||||||
|
|
||||||
extern "C" int LLVMFuzzerTestOneInput(const char *Data, size_t Size) {
|
extern "C" int LLVMFuzzerTestOneInput(const char *Data, size_t Size) {
|
||||||
QTextDocument().setMarkdown(QByteArray(Data, Size));
|
QTextDocument().setMarkdown(QByteArray::fromRawData(Data, Size));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user