Commit f38f0bb6 authored by Laszlo Agocs's avatar Laszlo Agocs
Browse files

add unfinished msaatexture test

...including some buffer upload improvements...
parent 36bce9c5
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of The Qt Company Ltd nor the names of its
** contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "../shared/examplefw.h"
// Renders into a non-multisample and then a multisample (4x) texture and then
// uses those textures to draw two quads.
static float vertexData[] =
{ // Y up, CCW
-0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, 1.0f, 1.0f,
0.5f, 0.5f, 1.0f, 0.0f
};
static quint16 indexData[] =
{
0, 1, 2, 0, 2, 3
};
static float triangleData[] =
{ // Y up, CCW
0.0f, 0.5f, 1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
0.5f, -0.5f, 0.0f, 0.0f, 1.0f,
};
const int UBUFSZ = 68;
struct {
QRhiBuffer *vbuf = nullptr;
QRhiBuffer *ibuf = nullptr;
QRhiBuffer *ubuf = nullptr;
QRhiTexture *tex = nullptr;
QRhiTexture *msaaTex = nullptr;
QRhiSampler *sampler = nullptr;
QRhiShaderResourceBindings *srbLeft = nullptr;
QRhiShaderResourceBindings *srbRight = nullptr;
QRhiGraphicsPipeline *psLeft = nullptr;
QRhiGraphicsPipeline *psRight = nullptr;
QRhiResourceUpdateBatch *initialUpdates = nullptr;
int rightOfs;
QRhiShaderResourceBindings *triSrb = nullptr;
QRhiGraphicsPipeline *msaaTriPs = nullptr;
QRhiGraphicsPipeline *triPs = nullptr;
QRhiBuffer *triUbuf = nullptr;
QRhiTextureRenderTarget *msaaRt = nullptr;
QRhiRenderPassDescriptor *msaaRtRp = nullptr;
QRhiTextureRenderTarget *rt = nullptr;
QRhiRenderPassDescriptor *rtRp = nullptr;
} d;
void Window::customInit()
{
d.vbuf = m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertexData) + sizeof(triangleData));
d.vbuf->build();
d.ibuf = m_r->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::IndexBuffer, sizeof(indexData));
d.ibuf->build();
d.rightOfs = m_r->ubufAligned(UBUFSZ);
d.ubuf = m_r->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, d.rightOfs + UBUFSZ);
d.ubuf->build();
d.tex = m_r->newTexture(QRhiTexture::RGBA8, QSize(512, 512), 1, QRhiTexture::RenderTarget);
d.tex->build();
d.msaaTex = m_r->newTexture(QRhiTexture::RGBA8, QSize(512, 512), 4, QRhiTexture::RenderTarget);
d.msaaTex->build();
d.initialUpdates = m_r->nextResourceUpdateBatch();
d.initialUpdates->uploadStaticBuffer(d.vbuf, 0, sizeof(vertexData), vertexData);
d.initialUpdates->uploadStaticBuffer(d.vbuf, sizeof(vertexData), sizeof(triangleData), triangleData);
d.initialUpdates->uploadStaticBuffer(d.ibuf, indexData);
d.sampler = m_r->newSampler(QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge);
d.sampler->build();
d.srbLeft = m_r->newShaderResourceBindings();
d.srbLeft->setBindings({
QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d.ubuf, 0, UBUFSZ),
QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.tex, d.sampler)
});
d.srbLeft->build();
d.srbRight = m_r->newShaderResourceBindings();
d.srbRight->setBindings({
QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d.ubuf, d.rightOfs, UBUFSZ),
QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, d.msaaTex, d.sampler)
});
d.srbRight->build();
d.psLeft = m_r->newGraphicsPipeline();
d.psLeft->setShaderStages({
{ QRhiGraphicsShaderStage::Vertex, getShader(QLatin1String(":/texture.vert.qsb")) },
{ QRhiGraphicsShaderStage::Fragment, getShader(QLatin1String(":/texture.frag.qsb")) }
});
QRhiVertexInputLayout inputLayout;
inputLayout.bindings = {
{ 4 * sizeof(float) }
};
inputLayout.attributes = {
{ 0, 0, QRhiVertexInputLayout::Attribute::Float2, 0 },
{ 0, 1, QRhiVertexInputLayout::Attribute::Float2, 2 * sizeof(float) }
};
d.psLeft->setVertexInputLayout(inputLayout);
d.psLeft->setShaderResourceBindings(d.srbLeft);
d.psLeft->setRenderPassDescriptor(m_rp);
d.psLeft->build();
d.psRight = m_r->newGraphicsPipeline();
d.psRight->setShaderStages({
{ QRhiGraphicsShaderStage::Vertex, getShader(QLatin1String(":/texture.vert.qsb")) },
{ QRhiGraphicsShaderStage::Fragment, getShader(QLatin1String(":/texture_ms4.frag.qsb")) }
});
d.psRight->setVertexInputLayout(d.psLeft->vertexInputLayout());
d.psRight->setShaderResourceBindings(d.srbRight);
d.psRight->setRenderPassDescriptor(m_rp);
d.psRight->build();
// set up the offscreen triangle that goes into tex and msaaTex
d.triUbuf = m_r->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 68);
d.triUbuf->build();
d.triSrb = m_r->newShaderResourceBindings();
d.triSrb->setBindings({
QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d.triUbuf)
});
d.triSrb->build();
d.rt = m_r->newTextureRenderTarget({ d.tex });
d.rtRp = d.rt->newCompatibleRenderPassDescriptor();
d.rt->setRenderPassDescriptor(d.rtRp);
d.rt->build();
d.msaaRt = m_r->newTextureRenderTarget({ d.msaaTex });
d.msaaRtRp = d.msaaRt->newCompatibleRenderPassDescriptor();
d.msaaRt->setRenderPassDescriptor(d.msaaRtRp);
d.msaaRt->build();
d.triPs = m_r->newGraphicsPipeline();
d.triPs->setSampleCount(1);
d.triPs->setShaderStages({
{ QRhiGraphicsShaderStage::Vertex, getShader(QLatin1String(":/color.vert.qsb")) },
{ QRhiGraphicsShaderStage::Fragment, getShader(QLatin1String(":/color.frag.qsb")) }
});
inputLayout.bindings = {
{ 5 * sizeof(float) }
};
inputLayout.attributes = {
{ 0, 0, QRhiVertexInputLayout::Attribute::Float2, 0 },
{ 0, 1, QRhiVertexInputLayout::Attribute::Float3, 2 * sizeof(float) }
};
d.triPs->setVertexInputLayout(inputLayout);
d.triPs->setShaderResourceBindings(d.triSrb);
d.triPs->setRenderPassDescriptor(d.rtRp);
d.triPs->build();
d.msaaTriPs = m_r->newGraphicsPipeline();
d.msaaTriPs->setSampleCount(4);
d.msaaTriPs->setShaderStages(d.triPs->shaderStages());
d.msaaTriPs->setVertexInputLayout(d.triPs->vertexInputLayout());
d.msaaTriPs->setShaderResourceBindings(d.triSrb);
d.msaaTriPs->setRenderPassDescriptor(d.msaaRtRp);
d.msaaTriPs->build();
}
void Window::customRelease()
{
if (d.psLeft) {
d.psLeft->releaseAndDestroy();
d.psLeft = nullptr;
}
if (d.psRight) {
d.psRight->releaseAndDestroy();
d.psRight = nullptr;
}
if (d.srbLeft) {
d.srbLeft->releaseAndDestroy();
d.srbLeft = nullptr;
}
if (d.srbRight) {
d.srbRight->releaseAndDestroy();
d.srbRight = nullptr;
}
if (d.triPs) {
d.triPs->releaseAndDestroy();
d.triPs = nullptr;
}
if (d.msaaTriPs) {
d.msaaTriPs->releaseAndDestroy();
d.msaaTriPs = nullptr;
}
if (d.triSrb) {
d.triSrb->releaseAndDestroy();
d.triSrb = nullptr;
}
if (d.triUbuf) {
d.triUbuf->releaseAndDestroy();
d.triUbuf = nullptr;
}
if (d.ubuf) {
d.ubuf->releaseAndDestroy();
d.ubuf = nullptr;
}
if (d.vbuf) {
d.vbuf->releaseAndDestroy();
d.vbuf = nullptr;
}
if (d.ibuf) {
d.ibuf->releaseAndDestroy();
d.ibuf = nullptr;
}
if (d.sampler) {
d.sampler->releaseAndDestroy();
d.sampler = nullptr;
}
if (d.rtRp) {
d.rtRp->releaseAndDestroy();
d.rtRp = nullptr;
}
if (d.rt) {
d.rt->releaseAndDestroy();
d.rt = nullptr;
}
if (d.msaaRtRp) {
d.msaaRtRp->releaseAndDestroy();
d.msaaRtRp = nullptr;
}
if (d.msaaRt) {
d.msaaRt->releaseAndDestroy();
d.msaaRt = nullptr;
}
if (d.msaaTex) {
d.msaaTex->releaseAndDestroy();
d.msaaTex = nullptr;
}
if (d.tex) {
d.tex->releaseAndDestroy();
d.tex = nullptr;
}
}
void Window::customRender()
{
QRhiCommandBuffer *cb = m_sc->currentFrameCommandBuffer();
QRhiResourceUpdateBatch *u = m_r->nextResourceUpdateBatch();
if (d.initialUpdates) {
u->merge(d.initialUpdates);
d.initialUpdates->release();
d.initialUpdates = nullptr;
// onscreen ubuf
QMatrix4x4 mvp = m_proj; // aspect ratio is then wrong when resizing but oh well
mvp.scale(2);
mvp.translate(-0.8f, 0, 0);
u->updateDynamicBuffer(d.ubuf, 0, 64, mvp.constData());
qint32 flip = 0;
u->updateDynamicBuffer(d.ubuf, 64, 4, &flip);
mvp.translate(1.6f, 0, 0);
u->updateDynamicBuffer(d.ubuf, d.rightOfs, 64, mvp.constData());
u->updateDynamicBuffer(d.ubuf, d.rightOfs + 64, 4, &flip);
// offscreen ubuf
mvp = m_r->clipSpaceCorrMatrix();
mvp.perspective(45.0f, d.msaaTex->pixelSize().width() / float(d.msaaTex->pixelSize().height()), 0.01f, 1000.0f);
mvp.translate(0, 0, -2);
u->updateDynamicBuffer(d.triUbuf, 0, 64, mvp.constData());
float opacity = 1.0f;
u->updateDynamicBuffer(d.triUbuf, 64, 4, &opacity);
}
// offscreen
cb->beginPass(d.rt, { 0.5f, 0.2f, 0, 1 }, { 1, 0 });
cb->setGraphicsPipeline(d.triPs);
cb->setViewport({ 0, 0, float(d.msaaTex->pixelSize().width()), float(d.msaaTex->pixelSize().height()) });
cb->setVertexInput(0, { { d.vbuf, sizeof(vertexData) } });
cb->draw(3);
cb->endPass();
// offscreen msaa
cb->beginPass(d.msaaRt, { 0.5f, 0.2f, 0, 1 }, { 1, 0 }, u);
cb->setGraphicsPipeline(d.msaaTriPs);
cb->setViewport({ 0, 0, float(d.msaaTex->pixelSize().width()), float(d.msaaTex->pixelSize().height()) });
cb->setVertexInput(0, { { d.vbuf, sizeof(vertexData) } });
cb->draw(3);
cb->endPass();
// onscreen
const QSize outputSizeInPixels = m_sc->effectivePixelSize();
cb->beginPass(m_sc->currentFrameRenderTarget(), { 0.4f, 0.7f, 0.0f, 1.0f }, { 1.0f, 0 });
cb->setGraphicsPipeline(d.psLeft); // showing the non-msaa version
cb->setViewport({ 0, 0, float(outputSizeInPixels.width()), float(outputSizeInPixels.height()) });
cb->setVertexInput(0, { { d.vbuf, 0 } }, d.ibuf, 0, QRhiCommandBuffer::IndexUInt16);
cb->drawIndexed(6);
cb->setGraphicsPipeline(d.psRight); // showing the msaa version, resolved in the shader
cb->drawIndexed(6);
cb->endPass();
}
TEMPLATE = app
QT += shadertools rhi
SOURCES = \
msaatexture.cpp
RESOURCES = msaatexture.qrc
target.path = $$[QT_INSTALL_EXAMPLES]/rhi/msaatexture
INSTALLS += target
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file alias="qt256.png">../shared/qt256.png</file>
<file alias="color.vert.qsb">../shared/color.vert.qsb</file>
<file alias="color.frag.qsb">../shared/color.frag.qsb</file>
<file alias="texture.vert.qsb">../shared/texture.vert.qsb</file>
<file alias="texture.frag.qsb">../shared/texture.frag.qsb</file>
<file alias="texture_ms4.frag.qsb">../shared/texture_ms4.frag.qsb</file>
</qresource>
</RCC>
......@@ -5,6 +5,7 @@ SUBDIRS += \
compressedtexture_bc1 \
compressedtexture_bc1_subupload \
texuploads \
msaatexture \
plainqwindow_gles2 \
offscreen_gles2
......
......@@ -2,3 +2,4 @@ qsb --glsl "100 es,120" --hlsl 50 --msl 12 -c color.vert -o color.vert.qsb
qsb --glsl "100 es,120" --hlsl 50 --msl 12 -c color.frag -o color.frag.qsb
qsb --glsl "100 es,120" --hlsl 50 --msl 12 -c texture.vert -o texture.vert.qsb
qsb --glsl "100 es,120" --hlsl 50 --msl 12 -c texture.frag -o texture.frag.qsb
qsb --hlsl 50 --msl 12 -c texture_ms4.frag -o texture_ms4.frag.qsb
#version 440
layout(location = 0) in vec2 v_texcoord;
layout(location = 0) out vec4 fragColor;
layout(std140, binding = 0) uniform buf {
mat4 mvp;
int flip;
} ubuf;
layout(binding = 1) uniform sampler2DMS tex;
void main()
{
ivec2 tc = ivec2(floor(vec2(textureSize(tex)) * v_texcoord));
vec4 c = texelFetch(tex, tc, 0) + texelFetch(tex, tc, 1) + texelFetch(tex, tc, 2) + texelFetch(tex, tc, 3);
c /= 4.0;
fragColor = vec4(c.rgb * c.a, c.a);
}
......@@ -434,9 +434,14 @@ void QRhiResourceUpdateBatch::updateDynamicBuffer(QRhiBuffer *buf, int offset, i
d->dynamicBufferUpdates.append({ buf, offset, size, data });
}
void QRhiResourceUpdateBatch::uploadStaticBuffer(QRhiBuffer *buf, int offset, int size, const void *data)
{
d->staticBufferUploads.append({ buf, offset, size, data });
}
void QRhiResourceUpdateBatch::uploadStaticBuffer(QRhiBuffer *buf, const void *data)
{
d->staticBufferUploads.append({ buf, data });
d->staticBufferUploads.append({ buf, 0, 0, data });
}
void QRhiResourceUpdateBatch::uploadTexture(QRhiTexture *tex, const QRhiTextureUploadDescription &desc)
......
......@@ -994,6 +994,7 @@ public:
// beginPass/endPass/resourceUpdate. What exactly then happens underneath
// is hidden from the applications.
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, const void *data);
void uploadTexture(QRhiTexture *tex, const QRhiTextureUploadDescription &desc);
void uploadTexture(QRhiTexture *tex, const QImage &image); // shortcut
......
......@@ -153,11 +153,12 @@ struct QRhiResourceUpdateBatchPrivate
struct StaticBufferUpload {
StaticBufferUpload() { }
StaticBufferUpload(QRhiBuffer *buf_, const void *data_)
: buf(buf_), data(reinterpret_cast<const char *>(data_), buf_->size())
StaticBufferUpload(QRhiBuffer *buf_, int offset_, int size_, const void *data_)
: buf(buf_), offset(offset_), data(reinterpret_cast<const char *>(data_), size_ ? size_ : buf_->size())
{ }
QRhiBuffer *buf = nullptr;
int offset = 0;
QByteArray data;
};
......
......@@ -681,25 +681,23 @@ void QRhiD3D11::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
for (const QRhiResourceUpdateBatchPrivate::StaticBufferUpload &u : ud->staticBufferUploads) {
QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, u.buf);
Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
Q_ASSERT(u.data.size() == bufD->m_size);
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;
if (!(u.data.size() & 0xFF)) {
cmd.args.updateSubRes.hasDstBox = false;
} else {
// Specify the region 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 = box.top = box.front = 0;
box.back = box.bottom = 1;
box.right = u.data.size(); // no -1: right, bottom, back are exclusive, see D3D11_BOX doc
cmd.args.updateSubRes.hasDstBox = true;
cmd.args.updateSubRes.dstBox = box;
}
// 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 = u.offset;
box.top = box.front = 0;
box.back = box.bottom = 1;
box.right = 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);
}
......@@ -735,7 +733,7 @@ void QRhiD3D11::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
}
if (img.depth() == 32) {
const int offset = sy * img.bytesPerLine() + sx * 4;
cmd.args.updateSubRes.src = static_cast<const uchar *>(cbD->retainImage(img)) + offset;
cmd.args.updateSubRes.src = cbD->retainImage(img) + offset;
} else {
img = img.copy(sx, sy, w, h);
bpl = img.bytesPerLine();
......
......@@ -335,11 +335,11 @@ struct QD3D11CommandBuffer : public QRhiCommandBuffer
QVector<QImage> imageRetainPool;
// relies heavily on implicit sharing (no copies of the actual data will be made)
const void *retainData(const QByteArray &data) {
const uchar *retainData(const QByteArray &data) {
dataRetainPool.append(data);
return dataRetainPool.constLast().constData();
return reinterpret_cast<const uchar *>(dataRetainPool.constLast().constData());
}
const void *retainImage(const QImage &image) {
const uchar *retainImage(const QImage &image) {
imageRetainPool.append(image);
return imageRetainPool.constLast().constBits();
}
......
......@@ -553,7 +553,7 @@ void QRhiGles2::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
Q_ASSERT(u.data.size() == bufD->m_size);
if (bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer)) {
memcpy(bufD->ubuf.data(), u.data.constData(), u.data.size());
memcpy(bufD->ubuf.data() + u.offset, u.data.constData(), u.data.size());
bufD->ubufChangeRange = { 0, u.data.size() };
} else {
QGles2CommandBuffer::Command cmd;
......@@ -563,6 +563,7 @@ void QRhiGles2::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
cmd.args.bufferData.size = u.data.size();
cmd.args.bufferData.data = cbD->retainData(u.data);
cbD->commands.append(cmd);
// ### offset??
}
}
......
......@@ -1786,7 +1786,7 @@ void QRhiVulkan::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdat
for (const QRhiResourceUpdateBatchPrivate::StaticBufferUpload &u : ud->staticBufferUploads) {
QVkBuffer *bufD = QRHI_RES(QVkBuffer, u.buf);
Q_ASSERT(bufD->m_type != QRhiBuffer::Dynamic);
Q_ASSERT(u.data.size() == bufD->m_size);
Q_ASSERT(u.offset + u.data.size() <= bufD->m_size);
if (!bufD->stagingBuffers[currentFrameSlot]) {
VkBufferCreateInfo bufferInfo;
......@@ -1817,13 +1817,15 @@ void QRhiVulkan::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdat
qWarning("Failed to map buffer: %d", err);
continue;
}
memcpy(p, u.data.constData(), bufD->m_size);
memcpy(static_cast<uchar *>(p) + u.offset, u.data.constData(), u.data.size());
vmaUnmapMemory(toVmaAllocator(allocator), a);
vmaFlushAllocation(toVmaAllocator(allocator), a, 0, bufD->m_size);
vmaFlushAllocation(toVmaAllocator(allocator), a, u.offset, u.data.size());
VkBufferCopy copyInfo;
memset(&copyInfo, 0, sizeof(copyInfo));
copyInfo.size = bufD->m_size;
copyInfo.srcOffset = u.offset;
copyInfo.dstOffset = u.offset;
copyInfo.size = u.data.size();
df->vkCmdCopyBuffer(cbD->cb, bufD->stagingBuffers[currentFrameSlot], bufD->buffers[0], 1, &copyInfo);
bufferBarrier(cb, u.buf);
......
......@@ -9,11 +9,14 @@ mtl: msaa (onscreen)
mtl: srgb (tex, swapchain buf)
mtl: msaa tex+rt
mtl: resolveimage (color)
mtl: buffer upload with offset/size
test cubemap
test cubemap face as target
face cubemap readback? (test vk/d3d, impl for gl/mtl)
gl: buffer upload with offset/size
d3d: resolveimage (color)
vk, gl: msaa tex+rt