diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformDescriptorBinder.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformDescriptorBinder.cpp index 5d973ccc..9786233d 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformDescriptorBinder.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformDescriptorBinder.cpp @@ -532,7 +532,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { } outImageInfo = { .sampler = m_samplerManager->GetOrCreateSampler(*samplerToUse), - .imageView = resource->view, + .imageView = resource->fullView, .imageLayout = resource->layout, }; return outImageInfo.sampler != VK_NULL_HANDLE; @@ -554,7 +554,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { outImageInfo = { .sampler = m_samplerManager->GetOrCreateSampler(*samplerBindingOverride.sampler), - .imageView = resource->view, + .imageView = resource->fullView, .imageLayout = resource->layout, }; return outImageInfo.sampler != VK_NULL_HANDLE; diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp index 97dbe669..ab53ddee 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkRenderPassManager.cpp @@ -66,6 +66,10 @@ namespace MobileGL::MG_Backend::DirectVulkan { else if (att.IsRenderbuffer()) contentPtr = att.GetRenderbuffer().get(); XXHASH_VERIFY(XXH64_update(m_hashState, &contentPtr, sizeof(contentPtr))); + if (att.IsTexture()) { + const Int textureLevel = att.GetTextureLevel(); + XXHASH_VERIFY(XXH64_update(m_hashState, &textureLevel, sizeof(textureLevel))); + } if (includePendingClear && att.IsTexture()) { auto* texture = att.GetTexture().get(); @@ -158,6 +162,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { auto& att = fbo.GetAttachment(drawbuf); auto* texture = att.GetTexture().get(); + const Uint32 attachmentMipLevel = static_cast(std::max(att.GetTextureLevel(), 0)); const auto textureTarget = texture->GetTarget(); // Color attachment description @@ -190,9 +195,9 @@ namespace MobileGL::MG_Backend::DirectVulkan { }); } if (width == 0) - width = texture2d->GetBaseSize().x(); + width = att.GetSize().x(); if (height == 0) - height = texture2d->GetBaseSize().y(); + height = att.GetSize().y(); if (isDefaultFbo) { const auto& swapchainViews = m_swapchainObject.GetImageViews(); @@ -215,7 +220,9 @@ namespace MobileGL::MG_Backend::DirectVulkan { .texture = texture, .finalLayout = desc.finalLayout, }); - attachmentViews[i] = textureResources[i]->view; + attachmentViews[i] = m_textureManager.GetOrCreateViewAtMipLevel(*texture, attachmentMipLevel); + MOBILEGL_ASSERT(attachmentViews[i] != VK_NULL_HANDLE, + "GetOrCreateRenderPass: GetOrCreateAttachmentView failed at color attachment %d", i); } if (!hasClear && trackedColorLayout == VK_IMAGE_LAYOUT_UNDEFINED) { @@ -249,6 +256,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { VkTextureManager::TextureResource* depthTextureResource = nullptr; if (depthAtt.IsComplete() && depthAtt.IsTexture()) { auto& texture = *depthAtt.GetTexture(); + const Uint32 attachmentMipLevel = static_cast(std::max(depthAtt.GetTextureLevel(), 0)); const Uint32 depthAttachmentIndex = static_cast(attachmentDescriptions.size()); ClearAttachmentPayload clearPayload{}; Bool hasClear = m_clearManager.GetPendingClear(&texture, clearPayload); @@ -311,11 +319,12 @@ namespace MobileGL::MG_Backend::DirectVulkan { .finalLayout = depthAttachmentDescription.finalLayout, }); textureResources.emplace_back(depthTextureResource); - attachmentViews.emplace_back(depthTextureResource->view); + attachmentViews.emplace_back(m_textureManager.GetOrCreateViewAtMipLevel(texture, attachmentMipLevel)); + MOBILEGL_ASSERT(attachmentViews.back() != VK_NULL_HANDLE, + "GetOrCreateRenderPass: GetOrCreateAttachmentView failed at depth attachment"); if (width == 0 || height == 0) { - auto texture2d = static_cast(&texture); - width = texture2d->GetBaseSize().x(); - height = texture2d->GetBaseSize().y(); + width = depthAtt.GetSize().x(); + height = depthAtt.GetSize().y(); } } attachmentDescriptions.emplace_back(depthAttachmentDescription); diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.cpp index 29b029a5..8068209f 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.cpp @@ -74,6 +74,30 @@ namespace MobileGL::MG_Backend::DirectVulkan { return &(it->second); } + VkImageView VkTextureManager::GetOrCreateViewAtMipLevel(MG_State::GLState::ITextureObject& texture, Uint32 mipLevel) { + TextureResource* resource = SyncTextureAndGetDescriptor(texture); + if (resource == nullptr || resource->image == VK_NULL_HANDLE || mipLevel >= resource->mipLevels) { + return VK_NULL_HANDLE; + } + + if (resource->perMipViews.size() != resource->mipLevels) { + resource->perMipViews.resize(resource->mipLevels, VK_NULL_HANDLE); + } + + VkImageView& perMipView = resource->perMipViews[mipLevel]; + if (perMipView != VK_NULL_HANDLE) { + return perMipView; + } + + perMipView = CreateImageView(resource->image, resource->format, resource->aspect, mipLevel, 1); + if (perMipView == VK_NULL_HANDLE) { + MGLOG_D("%s: CreateImageView failed for textureId=%d mipLevel=%u", __func__, texture.GetExternalIndex(), mipLevel); + return VK_NULL_HANDLE; + } + + return perMipView; + } + void VkTextureManager::UpdateTrackedImageLayout(MG_State::GLState::ITextureObject* texture, VkImageLayout newLayout) { MOBILEGL_ASSERT(texture != nullptr, "UpdateTrackedImageLayout: texture is null"); auto it = m_textureResources.find(texture); @@ -127,7 +151,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { const Bool ok = TransitionImageLayout(commandBuffer, resource->image, resource->layout, targetLayout, srcStageMask, kGraphicsSampledReadStages, srcAccessMask, - VK_ACCESS_SHADER_READ_BIT, resource->aspect); + VK_ACCESS_SHADER_READ_BIT, resource->aspect, 0, resource->mipLevels); MOBILEGL_ASSERT(ok, "TransitionTextureForSampling: transition failed for textureId=%d", texture.GetExternalIndex()); return ok; } @@ -136,7 +160,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { VkImageLayout& trackedLayout, VkImageLayout newLayout, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, - VkImageAspectFlags aspectMask) { + VkImageAspectFlags aspectMask, Uint32 baseMipLevel, Uint32 levelCount) { MOBILEGL_ASSERT(image != VK_NULL_HANDLE, "TransitionImageLayout: m_image == VK_NULL_HANDLE"); MOBILEGL_ASSERT(!((dstAccessMask & VK_ACCESS_TRANSFER_READ_BIT) != 0 && (dstStageMask & VK_PIPELINE_STAGE_TRANSFER_BIT) == 0), @@ -158,8 +182,8 @@ namespace MobileGL::MG_Backend::DirectVulkan { barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrier.image = image; barrier.subresourceRange.aspectMask = aspectMask; - barrier.subresourceRange.baseMipLevel = 0; - barrier.subresourceRange.levelCount = 1; + barrier.subresourceRange.baseMipLevel = baseMipLevel; + barrier.subresourceRange.levelCount = levelCount; barrier.subresourceRange.baseArrayLayer = 0; barrier.subresourceRange.layerCount = 1; vkCmdPipelineBarrier(commandBuffer, srcStageMask, dstStageMask, 0, 0, nullptr, 0, nullptr, 1, &barrier); @@ -205,6 +229,10 @@ namespace MobileGL::MG_Backend::DirectVulkan { MGLOG_D("%s: SyncTextureResource failed", __func__); return false; } + if (!SyncTextureViews(texture, outResource)) { + MGLOG_D("%s: SyncTextureViews failed", __func__); + return false; + } Bool hasDirtyMipLevel = false; for (Uint32 level = 0; level < mipLevelCount; ++level) { @@ -251,6 +279,9 @@ namespace MobileGL::MG_Backend::DirectVulkan { resource.extent.height == static_cast(texelSize.y()) && resource.mipLevels == mipLevels; if (compatible) { + if (resource.perMipViews.size() != mipLevels) { + resource.perMipViews.resize(mipLevels, VK_NULL_HANDLE); + } return true; } @@ -283,26 +314,68 @@ namespace MobileGL::MG_Backend::DirectVulkan { VK_VERIFY(vmaCreateImage(m_allocator, &imageInfo, &allocationInfo, &resource.image, &resource.allocation, nullptr), "vmaCreateImage(texture)"); - VkImageViewCreateInfo viewInfo{}; - viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - viewInfo.image = resource.image; - viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; - viewInfo.format = format; - viewInfo.subresourceRange.aspectMask = aspect; - viewInfo.subresourceRange.baseMipLevel = 0; - viewInfo.subresourceRange.levelCount = mipLevels; - viewInfo.subresourceRange.baseArrayLayer = 0; - viewInfo.subresourceRange.layerCount = 1; - VK_VERIFY(vkCreateImageView(m_device, &viewInfo, nullptr, &resource.view), "vkCreateImageView(texture)"); - resource.layout = VK_IMAGE_LAYOUT_UNDEFINED; resource.extent = {static_cast(texelSize.x()), static_cast(texelSize.y())}; resource.mipLevels = mipLevels; + resource.perMipViews.assign(mipLevels, VK_NULL_HANDLE); + resource.sampledBaseMipLevel = 0; + resource.sampledLevelCount = mipLevels; resource.format = format; - resource.aspect = viewInfo.subresourceRange.aspectMask; + resource.aspect = aspect; + resource.syncedTextureParamsVersion = 0; return true; } + Bool VkTextureManager::SyncTextureViews(const MG_State::GLState::ITextureObject& texture, TextureResource& resource) { + MOBILEGL_ASSERT(resource.image != VK_NULL_HANDLE, "SyncTextureViews: image == VK_NULL_HANDLE"); + + Uint32 baseMipLevel = 0; + Uint32 levelCount = 1; + ResolveViewMipRange(texture, resource.mipLevels, baseMipLevel, levelCount); + + const Bool needsRecreate = + resource.fullView == VK_NULL_HANDLE || + resource.sampledBaseMipLevel != baseMipLevel || + resource.sampledLevelCount != levelCount || + resource.syncedTextureParamsVersion != texture.GetTextureParamsVersion(); + if (!needsRecreate) { + return true; + } + + if (resource.fullView != VK_NULL_HANDLE) { + vkDestroyImageView(m_device, resource.fullView, nullptr); + resource.fullView = VK_NULL_HANDLE; + } + + resource.fullView = CreateImageView(resource.image, resource.format, resource.aspect, baseMipLevel, levelCount); + if (resource.fullView == VK_NULL_HANDLE) { + return false; + } + + resource.sampledBaseMipLevel = baseMipLevel; + resource.sampledLevelCount = levelCount; + resource.syncedTextureParamsVersion = texture.GetTextureParamsVersion(); + return true; + } + + VkImageView VkTextureManager::CreateImageView(VkImage image, VkFormat format, VkImageAspectFlags aspect, + Uint32 baseMipLevel, Uint32 levelCount) const { + VkImageViewCreateInfo viewInfo{}; + viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + viewInfo.image = image; + viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + viewInfo.format = format; + viewInfo.subresourceRange.aspectMask = aspect; + viewInfo.subresourceRange.baseMipLevel = baseMipLevel; + viewInfo.subresourceRange.levelCount = levelCount; + viewInfo.subresourceRange.baseArrayLayer = 0; + viewInfo.subresourceRange.layerCount = 1; + + VkImageView view = VK_NULL_HANDLE; + VK_VERIFY(vkCreateImageView(m_device, &viewInfo, nullptr, &view), "vkCreateImageView(texture)"); + return view; + } + Bool VkTextureManager::UploadDirtyMipLevels(MG_State::GLState::TextureObjectMipmap &mipmapTexture, TextureUploadTarget uploadTarget, TextureResource &outResource) { @@ -390,7 +463,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { VK_PIPELINE_STAGE_TRANSFER_BIT, outResource.layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ? VK_ACCESS_SHADER_READ_BIT : 0, VK_ACCESS_TRANSFER_WRITE_BIT, - aspectMask); + aspectMask, 0, outResource.mipLevels); MOBILEGL_ASSERT(ok, "TransitionImageLayout to VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL failed"); for (const auto& item : uploadItems) { @@ -415,7 +488,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { kGraphicsSampledReadStages, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, - aspectMask); + aspectMask, 0, outResource.mipLevels); MOBILEGL_ASSERT(ok, "TransitionImageLayout to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL failed"); outResource.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; @@ -472,15 +545,17 @@ namespace MobileGL::MG_Backend::DirectVulkan { continue; } - const auto level0TexelSize = mipTexture->GetMipmapTexelSize(target, 0); - const auto level0ByteSize = mipTexture->GetMipmapByteSize(target, 0); - if (level0TexelSize.x() <= 0 || level0TexelSize.y() <= 0 /*|| level0ByteSize == 0*/) { + // Backing VkImage allocation still uses storage mip 0 as the physical image extent. + // GL_TEXTURE_BASE_LEVEL / MAX_LEVEL are applied later when building the sampled view. + const auto storageBaseTexelSize = mipTexture->GetMipmapTexelSize(target, 0); + const auto storageBaseByteSize = mipTexture->GetMipmapByteSize(target, 0); + if (storageBaseTexelSize.x() <= 0 || storageBaseTexelSize.y() <= 0 /*|| storageBaseByteSize == 0*/) { continue; } outTarget = target; - outTexelSize = level0TexelSize; - outByteSize = level0ByteSize; + outTexelSize = storageBaseTexelSize; + outByteSize = storageBaseByteSize; outMipLevelCount = mipLevelCount; return true; } @@ -507,6 +582,22 @@ namespace MobileGL::MG_Backend::DirectVulkan { return validLevelCount; } + void VkTextureManager::ResolveViewMipRange(const MG_State::GLState::ITextureObject& texture, Uint32 mipLevels, + Uint32& outBaseMipLevel, Uint32& outLevelCount) { + MOBILEGL_ASSERT(mipLevels > 0, "ResolveViewMipRange: mipLevels must be > 0"); + + const auto& levelRange = texture.GetLevelRange(); + const Uint32 maxAvailableMipLevel = mipLevels - 1; + const Uint32 requestedBaseMipLevel = std::min(static_cast(levelRange.x()), maxAvailableMipLevel); + Uint32 requestedMaxMipLevel = std::min(static_cast(levelRange.y()), maxAvailableMipLevel); + if (requestedMaxMipLevel < requestedBaseMipLevel) { + requestedMaxMipLevel = requestedBaseMipLevel; + } + + outBaseMipLevel = requestedBaseMipLevel; + outLevelCount = requestedMaxMipLevel - requestedBaseMipLevel + 1; + } + VkImageAspectFlags VkTextureManager::GetAspectMaskForFormat(VkFormat format) { switch (format) { case VK_FORMAT_D16_UNORM: diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.h b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.h index a180f2e2..724b53e3 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.h +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.h @@ -31,41 +31,58 @@ public: struct TextureResource { VkImage image = VK_NULL_HANDLE; VmaAllocation allocation = nullptr; - VkImageView view = VK_NULL_HANDLE; + VkImageView fullView = VK_NULL_HANDLE; + Vector perMipViews; VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED; VkExtent2D extent = {0, 0}; Uint32 mipLevels = 1; + Uint32 sampledBaseMipLevel = 0; + Uint32 sampledLevelCount = 1; VkFormat format = VK_FORMAT_UNDEFINED; VkImageAspectFlags aspect = VK_IMAGE_ASPECT_NONE; + Uint16 syncedTextureParamsVersion = 0; TextureResource() = default; TextureResource(const TextureResource&) = delete; TextureResource(TextureResource&& that) noexcept { std::swap(this->image, that.image); std::swap(this->allocation, that.allocation); - std::swap(this->view, that.view); + std::swap(this->fullView, that.fullView); + std::swap(this->perMipViews, that.perMipViews); std::swap(this->layout, that.layout); std::swap(this->extent, that.extent); std::swap(this->mipLevels, that.mipLevels); + std::swap(this->sampledBaseMipLevel, that.sampledBaseMipLevel); + std::swap(this->sampledLevelCount, that.sampledLevelCount); std::swap(this->format, that.format); std::swap(this->aspect, that.aspect); + std::swap(this->syncedTextureParamsVersion, that.syncedTextureParamsVersion); } void Reset() { - if (view != VK_NULL_HANDLE) { - vkDestroyImageView(s_device, view, nullptr); + if (fullView != VK_NULL_HANDLE) { + vkDestroyImageView(s_device, fullView, nullptr); + } + for (const auto attachmentView : perMipViews) { + if (attachmentView != VK_NULL_HANDLE) { + vkDestroyImageView(s_device, attachmentView, nullptr); + } } if (image != VK_NULL_HANDLE && allocation != nullptr) { vmaDestroyImage(s_allocator, image, allocation); } - view = VK_NULL_HANDLE; + fullView = VK_NULL_HANDLE; + perMipViews.clear(); image = VK_NULL_HANDLE; allocation = nullptr; layout = VK_IMAGE_LAYOUT_UNDEFINED; extent = {0, 0}; mipLevels = 1; + sampledBaseMipLevel = 0; + sampledLevelCount = 1; format = VK_FORMAT_UNDEFINED; aspect = VK_IMAGE_ASPECT_NONE; + syncedTextureParamsVersion = 0; } ~TextureResource() { @@ -81,13 +98,15 @@ public: TextureResource* SyncTextureAndGetDescriptor( MG_State::GLState::ITextureObject& texture); + VkImageView GetOrCreateViewAtMipLevel(MG_State::GLState::ITextureObject& texture, Uint32 mipLevel); void UpdateTrackedImageLayout(MG_State::GLState::ITextureObject* texture, VkImageLayout newLayout); Bool TransitionTextureForSampling(VkCommandBuffer commandBuffer, MG_State::GLState::ITextureObject& texture); static Bool TransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout& trackedLayout, VkImageLayout newLayout, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask, - VkAccessFlags dstAccessMask, VkImageAspectFlags aspectMask); + VkAccessFlags dstAccessMask, VkImageAspectFlags aspectMask, + Uint32 baseMipLevel = 0, Uint32 levelCount = 1); SizeT CollectGarbage(); private: @@ -98,6 +117,9 @@ private: TextureUploadTarget uploadTarget, const IntVec3 &texelSize, SizeT byteSize, Uint32 mipLevels, TextureResource &resource); + Bool SyncTextureViews(const MG_State::GLState::ITextureObject& texture, TextureResource& resource); + VkImageView CreateImageView(VkImage image, VkFormat format, VkImageAspectFlags aspect, + Uint32 baseMipLevel, Uint32 levelCount) const; Bool UploadDirtyMipLevels(MG_State::GLState::TextureObjectMipmap &mipmapTexture, TextureUploadTarget uploadTarget, TextureResource &outResource); @@ -107,6 +129,8 @@ private: SizeT& outByteSize, Uint32& outMipLevelCount); static Uint32 GetUploadMipLevelCount(const MG_State::GLState::TextureObjectMipmap& texture, TextureUploadTarget target); + static void ResolveViewMipRange(const MG_State::GLState::ITextureObject& texture, Uint32 mipLevels, + Uint32& outBaseMipLevel, Uint32& outLevelCount); static VkImageAspectFlags GetAspectMaskForFormat(VkFormat format); VkDevice m_device = VK_NULL_HANDLE; diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp index c5f29cbf..f3d55ba6 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp @@ -93,6 +93,8 @@ namespace MobileGL::MG_Backend::DirectVulkan { VkImageLayout* trackedLayout = nullptr; VkImageAspectFlags aspectMask = VK_IMAGE_ASPECT_NONE; IntVec2 extent = {0, 0}; + Uint32 mipLevel = 0; + Uint32 mipLevelCount = 1; const char* label = nullptr; }; @@ -164,6 +166,8 @@ namespace MobileGL::MG_Backend::DirectVulkan { outBinding.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; const auto extent = swapchainObject.GetExtent(); outBinding.extent = {static_cast(extent.width), static_cast(extent.height)}; + outBinding.mipLevel = 0; + outBinding.mipLevelCount = 1; return true; } @@ -182,7 +186,10 @@ namespace MobileGL::MG_Backend::DirectVulkan { outBinding.image = resource->image; outBinding.trackedLayout = &resource->layout; outBinding.aspectMask = resource->aspect; - outBinding.extent = {static_cast(resource->extent.width), static_cast(resource->extent.height)}; + const auto attachmentExtent = attachment.GetSize(); + outBinding.extent = {attachmentExtent.x(), attachmentExtent.y()}; + outBinding.mipLevel = static_cast(std::max(attachment.GetTextureLevel(), 0)); + outBinding.mipLevelCount = resource->mipLevels; return true; } @@ -875,7 +882,7 @@ void main() { Bool ok = VkTextureManager::TransitionImageLayout( commandBuffer, resource->image, resource->layout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, srcStageMask, VK_PIPELINE_STAGE_TRANSFER_BIT, srcAccessMask, VK_ACCESS_TRANSFER_WRITE_BIT, - resource->aspect); + resource->aspect, 0, resource->mipLevels); MOBILEGL_ASSERT(ok, "MaterializePendingClearForTexture: failed to transition textureId=%d to TRANSFER_DST", texture.GetExternalIndex()); @@ -908,7 +915,7 @@ void main() { ok = VkTextureManager::TransitionImageLayout( commandBuffer, resource->image, resource->layout, sampledLayout, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, - VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, resource->aspect); + VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, resource->aspect, 0, resource->mipLevels); MOBILEGL_ASSERT(ok, "MaterializePendingClearForTexture: failed to transition textureId=%d to sampled layout", texture.GetExternalIndex()); @@ -1138,7 +1145,7 @@ void main() { Bool ok = VkTextureManager::TransitionImageLayout( frame.commandBuffer, srcBinding.image, *srcBinding.trackedLayout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, srcStageMask, VK_PIPELINE_STAGE_TRANSFER_BIT, - srcAccessMask, VK_ACCESS_TRANSFER_READ_BIT, srcBinding.aspectMask); + srcAccessMask, VK_ACCESS_TRANSFER_READ_BIT, srcBinding.aspectMask, 0, srcBinding.mipLevelCount); MOBILEGL_ASSERT(ok, "%s: failed to transition source image", __func__); } @@ -1156,19 +1163,19 @@ void main() { Bool ok = VkTextureManager::TransitionImageLayout( frame.commandBuffer, dstBinding.image, *dstBinding.trackedLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, dstStageMask, VK_PIPELINE_STAGE_TRANSFER_BIT, - dstAccessMask, VK_ACCESS_TRANSFER_WRITE_BIT, dstBinding.aspectMask); + dstAccessMask, VK_ACCESS_TRANSFER_WRITE_BIT, dstBinding.aspectMask, 0, dstBinding.mipLevelCount); MOBILEGL_ASSERT(ok, "%s: failed to transition destination image", __func__); } VkImageBlit blitRegion{}; blitRegion.srcSubresource.aspectMask = srcBinding.aspectMask; - blitRegion.srcSubresource.mipLevel = 0; + blitRegion.srcSubresource.mipLevel = srcBinding.mipLevel; blitRegion.srcSubresource.baseArrayLayer = 0; blitRegion.srcSubresource.layerCount = 1; blitRegion.srcOffsets[0] = {srcX0, srcY0, 0}; blitRegion.srcOffsets[1] = {srcX1, srcY1, 1}; blitRegion.dstSubresource.aspectMask = dstBinding.aspectMask; - blitRegion.dstSubresource.mipLevel = 0; + blitRegion.dstSubresource.mipLevel = dstBinding.mipLevel; blitRegion.dstSubresource.baseArrayLayer = 0; blitRegion.dstSubresource.layerCount = 1; blitRegion.dstOffsets[0] = {dstX0, dstY0, 0};