Skip to content

Commit

Permalink
vk: Transient attachment support (#8021)
Browse files Browse the repository at this point in the history
  • Loading branch information
mdagois authored Oct 8, 2024
1 parent 164a25c commit 1b0ff3a
Show file tree
Hide file tree
Showing 9 changed files with 74 additions and 14 deletions.
3 changes: 2 additions & 1 deletion filament/backend/include/backend/DriverEnums.h
Original file line number Diff line number Diff line change
Expand Up @@ -765,7 +765,8 @@ enum class TextureUsage : uint16_t {
BLIT_SRC = 0x0040, //!< Texture can be used the source of a blit()
BLIT_DST = 0x0080, //!< Texture can be used the destination of a blit()
PROTECTED = 0x0100, //!< Texture can be used for protected content
DEFAULT = UPLOADABLE | SAMPLEABLE //!< Default texture usage
DEFAULT = UPLOADABLE | SAMPLEABLE, //!< Default texture usage
ALL_ATTACHMENTS = COLOR_ATTACHMENT | DEPTH_ATTACHMENT | STENCIL_ATTACHMENT | SUBPASS_INPUT, //!< Mask of all attachments
};

inline const char* stringify(TextureUsage usage) {
Expand Down
5 changes: 5 additions & 0 deletions filament/backend/src/vulkan/VulkanContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,13 +144,18 @@ struct VulkanContext {
return mPhysicalDeviceFeatures.shaderClipDistance == VK_TRUE;
}

inline bool isLazilyAllocatedMemorySupported() const noexcept {
return mLazilyAllocatedMemorySupported;
}

private:
VkPhysicalDeviceMemoryProperties mMemoryProperties = {};
VkPhysicalDeviceProperties mPhysicalDeviceProperties = {};
VkPhysicalDeviceFeatures mPhysicalDeviceFeatures = {};
bool mDebugMarkersSupported = false;
bool mDebugUtilsSupported = false;
bool mMultiviewEnabled = false;
bool mLazilyAllocatedMemorySupported = false;

VkFormatList mDepthStencilFormats;
VkFormatList mBlittableDepthStencilFormats;
Expand Down
16 changes: 13 additions & 3 deletions filament/backend/src/vulkan/VulkanDriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1283,12 +1283,14 @@ void VulkanDriver::beginRenderPass(Handle<HwRenderTarget> rth, const RenderPassP

// Create the VkRenderPass or fetch it from cache.
VulkanFboCache::RenderPassKey rpkey = {
.initialDepthLayout = currentDepthLayout,
.depthFormat = depth.getFormat(),
.clear = clearVal,
.discardStart = discardStart,
.discardEnd = discardEndVal,
.initialDepthLayout = currentDepthLayout,
.samples = rt->getSamples(),
.needsResolveMask = 0,
.usesLazilyAllocatedMemory = 0,
.subpassMask = uint8_t(params.subpassMask),
.viewCount = renderTargetLayerCount,
};
Expand All @@ -1297,8 +1299,16 @@ void VulkanDriver::beginRenderPass(Handle<HwRenderTarget> rth, const RenderPassP
if (info.texture) {
assert_invariant(info.layerCount == renderTargetLayerCount);
rpkey.colorFormat[i] = info.getFormat();
if (rpkey.samples > 1 && info.texture->samples == 1) {
rpkey.needsResolveMask |= (1 << i);
if (rpkey.samples > 1) {
const VulkanTexture* sidecar = info.texture->getSidecar();
assert_invariant(sidecar);
assert_invariant(sidecar->samples > 1);
if (sidecar && sidecar->isTransientAttachment()) {
rpkey.usesLazilyAllocatedMemory |= (1 << i);
}
if (info.texture->samples == 1) {
rpkey.needsResolveMask |= (1 << i);
}
}
} else {
rpkey.colorFormat[i] = VK_FORMAT_UNDEFINED;
Expand Down
3 changes: 2 additions & 1 deletion filament/backend/src/vulkan/VulkanFboCache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ bool VulkanFboCache::RenderPassEq::operator()(const RenderPassKey& k1,
if (k1.discardEnd != k2.discardEnd) return false;
if (k1.samples != k2.samples) return false;
if (k1.needsResolveMask != k2.needsResolveMask) return false;
if (k1.usesLazilyAllocatedMemory != k2.usesLazilyAllocatedMemory) return false;
if (k1.subpassMask != k2.subpassMask) return false;
if (k1.viewCount != k2.viewCount) return false;
return true;
Expand Down Expand Up @@ -254,7 +255,7 @@ VkRenderPass VulkanFboCache::getRenderPass(RenderPassKey config) noexcept {
.format = config.colorFormat[i],
.samples = (VkSampleCountFlagBits) config.samples,
.loadOp = clear ? kClear : (discard ? kDontCare : kKeep),
.storeOp = kEnableStore,
.storeOp = (config.usesLazilyAllocatedMemory & (1 << i)) ? kDisableStore : kEnableStore,
.stencilLoadOp = kDontCare,
.stencilStoreOp = kDisableStore,
.initialLayout = imgutil::getVkLayout(VulkanLayout::COLOR_ATTACHMENT),
Expand Down
7 changes: 4 additions & 3 deletions filament/backend/src/vulkan/VulkanFboCache.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,18 +42,19 @@ class VulkanFboCache {
// RenderPassKey is a small POD representing the immutable state that is used to construct
// a VkRenderPass. It is hashed and used as a lookup key.
struct alignas(8) RenderPassKey {
VulkanLayout initialDepthLayout;
uint8_t padding[3] = {};

VkFormat colorFormat[MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT]; // 32 bytes
VkFormat depthFormat; // 4 bytes
TargetBufferFlags clear; // 4 bytes
TargetBufferFlags discardStart; // 4 bytes
TargetBufferFlags discardEnd; // 4 bytes

VulkanLayout initialDepthLayout; // 1 byte
uint8_t samples; // 1 byte
uint8_t needsResolveMask; // 1 byte
uint8_t usesLazilyAllocatedMemory; // 1 byte
uint8_t subpassMask; // 1 byte
uint8_t viewCount; // 1 byte
uint8_t padding[2];
};
struct RenderPassVal {
VkRenderPass handle;
Expand Down
7 changes: 6 additions & 1 deletion filament/backend/src/vulkan/VulkanHandles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -282,11 +282,16 @@ VulkanRenderTarget::VulkanRenderTarget(VkDevice device, VkPhysicalDevice physica
if (texture && texture->samples == 1) {
auto msTexture = texture->getSidecar();
if (UTILS_UNLIKELY(!msTexture)) {
// Clear all usage flags that are not related to attachments, so that we can
// use the transient usage flag.
const TextureUsage usage = texture->usage & TextureUsage::ALL_ATTACHMENTS;
assert_invariant(static_cast<uint16_t>(usage) != 0U);

// TODO: This should be allocated with the ResourceAllocator.
msTexture = new VulkanTexture(device, physicalDevice, context, allocator, commands,
handleAllocator,
texture->target, ((VulkanTexture const*) texture)->levels, texture->format,
samples, texture->width, texture->height, texture->depth, texture->usage,
samples, texture->width, texture->height, texture->depth, usage,
stagePool, true /* heap allocated */);
texture->setSidecar(msTexture);
}
Expand Down
27 changes: 22 additions & 5 deletions filament/backend/src/vulkan/VulkanTexture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,8 @@ VulkanTextureState::VulkanTextureState(
mStagePool(stagePool),
mDevice(device),
mAllocator(allocator),
mCommands(commands) {
mCommands(commands),
mIsTransientAttachment(false) {
}

VulkanTextureState* VulkanTexture::getSharedState() {
Expand Down Expand Up @@ -209,6 +210,19 @@ VulkanTexture::VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice,
imageInfo.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
}

// Determine if we can use the transient usage flag combined with lazily allocated memory.
const bool useTransientAttachment =
// Lazily allocated memory is available.
context.isLazilyAllocatedMemorySupported() &&
// Usage consists of attachment flags only.
none(tusage & ~TextureUsage::ALL_ATTACHMENTS) &&
// Usage contains at least one attachment flag.
any(tusage & TextureUsage::ALL_ATTACHMENTS);
state->mIsTransientAttachment = useTransientAttachment;

const VkImageUsageFlags transientFlag =
useTransientAttachment ? VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT : 0U;

if (any(usage & TextureUsage::SAMPLEABLE)) {

#if FVK_ENABLED(FVK_DEBUG_TEXTURE)
Expand All @@ -224,19 +238,19 @@ VulkanTexture::VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice,
imageInfo.usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
}
if (any(usage & TextureUsage::COLOR_ATTACHMENT)) {
imageInfo.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
imageInfo.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | transientFlag;
if (any(usage & TextureUsage::SUBPASS_INPUT)) {
imageInfo.usage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
}
}
if (any(usage & TextureUsage::STENCIL_ATTACHMENT)) {
imageInfo.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
imageInfo.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | transientFlag;
}
if (any(usage & TextureUsage::UPLOADABLE)) {
imageInfo.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
}
if (any(usage & TextureUsage::DEPTH_ATTACHMENT)) {
imageInfo.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
imageInfo.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | transientFlag;

// Depth resolves uses a custom shader and therefore needs to be sampleable.
if (samples > 1) {
Expand Down Expand Up @@ -285,8 +299,11 @@ VulkanTexture::VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice,
VkMemoryRequirements memReqs = {};
vkGetImageMemoryRequirements(state->mDevice, state->mTextureImage, &memReqs);

const VkFlags requiredMemoryFlags =
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
(useTransientAttachment ? VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT : 0U);
uint32_t memoryTypeIndex
= context.selectMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
= context.selectMemoryType(memReqs.memoryTypeBits, requiredMemoryFlags);

FILAMENT_CHECK_POSTCONDITION(memoryTypeIndex < VK_MAX_MEMORY_TYPES)
<< "VulkanTexture: unable to find a memory type that meets requirements.";
Expand Down
6 changes: 6 additions & 0 deletions filament/backend/src/vulkan/VulkanTexture.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ struct VulkanTextureState : public VulkanResource {
VmaAllocator mAllocator;
VulkanCommands* mCommands;
std::shared_ptr<VulkanCmdFence> mTransitionFence;
bool mIsTransientAttachment;
};


Expand Down Expand Up @@ -170,6 +171,11 @@ struct VulkanTexture : public HwTexture, VulkanResource {
return state->mSidecarMSAA.get();
}

bool isTransientAttachment() const {
VulkanTextureState const* state = getSharedState();
return state->mIsTransientAttachment;
}

bool transitionLayout(VulkanCommandBuffer* commands, const VkImageSubresourceRange& range,
VulkanLayout newLayout);

Expand Down
14 changes: 14 additions & 0 deletions filament/backend/src/vulkan/platform/VulkanPlatform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -740,6 +740,20 @@ Driver* VulkanPlatform::createDriver(void* sharedContext,
context.mDebugMarkersSupported = setContains(deviceExts, VK_EXT_DEBUG_MARKER_EXTENSION_NAME);
context.mMultiviewEnabled = setContains(deviceExts, VK_KHR_MULTIVIEW_EXTENSION_NAME);

// Check the availability of lazily allocated memory
{
context.mLazilyAllocatedMemorySupported = false;
const uint32_t typeCount = context.mMemoryProperties.memoryTypeCount;
for(uint32_t i = 0; i < typeCount; ++i) {
const VkMemoryType type = context.mMemoryProperties.memoryTypes[i];
if (type.propertyFlags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) {
context.mLazilyAllocatedMemorySupported = true;
assert_invariant(type.propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
break;
}
}
}

#ifdef NDEBUG
// If we are in release build, we should not have turned on debug extensions
FILAMENT_CHECK_POSTCONDITION(!context.mDebugUtilsSupported && !context.mDebugMarkersSupported)
Expand Down

0 comments on commit 1b0ff3a

Please sign in to comment.