[Feat] (MG_Backend/DirectVulkan): implement multisample texture backend

This commit is contained in:
BZLZHH
2026-06-10 01:56:37 +08:00
parent 5c1fd733da
commit 6051588458
7 changed files with 140 additions and 17 deletions
@@ -33,6 +33,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.pipelineLayout, sizeof(payload.pipelineLayout))); XXHASH_VERIFY(XXH64_update(m_hashState, &payload.pipelineLayout, sizeof(payload.pipelineLayout)));
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.renderPass, sizeof(payload.renderPass))); XXHASH_VERIFY(XXH64_update(m_hashState, &payload.renderPass, sizeof(payload.renderPass)));
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.colorAttachmentCount, sizeof(payload.colorAttachmentCount))); XXHASH_VERIFY(XXH64_update(m_hashState, &payload.colorAttachmentCount, sizeof(payload.colorAttachmentCount)));
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.rasterizationSamples, sizeof(payload.rasterizationSamples)));
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.subpass, sizeof(payload.subpass))); XXHASH_VERIFY(XXH64_update(m_hashState, &payload.subpass, sizeof(payload.subpass)));
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.topology, sizeof(payload.topology))); XXHASH_VERIFY(XXH64_update(m_hashState, &payload.topology, sizeof(payload.topology)));
XXHASH_VERIFY(XXH64_update(m_hashState, &payload.cullMode, sizeof(payload.cullMode))); XXHASH_VERIFY(XXH64_update(m_hashState, &payload.cullMode, sizeof(payload.cullMode)));
@@ -134,7 +135,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
raster.lineWidth = 1.0f; raster.lineWidth = 1.0f;
VkPipelineMultisampleStateCreateInfo ms{VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO}; VkPipelineMultisampleStateCreateInfo ms{VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO};
ms.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; ms.rasterizationSamples = payload.rasterizationSamples;
VkPipelineDepthStencilStateCreateInfo depthStencil{VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO}; VkPipelineDepthStencilStateCreateInfo depthStencil{VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO};
depthStencil.depthTestEnable = payload.depthTestEnable ? VK_TRUE : VK_FALSE; depthStencil.depthTestEnable = payload.depthTestEnable ? VK_TRUE : VK_FALSE;
@@ -26,6 +26,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
VkPipelineLayout pipelineLayout = VK_NULL_HANDLE; VkPipelineLayout pipelineLayout = VK_NULL_HANDLE;
VkRenderPass renderPass = VK_NULL_HANDLE; VkRenderPass renderPass = VK_NULL_HANDLE;
Uint32 colorAttachmentCount = 1; Uint32 colorAttachmentCount = 1;
VkSampleCountFlagBits rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
Uint32 subpass = 0; Uint32 subpass = 0;
VkPrimitiveTopology topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; VkPrimitiveTopology topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
VkCullModeFlags cullMode = VK_CULL_MODE_BACK_BIT; VkCullModeFlags cullMode = VK_CULL_MODE_BACK_BIT;
@@ -172,6 +172,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
auto* resource = m_textureManager.SyncTextureAndGetDescriptor(*texture); auto* resource = m_textureManager.SyncTextureAndGetDescriptor(*texture);
if (resource != nullptr) { if (resource != nullptr) {
imageIdentity = reinterpret_cast<Uint64>(resource->image); imageIdentity = reinterpret_cast<Uint64>(resource->image);
XXHASH_VERIFY(XXH64_update(m_hashState, &resource->sampleCount, sizeof(resource->sampleCount)));
} else {
const VkSampleCountFlagBits fallbackSampleCount = VK_SAMPLE_COUNT_1_BIT;
XXHASH_VERIFY(XXH64_update(m_hashState, &fallbackSampleCount, sizeof(fallbackSampleCount)));
} }
XXHASH_VERIFY(XXH64_update(m_hashState, &imageIdentity, sizeof(imageIdentity))); XXHASH_VERIFY(XXH64_update(m_hashState, &imageIdentity, sizeof(imageIdentity)));
} }
@@ -289,6 +293,21 @@ namespace MobileGL::MG_Backend::DirectVulkan {
textureResources.reserve(colorAttachmentSlotCount + 1); textureResources.reserve(colorAttachmentSlotCount + 1);
Vector<VkImageView> attachmentViews; Vector<VkImageView> attachmentViews;
attachmentViews.reserve(colorAttachmentSlotCount + 1); attachmentViews.reserve(colorAttachmentSlotCount + 1);
VkSampleCountFlagBits renderPassSampleCount = VK_SAMPLE_COUNT_1_BIT;
Bool hasRenderPassSampleCount = false;
const auto adoptRenderPassSampleCount = [&](VkSampleCountFlagBits sampleCount,
const char* attachmentKind,
Int attachmentId) {
if (!hasRenderPassSampleCount) {
renderPassSampleCount = sampleCount;
hasRenderPassSampleCount = true;
return;
}
MOBILEGL_ASSERT(renderPassSampleCount == sampleCount,
"GetOrCreateRenderPass: mismatched sample count %d on %s attachment %d (expected %d)",
static_cast<Int>(sampleCount), attachmentKind, attachmentId,
static_cast<Int>(renderPassSampleCount));
};
// This should automatically work on default & offscreen FBO // This should automatically work on default & offscreen FBO
// assuming default FBO has the right param // assuming default FBO has the right param
for (Uint32 i = 0; i < colorAttachmentSlotCount; ++i) { for (Uint32 i = 0; i < colorAttachmentSlotCount; ++i) {
@@ -306,15 +325,14 @@ namespace MobileGL::MG_Backend::DirectVulkan {
// Color attachment description // Color attachment description
VkAttachmentDescription& desc = attachmentDescriptions.back(); VkAttachmentDescription& desc = attachmentDescriptions.back();
switch (textureTarget) { switch (textureTarget) {
case TextureTarget::Texture2D: { case TextureTarget::Texture2D:
auto* texture2d = case TextureTarget::Texture2DMultisample: {
static_cast<MG_State::GLState::TextureObject2D*>(texture);
desc.flags = 0; desc.flags = 0;
desc.format = isDefaultFbo ? desc.format = isDefaultFbo ?
m_swapchainObject.GetSurfaceFormat().format : m_swapchainObject.GetSurfaceFormat().format :
MG_Util::ConvertTextureInternalFormatToVkEnum( MG_Util::ConvertTextureInternalFormatToVkEnum(
texture2d->GetFormat()); texture->GetFormat());
desc.samples = VK_SAMPLE_COUNT_1_BIT; VkSampleCountFlagBits attachmentSampleCount = VK_SAMPLE_COUNT_1_BIT;
ClearAttachmentPayload clearPayload{}; ClearAttachmentPayload clearPayload{};
Bool hasClear = m_clearManager.GetPendingClear(att, clearPayload); Bool hasClear = m_clearManager.GetPendingClear(att, clearPayload);
VkImageLayout trackedColorLayout = VK_IMAGE_LAYOUT_UNDEFINED; VkImageLayout trackedColorLayout = VK_IMAGE_LAYOUT_UNDEFINED;
@@ -348,6 +366,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
.swapchainImageIndex = swapchainImageIndex, .swapchainImageIndex = swapchainImageIndex,
.finalLayout = desc.finalLayout, .finalLayout = desc.finalLayout,
}); });
attachmentSampleCount = VK_SAMPLE_COUNT_1_BIT;
textureResources.emplace_back(nullptr); textureResources.emplace_back(nullptr);
attachmentViews.emplace_back(swapchainViews[swapchainImageIndex]); attachmentViews.emplace_back(swapchainViews[swapchainImageIndex]);
} else { } else {
@@ -356,6 +375,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
"GetOrCreateRenderPass: SyncTextureAndGetDescriptor failed at color attachment %d", i); "GetOrCreateRenderPass: SyncTextureAndGetDescriptor failed at color attachment %d", i);
textureResources.emplace_back(textureResource); textureResources.emplace_back(textureResource);
desc.format = textureResource->format; desc.format = textureResource->format;
attachmentSampleCount = textureResource->sampleCount;
trackedColorLayout = textureResource->layout; trackedColorLayout = textureResource->layout;
trackedAttachmentLayouts.emplace_back(TrackedAttachmentLayoutInfo { trackedAttachmentLayouts.emplace_back(TrackedAttachmentLayoutInfo {
.target = TrackedAttachmentTarget::Texture, .target = TrackedAttachmentTarget::Texture,
@@ -372,6 +392,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
MOBILEGL_ASSERT(attachmentViews.back() != VK_NULL_HANDLE, MOBILEGL_ASSERT(attachmentViews.back() != VK_NULL_HANDLE,
"GetOrCreateRenderPass: GetOrCreateAttachmentView failed at color attachment %d", i); "GetOrCreateRenderPass: GetOrCreateAttachmentView failed at color attachment %d", i);
} }
desc.samples = attachmentSampleCount;
adoptRenderPassSampleCount(attachmentSampleCount, "color", texture->GetExternalIndex());
if (!hasClear && trackedColorLayout == VK_IMAGE_LAYOUT_UNDEFINED) { if (!hasClear && trackedColorLayout == VK_IMAGE_LAYOUT_UNDEFINED) {
MGLOG_W("GetOrCreateRenderPass: color attachment textureId=%d starts with undefined layout and no clear; " MGLOG_W("GetOrCreateRenderPass: color attachment textureId=%d starts with undefined layout and no clear; "
@@ -439,10 +461,13 @@ namespace MobileGL::MG_Backend::DirectVulkan {
depthAttachmentDescription.format = isDefaultFbo ? depthAttachmentDescription.format = isDefaultFbo ?
m_swapchainObject.GetDepthStencilFormat() : m_swapchainObject.GetDepthStencilFormat() :
MG_Util::ConvertTextureInternalFormatToVkEnum(texture.GetFormat()); MG_Util::ConvertTextureInternalFormatToVkEnum(texture.GetFormat());
VkSampleCountFlagBits depthAttachmentSampleCount = VK_SAMPLE_COUNT_1_BIT;
if (!isDefaultFbo) { if (!isDefaultFbo) {
depthAttachmentDescription.format = depthTextureResource->format; depthAttachmentDescription.format = depthTextureResource->format;
depthAttachmentSampleCount = depthTextureResource->sampleCount;
} }
depthAttachmentDescription.samples = VK_SAMPLE_COUNT_1_BIT; depthAttachmentDescription.samples = depthAttachmentSampleCount;
adoptRenderPassSampleCount(depthAttachmentSampleCount, "depth/stencil", texture.GetExternalIndex());
const auto loadInfo = const auto loadInfo =
ResolveDepthStencilAttachmentLoadInfo(trackedDepthLayout, clearDepth, clearStencil); ResolveDepthStencilAttachmentLoadInfo(trackedDepthLayout, clearDepth, clearStencil);
depthAttachmentDescription.loadOp = loadInfo.depthLoadOp; depthAttachmentDescription.loadOp = loadInfo.depthLoadOp;
@@ -556,13 +581,15 @@ namespace MobileGL::MG_Backend::DirectVulkan {
static_cast<Uint32>(attachmentViews.size()), static_cast<Uint32>(attachmentViews.size()),
static_cast<Uint32>(colorAttachmentRefs.size()), static_cast<Uint32>(colorAttachmentRefs.size()),
hasDepthStencilAttachment, hasDepthStencilAttachment,
renderPassSampleCount,
extent, extent,
1 }; 1 };
MGLOG_D("VkRenderPassManager::GetOrCreateRenderPass: hash=0x%llx compatibilityHash=0x%llx attachmentCount=%u colorAttachmentCount=%u extent=%dx%d", MGLOG_D("VkRenderPassManager::GetOrCreateRenderPass: hash=0x%llx compatibilityHash=0x%llx attachmentCount=%u colorAttachmentCount=%u samples=%d extent=%dx%d",
static_cast<unsigned long long>(hash), static_cast<unsigned long long>(hash),
static_cast<unsigned long long>(compatibilityHash), static_cast<unsigned long long>(compatibilityHash),
renderPassEntry.attachmentCount, renderPassEntry.attachmentCount,
renderPassEntry.colorAttachmentCount, renderPassEntry.colorAttachmentCount,
static_cast<Int>(renderPassEntry.sampleCount),
extent.x(), extent.x(),
extent.y()); extent.y());
auto [insertedIt, _] = m_renderPasses.emplace(hash, Move(renderPassEntry)); auto [insertedIt, _] = m_renderPasses.emplace(hash, Move(renderPassEntry));
@@ -58,6 +58,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
Uint32 attachmentCount = 0; Uint32 attachmentCount = 0;
Uint32 colorAttachmentCount = 0; Uint32 colorAttachmentCount = 0;
Bool hasDepthStencilAttachment = false; Bool hasDepthStencilAttachment = false;
VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT;
IntVec2 extent = {0, 0}; IntVec2 extent = {0, 0};
Uint32 subpass = 0; Uint32 subpass = 0;
@@ -73,6 +74,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
std::swap(attachmentCount, that.attachmentCount); std::swap(attachmentCount, that.attachmentCount);
std::swap(colorAttachmentCount, that.colorAttachmentCount); std::swap(colorAttachmentCount, that.colorAttachmentCount);
std::swap(hasDepthStencilAttachment, that.hasDepthStencilAttachment); std::swap(hasDepthStencilAttachment, that.hasDepthStencilAttachment);
std::swap(sampleCount, that.sampleCount);
std::swap(extent, that.extent); std::swap(extent, that.extent);
std::swap(subpass, that.subpass); std::swap(subpass, that.subpass);
} }
@@ -86,6 +88,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
Uint32 attachmentCount, Uint32 attachmentCount,
Uint32 colorAttachmentCount, Uint32 colorAttachmentCount,
Bool hasDepthStencilAttachment, Bool hasDepthStencilAttachment,
VkSampleCountFlagBits sampleCount,
IntVec2 extent, int subpass): IntVec2 extent, int subpass):
hash(hash), hash(hash),
renderPass(renderpass), renderPass(renderpass),
@@ -96,6 +99,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
attachmentCount(attachmentCount), attachmentCount(attachmentCount),
colorAttachmentCount(colorAttachmentCount), colorAttachmentCount(colorAttachmentCount),
hasDepthStencilAttachment(hasDepthStencilAttachment), hasDepthStencilAttachment(hasDepthStencilAttachment),
sampleCount(sampleCount),
extent(extent), extent(extent),
subpass(subpass) subpass(subpass)
{} {}
@@ -46,6 +46,41 @@ namespace MobileGL::MG_Backend::DirectVulkan {
Uint32 arrayLayers = 1; Uint32 arrayLayers = 1;
}; };
static Bool IsMultisampleTextureUploadTarget(TextureUploadTarget target) {
return target == TextureUploadTarget::Texture2DMultisample ||
target == TextureUploadTarget::ProxyTexture2DMultisample ||
target == TextureUploadTarget::Texture2DMultisampleArray ||
target == TextureUploadTarget::ProxyTexture2DMultisampleArray;
}
static Bool TryResolveSampleCountFlagBits(Int requestedSamples, VkSampleCountFlagBits& outSampleCount) {
switch (requestedSamples) {
case 1:
outSampleCount = VK_SAMPLE_COUNT_1_BIT;
return true;
case 2:
outSampleCount = VK_SAMPLE_COUNT_2_BIT;
return true;
case 4:
outSampleCount = VK_SAMPLE_COUNT_4_BIT;
return true;
case 8:
outSampleCount = VK_SAMPLE_COUNT_8_BIT;
return true;
case 16:
outSampleCount = VK_SAMPLE_COUNT_16_BIT;
return true;
case 32:
outSampleCount = VK_SAMPLE_COUNT_32_BIT;
return true;
case 64:
outSampleCount = VK_SAMPLE_COUNT_64_BIT;
return true;
default:
return false;
}
}
static Bool IsCubeMapFaceUploadTarget(TextureUploadTarget target) { static Bool IsCubeMapFaceUploadTarget(TextureUploadTarget target) {
return target >= TextureUploadTarget::CubeMapPositiveX && return target >= TextureUploadTarget::CubeMapPositiveX &&
target <= TextureUploadTarget::CubeMapNegativeZ; target <= TextureUploadTarget::CubeMapNegativeZ;
@@ -468,6 +503,20 @@ namespace MobileGL::MG_Backend::DirectVulkan {
case TextureUploadTarget::ProxyTextureRectangle: case TextureUploadTarget::ProxyTextureRectangle:
outShape = {}; outShape = {};
return true; return true;
case TextureUploadTarget::Texture2DMultisample:
case TextureUploadTarget::ProxyTexture2DMultisample:
outShape = {};
return true;
case TextureUploadTarget::Texture2DMultisampleArray:
case TextureUploadTarget::ProxyTexture2DMultisampleArray:
MOBILEGL_ASSERT(texelSize.z() > 0,
"TryResolveTextureShapeInfo: invalid 2D multisample array depth=%d for textureId=%d",
texelSize.z(), texture.GetExternalIndex());
outShape.imageType = VK_IMAGE_TYPE_2D;
outShape.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
outShape.depth = 1;
outShape.arrayLayers = static_cast<Uint32>(texelSize.z());
return true;
case TextureUploadTarget::Texture3D: case TextureUploadTarget::Texture3D:
case TextureUploadTarget::ProxyTexture3D: case TextureUploadTarget::ProxyTexture3D:
MOBILEGL_ASSERT(texelSize.z() > 0, MOBILEGL_ASSERT(texelSize.z() > 0,
@@ -806,6 +855,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
if (resource == nullptr) { if (resource == nullptr) {
return false; return false;
} }
if (resource->sampleCount != VK_SAMPLE_COUNT_1_BIT) {
MGLOG_D("TransitionTextureForStorageImage: multisample textureId=%d is not exposed as a storage image",
texture.GetExternalIndex());
return false;
}
if (resource->layout == VK_IMAGE_LAYOUT_GENERAL) { if (resource->layout == VK_IMAGE_LAYOUT_GENERAL) {
return true; return true;
} }
@@ -958,7 +1012,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
MGLOG_D("%s: no mip levels", __func__); MGLOG_D("%s: no mip levels", __func__);
return false; return false;
} }
const Uint32 backingMipLevels = std::max(mipLevels, ComputeFullMipLevelCount(texelSize)); const Bool isMultisampleTexture = IsMultisampleTextureUploadTarget(uploadTarget);
const Uint32 backingMipLevels =
isMultisampleTexture ? 1u : std::max(mipLevels, ComputeFullMipLevelCount(texelSize));
TextureShapeInfo shapeInfo{}; TextureShapeInfo shapeInfo{};
const Bool supportedShape = TryResolveTextureShapeInfo(texture, uploadTarget, texelSize, shapeInfo); const Bool supportedShape = TryResolveTextureShapeInfo(texture, uploadTarget, texelSize, shapeInfo);
MOBILEGL_ASSERT(supportedShape, MOBILEGL_ASSERT(supportedShape,
@@ -972,6 +1028,14 @@ namespace MobileGL::MG_Backend::DirectVulkan {
MGLOG_D("%s: not Texture2D, unsupported", __func__); MGLOG_D("%s: not Texture2D, unsupported", __func__);
return false; return false;
} }
VkSampleCountFlagBits resolvedSampleCount = VK_SAMPLE_COUNT_1_BIT;
if (isMultisampleTexture &&
!TryResolveSampleCountFlagBits(texture.GetSamples(), resolvedSampleCount)) {
MGLOG_D("%s: unsupported multisample count=%d for textureId=%d target=%s", __func__,
texture.GetSamples(), texture.GetExternalIndex(),
MG_Util::ConvertTextureUploadTargetToString(uploadTarget).c_str());
return false;
}
const Bool compatible = resource.image != VK_NULL_HANDLE && resource.format == format && const Bool compatible = resource.image != VK_NULL_HANDLE && resource.format == format &&
resource.extent.width == static_cast<Uint32>(texelSize.x()) && resource.extent.width == static_cast<Uint32>(texelSize.x()) &&
@@ -979,6 +1043,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
resource.depth == shapeInfo.depth && resource.depth == shapeInfo.depth &&
resource.arrayLayers == shapeInfo.arrayLayers && resource.arrayLayers == shapeInfo.arrayLayers &&
resource.viewType == shapeInfo.viewType && resource.viewType == shapeInfo.viewType &&
resource.sampleCount == resolvedSampleCount &&
resource.mipLevels == backingMipLevels; resource.mipLevels == backingMipLevels;
if (compatible) { if (compatible) {
if (resource.perMipViews.size() != backingMipLevels) { if (resource.perMipViews.size() != backingMipLevels) {
@@ -998,6 +1063,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
resource.depth == shapeInfo.depth && resource.depth == shapeInfo.depth &&
resource.arrayLayers == shapeInfo.arrayLayers && resource.arrayLayers == shapeInfo.arrayLayers &&
resource.viewType == shapeInfo.viewType && resource.viewType == shapeInfo.viewType &&
resource.sampleCount == resolvedSampleCount &&
resolvedSampleCount == VK_SAMPLE_COUNT_1_BIT &&
resource.mipLevels < backingMipLevels && resource.mipLevels < backingMipLevels &&
resource.layout != VK_IMAGE_LAYOUT_UNDEFINED; resource.layout != VK_IMAGE_LAYOUT_UNDEFINED;
@@ -1025,16 +1092,33 @@ namespace MobileGL::MG_Backend::DirectVulkan {
VkFormatProperties formatProperties{}; VkFormatProperties formatProperties{};
vkGetPhysicalDeviceFormatProperties(m_physicalDevice, format, &formatProperties); vkGetPhysicalDeviceFormatProperties(m_physicalDevice, format, &formatProperties);
const Bool supportsStorageImage = const Bool supportsStorageImage =
!isMultisampleTexture &&
(aspect & VK_IMAGE_ASPECT_COLOR_BIT) != 0 && (aspect & VK_IMAGE_ASPECT_COLOR_BIT) != 0 &&
(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) != 0; (formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) != 0;
imageInfo.usage = imageInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT |
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
(supportsStorageImage ? VK_IMAGE_USAGE_STORAGE_BIT : 0) | (supportsStorageImage ? VK_IMAGE_USAGE_STORAGE_BIT : 0) |
((aspect & VK_IMAGE_ASPECT_COLOR_BIT) ? ((aspect & VK_IMAGE_ASPECT_COLOR_BIT) ? VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT : 0) |
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT : 0) | (((aspect & VK_IMAGE_ASPECT_DEPTH_BIT) || (aspect & VK_IMAGE_ASPECT_STENCIL_BIT)) ?
((aspect & VK_IMAGE_ASPECT_DEPTH_BIT || aspect & VK_IMAGE_ASPECT_STENCIL_BIT) ? VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT :
VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT : 0); 0);
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; if (!isMultisampleTexture) {
imageInfo.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
}
imageInfo.samples = resolvedSampleCount;
if (isMultisampleTexture) {
VkImageFormatProperties imageFormatProperties{};
const VkResult imageFormatResult = vkGetPhysicalDeviceImageFormatProperties(
m_physicalDevice, format, imageInfo.imageType, imageInfo.tiling, imageInfo.usage,
imageInfo.flags, &imageFormatProperties);
if (imageFormatResult != VK_SUCCESS ||
(imageFormatProperties.sampleCounts & resolvedSampleCount) == 0) {
MGLOG_D("%s: sampleCount=%d is unsupported for textureId=%d target=%s format=%d usage=0x%x",
__func__, texture.GetSamples(), texture.GetExternalIndex(),
MG_Util::ConvertTextureUploadTargetToString(uploadTarget).c_str(),
static_cast<Int>(format), static_cast<Uint32>(imageInfo.usage));
return false;
}
}
imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
VmaAllocationCreateInfo allocationInfo{}; VmaAllocationCreateInfo allocationInfo{};
allocationInfo.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE; allocationInfo.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
@@ -1054,6 +1138,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
resource.format = format; resource.format = format;
resource.aspect = aspect; resource.aspect = aspect;
resource.viewType = shapeInfo.viewType; resource.viewType = shapeInfo.viewType;
resource.sampleCount = resolvedSampleCount;
resource.syncedTextureParamsVersion = 0; resource.syncedTextureParamsVersion = 0;
if (preservedResource) { if (preservedResource) {
@@ -72,6 +72,7 @@ public:
VkFormat format = VK_FORMAT_UNDEFINED; VkFormat format = VK_FORMAT_UNDEFINED;
VkImageAspectFlags aspect = VK_IMAGE_ASPECT_NONE; VkImageAspectFlags aspect = VK_IMAGE_ASPECT_NONE;
VkImageViewType viewType = VK_IMAGE_VIEW_TYPE_2D; VkImageViewType viewType = VK_IMAGE_VIEW_TYPE_2D;
VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT;
Uint16 syncedTextureParamsVersion = 0; Uint16 syncedTextureParamsVersion = 0;
TextureResource() = default; TextureResource() = default;
@@ -94,6 +95,7 @@ public:
std::swap(this->format, that.format); std::swap(this->format, that.format);
std::swap(this->aspect, that.aspect); std::swap(this->aspect, that.aspect);
std::swap(this->viewType, that.viewType); std::swap(this->viewType, that.viewType);
std::swap(this->sampleCount, that.sampleCount);
std::swap(this->syncedTextureParamsVersion, that.syncedTextureParamsVersion); std::swap(this->syncedTextureParamsVersion, that.syncedTextureParamsVersion);
} }
@@ -139,6 +141,7 @@ public:
format = VK_FORMAT_UNDEFINED; format = VK_FORMAT_UNDEFINED;
aspect = VK_IMAGE_ASPECT_NONE; aspect = VK_IMAGE_ASPECT_NONE;
viewType = VK_IMAGE_VIEW_TYPE_2D; viewType = VK_IMAGE_VIEW_TYPE_2D;
sampleCount = VK_SAMPLE_COUNT_1_BIT;
syncedTextureParamsVersion = 0; syncedTextureParamsVersion = 0;
} }
@@ -2167,6 +2167,7 @@ void main() {
.pipelineLayout = programObj.pipelineLayout, .pipelineLayout = programObj.pipelineLayout,
.renderPass = renderPassEntry.renderPass, .renderPass = renderPassEntry.renderPass,
.colorAttachmentCount = renderPassEntry.colorAttachmentCount, .colorAttachmentCount = renderPassEntry.colorAttachmentCount,
.rasterizationSamples = renderPassEntry.sampleCount,
.subpass = 0, .subpass = 0,
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
.cullMode = VK_CULL_MODE_NONE, .cullMode = VK_CULL_MODE_NONE,
@@ -2633,6 +2634,7 @@ void main() {
.pipelineLayout = programObj.pipelineLayout, .pipelineLayout = programObj.pipelineLayout,
.renderPass = renderPassEntry.renderPass, .renderPass = renderPassEntry.renderPass,
.colorAttachmentCount = renderPassEntry.colorAttachmentCount, .colorAttachmentCount = renderPassEntry.colorAttachmentCount,
.rasterizationSamples = renderPassEntry.sampleCount,
.subpass = 0, .subpass = 0,
.topology = MG_Util::ConvertPrimitiveModeToVkEnum(mode), .topology = MG_Util::ConvertPrimitiveModeToVkEnum(mode),
.cullMode = cullFaceEnabled .cullMode = cullFaceEnabled