From 847455bab1026bb640d8d16a0f3537aaff17d67e Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Wed, 5 Dec 2018 15:52:06 +0100 Subject: [PATCH] vk, d3d, gl: Mipmap generation --- examples/rhi/shared/texturedcuberenderer.cpp | 17 +++- .../rhi/shared/triangleoncuberenderer.cpp | 27 +++-- examples/rhi/shared/triangleoncuberenderer.h | 1 + src/rhi/qrhi.cpp | 7 ++ src/rhi/qrhi.h | 6 +- src/rhi/qrhi_p.h | 6 ++ src/rhi/qrhid3d11.cpp | 26 ++++- src/rhi/qrhid3d11_p.h | 6 +- src/rhi/qrhigles2.cpp | 11 +++ src/rhi/qrhigles2_p.h | 6 +- src/rhi/qrhivulkan.cpp | 99 ++++++++++++++++++- src/rhi/qrhivulkan_p.h | 5 + todo.txt | 4 +- 13 files changed, 203 insertions(+), 18 deletions(-) diff --git a/examples/rhi/shared/texturedcuberenderer.cpp b/examples/rhi/shared/texturedcuberenderer.cpp index 5ee995e..22eb77f 100644 --- a/examples/rhi/shared/texturedcuberenderer.cpp +++ b/examples/rhi/shared/texturedcuberenderer.cpp @@ -55,6 +55,7 @@ #include "cube.h" const bool MIPMAP = true; +const bool AUTOGENMIPMAP = true; static QBakedShader getShader(const QString &name) { @@ -78,6 +79,8 @@ void TexturedCubeRenderer::initResources(QRhiRenderPassDescriptor *rp) QRhiTexture::Flags texFlags = 0; if (MIPMAP) 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->build(); @@ -189,12 +192,18 @@ void TexturedCubeRenderer::queueResourceUpdates(QRhiResourceUpdateBatch *resourc if (MIPMAP) { QRhiTextureUploadDescription desc; desc.layers.append(QRhiTextureUploadDescription::Layer()); - // the ghetto mipmap generator... - for (int i = 0, ie = m_r->mipLevelsForSize(m_image.size()); i != ie; ++i) { - QImage image = m_image.scaled(m_r->sizeForMipLevel(i, m_image.size())); - desc.layers[0].mipImages.push_back({ image }); + if (!AUTOGENMIPMAP) { + // the ghetto mipmap generator... + for (int i = 0, ie = m_r->mipLevelsForSize(m_image.size()); i != ie; ++i) { + 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); + if (AUTOGENMIPMAP) + resourceUpdates->generateMips(m_tex); } else { resourceUpdates->uploadTexture(m_tex, m_image); } diff --git a/examples/rhi/shared/triangleoncuberenderer.cpp b/examples/rhi/shared/triangleoncuberenderer.cpp index aa7f9cb..a96e27a 100644 --- a/examples/rhi/shared/triangleoncuberenderer.cpp +++ b/examples/rhi/shared/triangleoncuberenderer.cpp @@ -56,6 +56,8 @@ const bool IMAGE_UNDER_OFFSCREEN_RENDERING = 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 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) 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->build(); @@ -141,12 +155,6 @@ void TriangleOnCubeRenderer::initResources(QRhiRenderPassDescriptor *rp) 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; if (IMAGE_UNDER_OFFSCREEN_RENDERING) rtFlags |= QRhiTextureRenderTarget::PreserveColorContents; @@ -157,6 +165,8 @@ void TriangleOnCubeRenderer::initResources(QRhiRenderPassDescriptor *rp) m_rt = m_r->newTextureRenderTarget(desc, rtFlags); } else { QRhiTextureRenderTargetDescription desc { m_tex }; + if (DS_ATT) + desc.depthStencilBuffer = m_ds; if (MRT) { m_offscreenTriangle.setColorAttCount(2); desc.colorAttachments.append(m_tex2); @@ -228,6 +238,11 @@ void TriangleOnCubeRenderer::releaseResources() m_tex = nullptr; } + if (m_ds) { + m_ds->releaseAndDestroy(); + m_ds = nullptr; + } + if (m_ubuf) { m_ubuf->releaseAndDestroy(); m_ubuf = nullptr; diff --git a/examples/rhi/shared/triangleoncuberenderer.h b/examples/rhi/shared/triangleoncuberenderer.h index ec320a2..5a56bf6 100644 --- a/examples/rhi/shared/triangleoncuberenderer.h +++ b/examples/rhi/shared/triangleoncuberenderer.h @@ -73,6 +73,7 @@ private: bool m_vbufReady = false; QRhiBuffer *m_ubuf = nullptr; QRhiTexture *m_tex = nullptr; + QRhiRenderBuffer *m_ds = nullptr; QRhiTexture *m_tex2 = nullptr; QRhiTexture *m_depthTex = nullptr; QRhiSampler *m_sampler = nullptr; diff --git a/src/rhi/qrhi.cpp b/src/rhi/qrhi.cpp index 667332d..decfee7 100644 --- a/src/rhi/qrhi.cpp +++ b/src/rhi/qrhi.cpp @@ -469,6 +469,11 @@ void QRhiResourceUpdateBatch::readBackTexture(const QRhiReadbackDescription &rb, d->textureReadbacks.append({ rb, result }); } +void QRhiResourceUpdateBatch::generateMips(QRhiTexture *tex) +{ + d->textureMipGens.append({ tex }); +} + void QRhiResourceUpdateBatch::prepareTextureForUse(QRhiTexture *tex, TexturePrepareFlags flags) { d->texturePrepares.append({ tex, flags }); @@ -513,6 +518,7 @@ void QRhiResourceUpdateBatchPrivate::free() textureCopies.clear(); textureResolves.clear(); textureReadbacks.clear(); + textureMipGens.clear(); texturePrepares.clear(); rhi->resUpdPoolMap.clearBit(poolIndex); @@ -527,6 +533,7 @@ void QRhiResourceUpdateBatchPrivate::merge(QRhiResourceUpdateBatchPrivate *other textureCopies += other->textureCopies; textureResolves += other->textureResolves; textureReadbacks += other->textureReadbacks; + textureMipGens += other->textureMipGens; texturePrepares += other->texturePrepares; } diff --git a/src/rhi/qrhi.h b/src/rhi/qrhi.h index 3e5cb44..dbb63c7 100644 --- a/src/rhi/qrhi.h +++ b/src/rhi/qrhi.h @@ -415,7 +415,8 @@ public: CubeMap = 1 << 2, MipMapped = 1 << 3, 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) @@ -918,7 +919,7 @@ public: // Sometimes committing the updates is necessary without starting a render // 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 beginPass(QRhiRenderTarget *rt, @@ -1030,6 +1031,7 @@ public: void copyTexture(QRhiTexture *dst, QRhiTexture *src, const QRhiTextureCopyDescription &desc = QRhiTextureCopyDescription()); void resolveTexture(QRhiTexture *dst, const QRhiTextureResolveDescription &desc); void readBackTexture(const QRhiReadbackDescription &rb, QRhiReadbackResult *result); + void generateMips(QRhiTexture *tex); // 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. diff --git a/src/rhi/qrhi_p.h b/src/rhi/qrhi_p.h index 8177709..912dea4 100644 --- a/src/rhi/qrhi_p.h +++ b/src/rhi/qrhi_p.h @@ -204,6 +204,10 @@ struct QRhiResourceUpdateBatchPrivate QRhiReadbackResult *result; }; + struct TextureMipGen { + QRhiTexture *tex = nullptr; + }; + struct TexturePrepare { TexturePrepare() { } TexturePrepare(QRhiTexture *tex_, QRhiResourceUpdateBatch::TexturePrepareFlags flags_) @@ -220,6 +224,7 @@ struct QRhiResourceUpdateBatchPrivate QVector textureCopies; QVector textureResolves; QVector textureReadbacks; + QVector textureMipGens; QVector texturePrepares; QRhiResourceUpdateBatch *q = nullptr; @@ -238,6 +243,7 @@ Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::TextureUpload, Q_MOVABLE_TYPE Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::TextureCopy, Q_MOVABLE_TYPE); Q_DECLARE_TYPEINFO(QRhiResourceUpdateBatchPrivate::TextureResolve, 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); template diff --git a/src/rhi/qrhid3d11.cpp b/src/rhi/qrhid3d11.cpp index 5b050ba..7a2f9a2 100644 --- a/src/rhi/qrhid3d11.cpp +++ b/src/rhi/qrhid3d11.cpp @@ -955,6 +955,14 @@ void QRhiD3D11::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate 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(); } @@ -1351,6 +1359,9 @@ void QRhiD3D11::executeCommandBuffer(QD3D11CommandBuffer *cbD) cmd.args.resolveSubRes.src, cmd.args.resolveSubRes.srcSubRes, cmd.args.resolveSubRes.format); break; + case QD3D11CommandBuffer::Command::GenMip: + context->GenerateMips(cmd.args.genMip.tex->srv); + break; default: break; } @@ -1574,14 +1585,27 @@ bool QD3D11Texture::build() return false; } } + if (isDepth && hasMipMaps) { + qWarning("Depth texture cannot have mipmaps"); + return false; + } uint bindFlags = D3D11_BIND_SHADER_RESOURCE; + uint miscFlags = isCube ? D3D11_RESOURCE_MISC_TEXTURECUBE : 0; if (m_flags.testFlag(RenderTarget)) { if (isDepth) bindFlags |= D3D11_BIND_DEPTH_STENCIL; else 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; memset(&desc, 0, sizeof(desc)); @@ -1593,7 +1617,7 @@ bool QD3D11Texture::build() desc.SampleDesc = sampleDesc; desc.Usage = D3D11_USAGE_DEFAULT; desc.BindFlags = bindFlags; - desc.MiscFlags = isCube ? D3D11_RESOURCE_MISC_TEXTURECUBE : 0; + desc.MiscFlags = miscFlags; HRESULT hr = rhiD->dev->CreateTexture2D(&desc, nullptr, &tex); if (FAILED(hr)) { diff --git a/src/rhi/qrhid3d11_p.h b/src/rhi/qrhid3d11_p.h index a6db830..3316ca6 100644 --- a/src/rhi/qrhid3d11_p.h +++ b/src/rhi/qrhid3d11_p.h @@ -248,7 +248,8 @@ struct QD3D11CommandBuffer : public QRhiCommandBuffer DrawIndexed, UpdateSubRes, CopySubRes, - ResolveSubRes + ResolveSubRes, + GenMip }; enum ClearFlag { Color = 1, Depth = 2, Stencil = 4 }; Cmd cmd; @@ -335,6 +336,9 @@ struct QD3D11CommandBuffer : public QRhiCommandBuffer UINT srcSubRes; DXGI_FORMAT format; } resolveSubRes; + struct { + QD3D11Texture *tex; + } genMip; } args; }; diff --git a/src/rhi/qrhigles2.cpp b/src/rhi/qrhigles2.cpp index dfedc8b..def8a77 100644 --- a/src/rhi/qrhigles2.cpp +++ b/src/rhi/qrhigles2.cpp @@ -736,6 +736,13 @@ void QRhiGles2::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate 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(); } @@ -1192,6 +1199,10 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb) f->glBindFramebuffer(GL_FRAMEBUFFER, ctx->defaultFramebufferObject()); } 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: break; } diff --git a/src/rhi/qrhigles2_p.h b/src/rhi/qrhigles2_p.h index dd9a2b0..992a004 100644 --- a/src/rhi/qrhigles2_p.h +++ b/src/rhi/qrhigles2_p.h @@ -242,7 +242,8 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer SubImage, CompressedImage, CompressedSubImage, - BlitFromRenderbuffer + BlitFromRenderbuffer, + GenMip }; Cmd cmd; union { @@ -361,6 +362,9 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer int dstLayer; int dstLevel; } blitFromRb; + struct { + QGles2Texture *tex; + } genMip; } args; }; diff --git a/src/rhi/qrhivulkan.cpp b/src/rhi/qrhivulkan.cpp index d4ceedb..85461fb 100644 --- a/src/rhi/qrhivulkan.cpp +++ b/src/rhi/qrhivulkan.cpp @@ -1768,6 +1768,35 @@ void QRhiVulkan::bufferBarrier(QRhiCommandBuffer *cb, QRhiBuffer *buf) 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, VkImageLayout newLayout, VkAccessFlags srcAccess, VkAccessFlags dstAccess, @@ -1817,7 +1846,8 @@ void QRhiVulkan::prepareForTransferDest(QRhiCommandBuffer *cb, QVkTexture *texD) void QRhiVulkan::prepareForTransferSrc(QRhiCommandBuffer *cb, QVkTexture *texD) { 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) imageBarrier(cb, texD, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, @@ -2268,6 +2298,71 @@ void QRhiVulkan::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdat 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(®ion, 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, ®ion, + 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) { if (u.flags.testFlag(QRhiResourceUpdateBatch::TextureRead)) { QVkTexture *utexD = QRHI_RES(QVkTexture, u.tex); @@ -3339,6 +3434,8 @@ bool QVkTexture::build() } if (m_flags.testFlag(QRhiTexture::UsedAsTransferSource)) imageInfo.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + if (m_flags.testFlag(QRhiTexture::UsedWithGenerateMips)) + imageInfo.usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; VmaAllocationCreateInfo allocInfo; memset(&allocInfo, 0, sizeof(allocInfo)); diff --git a/src/rhi/qrhivulkan_p.h b/src/rhi/qrhivulkan_p.h index d0c1853..4ebe6be 100644 --- a/src/rhi/qrhivulkan_p.h +++ b/src/rhi/qrhivulkan_p.h @@ -426,6 +426,11 @@ public: void finishActiveReadbacks(bool forced = false); void bufferBarrier(QRhiCommandBuffer *cb, QRhiBuffer *buf); + void imageSubResBarrier(QRhiCommandBuffer *cb, QRhiTexture *tex, + VkImageLayout oldLayout, VkImageLayout newLayout, + VkAccessFlags srcAccess, VkAccessFlags dstAccess, + VkPipelineStageFlags srcStage, VkPipelineStageFlags dstStage, + int layer, int level); void imageBarrier(QRhiCommandBuffer *cb, QRhiTexture *tex, VkImageLayout newLayout, VkAccessFlags srcAccess, VkAccessFlags dstAccess, diff --git a/todo.txt b/todo.txt index 824b6c4..e39da76 100644 --- a/todo.txt +++ b/todo.txt @@ -11,6 +11,7 @@ mtl: msaa tex+rt mtl: resolveimage (color) mtl: buffer upload with offset/size mtl: color renderbuffer +mtl: mipmap generation gl: tex formats (texture, readback) gl: srgb @@ -19,8 +20,6 @@ test cubemap test cubemap face as target test cubemap face readback -mipmap generation? - advanced blend modes resource import/export, what's the interop story @@ -67,6 +66,7 @@ dxc for d3d as an alternative to fxc? hlsl -> dxc -> spirv -> spirv-cross hmmm... +++ done +vk, d3d, gl: mipmap gen msaa swapchain readback d3d: resolveimage (color) vk: resolveimage (color) -- GitLab