mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-07 19:58:32 +09:00
[Feat] (MG_Backend/DirectVulkan): generate mipmap, add fallback texture, implement shader-based depth mipmap blit, enumerate more vk physical device features
- Supporting iterationT
This commit is contained in:
@@ -10,10 +10,15 @@
|
||||
|
||||
#include "MG_State/GLState/Core.h"
|
||||
#include "MG_State/GLState/ProgramState/ProgramObject.h"
|
||||
#include "MG_State/GLState/TextureState/TextureObject2D.h"
|
||||
#include "MG_Util/Converters/MGToStr/FramebufferEnumConverter.h"
|
||||
#include <limits>
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
namespace {
|
||||
constexpr Uint kFallbackTexture2DExternalIndex = 0xFFFFFF00u;
|
||||
}
|
||||
|
||||
static Bool FindFramebufferAttachmentForTexture(const MG_State::GLState::FramebufferObject& framebuffer,
|
||||
const MG_State::GLState::ITextureObject& texture,
|
||||
FramebufferAttachmentType& outAttachment, Int& outLevel) {
|
||||
@@ -145,6 +150,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
m_peakDescriptorSetsObserved = 0;
|
||||
m_textureManager = nullptr;
|
||||
m_samplerManager = nullptr;
|
||||
m_fallbackTexture2D.reset();
|
||||
}
|
||||
|
||||
void UniformManager::BeginFrame(Uint32 frameIndex) {
|
||||
@@ -190,12 +196,16 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
const Int unit = ResolveSamplerUnitIndex(program, location, binding);
|
||||
auto& textureUnit = MG_State::pGLContext->GetTextureUnitObject(unit);
|
||||
const auto samplerOverride = textureUnit.GetSamplerObject();
|
||||
const auto preferredTarget = programObj.samplerTextureTargetByBinding[binding];
|
||||
if (texture == nullptr) {
|
||||
MGLOG_E(
|
||||
"ResolveSamplerDescriptor: sampler binding %u ('%s') resolved null texture (location=%d unit=%d target=%d)",
|
||||
texture = GetFallbackTexture(preferredTarget);
|
||||
MOBILEGL_ASSERT(texture != nullptr,
|
||||
"ResolveSamplerDescriptor: no fallback texture available for binding=%u location=%d unit=%d target=%d",
|
||||
binding, location, unit, static_cast<Int>(preferredTarget));
|
||||
MGLOG_W(
|
||||
"ResolveSamplerDescriptor: using fallback texture for unbound sampler binding=%u ('%s') location=%d unit=%d target=%d",
|
||||
binding, programObj.samplerNameByBinding[binding].c_str(), location, unit,
|
||||
static_cast<Int>(programObj.samplerTextureTargetByBinding[binding]));
|
||||
return false;
|
||||
static_cast<Int>(preferredTarget));
|
||||
}
|
||||
|
||||
const MG_State::GLState::SamplerObject* samplerToUse =
|
||||
@@ -291,11 +301,24 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
const TextureTarget preferredTarget = programObj.samplerTextureTargetByBinding[binding];
|
||||
outTexture = textureUnit.GetBindingSlot(preferredTarget).GetBoundObject();
|
||||
|
||||
MOBILEGL_ASSERT(outTexture,
|
||||
"ResolveSamplerTexture: no texture bound for active sampler binding=%u location=%d unit=%d target=%d",
|
||||
binding, location, unit, static_cast<Int>(preferredTarget));
|
||||
return true;
|
||||
}
|
||||
|
||||
return outTexture != nullptr;
|
||||
SharedPtr<MG_State::GLState::ITextureObject> UniformManager::GetFallbackTexture(TextureTarget target) const {
|
||||
MOBILEGL_ASSERT(target == TextureTarget::Texture2D || target == TextureTarget::TextureRectangle,
|
||||
"UniformManager::GetFallbackTexture: unsupported fallback target=%d",
|
||||
static_cast<Int>(target));
|
||||
|
||||
if (m_fallbackTexture2D == nullptr) {
|
||||
auto fallbackTexture = MakeShared<MG_State::GLState::TextureObject2D>(kFallbackTexture2DExternalIndex);
|
||||
fallbackTexture->SetInternalFormat(TextureInternalFormat::RGBA8);
|
||||
fallbackTexture->AllocateStorage(TextureUploadTarget::Texture2D, 0,
|
||||
{.texelSize = {1, 1, 1}, .byteSize = 4});
|
||||
fallbackTexture->MarkStorageDirty(TextureUploadTarget::Texture2D, 0, true);
|
||||
m_fallbackTexture2D = fallbackTexture;
|
||||
}
|
||||
|
||||
return m_fallbackTexture2D;
|
||||
}
|
||||
|
||||
Bool UniformManager::CollectSampledTextures(const MG_State::GLState::ProgramObject& program,
|
||||
|
||||
@@ -65,6 +65,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
static Bool ResolveSamplerTexture(const MG_State::GLState::ProgramObject& program,
|
||||
const ProgramFactory::VkProgramObject& programObj, Uint32 binding,
|
||||
SharedPtr<MG_State::GLState::ITextureObject>& outTexture);
|
||||
SharedPtr<MG_State::GLState::ITextureObject> GetFallbackTexture(TextureTarget target) const;
|
||||
Bool ResolveSamplerDescriptor(VkCommandBuffer commandBuffer, const MG_State::GLState::ProgramObject& program,
|
||||
const ProgramFactory::VkProgramObject& programObj, Uint32 binding,
|
||||
VkDescriptorImageInfo& outImageInfo) const;
|
||||
@@ -90,6 +91,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
Uint32 m_peakDescriptorSetsObserved = 0;
|
||||
VkTextureManager* m_textureManager = nullptr;
|
||||
VkSamplerManager* m_samplerManager = nullptr;
|
||||
mutable SharedPtr<MG_State::GLState::ITextureObject> m_fallbackTexture2D;
|
||||
};
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
|
||||
|
||||
@@ -267,6 +267,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
trackedAttachmentLayouts.emplace_back(TrackedAttachmentLayoutInfo {
|
||||
.target = TrackedAttachmentTarget::Texture,
|
||||
.texture = texture,
|
||||
.textureMipLevel = attachmentMipLevel,
|
||||
.finalLayout = desc.finalLayout,
|
||||
});
|
||||
attachmentViews.emplace_back(m_textureManager.GetOrCreateViewAtMipLevel(*texture, attachmentMipLevel));
|
||||
@@ -369,6 +370,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
trackedAttachmentLayouts.emplace_back(TrackedAttachmentLayoutInfo {
|
||||
.target = TrackedAttachmentTarget::Texture,
|
||||
.texture = &texture,
|
||||
.textureMipLevel = attachmentMipLevel,
|
||||
.finalLayout = depthAttachmentDescription.finalLayout,
|
||||
});
|
||||
textureResources.emplace_back(depthTextureResource);
|
||||
@@ -512,7 +514,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
switch (trackedAttachment.target) {
|
||||
case TrackedAttachmentTarget::Texture:
|
||||
MOBILEGL_ASSERT(s_textureManager != nullptr, "EndRenderPass: texture manager is null");
|
||||
s_textureManager->UpdateTrackedImageLayout(trackedAttachment.texture, trackedAttachment.finalLayout);
|
||||
s_textureManager->UpdateTrackedImageLayoutAfterAttachmentWrite(
|
||||
commandBuffer,
|
||||
trackedAttachment.texture,
|
||||
trackedAttachment.textureMipLevel,
|
||||
trackedAttachment.finalLayout);
|
||||
break;
|
||||
case TrackedAttachmentTarget::SwapchainColor:
|
||||
MOBILEGL_ASSERT(s_swapchainObject != nullptr, "EndRenderPass: swapchain object is null");
|
||||
|
||||
@@ -32,6 +32,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
struct TrackedAttachmentLayoutInfo {
|
||||
TrackedAttachmentTarget target = TrackedAttachmentTarget::Texture;
|
||||
MG_State::GLState::ITextureObject* texture = nullptr;
|
||||
Uint32 textureMipLevel = 0;
|
||||
Uint32 swapchainImageIndex = 0;
|
||||
VkImageLayout finalLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
};
|
||||
|
||||
@@ -17,6 +17,17 @@
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
static constexpr VkPipelineStageFlags kGraphicsSampledReadStages = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
|
||||
|
||||
static Uint32 ComputeFullMipLevelCount(const IntVec3& baseTexelSize) {
|
||||
Int maxDimension = std::max<Int>(baseTexelSize.x(),
|
||||
std::max<Int>(baseTexelSize.y(), std::max<Int>(baseTexelSize.z(), 1)));
|
||||
Uint32 mipLevelCount = 1;
|
||||
while (maxDimension > 1) {
|
||||
maxDimension = std::max<Int>(maxDimension / 2, 1);
|
||||
++mipLevelCount;
|
||||
}
|
||||
return mipLevelCount;
|
||||
}
|
||||
|
||||
struct TextureFormatInfo {
|
||||
VkFormat format = VK_FORMAT_UNDEFINED;
|
||||
Bool expandRgbToRgba = false;
|
||||
@@ -290,16 +301,34 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
return true;
|
||||
}
|
||||
|
||||
static VkComponentMapping ResolveSampledViewComponents(const MG_State::GLState::ITextureObject& texture) {
|
||||
VkComponentMapping components{
|
||||
VK_COMPONENT_SWIZZLE_R,
|
||||
VK_COMPONENT_SWIZZLE_G,
|
||||
VK_COMPONENT_SWIZZLE_B,
|
||||
VK_COMPONENT_SWIZZLE_A,
|
||||
};
|
||||
if (ResolveTextureFormatInfo(texture.GetFormat()).expandRgbToRgba) {
|
||||
components.a = VK_COMPONENT_SWIZZLE_ONE;
|
||||
static VkComponentSwizzle ToVkComponentSwizzle(TextureSwizzleParam swizzle) {
|
||||
switch (swizzle) {
|
||||
case TextureSwizzleParam::Red:
|
||||
return VK_COMPONENT_SWIZZLE_R;
|
||||
case TextureSwizzleParam::Green:
|
||||
return VK_COMPONENT_SWIZZLE_G;
|
||||
case TextureSwizzleParam::Blue:
|
||||
return VK_COMPONENT_SWIZZLE_B;
|
||||
case TextureSwizzleParam::Alpha:
|
||||
return VK_COMPONENT_SWIZZLE_A;
|
||||
case TextureSwizzleParam::Zero:
|
||||
return VK_COMPONENT_SWIZZLE_ZERO;
|
||||
case TextureSwizzleParam::One:
|
||||
return VK_COMPONENT_SWIZZLE_ONE;
|
||||
default:
|
||||
MOBILEGL_ASSERT(false, "ToVkComponentSwizzle: unsupported swizzle=%d", static_cast<Int>(swizzle));
|
||||
return VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||
}
|
||||
}
|
||||
|
||||
static VkComponentMapping ResolveSampledViewComponents(const MG_State::GLState::ITextureObject& texture) {
|
||||
const auto& swizzles = texture.GetAllSwizzleParams();
|
||||
VkComponentMapping components{
|
||||
ToVkComponentSwizzle(swizzles.x()),
|
||||
ToVkComponentSwizzle(swizzles.y()),
|
||||
ToVkComponentSwizzle(swizzles.z()),
|
||||
ToVkComponentSwizzle(swizzles.w()),
|
||||
};
|
||||
return components;
|
||||
}
|
||||
|
||||
@@ -335,10 +364,17 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
m_allocator = initInfo.allocator;
|
||||
m_commandPool = initInfo.commandPool;
|
||||
m_graphicsQueue = initInfo.graphicsQueue;
|
||||
m_currentFrameIndex = 0;
|
||||
m_deferredReleases.clear();
|
||||
m_deferredReleases.resize(initInfo.frameCount);
|
||||
m_deferredViewReleases.clear();
|
||||
m_deferredViewReleases.resize(initInfo.frameCount);
|
||||
|
||||
MOBILEGL_ASSERT(m_device != VK_NULL_HANDLE && m_physicalDevice != VK_NULL_HANDLE && m_allocator != nullptr &&
|
||||
m_commandPool != VK_NULL_HANDLE && m_graphicsQueue != VK_NULL_HANDLE,
|
||||
"VkTextureManager::Initialize failed: invalid initialization info");
|
||||
MOBILEGL_ASSERT(initInfo.frameCount > 0,
|
||||
"VkTextureManager::Initialize failed: frameCount must be > 0");
|
||||
|
||||
TextureResource::s_device = m_device;
|
||||
TextureResource::s_allocator = m_allocator;
|
||||
@@ -347,6 +383,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
}
|
||||
|
||||
void VkTextureManager::Shutdown() {
|
||||
DestroyDeferredReleases();
|
||||
m_textureResources.clear();
|
||||
|
||||
m_device = VK_NULL_HANDLE;
|
||||
@@ -354,6 +391,18 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
m_allocator = nullptr;
|
||||
m_commandPool = VK_NULL_HANDLE;
|
||||
m_graphicsQueue = VK_NULL_HANDLE;
|
||||
m_currentFrameIndex = 0;
|
||||
}
|
||||
|
||||
void VkTextureManager::BeginFrame(Uint32 frameIndex) {
|
||||
MOBILEGL_ASSERT(frameIndex < m_deferredReleases.size(),
|
||||
"VkTextureManager::BeginFrame invalid frame index %u (size=%zu)",
|
||||
frameIndex, m_deferredReleases.size());
|
||||
MOBILEGL_ASSERT(frameIndex < m_deferredViewReleases.size(),
|
||||
"VkTextureManager::BeginFrame invalid deferred-view frame index %u (size=%zu)",
|
||||
frameIndex, m_deferredViewReleases.size());
|
||||
m_currentFrameIndex = frameIndex;
|
||||
CollectDeferredReleases(frameIndex);
|
||||
}
|
||||
|
||||
VkTextureManager::TextureResource* VkTextureManager::SyncTextureAndGetDescriptor(MG_State::GLState::ITextureObject& texture) {
|
||||
@@ -437,6 +486,60 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
it->second.layout = newLayout;
|
||||
}
|
||||
|
||||
void VkTextureManager::UpdateTrackedImageLayoutAfterAttachmentWrite(VkCommandBuffer commandBuffer,
|
||||
MG_State::GLState::ITextureObject* texture,
|
||||
Uint32 writtenMipLevel,
|
||||
VkImageLayout newLayout) {
|
||||
MOBILEGL_ASSERT(texture != nullptr, "UpdateTrackedImageLayoutAfterAttachmentWrite: texture is null");
|
||||
auto it = m_textureResources.find(texture);
|
||||
MOBILEGL_ASSERT(it != m_textureResources.end(),
|
||||
"UpdateTrackedImageLayoutAfterAttachmentWrite: textureId=%d has no tracked resource",
|
||||
texture->GetExternalIndex());
|
||||
|
||||
auto& resource = it->second;
|
||||
MOBILEGL_ASSERT(resource.image != VK_NULL_HANDLE,
|
||||
"UpdateTrackedImageLayoutAfterAttachmentWrite: textureId=%d has null image",
|
||||
texture->GetExternalIndex());
|
||||
MOBILEGL_ASSERT(writtenMipLevel < resource.mipLevels,
|
||||
"UpdateTrackedImageLayoutAfterAttachmentWrite: textureId=%d mipLevel=%u out of range %u",
|
||||
texture->GetExternalIndex(), writtenMipLevel, resource.mipLevels);
|
||||
|
||||
if (resource.layout != newLayout && resource.mipLevels > 1) {
|
||||
VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||
VkAccessFlags srcAccessMask = 0;
|
||||
GetImageTransitionSourceState(resource.layout, srcStageMask, srcAccessMask);
|
||||
|
||||
VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||
VkAccessFlags dstAccessMask = 0;
|
||||
GetImageTransitionDestinationState(newLayout, dstStageMask, dstAccessMask);
|
||||
|
||||
if (writtenMipLevel > 0) {
|
||||
VkImageLayout lowerMipLayout = resource.layout;
|
||||
const Bool lowerTransitioned = TransitionImageLayout(
|
||||
commandBuffer, resource.image, lowerMipLayout, newLayout,
|
||||
srcStageMask, dstStageMask, srcAccessMask, dstAccessMask,
|
||||
resource.aspect, 0, writtenMipLevel);
|
||||
MOBILEGL_ASSERT(lowerTransitioned,
|
||||
"UpdateTrackedImageLayoutAfterAttachmentWrite: failed to transition lower mip levels for textureId=%d",
|
||||
texture->GetExternalIndex());
|
||||
}
|
||||
|
||||
const Uint32 upperBaseMipLevel = writtenMipLevel + 1;
|
||||
if (upperBaseMipLevel < resource.mipLevels) {
|
||||
VkImageLayout upperMipLayout = resource.layout;
|
||||
const Bool upperTransitioned = TransitionImageLayout(
|
||||
commandBuffer, resource.image, upperMipLayout, newLayout,
|
||||
srcStageMask, dstStageMask, srcAccessMask, dstAccessMask,
|
||||
resource.aspect, upperBaseMipLevel, resource.mipLevels - upperBaseMipLevel);
|
||||
MOBILEGL_ASSERT(upperTransitioned,
|
||||
"UpdateTrackedImageLayoutAfterAttachmentWrite: failed to transition upper mip levels for textureId=%d",
|
||||
texture->GetExternalIndex());
|
||||
}
|
||||
}
|
||||
|
||||
resource.layout = newLayout;
|
||||
}
|
||||
|
||||
Bool VkTextureManager::TransitionTextureForSampling(VkCommandBuffer commandBuffer, MG_State::GLState::ITextureObject& texture) {
|
||||
TextureResource* resource = SyncTextureAndGetDescriptor(texture);
|
||||
if (resource == nullptr) {
|
||||
@@ -599,6 +702,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
MGLOG_D("%s: no mip levels", __func__);
|
||||
return false;
|
||||
}
|
||||
const Uint32 backingMipLevels = std::max(mipLevels, ComputeFullMipLevelCount(texelSize));
|
||||
TextureShapeInfo shapeInfo{};
|
||||
const Bool supportedShape = TryResolveTextureShapeInfo(texture, uploadTarget, texelSize, shapeInfo);
|
||||
MOBILEGL_ASSERT(supportedShape,
|
||||
@@ -619,13 +723,13 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
resource.depth == shapeInfo.depth &&
|
||||
resource.arrayLayers == shapeInfo.arrayLayers &&
|
||||
resource.viewType == shapeInfo.viewType &&
|
||||
resource.mipLevels == mipLevels;
|
||||
resource.mipLevels == backingMipLevels;
|
||||
if (compatible) {
|
||||
if (resource.perMipViews.size() != mipLevels) {
|
||||
resource.perMipViews.resize(mipLevels, VK_NULL_HANDLE);
|
||||
if (resource.perMipViews.size() != backingMipLevels) {
|
||||
resource.perMipViews.resize(backingMipLevels, VK_NULL_HANDLE);
|
||||
}
|
||||
if (resource.perMipSampledViews.size() != mipLevels) {
|
||||
resource.perMipSampledViews.resize(mipLevels, VK_NULL_HANDLE);
|
||||
if (resource.perMipSampledViews.size() != backingMipLevels) {
|
||||
resource.perMipSampledViews.resize(backingMipLevels, VK_NULL_HANDLE);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -638,14 +742,14 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
resource.depth == shapeInfo.depth &&
|
||||
resource.arrayLayers == shapeInfo.arrayLayers &&
|
||||
resource.viewType == shapeInfo.viewType &&
|
||||
resource.mipLevels < mipLevels &&
|
||||
resource.mipLevels < backingMipLevels &&
|
||||
resource.layout != VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
|
||||
std::unique_ptr<TextureResource> preservedResource;
|
||||
if (preserveExistingContent) {
|
||||
preservedResource = std::make_unique<TextureResource>(Move(resource));
|
||||
} else {
|
||||
resource.Reset();
|
||||
DeferResourceRelease(Move(resource));
|
||||
}
|
||||
|
||||
auto aspect = GetAspectMaskForFormat(format);
|
||||
@@ -657,7 +761,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
imageInfo.extent.width = static_cast<Uint32>(texelSize.x());
|
||||
imageInfo.extent.height = static_cast<Uint32>(texelSize.y());
|
||||
imageInfo.extent.depth = shapeInfo.depth;
|
||||
imageInfo.mipLevels = mipLevels;
|
||||
imageInfo.mipLevels = backingMipLevels;
|
||||
imageInfo.arrayLayers = shapeInfo.arrayLayers;
|
||||
imageInfo.format = format;
|
||||
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
@@ -680,9 +784,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
resource.extent = {static_cast<Uint32>(texelSize.x()), static_cast<Uint32>(texelSize.y())};
|
||||
resource.depth = shapeInfo.depth;
|
||||
resource.arrayLayers = shapeInfo.arrayLayers;
|
||||
resource.mipLevels = mipLevels;
|
||||
resource.perMipViews.assign(mipLevels, VK_NULL_HANDLE);
|
||||
resource.perMipSampledViews.assign(mipLevels, VK_NULL_HANDLE);
|
||||
resource.mipLevels = backingMipLevels;
|
||||
resource.perMipViews.assign(backingMipLevels, VK_NULL_HANDLE);
|
||||
resource.perMipSampledViews.assign(backingMipLevels, VK_NULL_HANDLE);
|
||||
resource.sampledBaseMipLevel = 0;
|
||||
resource.sampledLevelCount = mipLevels;
|
||||
resource.format = format;
|
||||
@@ -695,10 +799,78 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
m_device, m_commandPool, m_graphicsQueue, *preservedResource, resource);
|
||||
MOBILEGL_ASSERT(preserved,
|
||||
"SyncTextureResource: failed to preserve texture contents while growing mip chain");
|
||||
DeferResourceRelease(Move(*preservedResource));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void VkTextureManager::DeferResourceRelease(TextureResource&& resource) {
|
||||
if (resource.image == VK_NULL_HANDLE && resource.fullView == VK_NULL_HANDLE &&
|
||||
resource.perMipViews.empty() && resource.perMipSampledViews.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_deferredReleases.empty()) {
|
||||
resource.Reset();
|
||||
return;
|
||||
}
|
||||
|
||||
MOBILEGL_ASSERT(m_currentFrameIndex < m_deferredReleases.size(),
|
||||
"VkTextureManager::DeferResourceRelease invalid current frame index %u (size=%zu)",
|
||||
m_currentFrameIndex, m_deferredReleases.size());
|
||||
m_deferredReleases[m_currentFrameIndex].push_back(Move(resource));
|
||||
}
|
||||
|
||||
void VkTextureManager::CollectDeferredReleases(Uint32 frameIndex) {
|
||||
MOBILEGL_ASSERT(frameIndex < m_deferredReleases.size(),
|
||||
"VkTextureManager::CollectDeferredReleases invalid frame index %u (size=%zu)",
|
||||
frameIndex, m_deferredReleases.size());
|
||||
m_deferredReleases[frameIndex].clear();
|
||||
|
||||
MOBILEGL_ASSERT(frameIndex < m_deferredViewReleases.size(),
|
||||
"VkTextureManager::CollectDeferredReleases invalid deferred-view frame index %u (size=%zu)",
|
||||
frameIndex, m_deferredViewReleases.size());
|
||||
for (const VkImageView view : m_deferredViewReleases[frameIndex]) {
|
||||
if (view != VK_NULL_HANDLE) {
|
||||
vkDestroyImageView(m_device, view, nullptr);
|
||||
}
|
||||
}
|
||||
m_deferredViewReleases[frameIndex].clear();
|
||||
}
|
||||
|
||||
void VkTextureManager::DestroyDeferredReleases() {
|
||||
for (auto& deferredReleases : m_deferredReleases) {
|
||||
deferredReleases.clear();
|
||||
}
|
||||
m_deferredReleases.clear();
|
||||
|
||||
for (auto& deferredViews : m_deferredViewReleases) {
|
||||
for (const VkImageView view : deferredViews) {
|
||||
if (view != VK_NULL_HANDLE) {
|
||||
vkDestroyImageView(m_device, view, nullptr);
|
||||
}
|
||||
}
|
||||
deferredViews.clear();
|
||||
}
|
||||
m_deferredViewReleases.clear();
|
||||
}
|
||||
|
||||
void VkTextureManager::DeferViewRelease(VkImageView view) {
|
||||
if (view == VK_NULL_HANDLE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_deferredViewReleases.empty()) {
|
||||
vkDestroyImageView(m_device, view, nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
MOBILEGL_ASSERT(m_currentFrameIndex < m_deferredViewReleases.size(),
|
||||
"VkTextureManager::DeferViewRelease invalid current frame index %u (size=%zu)",
|
||||
m_currentFrameIndex, m_deferredViewReleases.size());
|
||||
m_deferredViewReleases[m_currentFrameIndex].push_back(view);
|
||||
}
|
||||
|
||||
Bool VkTextureManager::SyncTextureViews(const MG_State::GLState::ITextureObject& texture, TextureResource& resource) {
|
||||
MOBILEGL_ASSERT(resource.image != VK_NULL_HANDLE, "SyncTextureViews: image == VK_NULL_HANDLE");
|
||||
|
||||
@@ -716,7 +888,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
}
|
||||
|
||||
if (resource.fullView != VK_NULL_HANDLE) {
|
||||
vkDestroyImageView(m_device, resource.fullView, nullptr);
|
||||
DeferViewRelease(resource.fullView);
|
||||
resource.fullView = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
@@ -770,11 +942,16 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
};
|
||||
|
||||
Vector<UploadItem> uploadItems;
|
||||
uploadItems.reserve(outResource.mipLevels);
|
||||
const Uint32 definedMipLevels = GetUploadMipLevelCount(mipmapTexture, uploadTarget);
|
||||
MOBILEGL_ASSERT(definedMipLevels <= outResource.mipLevels,
|
||||
"UploadDirtyMipLevels: defined mip level count %u exceeds backing mip level count %u for textureId=%d",
|
||||
definedMipLevels, outResource.mipLevels, mipmapTexture.GetExternalIndex());
|
||||
|
||||
uploadItems.reserve(definedMipLevels);
|
||||
const TextureFormatInfo formatInfo = ResolveTextureFormatInfo(mipmapTexture.GetFormat());
|
||||
|
||||
VkDeviceSize stagingSize = 0;
|
||||
for (Uint32 level = 0; level < outResource.mipLevels; ++level) {
|
||||
for (Uint32 level = 0; level < definedMipLevels; ++level) {
|
||||
if (!mipmapTexture.IsStorageDirty(uploadTarget, level)) {
|
||||
continue;
|
||||
}
|
||||
@@ -987,8 +1164,22 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
Uint32& outBaseMipLevel, Uint32& outLevelCount) {
|
||||
MOBILEGL_ASSERT(mipLevels > 0, "ResolveViewMipRange: mipLevels must be > 0");
|
||||
|
||||
Uint32 definedMipLevels = mipLevels;
|
||||
if (const auto* mipTexture = dynamic_cast<const MG_State::GLState::TextureObjectMipmap*>(&texture)) {
|
||||
const auto& targets = texture.GetUploadTargets();
|
||||
for (const auto target : targets) {
|
||||
const Uint32 uploadMipLevels = GetUploadMipLevelCount(*mipTexture, target);
|
||||
if (uploadMipLevels == 0) {
|
||||
continue;
|
||||
}
|
||||
definedMipLevels = std::min(mipLevels, uploadMipLevels);
|
||||
break;
|
||||
}
|
||||
}
|
||||
MOBILEGL_ASSERT(definedMipLevels > 0, "ResolveViewMipRange: texture has no defined mip levels");
|
||||
|
||||
const auto& levelRange = texture.GetLevelRange();
|
||||
const Uint32 maxAvailableMipLevel = mipLevels - 1;
|
||||
const Uint32 maxAvailableMipLevel = definedMipLevels - 1;
|
||||
const Uint32 requestedBaseMipLevel = std::min(static_cast<Uint32>(levelRange.x()), maxAvailableMipLevel);
|
||||
Uint32 requestedMaxMipLevel = std::min(static_cast<Uint32>(levelRange.y()), maxAvailableMipLevel);
|
||||
if (requestedMaxMipLevel < requestedBaseMipLevel) {
|
||||
|
||||
@@ -26,6 +26,7 @@ public:
|
||||
VmaAllocator allocator = nullptr;
|
||||
VkCommandPool commandPool = VK_NULL_HANDLE;
|
||||
VkQueue graphicsQueue = VK_NULL_HANDLE;
|
||||
Uint32 frameCount = 0;
|
||||
};
|
||||
|
||||
struct TextureResource {
|
||||
@@ -112,12 +113,17 @@ public:
|
||||
|
||||
Bool Initialize(const InitInfo& initInfo);
|
||||
void Shutdown();
|
||||
void BeginFrame(Uint32 frameIndex);
|
||||
|
||||
TextureResource* SyncTextureAndGetDescriptor(
|
||||
MG_State::GLState::ITextureObject& texture);
|
||||
VkImageView GetOrCreateViewAtMipLevel(MG_State::GLState::ITextureObject& texture, Uint32 mipLevel);
|
||||
VkImageView GetOrCreateSampledViewAtMipLevel(MG_State::GLState::ITextureObject& texture, Uint32 mipLevel);
|
||||
void UpdateTrackedImageLayout(MG_State::GLState::ITextureObject* texture, VkImageLayout newLayout);
|
||||
void UpdateTrackedImageLayoutAfterAttachmentWrite(VkCommandBuffer commandBuffer,
|
||||
MG_State::GLState::ITextureObject* texture,
|
||||
Uint32 writtenMipLevel,
|
||||
VkImageLayout newLayout);
|
||||
Bool TransitionTextureForSampling(VkCommandBuffer commandBuffer, MG_State::GLState::ITextureObject& texture);
|
||||
|
||||
static Bool TransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout& trackedLayout,
|
||||
@@ -152,15 +158,22 @@ private:
|
||||
static void ResolveViewMipRange(const MG_State::GLState::ITextureObject& texture, Uint32 mipLevels,
|
||||
Uint32& outBaseMipLevel, Uint32& outLevelCount);
|
||||
static VkImageAspectFlags GetAspectMaskForFormat(VkFormat format);
|
||||
void DeferResourceRelease(TextureResource&& resource);
|
||||
void DeferViewRelease(VkImageView view);
|
||||
void CollectDeferredReleases(Uint32 frameIndex);
|
||||
void DestroyDeferredReleases();
|
||||
|
||||
VkDevice m_device = VK_NULL_HANDLE;
|
||||
VkPhysicalDevice m_physicalDevice = VK_NULL_HANDLE;
|
||||
VmaAllocator m_allocator = nullptr;
|
||||
VkCommandPool m_commandPool = VK_NULL_HANDLE;
|
||||
VkQueue m_graphicsQueue = VK_NULL_HANDLE;
|
||||
Uint32 m_currentFrameIndex = 0;
|
||||
|
||||
Uint8 m_gcCounter = 0;
|
||||
UnorderedMap<MG_State::GLState::ITextureObject*, WeakPtr<MG_State::GLState::ITextureObject>> m_aliveObjects;
|
||||
UnorderedMap<MG_State::GLState::ITextureObject*, TextureResource> m_textureResources;
|
||||
Vector<Vector<TextureResource>> m_deferredReleases;
|
||||
Vector<Vector<VkImageView>> m_deferredViewReleases;
|
||||
};
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -153,6 +153,22 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
Uint32 samplerBinding = 0;
|
||||
};
|
||||
|
||||
struct DepthMipmapResources {
|
||||
SharedPtr<MG_State::GLState::ProgramObject> program;
|
||||
Int srcRectLocation = -1;
|
||||
Int dstRectLocation = -1;
|
||||
Int surfaceTransformLocation = -1;
|
||||
Int srcTexelSizeLocation = -1;
|
||||
Uint32 samplerBinding = 0;
|
||||
};
|
||||
|
||||
struct DeferredDepthMipmapCleanup {
|
||||
Vector<VkImageView> imageViews;
|
||||
Vector<VkFramebuffer> framebuffers;
|
||||
Vector<VkRenderPass> renderPasses;
|
||||
Vector<VkPipeline> pipelines;
|
||||
};
|
||||
|
||||
void QueueClearBufferPayload(GLenum buffer, GLint drawbuffer, const ClearAttachmentPayload& clearPayload);
|
||||
|
||||
NativeWindowType m_window = 0;
|
||||
@@ -196,6 +212,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
UniquePtr<VkTextureManager> m_textureManager;
|
||||
UniquePtr<VkSamplerManager> m_samplerManager;
|
||||
BlitResources m_blitResources;
|
||||
DepthMipmapResources m_depthMipmapResources;
|
||||
Vector<DeferredDepthMipmapCleanup> m_deferredDepthMipmapCleanup;
|
||||
|
||||
void CreateInstance();
|
||||
VkResult SetupDebugMessenger();
|
||||
@@ -220,7 +238,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
const MG_State::GLState::VertexArrayObject& vao,
|
||||
const IndexBufferView* pIndexBufferView = nullptr);
|
||||
Bool InitializeBlitResources();
|
||||
Bool InitializeDepthMipmapResources();
|
||||
void ShutdownBlitResources();
|
||||
void ShutdownDepthMipmapResources();
|
||||
void CollectDeferredDepthMipmapCleanup(Uint32 frameIndex);
|
||||
void DestroyDeferredDepthMipmapCleanup();
|
||||
Bool TryBlitToDefaultFramebufferWithShader(FrameContext::FrameData& frame,
|
||||
MG_State::GLState::FramebufferObject& readFbo,
|
||||
MG_State::GLState::FramebufferObject& drawFbo,
|
||||
@@ -230,6 +252,14 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
Bool MaterializePendingClearForTexture(VkCommandBuffer commandBuffer,
|
||||
MG_State::GLState::ITextureObject& texture);
|
||||
VkPipeline GetOrCreateBlitPipeline(const RenderPassEntry& renderPassEntry);
|
||||
Bool GenerateDepthMipmapWithShader(FrameContext::FrameData& frame,
|
||||
MG_State::GLState::ITextureObject& texture,
|
||||
VkTextureManager::TextureResource& resource,
|
||||
Uint32 baseMipLevel,
|
||||
Uint32 generateMipLevelCount,
|
||||
const IntVec3& storageBaseTexelSize,
|
||||
VkImageLayout originalLayout,
|
||||
VkImageLayout finalLayout);
|
||||
|
||||
void ShutdownSwapchain();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user