Commit 847455ba authored by Laszlo Agocs's avatar Laszlo Agocs

vk, d3d, gl: Mipmap generation

parent 1c951c31
...@@ -55,6 +55,7 @@ ...@@ -55,6 +55,7 @@
#include "cube.h" #include "cube.h"
const bool MIPMAP = true; const bool MIPMAP = true;
const bool AUTOGENMIPMAP = true;
static QBakedShader getShader(const QString &name) static QBakedShader getShader(const QString &name)
{ {
...@@ -78,6 +79,8 @@ void TexturedCubeRenderer::initResources(QRhiRenderPassDescriptor *rp) ...@@ -78,6 +79,8 @@ void TexturedCubeRenderer::initResources(QRhiRenderPassDescriptor *rp)
QRhiTexture::Flags texFlags = 0; QRhiTexture::Flags texFlags = 0;
if (MIPMAP) if (MIPMAP)
texFlags |= QRhiTexture::MipMapped; texFlags |= QRhiTexture::MipMapped;
if (AUTOGENMIPMAP)
texFlags |= QRhiTexture::UsedWithGenerateMips;
m_tex = m_r->newTexture(QRhiTexture::RGBA8, QSize(m_image.width(), m_image.height()), 1, texFlags); m_tex = m_r->newTexture(QRhiTexture::RGBA8, QSize(m_image.width(), m_image.height()), 1, texFlags);
m_tex->build(); m_tex->build();
...@@ -189,12 +192,18 @@ void TexturedCubeRenderer::queueResourceUpdates(QRhiResourceUpdateBatch *resourc ...@@ -189,12 +192,18 @@ void TexturedCubeRenderer::queueResourceUpdates(QRhiResourceUpdateBatch *resourc
if (MIPMAP) { if (MIPMAP) {
QRhiTextureUploadDescription desc; QRhiTextureUploadDescription desc;
desc.layers.append(QRhiTextureUploadDescription::Layer()); desc.layers.append(QRhiTextureUploadDescription::Layer());
// the ghetto mipmap generator... if (!AUTOGENMIPMAP) {
for (int i = 0, ie = m_r->mipLevelsForSize(m_image.size()); i != ie; ++i) { // the ghetto mipmap generator...
QImage image = m_image.scaled(m_r->sizeForMipLevel(i, m_image.size())); for (int i = 0, ie = m_r->mipLevelsForSize(m_image.size()); i != ie; ++i) {
desc.layers[0].mipImages.push_back({ image }); QImage image = m_image.scaled(m_r->sizeForMipLevel(i, m_image.size()));
desc.layers[0].mipImages.push_back({ image });
}
} else {
desc.layers[0].mipImages.push_back({ m_image });
} }
resourceUpdates->uploadTexture(m_tex, desc); resourceUpdates->uploadTexture(m_tex, desc);
if (AUTOGENMIPMAP)
resourceUpdates->generateMips(m_tex);
} else { } else {
resourceUpdates->uploadTexture(m_tex, m_image); resourceUpdates->uploadTexture(m_tex, m_image);
} }
......
...@@ -56,6 +56,8 @@ ...@@ -56,6 +56,8 @@
const bool IMAGE_UNDER_OFFSCREEN_RENDERING = false; const bool IMAGE_UNDER_OFFSCREEN_RENDERING = false;
const bool UPLOAD_UNDERLAY_ON_EVERY_FRAME = false; const bool UPLOAD_UNDERLAY_ON_EVERY_FRAME = false;
const bool DS_ATT = false; // have a depth-stencil attachment for the offscreen pass
const bool DEPTH_TEXTURE = false; // offscreen pass uses a depth texture (verify with renderdoc etc., ignore valid.layer about ps slot 0) const bool DEPTH_TEXTURE = false; // offscreen pass uses a depth texture (verify with renderdoc etc., ignore valid.layer about ps slot 0)
const bool MRT = false; // two textures, the second is just cleared as the shader does not write anything (valid.layer may warn but for testing that's ok) const bool MRT = false; // two textures, the second is just cleared as the shader does not write anything (valid.layer may warn but for testing that's ok)
...@@ -95,6 +97,18 @@ void TriangleOnCubeRenderer::initResources(QRhiRenderPassDescriptor *rp) ...@@ -95,6 +97,18 @@ void TriangleOnCubeRenderer::initResources(QRhiRenderPassDescriptor *rp)
m_tex2->build(); m_tex2->build();
} }
if (DS_ATT) {
m_offscreenTriangle.setDepthWrite(true);
m_ds = m_r->newRenderBuffer(QRhiRenderBuffer::DepthStencil, m_tex->pixelSize());
m_ds->build();
}
if (DEPTH_TEXTURE) {
m_offscreenTriangle.setDepthWrite(true);
m_depthTex = m_r->newTexture(QRhiTexture::D32, OFFSCREEN_SIZE, 1, QRhiTexture::RenderTarget);
m_depthTex->build();
}
m_sampler = m_r->newSampler(QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None, QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge); m_sampler = m_r->newSampler(QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None, QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge);
m_sampler->build(); m_sampler->build();
...@@ -141,12 +155,6 @@ void TriangleOnCubeRenderer::initResources(QRhiRenderPassDescriptor *rp) ...@@ -141,12 +155,6 @@ void TriangleOnCubeRenderer::initResources(QRhiRenderPassDescriptor *rp)
m_ps->build(); m_ps->build();
if (DEPTH_TEXTURE) {
m_offscreenTriangle.setDepthWrite(true);
m_depthTex = m_r->newTexture(QRhiTexture::D32, OFFSCREEN_SIZE, 1, QRhiTexture::RenderTarget);
m_depthTex->build();
}
QRhiTextureRenderTarget::Flags rtFlags = 0; QRhiTextureRenderTarget::Flags rtFlags = 0;
if (IMAGE_UNDER_OFFSCREEN_RENDERING) if (IMAGE_UNDER_OFFSCREEN_RENDERING)
rtFlags |= QRhiTextureRenderTarget::PreserveColorContents; rtFlags |= QRhiTextureRenderTarget::PreserveColorContents;
...@@ -157,6 +165,8 @@ void TriangleOnCubeRenderer::initResources(QRhiRenderPassDescriptor *rp) ...@@ -157,6 +165,8 @@ void TriangleOnCubeRenderer::initResources(QRhiRenderPassDescriptor *rp)
m_rt = m_r->newTextureRenderTarget(desc, rtFlags); m_rt = m_r->newTextureRenderTarget(desc, rtFlags);
} else { } else {
QRhiTextureRenderTargetDescription desc { m_tex }; QRhiTextureRenderTargetDescription desc { m_tex };
if (DS_ATT)
desc.depthStencilBuffer = m_ds;
if (MRT) { if (MRT) {
m_offscreenTriangle.setColorAttCount(2); m_offscreenTriangle.setColorAttCount(2);
desc.colorAttachments.append(m_tex2); desc.colorAttachments.append(m_tex2);
...@@ -228,6 +238,11 @@ void TriangleOnCubeRenderer::releaseResources() ...@@ -228,6 +238,11 @@ void TriangleOnCubeRenderer::releaseResources()
m_tex = nullptr; m_tex = nullptr;
} }
if (m_ds) {
m_ds->releaseAndDestroy();
m_ds = nullptr;
}
if (m_ubuf) { if (m_ubuf) {
m_ubuf->releaseAndDestroy(); m_ubuf->releaseAndDestroy();
m_ubuf = nullptr; m_ubuf = nullptr;
......
...@@ -73,6 +73,7 @@ private: ...@@ -73,6 +73,7 @@ private:
bool m_vbufReady = false; bool m_vbufReady = false;
QRhiBuffer *m_ubuf = nullptr; QRhiBuffer *m_ubuf = nullptr;
QRhiTexture *m_tex = nullptr; QRhiTexture *m_tex = nullptr;
QRhiRenderBuffer *m_ds = nullptr;
QRhiTexture *m_tex2 = nullptr; QRhiTexture *m_tex2 = nullptr;
QRhiTexture *m_depthTex = nullptr; QRhiTexture *m_depthTex = nullptr;
QRhiSampler *m_sampler = nullptr; QRhiSampler *m_sampler = nullptr;
......
...@@ -469,6 +469,11 @@ void QRhiResourceUpdateBatch::readBackTexture(const QRhiReadbackDescription &rb, ...@@ -469,6 +469,11 @@ void QRhiResourceUpdateBatch::readBackTexture(const QRhiReadbackDescription &rb,
d->textureReadbacks.append({ rb, result }); d->textureReadbacks.append({ rb, result });
} }
void QRhiResourceUpdateBatch::generateMips(QRhiTexture *tex)
{
d->textureMipGens.append({ tex });
}
void QRhiResourceUpdateBatch::prepareTextureForUse(QRhiTexture *tex, TexturePrepareFlags flags) void QRhiResourceUpdateBatch::prepareTextureForUse(QRhiTexture *tex, TexturePrepareFlags flags)
{ {
d->texturePrepares.append({ tex, flags }); d->texturePrepares.append({ tex, flags });
...@@ -513,6 +518,7 @@ void QRhiResourceUpdateBatchPrivate::free() ...@@ -513,6 +518,7 @@ void QRhiResourceUpdateBatchPrivate::free()
textureCopies.clear(); textureCopies.clear();
textureResolves.clear(); textureResolves.clear();
textureReadbacks.clear(); textureReadbacks.clear();
textureMipGens.clear();
texturePrepares.clear(); texturePrepares.clear();
rhi->resUpdPoolMap.clearBit(poolIndex); rhi->resUpdPoolMap.clearBit(poolIndex);
...@@ -527,6 +533,7 @@ void QRhiResourceUpdateBatchPrivate::merge(QRhiResourceUpdateBatchPrivate *other ...@@ -527,6 +533,7 @@ void QRhiResourceUpdateBatchPrivate::merge(QRhiResourceUpdateBatchPrivate *other
textureCopies += other->textureCopies; textureCopies += other->textureCopies;
textureResolves += other->textureResolves; textureResolves += other->textureResolves;
textureReadbacks += other->textureReadbacks; textureReadbacks += other->textureReadbacks;
textureMipGens += other->textureMipGens;
texturePrepares += other->texturePrepares; texturePrepares += other->texturePrepares;
} }
......
...@@ -415,7 +415,8 @@ public: ...@@ -415,7 +415,8 @@ public:
CubeMap = 1 << 2, CubeMap = 1 << 2,
MipMapped = 1 << 3, MipMapped = 1 << 3,
sRGB = 1 << 4, sRGB = 1 << 4,
UsedAsTransferSource = 1 << 5 // will (also) be used as the source of a readback or copy or resolve UsedAsTransferSource = 1 << 5, // will (also) be used as the source of a readback or copy or resolve
UsedWithGenerateMips = 1 << 6
}; };
Q_DECLARE_FLAGS(Flags, Flag) Q_DECLARE_FLAGS(Flags, Flag)
...@@ -918,7 +919,7 @@ public: ...@@ -918,7 +919,7 @@ public:
// Sometimes committing the updates is necessary without starting a render // Sometimes committing the updates is necessary without starting a render
// pass. Not often needed, updates should typically be passed to beginPass // pass. Not often needed, updates should typically be passed to beginPass
// (or endPass, in case of readbacks) instead. // (or endPass, in case of readbacks or resolves) instead.
void resourceUpdate(QRhiResourceUpdateBatch *resourceUpdates); void resourceUpdate(QRhiResourceUpdateBatch *resourceUpdates);
void beginPass(QRhiRenderTarget *rt, void beginPass(QRhiRenderTarget *rt,
...@@ -1030,6 +1031,7 @@ public: ...@@ -1030,6 +1031,7 @@ public:
void copyTexture(QRhiTexture *dst, QRhiTexture *src, const QRhiTextureCopyDescription &desc = QRhiTextureCopyDescription()); void copyTexture(QRhiTexture *dst, QRhiTexture *src, const QRhiTextureCopyDescription &desc = QRhiTextureCopyDescription());
void resolveTexture(QRhiTexture *dst, const QRhiTextureResolveDescription &desc); void resolveTexture(QRhiTexture *dst, const QRhiTextureResolveDescription &desc);
void readBackTexture(const QRhiReadbackDescription &rb, QRhiReadbackResult *result); void readBackTexture(const QRhiReadbackDescription &rb, QRhiReadbackResult *result);
void generateMips(QRhiTexture *tex);
// This is not normally needed, textures that have an upload or are used // This is not normally needed, textures that have an upload or are used
// with a TextureRenderTarget will be fine without it. May be more relevant later. // with a TextureRenderTarget will be fine without it. May be more relevant later.
......
...@@ -204,6 +204,10 @@ struct QRhiResourceUpdateBatchPrivate ...@@ -204,6 +204,10 @@ struct QRhiResourceUpdateBatchPrivate
QRhiReadbackResult *result; QRhiReadbackResult *result;
}; };
struct TextureMipGen {
QRhiTexture *tex = nullptr;
};
struct TexturePrepare { struct TexturePrepare {
TexturePrepare() { } TexturePrepare() { }
TexturePrepare(QRhiTexture *tex_, QRhiResourceUpdateBatch::TexturePrepareFlags flags_) TexturePrepare(QRhiTexture *tex_, QRhiResourceUpdateBatch::TexturePrepareFlags flags_)
...@@ -220,6 +224,7 @@ struct QRhiResourceUpdateBatchPrivate ...@@ -220,6 +224,7 @@ struct QRhiResourceUpdateBatchPrivate
QVector<TextureCopy> textureCopies; QVector<TextureCopy> textureCopies;
QVector<TextureResolve> textureResolves; QVector<TextureResolve> textureResolves;
QVector<TextureRead> textureReadbacks; QVector<TextureRead> textureReadbacks;
QVector<TextureMipGen> textureMipGens;
QVector<TexturePrepare> texturePrepares; QVector<TexturePrepare> texturePrepares;
QRhiResourceUpdateBatch *q = nullptr; QRhiResourceUpdateBatch *q = nullptr;
...@@ -238,6 +243,7 @@ Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::TextureUpload, Q_MOVABLE_TYPE ...@@ -238,6 +243,7 @@ Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::TextureUpload, Q_MOVABLE_TYPE
Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::TextureCopy, Q_MOVABLE_TYPE); Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::TextureCopy, Q_MOVABLE_TYPE);
Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::TextureResolve, Q_MOVABLE_TYPE); Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::TextureResolve, Q_MOVABLE_TYPE);
Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::TextureRead, Q_MOVABLE_TYPE); Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::TextureRead, Q_MOVABLE_TYPE);
Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::TextureMipGen, Q_MOVABLE_TYPE);
Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::TexturePrepare, Q_MOVABLE_TYPE); Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::TexturePrepare, Q_MOVABLE_TYPE);
template<typename T> template<typename T>
......
...@@ -955,6 +955,14 @@ void QRhiD3D11::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate ...@@ -955,6 +955,14 @@ void QRhiD3D11::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
activeReadbacks.append(aRb); activeReadbacks.append(aRb);
} }
for (const QRhiResourceUpdateBatchPrivate::TextureMipGen &u : ud->textureMipGens) {
Q_ASSERT(u.tex->flags().testFlag(QRhiTexture::UsedWithGenerateMips));
QD3D11CommandBuffer::Command cmd;
cmd.cmd = QD3D11CommandBuffer::Command::GenMip;
cmd.args.genMip.tex = QRHI_RES(QD3D11Texture, u.tex);
cbD->commands.append(cmd);
}
ud->free(); ud->free();
} }
...@@ -1351,6 +1359,9 @@ void QRhiD3D11::executeCommandBuffer(QD3D11CommandBuffer *cbD) ...@@ -1351,6 +1359,9 @@ void QRhiD3D11::executeCommandBuffer(QD3D11CommandBuffer *cbD)
cmd.args.resolveSubRes.src, cmd.args.resolveSubRes.srcSubRes, cmd.args.resolveSubRes.src, cmd.args.resolveSubRes.srcSubRes,
cmd.args.resolveSubRes.format); cmd.args.resolveSubRes.format);
break; break;
case QD3D11CommandBuffer::Command::GenMip:
context->GenerateMips(cmd.args.genMip.tex->srv);
break;
default: default:
break; break;
} }
...@@ -1574,14 +1585,27 @@ bool QD3D11Texture::build() ...@@ -1574,14 +1585,27 @@ bool QD3D11Texture::build()
return false; return false;
} }
} }
if (isDepth && hasMipMaps) {
qWarning("Depth texture cannot have mipmaps");
return false;
}
uint bindFlags = D3D11_BIND_SHADER_RESOURCE; uint bindFlags = D3D11_BIND_SHADER_RESOURCE;
uint miscFlags = isCube ? D3D11_RESOURCE_MISC_TEXTURECUBE : 0;
if (m_flags.testFlag(RenderTarget)) { if (m_flags.testFlag(RenderTarget)) {
if (isDepth) if (isDepth)
bindFlags |= D3D11_BIND_DEPTH_STENCIL; bindFlags |= D3D11_BIND_DEPTH_STENCIL;
else else
bindFlags |= D3D11_BIND_RENDER_TARGET; bindFlags |= D3D11_BIND_RENDER_TARGET;
} }
if (m_flags.testFlag(UsedWithGenerateMips)) {
if (isDepth) {
qWarning("Depth texture cannot have mipmaps generated");
return false;
}
bindFlags |= D3D11_BIND_RENDER_TARGET;
miscFlags |= D3D11_RESOURCE_MISC_GENERATE_MIPS;
}
D3D11_TEXTURE2D_DESC desc; D3D11_TEXTURE2D_DESC desc;
memset(&desc, 0, sizeof(desc)); memset(&desc, 0, sizeof(desc));
...@@ -1593,7 +1617,7 @@ bool QD3D11Texture::build() ...@@ -1593,7 +1617,7 @@ bool QD3D11Texture::build()
desc.SampleDesc = sampleDesc; desc.SampleDesc = sampleDesc;
desc.Usage = D3D11_USAGE_DEFAULT; desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = bindFlags; desc.BindFlags = bindFlags;
desc.MiscFlags = isCube ? D3D11_RESOURCE_MISC_TEXTURECUBE : 0; desc.MiscFlags = miscFlags;
HRESULT hr = rhiD->dev->CreateTexture2D(&desc, nullptr, &tex); HRESULT hr = rhiD->dev->CreateTexture2D(&desc, nullptr, &tex);
if (FAILED(hr)) { if (FAILED(hr)) {
......
...@@ -248,7 +248,8 @@ struct QD3D11CommandBuffer : public QRhiCommandBuffer ...@@ -248,7 +248,8 @@ struct QD3D11CommandBuffer : public QRhiCommandBuffer
DrawIndexed, DrawIndexed,
UpdateSubRes, UpdateSubRes,
CopySubRes, CopySubRes,
ResolveSubRes ResolveSubRes,
GenMip
}; };
enum ClearFlag { Color = 1, Depth = 2, Stencil = 4 }; enum ClearFlag { Color = 1, Depth = 2, Stencil = 4 };
Cmd cmd; Cmd cmd;
...@@ -335,6 +336,9 @@ struct QD3D11CommandBuffer : public QRhiCommandBuffer ...@@ -335,6 +336,9 @@ struct QD3D11CommandBuffer : public QRhiCommandBuffer
UINT srcSubRes; UINT srcSubRes;
DXGI_FORMAT format; DXGI_FORMAT format;
} resolveSubRes; } resolveSubRes;
struct {
QD3D11Texture *tex;
} genMip;
} args; } args;
}; };
......
...@@ -736,6 +736,13 @@ void QRhiGles2::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate ...@@ -736,6 +736,13 @@ void QRhiGles2::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
cbD->commands.append(cmd); cbD->commands.append(cmd);
} }
for (const QRhiResourceUpdateBatchPrivate::TextureMipGen &u : ud->textureMipGens) {
QGles2CommandBuffer::Command cmd;
cmd.cmd = QGles2CommandBuffer::Command::GenMip;
cmd.args.genMip.tex = QRHI_RES(QGles2Texture, u.tex);
cbD->commands.append(cmd);
}
ud->free(); ud->free();
} }
...@@ -1192,6 +1199,10 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb) ...@@ -1192,6 +1199,10 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
f->glBindFramebuffer(GL_FRAMEBUFFER, ctx->defaultFramebufferObject()); f->glBindFramebuffer(GL_FRAMEBUFFER, ctx->defaultFramebufferObject());
} }
break; break;
case QGles2CommandBuffer::Command::GenMip:
f->glBindTexture(cmd.args.genMip.tex->target, cmd.args.genMip.tex->texture);
f->glGenerateMipmap(cmd.args.genMip.tex->target);
break;
default: default:
break; break;
} }
......
...@@ -242,7 +242,8 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer ...@@ -242,7 +242,8 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer
SubImage, SubImage,
CompressedImage, CompressedImage,
CompressedSubImage, CompressedSubImage,
BlitFromRenderbuffer BlitFromRenderbuffer,
GenMip
}; };
Cmd cmd; Cmd cmd;
union { union {
...@@ -361,6 +362,9 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer ...@@ -361,6 +362,9 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer
int dstLayer; int dstLayer;
int dstLevel; int dstLevel;
} blitFromRb; } blitFromRb;
struct {
QGles2Texture *tex;
} genMip;
} args; } args;
}; };
......
...@@ -1768,6 +1768,35 @@ void QRhiVulkan::bufferBarrier(QRhiCommandBuffer *cb, QRhiBuffer *buf) ...@@ -1768,6 +1768,35 @@ void QRhiVulkan::bufferBarrier(QRhiCommandBuffer *cb, QRhiBuffer *buf)
0, 0, nullptr, 1, &bufMemBarrier, 0, nullptr); 0, 0, nullptr, 1, &bufMemBarrier, 0, nullptr);
} }
void QRhiVulkan::imageSubResBarrier(QRhiCommandBuffer *cb, QRhiTexture *tex,
VkImageLayout oldLayout, VkImageLayout newLayout,
VkAccessFlags srcAccess, VkAccessFlags dstAccess,
VkPipelineStageFlags srcStage, VkPipelineStageFlags dstStage,
int layer, int level)
{
QVkTexture *texD = QRHI_RES(QVkTexture, tex);
VkImageMemoryBarrier barrier;
memset(&barrier, 0, sizeof(barrier));
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
barrier.subresourceRange.baseMipLevel = level;
barrier.subresourceRange.levelCount = 1;
barrier.subresourceRange.baseArrayLayer = layer;
barrier.subresourceRange.layerCount = 1;
barrier.oldLayout = oldLayout;
barrier.newLayout = newLayout;
barrier.srcAccessMask = srcAccess;
barrier.dstAccessMask = dstAccess;
barrier.image = texD->image;
df->vkCmdPipelineBarrier(QRHI_RES(QVkCommandBuffer, cb)->cb,
srcStage,
dstStage,
0, 0, nullptr, 0, nullptr,
1, &barrier);
}
void QRhiVulkan::imageBarrier(QRhiCommandBuffer *cb, QRhiTexture *tex, void QRhiVulkan::imageBarrier(QRhiCommandBuffer *cb, QRhiTexture *tex,
VkImageLayout newLayout, VkImageLayout newLayout,
VkAccessFlags srcAccess, VkAccessFlags dstAccess, VkAccessFlags srcAccess, VkAccessFlags dstAccess,
...@@ -1817,7 +1846,8 @@ void QRhiVulkan::prepareForTransferDest(QRhiCommandBuffer *cb, QVkTexture *texD) ...@@ -1817,7 +1846,8 @@ void QRhiVulkan::prepareForTransferDest(QRhiCommandBuffer *cb, QVkTexture *texD)
void QRhiVulkan::prepareForTransferSrc(QRhiCommandBuffer *cb, QVkTexture *texD) void QRhiVulkan::prepareForTransferSrc(QRhiCommandBuffer *cb, QVkTexture *texD)
{ {
if (texD->layout != VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) { if (texD->layout != VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) {
Q_ASSERT(texD->m_flags.testFlag(QRhiTexture::UsedAsTransferSource)); Q_ASSERT(texD->m_flags.testFlag(QRhiTexture::UsedAsTransferSource)
|| texD->m_flags.testFlag(QRhiTexture::UsedWithGenerateMips));
// assume the texture was written (so block up to color output, not just fragment) // assume the texture was written (so block up to color output, not just fragment)
imageBarrier(cb, texD, imageBarrier(cb, texD,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
...@@ -2268,6 +2298,71 @@ void QRhiVulkan::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdat ...@@ -2268,6 +2298,71 @@ void QRhiVulkan::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdat
activeReadbacks.append(aRb); activeReadbacks.append(aRb);
} }
for (const QRhiResourceUpdateBatchPrivate::TextureMipGen &u : ud->textureMipGens) {
QVkTexture *utexD = QRHI_RES(QVkTexture, u.tex);
Q_ASSERT(utexD->m_flags.testFlag(QRhiTexture::UsedWithGenerateMips));
int w = utexD->m_pixelSize.width();
int h = utexD->m_pixelSize.height();
prepareForTransferSrc(cb, utexD);
for (int level = 1; level < utexD->mipLevelCount; ++level) {
if (level > 1) {
imageSubResBarrier(cb, utexD,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
0, level - 1);
}
imageSubResBarrier(cb, utexD,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_ACCESS_TRANSFER_READ_BIT, VK_ACCESS_TRANSFER_WRITE_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
0, level);
VkImageBlit region;
memset(&region, 0, sizeof(region));
region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
region.srcSubresource.mipLevel = level - 1;
region.srcSubresource.baseArrayLayer = 0;
region.srcSubresource.layerCount = 1;
region.srcOffsets[1].x = w;
region.srcOffsets[1].y = h;
region.srcOffsets[1].z = 1;
region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
region.dstSubresource.mipLevel = level;
region.dstSubresource.baseArrayLayer = 0;
region.dstSubresource.layerCount = 1;
region.dstOffsets[1].x = w >> 1;
region.dstOffsets[1].y = h >> 1;
region.dstOffsets[1].z = 1;
df->vkCmdBlitImage(cbD->cb,
utexD->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
utexD->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1, &region,
VK_FILTER_LINEAR);
w >>= 1;
h >>= 1;
if (level == utexD->mipLevelCount - 1) {
imageSubResBarrier(cb, utexD,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
0, level);
}
}
finishTransferDest(cb, utexD);
}
for (const QRhiResourceUpdateBatchPrivate::TexturePrepare &u : ud->texturePrepares) { for (const QRhiResourceUpdateBatchPrivate::TexturePrepare &u : ud->texturePrepares) {
if (u.flags.testFlag(QRhiResourceUpdateBatch::TextureRead)) { if (u.flags.testFlag(QRhiResourceUpdateBatch::TextureRead)) {
QVkTexture *utexD = QRHI_RES(QVkTexture, u.tex); QVkTexture *utexD = QRHI_RES(QVkTexture, u.tex);
...@@ -3339,6 +3434,8 @@ bool QVkTexture::build() ...@@ -3339,6 +3434,8 @@ bool QVkTexture::build()
} }
if (m_flags.testFlag(QRhiTexture::UsedAsTransferSource)) if (m_flags.testFlag(QRhiTexture::UsedAsTransferSource))
imageInfo.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; imageInfo.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
if (m_flags.testFlag(QRhiTexture::UsedWithGenerateMips))
imageInfo.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
VmaAllocationCreateInfo allocInfo; VmaAllocationCreateInfo allocInfo;
memset(&allocInfo, 0, sizeof(allocInfo)); memset(&allocInfo, 0, sizeof(allocInfo));
......
...@@ -426,6 +426,11 @@ public: ...@@ -426,6 +426,11 @@ public:
void finishActiveReadbacks(bool forced = false); void finishActiveReadbacks(bool forced = false);