mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-07 19:58:32 +09:00
[Fix] (MG_Backend/DirectVulkan): fix Minecraft 26.2 startup crashes
- Support cube map face uploads with cube-compatible images and per-face array layers - Add uniform texel buffer descriptor support for samplerBuffer bindings - Cache transient vertex/index buffer uploads per frame to avoid VMA allocation failures
This commit is contained in:
@@ -931,6 +931,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
case SPV_REFLECT_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
|
||||
case SPV_REFLECT_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
|
||||
return ProgramFactory::DescriptorBindingKind::CombinedImageSampler;
|
||||
case SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
|
||||
return ProgramFactory::DescriptorBindingKind::UniformTexelBuffer;
|
||||
default:
|
||||
MOBILEGL_ASSERT(false, "ProgramFactory: unsupported reflected descriptor type %d",
|
||||
static_cast<Int>(descriptorType));
|
||||
@@ -951,7 +953,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
static_cast<Int>(binding.descriptor_type));
|
||||
|
||||
String name = rawName;
|
||||
if (kind == ProgramFactory::DescriptorBindingKind::CombinedImageSampler) {
|
||||
if (kind == ProgramFactory::DescriptorBindingKind::CombinedImageSampler ||
|
||||
kind == ProgramFactory::DescriptorBindingKind::UniformTexelBuffer) {
|
||||
const auto arraySuffix = name.find("[0]");
|
||||
if (arraySuffix != String::npos) {
|
||||
name = name.substr(0, arraySuffix);
|
||||
@@ -1404,7 +1407,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
entry.uniformBlockIndexByBinding[binding] = static_cast<Int>(blockIndex);
|
||||
}
|
||||
|
||||
// Reflect sampled images
|
||||
// Reflect sampled images and samplerBuffer uniforms.
|
||||
uint32_t reflectedBindingCount = 0;
|
||||
SpvReflectResult reflectResult =
|
||||
spvReflectEnumerateDescriptorBindings(&reflectModule, &reflectedBindingCount, nullptr);
|
||||
@@ -1426,13 +1429,14 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
if (sampler == nullptr) {
|
||||
continue;
|
||||
}
|
||||
if (sampler->descriptor_type != SPV_REFLECT_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER &&
|
||||
sampler->descriptor_type != SPV_REFLECT_DESCRIPTOR_TYPE_SAMPLED_IMAGE) {
|
||||
const auto descriptorKind = ReflectDescriptorTypeToBindingKind(sampler->descriptor_type);
|
||||
if (descriptorKind != DescriptorBindingKind::CombinedImageSampler &&
|
||||
descriptorKind != DescriptorBindingKind::UniformTexelBuffer) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const Uint32 binding = sampler->binding;
|
||||
const String uniformName = NormalizeDescriptorName(*sampler, DescriptorBindingKind::CombinedImageSampler);
|
||||
const String uniformName = NormalizeDescriptorName(*sampler, descriptorKind);
|
||||
MOBILEGL_ASSERT(binding < m_maxBindings,
|
||||
"ProgramFactory::ReflectLayout: sampler binding %u exceeds maxBindings=%u for '%s'",
|
||||
binding, m_maxBindings, uniformName.c_str());
|
||||
@@ -1443,10 +1447,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
}
|
||||
|
||||
MOBILEGL_ASSERT(entry.bindingKinds[binding] == DescriptorBindingKind::None ||
|
||||
entry.bindingKinds[binding] == DescriptorBindingKind::CombinedImageSampler,
|
||||
entry.bindingKinds[binding] == descriptorKind,
|
||||
"ProgramFactory::ReflectLayout: descriptor binding %u has conflicting kinds for sampler '%s'",
|
||||
binding, uniformName.c_str());
|
||||
entry.bindingKinds[binding] = DescriptorBindingKind::CombinedImageSampler;
|
||||
entry.bindingKinds[binding] = descriptorKind;
|
||||
|
||||
const TextureTarget target = UniformTypeToTextureTarget(program.GetUniformType(static_cast<Uint>(location)));
|
||||
MOBILEGL_ASSERT(target != TextureTarget::Unknown,
|
||||
@@ -1493,6 +1497,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
if (kind == DescriptorBindingKind::UniformBufferDynamic) {
|
||||
layoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
|
||||
entry.dynamicBindings.push_back(binding);
|
||||
} else if (kind == DescriptorBindingKind::UniformTexelBuffer) {
|
||||
layoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
|
||||
} else {
|
||||
layoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
enum class DescriptorBindingKind : Uint8 {
|
||||
None = 0,
|
||||
UniformBufferDynamic,
|
||||
CombinedImageSampler
|
||||
CombinedImageSampler,
|
||||
UniformTexelBuffer
|
||||
};
|
||||
|
||||
enum class CompileOptionBit : Uint {
|
||||
|
||||
@@ -11,7 +11,10 @@
|
||||
#include "MG_State/GLState/Core.h"
|
||||
#include "MG_State/GLState/ProgramState/ProgramObject.h"
|
||||
#include "MG_State/GLState/TextureState/TextureObject2D.h"
|
||||
#include "MG_State/GLState/TextureState/TextureObjectBuffer.h"
|
||||
#include "MG_Util/Converters/MGToStr/FramebufferEnumConverter.h"
|
||||
#include "MG_Util/Converters/MGToVk/TextureEnumConverter.h"
|
||||
#include "MG_Util/Metrics/TextureMetrics.h"
|
||||
#include <limits>
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
@@ -126,6 +129,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
void UniformManager::Shutdown() {
|
||||
for (auto& frame : m_frames) {
|
||||
if (m_device != VK_NULL_HANDLE) {
|
||||
for (auto& view : frame.texelBufferViews) {
|
||||
if (view != VK_NULL_HANDLE) {
|
||||
vkDestroyBufferView(m_device, view, nullptr);
|
||||
}
|
||||
}
|
||||
frame.texelBufferViews.clear();
|
||||
for (auto& bucket : frame.descriptorPools) {
|
||||
if (bucket.handle != VK_NULL_HANDLE) {
|
||||
vkDestroyDescriptorPool(m_device, bucket.handle, nullptr);
|
||||
@@ -156,6 +165,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
void UniformManager::BeginFrame(Uint32 frameIndex) {
|
||||
MOBILEGL_ASSERT(frameIndex < m_frames.size(), "UniformDescriptorBinder::BeginFrame invalid frame index");
|
||||
auto& frame = m_frames[frameIndex];
|
||||
for (auto& view : frame.texelBufferViews) {
|
||||
if (view != VK_NULL_HANDLE) {
|
||||
vkDestroyBufferView(m_device, view, nullptr);
|
||||
}
|
||||
}
|
||||
frame.texelBufferViews.clear();
|
||||
if (frame.peakAllocatedSetsThisFrame > m_peakDescriptorSetsObserved) {
|
||||
m_peakDescriptorSetsObserved = frame.peakAllocatedSetsThisFrame;
|
||||
MGLOG_D(
|
||||
@@ -304,6 +319,84 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
return true;
|
||||
}
|
||||
|
||||
Bool UniformManager::ResolveTexelBufferDescriptor(const MG_State::GLState::ProgramObject& program,
|
||||
const ProgramFactory::VkProgramObject& programObj,
|
||||
Uint32 binding, Uint32 frameIndex,
|
||||
VkBufferView& outBufferView) {
|
||||
outBufferView = VK_NULL_HANDLE;
|
||||
MOBILEGL_ASSERT(m_bufferManager != nullptr, "ResolveTexelBufferDescriptor: buffer manager is null");
|
||||
MOBILEGL_ASSERT(frameIndex < m_frames.size(), "ResolveTexelBufferDescriptor: frame index out of range");
|
||||
|
||||
SharedPtr<MG_State::GLState::ITextureObject> texture;
|
||||
if (!ResolveSamplerTexture(program, programObj, binding, texture) || texture == nullptr) {
|
||||
MGLOG_E("ResolveTexelBufferDescriptor: texture buffer binding %u ('%s') is unbound", binding,
|
||||
programObj.samplerNameByBinding[binding].c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (texture->GetStorageType() != TextureStorageType::Buffer ||
|
||||
texture->GetTarget() != TextureTarget::TextureBuffer) {
|
||||
MGLOG_E(
|
||||
"ResolveTexelBufferDescriptor: binding %u ('%s') expected texture buffer, got textureId=%u target=%d storage=%d",
|
||||
binding, programObj.samplerNameByBinding[binding].c_str(), texture->GetExternalIndex(),
|
||||
static_cast<Int>(texture->GetTarget()), static_cast<Int>(texture->GetStorageType()));
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* textureBuffer = static_cast<MG_State::GLState::TextureObjectBuffer*>(texture.get());
|
||||
const auto bufferObject = textureBuffer->GetBufferBindingSlot().GetBoundObject();
|
||||
if (bufferObject == nullptr) {
|
||||
MGLOG_E("ResolveTexelBufferDescriptor: texture buffer binding %u ('%s') has no GL buffer bound",
|
||||
binding, programObj.samplerNameByBinding[binding].c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
BufferSlice slice{};
|
||||
if (!m_bufferManager->SyncResidentBuffer(BufferKind::TextureBuffer, bufferObject, slice) || !slice.IsValid()) {
|
||||
MGLOG_E("ResolveTexelBufferDescriptor: failed to sync GL buffer %u for texture buffer %u",
|
||||
bufferObject->GetExternalIndex(), texture->GetExternalIndex());
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto internalFormat = textureBuffer->GetFormat();
|
||||
const VkFormat vkFormat = MG_Util::ConvertTextureInternalFormatToVkEnum(internalFormat);
|
||||
if (vkFormat == VK_FORMAT_UNDEFINED) {
|
||||
MGLOG_E("ResolveTexelBufferDescriptor: unsupported texture buffer internal format %d",
|
||||
static_cast<Int>(internalFormat));
|
||||
return false;
|
||||
}
|
||||
|
||||
const VkDeviceSize texelSize =
|
||||
static_cast<VkDeviceSize>(MG_Util::GetSizedInternalFormatSizeInBytes(internalFormat));
|
||||
VkDeviceSize viewRange = slice.size;
|
||||
if (texelSize > 0) {
|
||||
viewRange = (viewRange / texelSize) * texelSize;
|
||||
}
|
||||
if (viewRange == 0) {
|
||||
MGLOG_E("ResolveTexelBufferDescriptor: texture buffer %u has empty view range", texture->GetExternalIndex());
|
||||
return false;
|
||||
}
|
||||
|
||||
VkBufferViewCreateInfo viewInfo{};
|
||||
viewInfo.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO;
|
||||
viewInfo.buffer = slice.buffer;
|
||||
viewInfo.format = vkFormat;
|
||||
viewInfo.offset = slice.offset;
|
||||
viewInfo.range = viewRange;
|
||||
|
||||
VkBufferView bufferView = VK_NULL_HANDLE;
|
||||
const VkResult result = vkCreateBufferView(m_device, &viewInfo, nullptr, &bufferView);
|
||||
if (result != VK_SUCCESS || bufferView == VK_NULL_HANDLE) {
|
||||
MGLOG_E("ResolveTexelBufferDescriptor: vkCreateBufferView failed result=%d format=%d range=%zu",
|
||||
result, static_cast<Int>(vkFormat), static_cast<SizeT>(viewRange));
|
||||
return false;
|
||||
}
|
||||
|
||||
m_frames[frameIndex].texelBufferViews.push_back(bufferView);
|
||||
outBufferView = bufferView;
|
||||
return true;
|
||||
}
|
||||
|
||||
SharedPtr<MG_State::GLState::ITextureObject> UniformManager::GetFallbackTexture(TextureTarget target) const {
|
||||
MOBILEGL_ASSERT(target == TextureTarget::Texture2D || target == TextureTarget::TextureRectangle,
|
||||
"UniformManager::GetFallbackTexture: unsupported fallback target=%d",
|
||||
@@ -441,11 +534,13 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
}
|
||||
|
||||
const Uint32 descriptorCount = static_cast<Uint32>(descriptorCount64);
|
||||
VkDescriptorPoolSize poolSizes[2]{};
|
||||
VkDescriptorPoolSize poolSizes[3]{};
|
||||
poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
|
||||
poolSizes[0].descriptorCount = descriptorCount;
|
||||
poolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
poolSizes[1].descriptorCount = descriptorCount;
|
||||
poolSizes[2].type = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
|
||||
poolSizes[2].descriptorCount = descriptorCount;
|
||||
|
||||
VkDescriptorPoolCreateInfo poolInfo{};
|
||||
poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
||||
@@ -543,9 +638,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
writes.reserve(m_maxBindings);
|
||||
Vector<VkDescriptorBufferInfo> bufferInfos;
|
||||
Vector<VkDescriptorImageInfo> imageInfos;
|
||||
Vector<VkBufferView> texelBufferViews;
|
||||
Vector<Uint32> dynamicOffsets;
|
||||
bufferInfos.reserve(m_maxBindings);
|
||||
imageInfos.reserve(m_maxBindings);
|
||||
texelBufferViews.reserve(m_maxBindings);
|
||||
dynamicOffsets.reserve(programObj.dynamicBindings.size());
|
||||
|
||||
const Uint32 bindingCount =
|
||||
@@ -589,6 +686,20 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
write.pBufferInfo = &bufferInfos.back();
|
||||
writes.push_back(write);
|
||||
dynamicOffsets.push_back(static_cast<Uint32>(slice.offset));
|
||||
} else if (kind == ProgramFactory::DescriptorBindingKind::UniformTexelBuffer) {
|
||||
VkBufferView bufferView = VK_NULL_HANDLE;
|
||||
if (!ResolveTexelBufferDescriptor(program, programObj, binding, frameIndex, bufferView) ||
|
||||
bufferView == VK_NULL_HANDLE) {
|
||||
MGLOG_E(
|
||||
"UniformDescriptorBinder::BindProgramUniformBuffers failed: texture buffer binding %u has no valid descriptor",
|
||||
binding);
|
||||
return false;
|
||||
}
|
||||
|
||||
texelBufferViews.push_back(bufferView);
|
||||
write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
|
||||
write.pTexelBufferView = &texelBufferViews.back();
|
||||
writes.push_back(write);
|
||||
} else {
|
||||
VkDescriptorImageInfo imageInfo{};
|
||||
Bool hasImage = false;
|
||||
|
||||
@@ -57,6 +57,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
|
||||
struct FrameResources {
|
||||
Vector<DescriptorPoolBucket> descriptorPools;
|
||||
Vector<VkBufferView> texelBufferViews;
|
||||
Uint32 activeDescriptorPoolIndex = 0;
|
||||
Uint32 allocatedSetsThisFrame = 0;
|
||||
Uint32 peakAllocatedSetsThisFrame = 0;
|
||||
@@ -71,6 +72,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
VkDescriptorImageInfo& outImageInfo) const;
|
||||
Bool ResolveSamplerDescriptorOverride(const SamplerBindingOverride& samplerBindingOverride,
|
||||
VkDescriptorImageInfo& outImageInfo) const;
|
||||
Bool ResolveTexelBufferDescriptor(const MG_State::GLState::ProgramObject& program,
|
||||
const ProgramFactory::VkProgramObject& programObj, Uint32 binding,
|
||||
Uint32 frameIndex, VkBufferView& outBufferView);
|
||||
Bool ResolveUniformBufferPayload(const MG_State::GLState::ProgramObject& program,
|
||||
const ProgramFactory::VkProgramObject& programObj, Uint32 binding,
|
||||
const void*& outData, VkDeviceSize& outSize) const;
|
||||
|
||||
@@ -80,7 +80,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
BufferSlice& outSlice) {
|
||||
const VkBufferUsageFlags requiredUsage = GetVkBufferUsage(kind);
|
||||
MOBILEGL_ASSERT(requiredUsage != 0,
|
||||
"VkBufferManager::SyncResidentBuffer only supports resident vertex/index buffers");
|
||||
"VkBufferManager::SyncResidentBuffer unsupported resident buffer kind");
|
||||
MOBILEGL_ASSERT(bufferObject != nullptr, "VkBufferManager::SyncResidentBuffer requires valid buffer object");
|
||||
CollectResidentGarbageIfNeeded();
|
||||
|
||||
@@ -196,6 +196,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
// never need to recreate a buffer after it has already been bound.
|
||||
return VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
|
||||
case BufferKind::Uniform:
|
||||
return VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
|
||||
case BufferKind::TextureBuffer:
|
||||
return VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
Vertex,
|
||||
Index,
|
||||
Uniform,
|
||||
TextureBuffer,
|
||||
};
|
||||
|
||||
struct VkBufferManagerInitInfo {
|
||||
|
||||
@@ -43,6 +43,18 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
Uint32 arrayLayers = 1;
|
||||
};
|
||||
|
||||
static Bool IsCubeMapFaceUploadTarget(TextureUploadTarget target) {
|
||||
return target >= TextureUploadTarget::CubeMapPositiveX &&
|
||||
target <= TextureUploadTarget::CubeMapNegativeZ;
|
||||
}
|
||||
|
||||
static Uint32 ResolveUploadArrayLayer(TextureUploadTarget target) {
|
||||
if (!IsCubeMapFaceUploadTarget(target)) {
|
||||
return 0;
|
||||
}
|
||||
return static_cast<Uint32>(target) - static_cast<Uint32>(TextureUploadTarget::CubeMapPositiveX);
|
||||
}
|
||||
|
||||
static Bool IsValidSampledImageLayout(VkImageLayout layout) {
|
||||
switch (layout) {
|
||||
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
|
||||
@@ -174,7 +186,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
Bool ok = VkTextureManager::TransitionImageLayout(
|
||||
commandBuffer, newResource.image, newResource.layout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
0, VK_ACCESS_TRANSFER_WRITE_BIT, newResource.aspect, 0, newResource.mipLevels);
|
||||
0, VK_ACCESS_TRANSFER_WRITE_BIT, newResource.aspect, 0, newResource.mipLevels,
|
||||
newResource.arrayLayers);
|
||||
MOBILEGL_ASSERT(ok, "PreserveTextureContentsOnRecreate: failed to prepare destination image");
|
||||
|
||||
VkImageLayout srcTrackedLayout = oldResource.layout;
|
||||
@@ -184,7 +197,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
ok = VkTextureManager::TransitionImageLayout(
|
||||
commandBuffer, oldResource.image, srcTrackedLayout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||
srcStageMask, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
srcAccessMask, VK_ACCESS_TRANSFER_READ_BIT, oldResource.aspect, 0, preservedMipLevels);
|
||||
srcAccessMask, VK_ACCESS_TRANSFER_READ_BIT, oldResource.aspect, 0, preservedMipLevels,
|
||||
oldResource.arrayLayers);
|
||||
MOBILEGL_ASSERT(ok, "PreserveTextureContentsOnRecreate: failed to prepare source image");
|
||||
|
||||
Vector<VkImageCopy> copyRegions;
|
||||
@@ -216,7 +230,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
ok = VkTextureManager::TransitionImageLayout(
|
||||
commandBuffer, newResource.image, newResource.layout, oldResource.layout,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, dstStageMask,
|
||||
VK_ACCESS_TRANSFER_WRITE_BIT, dstAccessMask, newResource.aspect, 0, newResource.mipLevels);
|
||||
VK_ACCESS_TRANSFER_WRITE_BIT, dstAccessMask, newResource.aspect, 0, newResource.mipLevels,
|
||||
newResource.arrayLayers);
|
||||
MOBILEGL_ASSERT(ok, "PreserveTextureContentsOnRecreate: failed to restore destination layout");
|
||||
|
||||
VK_VERIFY(vkEndCommandBuffer(commandBuffer), "vkEndCommandBuffer(texture preserve)");
|
||||
@@ -351,6 +366,26 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
outShape.viewType = VK_IMAGE_VIEW_TYPE_3D;
|
||||
outShape.depth = static_cast<Uint32>(texelSize.z());
|
||||
return true;
|
||||
case TextureUploadTarget::CubeMapPositiveX:
|
||||
case TextureUploadTarget::CubeMapNegativeX:
|
||||
case TextureUploadTarget::CubeMapPositiveY:
|
||||
case TextureUploadTarget::CubeMapNegativeY:
|
||||
case TextureUploadTarget::CubeMapPositiveZ:
|
||||
case TextureUploadTarget::CubeMapNegativeZ:
|
||||
case TextureUploadTarget::ProxyCubeMap:
|
||||
MOBILEGL_ASSERT(texture.GetTarget() == TextureTarget::TextureCubeMap,
|
||||
"TryResolveTextureShapeInfo: cube upload target on non-cube textureId=%d target=%s",
|
||||
texture.GetExternalIndex(),
|
||||
MG_Util::ConvertTextureTargetToString(texture.GetTarget()).c_str());
|
||||
MOBILEGL_ASSERT(texelSize.x() == texelSize.y(),
|
||||
"TryResolveTextureShapeInfo: cube map textureId=%d is not square (%d x %d)",
|
||||
texture.GetExternalIndex(), texelSize.x(), texelSize.y());
|
||||
outShape.imageType = VK_IMAGE_TYPE_2D;
|
||||
outShape.viewType = VK_IMAGE_VIEW_TYPE_CUBE;
|
||||
outShape.imageFlags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
|
||||
outShape.depth = 1;
|
||||
outShape.arrayLayers = 6;
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -518,7 +553,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
const Bool lowerTransitioned = TransitionImageLayout(
|
||||
commandBuffer, resource.image, lowerMipLayout, newLayout,
|
||||
srcStageMask, dstStageMask, srcAccessMask, dstAccessMask,
|
||||
resource.aspect, 0, writtenMipLevel);
|
||||
resource.aspect, 0, writtenMipLevel, resource.arrayLayers);
|
||||
MOBILEGL_ASSERT(lowerTransitioned,
|
||||
"UpdateTrackedImageLayoutAfterAttachmentWrite: failed to transition lower mip levels for textureId=%d",
|
||||
texture->GetExternalIndex());
|
||||
@@ -530,7 +565,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
const Bool upperTransitioned = TransitionImageLayout(
|
||||
commandBuffer, resource.image, upperMipLayout, newLayout,
|
||||
srcStageMask, dstStageMask, srcAccessMask, dstAccessMask,
|
||||
resource.aspect, upperBaseMipLevel, resource.mipLevels - upperBaseMipLevel);
|
||||
resource.aspect, upperBaseMipLevel, resource.mipLevels - upperBaseMipLevel,
|
||||
resource.arrayLayers);
|
||||
MOBILEGL_ASSERT(upperTransitioned,
|
||||
"UpdateTrackedImageLayoutAfterAttachmentWrite: failed to transition upper mip levels for textureId=%d",
|
||||
texture->GetExternalIndex());
|
||||
@@ -583,7 +619,8 @@ 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, 0, resource->mipLevels);
|
||||
VK_ACCESS_SHADER_READ_BIT, resource->aspect, 0, resource->mipLevels,
|
||||
resource->arrayLayers);
|
||||
MOBILEGL_ASSERT(ok, "TransitionTextureForSampling: transition failed for textureId=%d", texture.GetExternalIndex());
|
||||
return ok;
|
||||
}
|
||||
@@ -592,7 +629,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
VkImageLayout& trackedLayout, VkImageLayout newLayout,
|
||||
VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask,
|
||||
VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask,
|
||||
VkImageAspectFlags aspectMask, Uint32 baseMipLevel, Uint32 levelCount) {
|
||||
VkImageAspectFlags aspectMask, Uint32 baseMipLevel, Uint32 levelCount,
|
||||
Uint32 layerCount) {
|
||||
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),
|
||||
@@ -617,7 +655,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
barrier.subresourceRange.baseMipLevel = baseMipLevel;
|
||||
barrier.subresourceRange.levelCount = levelCount;
|
||||
barrier.subresourceRange.baseArrayLayer = 0;
|
||||
barrier.subresourceRange.layerCount = 1;
|
||||
barrier.subresourceRange.layerCount = layerCount;
|
||||
vkCmdPipelineBarrier(commandBuffer, srcStageMask, dstStageMask, 0, 0, nullptr, 0, nullptr, 1, &barrier);
|
||||
|
||||
trackedLayout = newLayout;
|
||||
@@ -666,10 +704,22 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
return false;
|
||||
}
|
||||
|
||||
Vector<TextureUploadTarget> dirtyTargets;
|
||||
if (outResource.viewType == VK_IMAGE_VIEW_TYPE_CUBE) {
|
||||
dirtyTargets = mipTexture->GetUploadTargets();
|
||||
} else {
|
||||
dirtyTargets.push_back(uploadTarget);
|
||||
}
|
||||
Bool hasDirtyMipLevel = false;
|
||||
for (Uint32 level = 0; level < mipLevelCount; ++level) {
|
||||
if (mipTexture->IsStorageDirty(uploadTarget, level)) {
|
||||
hasDirtyMipLevel = true;
|
||||
for (const TextureUploadTarget target : dirtyTargets) {
|
||||
const Uint32 targetMipLevelCount = std::min(mipLevelCount, GetUploadMipLevelCount(*mipTexture, target));
|
||||
for (Uint32 level = 0; level < targetMipLevelCount; ++level) {
|
||||
if (mipTexture->IsStorageDirty(target, level)) {
|
||||
hasDirtyMipLevel = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hasDirtyMipLevel) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -933,7 +983,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
TextureUploadTarget uploadTarget,
|
||||
TextureResource &outResource) {
|
||||
struct UploadItem {
|
||||
TextureUploadTarget target = TextureUploadTarget::Unknown;
|
||||
Uint32 level = 0;
|
||||
Uint32 baseArrayLayer = 0;
|
||||
SizeT uploadByteSize = 0;
|
||||
IntVec3 texelSize = {0, 0, 0};
|
||||
const void* source = nullptr;
|
||||
@@ -942,52 +994,64 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
};
|
||||
|
||||
Vector<UploadItem> uploadItems;
|
||||
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);
|
||||
Vector<TextureUploadTarget> targets;
|
||||
if (outResource.viewType == VK_IMAGE_VIEW_TYPE_CUBE) {
|
||||
targets = mipmapTexture.GetUploadTargets();
|
||||
} else {
|
||||
targets.push_back(uploadTarget);
|
||||
}
|
||||
const TextureFormatInfo formatInfo = ResolveTextureFormatInfo(mipmapTexture.GetFormat());
|
||||
|
||||
VkDeviceSize stagingSize = 0;
|
||||
for (Uint32 level = 0; level < definedMipLevels; ++level) {
|
||||
if (!mipmapTexture.IsStorageDirty(uploadTarget, level)) {
|
||||
continue;
|
||||
}
|
||||
for (const TextureUploadTarget target : targets) {
|
||||
const Uint32 definedMipLevels = GetUploadMipLevelCount(mipmapTexture, target);
|
||||
MOBILEGL_ASSERT(definedMipLevels <= outResource.mipLevels,
|
||||
"UploadDirtyMipLevels: defined mip level count %u exceeds backing mip level count %u for textureId=%d target=%s",
|
||||
definedMipLevels, outResource.mipLevels, mipmapTexture.GetExternalIndex(),
|
||||
MG_Util::ConvertTextureUploadTargetToString(target).c_str());
|
||||
|
||||
const auto texelSize = mipmapTexture.GetMipmapTexelSize(uploadTarget, level);
|
||||
const auto byteSize = mipmapTexture.GetMipmapByteSize(uploadTarget, level);
|
||||
if (texelSize.x() <= 0 || texelSize.y() <= 0 || byteSize == 0) {
|
||||
mipmapTexture.MarkStorageDirty(uploadTarget, level, false);
|
||||
continue;
|
||||
}
|
||||
for (Uint32 level = 0; level < definedMipLevels; ++level) {
|
||||
if (!mipmapTexture.IsStorageDirty(target, level)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const void* source = mipmapTexture.MapMipmapData(uploadTarget, level);
|
||||
if (source == nullptr) {
|
||||
MGLOG_D("%s: MapmipmapData failed at level %d", __func__, level);
|
||||
return false;
|
||||
}
|
||||
const auto texelSize = mipmapTexture.GetMipmapTexelSize(target, level);
|
||||
const auto byteSize = mipmapTexture.GetMipmapByteSize(target, level);
|
||||
if (texelSize.x() <= 0 || texelSize.y() <= 0 || byteSize == 0) {
|
||||
mipmapTexture.MarkStorageDirty(target, level, false);
|
||||
continue;
|
||||
}
|
||||
|
||||
UploadItem uploadItem{};
|
||||
uploadItem.level = level;
|
||||
uploadItem.texelSize = texelSize;
|
||||
uploadItem.source = source;
|
||||
uploadItem.offset = stagingSize;
|
||||
uploadItem.uploadByteSize = byteSize;
|
||||
if (formatInfo.expandRgbToRgba) {
|
||||
const Bool expanded = ExpandRgbSourceToRgba(source, byteSize, texelSize, formatInfo,
|
||||
uploadItem.expandedData);
|
||||
MOBILEGL_ASSERT(expanded,
|
||||
"UploadDirtyMipLevels: failed to expand RGB textureId=%d level=%u to RGBA staging data",
|
||||
mipmapTexture.GetExternalIndex(), level);
|
||||
uploadItem.uploadByteSize = uploadItem.expandedData.size();
|
||||
const void* source = mipmapTexture.MapMipmapData(target, level);
|
||||
if (source == nullptr) {
|
||||
MGLOG_D("%s: MapmipmapData failed at target %s level %d", __func__,
|
||||
MG_Util::ConvertTextureUploadTargetToString(target).c_str(), level);
|
||||
return false;
|
||||
}
|
||||
|
||||
UploadItem uploadItem{};
|
||||
uploadItem.target = target;
|
||||
uploadItem.level = level;
|
||||
uploadItem.baseArrayLayer = ResolveUploadArrayLayer(target);
|
||||
uploadItem.texelSize = texelSize;
|
||||
uploadItem.source = source;
|
||||
uploadItem.offset = stagingSize;
|
||||
uploadItem.uploadByteSize = byteSize;
|
||||
if (formatInfo.expandRgbToRgba) {
|
||||
const Bool expanded = ExpandRgbSourceToRgba(source, byteSize, texelSize, formatInfo,
|
||||
uploadItem.expandedData);
|
||||
MOBILEGL_ASSERT(expanded,
|
||||
"UploadDirtyMipLevels: failed to expand RGB textureId=%d target=%s level=%u to RGBA staging data",
|
||||
mipmapTexture.GetExternalIndex(),
|
||||
MG_Util::ConvertTextureUploadTargetToString(target).c_str(), level);
|
||||
uploadItem.uploadByteSize = uploadItem.expandedData.size();
|
||||
}
|
||||
uploadItems.push_back(Move(uploadItem));
|
||||
if (!uploadItems.back().expandedData.empty()) {
|
||||
uploadItems.back().source = uploadItems.back().expandedData.data();
|
||||
}
|
||||
stagingSize += static_cast<VkDeviceSize>(uploadItems.back().uploadByteSize);
|
||||
}
|
||||
uploadItems.push_back(Move(uploadItem));
|
||||
if (!uploadItems.back().expandedData.empty()) {
|
||||
uploadItems.back().source = uploadItems.back().expandedData.data();
|
||||
}
|
||||
stagingSize += static_cast<VkDeviceSize>(uploadItems.back().uploadByteSize);
|
||||
}
|
||||
|
||||
if (uploadItems.empty()) {
|
||||
@@ -1034,13 +1098,13 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
Bool ok = TransitionImageLayout(commandBuffer, outResource.image,
|
||||
outResource.layout,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
outResource.layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ?
|
||||
kGraphicsSampledReadStages :
|
||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||
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, 0, outResource.mipLevels);
|
||||
outResource.layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ?
|
||||
kGraphicsSampledReadStages :
|
||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||
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, 0, outResource.mipLevels, outResource.arrayLayers);
|
||||
MOBILEGL_ASSERT(ok, "TransitionImageLayout to VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL failed");
|
||||
|
||||
for (const auto& item : uploadItems) {
|
||||
@@ -1050,7 +1114,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
copy.bufferImageHeight = 0;
|
||||
copy.imageSubresource.aspectMask = aspectMask;
|
||||
copy.imageSubresource.mipLevel = item.level;
|
||||
copy.imageSubresource.baseArrayLayer = 0;
|
||||
copy.imageSubresource.baseArrayLayer = item.baseArrayLayer;
|
||||
copy.imageSubresource.layerCount = 1;
|
||||
copy.imageOffset = {0, 0, 0};
|
||||
copy.imageExtent = {static_cast<Uint32>(item.texelSize.x()), static_cast<Uint32>(item.texelSize.y()),
|
||||
@@ -1066,7 +1130,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
kGraphicsSampledReadStages,
|
||||
VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
VK_ACCESS_SHADER_READ_BIT,
|
||||
aspectMask, 0, outResource.mipLevels);
|
||||
aspectMask, 0, outResource.mipLevels, outResource.arrayLayers);
|
||||
MOBILEGL_ASSERT(ok, "TransitionImageLayout to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL failed");
|
||||
outResource.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
|
||||
@@ -1094,7 +1158,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
return false;
|
||||
}
|
||||
for (const auto& item : uploadItems) {
|
||||
mipmapTexture.MarkStorageDirty(uploadTarget, item.level, false);
|
||||
mipmapTexture.MarkStorageDirty(item.target, item.level, false);
|
||||
}
|
||||
outResource.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
return true;
|
||||
|
||||
@@ -130,7 +130,8 @@ public:
|
||||
VkImageLayout newLayout, VkPipelineStageFlags srcStageMask,
|
||||
VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask,
|
||||
VkAccessFlags dstAccessMask, VkImageAspectFlags aspectMask,
|
||||
Uint32 baseMipLevel = 0, Uint32 levelCount = 1);
|
||||
Uint32 baseMipLevel = 0, Uint32 levelCount = 1,
|
||||
Uint32 layerCount = 1);
|
||||
|
||||
SizeT CollectGarbage();
|
||||
private:
|
||||
|
||||
@@ -332,12 +332,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
}
|
||||
}
|
||||
|
||||
static Bool HasTransientVertexIndexBufferThisFrame(
|
||||
const Vector<const MG_State::GLState::BufferObject*>& buffers,
|
||||
const MG_State::GLState::BufferObject* buffer) {
|
||||
return std::find(buffers.begin(), buffers.end(), buffer) != buffers.end();
|
||||
}
|
||||
|
||||
static Uint32 BuildVertexInputAttributeMask(const Vector<VkVertexInputAttributeDescription>& attributes) {
|
||||
Uint32 attributeMask = 0;
|
||||
for (const auto& attribute : attributes) {
|
||||
@@ -1218,7 +1212,7 @@ void main() {
|
||||
"Initialize, WaitAndAcquireNextImage");
|
||||
m_textureManager->BeginFrame(m_frameContext.GetCurrentFrameIndex());
|
||||
m_bufferManager.BeginFrame(m_frameContext.GetCurrentFrameIndex());
|
||||
m_transientVertexIndexBuffersThisFrame.clear();
|
||||
m_transientVertexIndexBufferSlicesThisFrame.clear();
|
||||
|
||||
MGLOG_D("VulkanRenderer initialized");
|
||||
}
|
||||
@@ -1241,7 +1235,7 @@ void main() {
|
||||
}
|
||||
m_vertexInputStateFactory.reset();
|
||||
m_bufferManager.Shutdown();
|
||||
m_transientVertexIndexBuffersThisFrame.clear();
|
||||
m_transientVertexIndexBufferSlicesThisFrame.clear();
|
||||
|
||||
m_frameContext.Destroy(m_device, m_commandPool);
|
||||
|
||||
@@ -1328,10 +1322,11 @@ void main() {
|
||||
MOBILEGL_ASSERT(sourceBufferShared != nullptr,
|
||||
"UploadAndBindVertexStreams failed to resolve shared source buffer");
|
||||
BufferSlice slice{};
|
||||
const Bool transientThisFrame =
|
||||
HasTransientVertexIndexBufferThisFrame(m_transientVertexIndexBuffersThisFrame, sourceBufferShared.get());
|
||||
const Bool isDirty = (sourceBufferShared->GetChangeBits() & BufferChangeBits::DirtyBit);
|
||||
if (ShouldUseTransientVertexIndexBuffer(*sourceBufferShared) || transientThisFrame || isDirty) {
|
||||
auto cachedTransient = m_transientVertexIndexBufferSlicesThisFrame.find(sourceBufferShared.get());
|
||||
if (cachedTransient != m_transientVertexIndexBufferSlicesThisFrame.end() && !isDirty) {
|
||||
slice = cachedTransient->second;
|
||||
} else if (ShouldUseTransientVertexIndexBuffer(*sourceBufferShared) || isDirty) {
|
||||
const auto sourceData = sourceBufferShared->GetDataReadOnly();
|
||||
const SizeT sourceSize = sourceBufferShared->GetSize();
|
||||
if (!m_bufferManager.UploadTransient(BufferKind::Vertex, m_frameContext.GetCurrentFrameIndex(),
|
||||
@@ -1340,9 +1335,7 @@ void main() {
|
||||
MOBILEGL_ASSERT(false, "UploadAndBindVertexStreams skipped: failed to upload transient binding %zu", binding);
|
||||
return false;
|
||||
}
|
||||
if (!transientThisFrame) {
|
||||
m_transientVertexIndexBuffersThisFrame.push_back(sourceBufferShared.get());
|
||||
}
|
||||
m_transientVertexIndexBufferSlicesThisFrame[sourceBufferShared.get()] = slice;
|
||||
m_bufferManager.DowngradeResidentBufferToTransient(sourceBufferShared);
|
||||
sourceBufferShared->ClearDirty();
|
||||
} else {
|
||||
@@ -1421,24 +1414,33 @@ void main() {
|
||||
BufferSlice slice{};
|
||||
auto indexBufferShared = MG_State::pGLContext->GetBufferObject(indexBuffer->GetExternalIndex());
|
||||
MOBILEGL_ASSERT(indexBufferShared != nullptr, "UploadAndBindIndexBuffer failed to resolve shared EBO");
|
||||
const Bool transientThisFrame =
|
||||
HasTransientVertexIndexBufferThisFrame(m_transientVertexIndexBuffersThisFrame, indexBufferShared.get());
|
||||
const Bool isDirty = (indexBufferShared->GetChangeBits() & BufferChangeBits::DirtyBit);
|
||||
if (ShouldUseTransientVertexIndexBuffer(*indexBufferShared) || transientThisFrame || isDirty) {
|
||||
auto cachedTransient = m_transientVertexIndexBufferSlicesThisFrame.find(indexBufferShared.get());
|
||||
if (cachedTransient != m_transientVertexIndexBufferSlicesThisFrame.end() && !isDirty) {
|
||||
slice = cachedTransient->second;
|
||||
vkCmdBindIndexBuffer(frame.commandBuffer,
|
||||
slice.buffer,
|
||||
slice.offset + static_cast<VkDeviceSize>(pIndexBufferView->indexByteOffset),
|
||||
vkIndexType);
|
||||
return true;
|
||||
}
|
||||
if (ShouldUseTransientVertexIndexBuffer(*indexBufferShared) || isDirty) {
|
||||
const auto indexData = indexBufferShared->GetDataReadOnly();
|
||||
MOBILEGL_ASSERT(indexData != nullptr && !indexData->empty(), "DrawElements requires non-empty EBO data");
|
||||
if (!m_bufferManager.UploadTransient(BufferKind::Index, m_frameContext.GetCurrentFrameIndex(),
|
||||
indexData->data() + pIndexBufferView->indexByteOffset,
|
||||
static_cast<VkDeviceSize>(indexDataSizeBytes), indexSize, slice)) {
|
||||
indexData->data(),
|
||||
static_cast<VkDeviceSize>(indexBufferShared->GetSize()), indexSize,
|
||||
slice)) {
|
||||
MOBILEGL_ASSERT(false, "DrawElements skipped: failed to prepare transient index buffer");
|
||||
return false;
|
||||
}
|
||||
if (!transientThisFrame) {
|
||||
m_transientVertexIndexBuffersThisFrame.push_back(indexBufferShared.get());
|
||||
}
|
||||
m_transientVertexIndexBufferSlicesThisFrame[indexBufferShared.get()] = slice;
|
||||
m_bufferManager.DowngradeResidentBufferToTransient(indexBufferShared);
|
||||
indexBufferShared->ClearDirty();
|
||||
vkCmdBindIndexBuffer(frame.commandBuffer, slice.buffer, slice.offset, vkIndexType);
|
||||
vkCmdBindIndexBuffer(frame.commandBuffer,
|
||||
slice.buffer,
|
||||
slice.offset + static_cast<VkDeviceSize>(pIndexBufferView->indexByteOffset),
|
||||
vkIndexType);
|
||||
return true;
|
||||
}
|
||||
if (!m_bufferManager.SyncResidentBuffer(BufferKind::Index, indexBufferShared, slice)) {
|
||||
@@ -3576,7 +3578,7 @@ void main() {
|
||||
CollectDeferredDepthMipmapCleanup(m_frameContext.GetCurrentFrameIndex());
|
||||
m_textureManager->BeginFrame(m_frameContext.GetCurrentFrameIndex());
|
||||
m_bufferManager.BeginFrame(m_frameContext.GetCurrentFrameIndex());
|
||||
m_transientVertexIndexBuffersThisFrame.clear();
|
||||
m_transientVertexIndexBufferSlicesThisFrame.clear();
|
||||
}
|
||||
|
||||
void VulkanRenderer::CreateInstance() {
|
||||
@@ -4178,7 +4180,7 @@ void main() {
|
||||
m_textureManager->BeginFrame(m_frameContext.GetCurrentFrameIndex());
|
||||
}
|
||||
m_bufferManager.BeginFrame(m_frameContext.GetCurrentFrameIndex());
|
||||
m_transientVertexIndexBuffersThisFrame.clear();
|
||||
m_transientVertexIndexBufferSlicesThisFrame.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -198,7 +198,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
VkCommandPool m_commandPool = VK_NULL_HANDLE;
|
||||
|
||||
VkBufferManager m_bufferManager;
|
||||
Vector<const MG_State::GLState::BufferObject*> m_transientVertexIndexBuffersThisFrame;
|
||||
UnorderedMap<const MG_State::GLState::BufferObject*, BufferSlice> m_transientVertexIndexBufferSlicesThisFrame;
|
||||
|
||||
Uint m_imageIndexAcquired = 0;
|
||||
FrameContext m_frameContext;
|
||||
|
||||
Reference in New Issue
Block a user