vk_texture_runtime: Tune barriers

* Using eAllCommandBit is really bad for Mali GPUs. Also most access flags were redundant mostly for edge cases.

* To address this track surface usage and decide the best barrier flags at runtime. This gives a significant performance boost to mobile GPUs
This commit is contained in:
GPUCode
2022-12-29 21:23:40 +02:00
parent d3392ae0b1
commit 410b8b8809
5 changed files with 251 additions and 219 deletions

View File

@ -562,7 +562,7 @@ void RendererVulkan::LoadColorToActiveVkTexture(u8 color_r, u8 color_g, u8 color
.subresourceRange = range, .subresourceRange = range,
}; };
render_cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eAllCommands, render_cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eFragmentShader,
vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer,
vk::DependencyFlagBits::eByRegion, {}, {}, pre_barrier); vk::DependencyFlagBits::eByRegion, {}, {}, pre_barrier);
@ -570,7 +570,7 @@ void RendererVulkan::LoadColorToActiveVkTexture(u8 color_r, u8 color_g, u8 color
range); range);
render_cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, render_cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer,
vk::PipelineStageFlagBits::eAllCommands, vk::PipelineStageFlagBits::eFragmentShader,
vk::DependencyFlagBits::eByRegion, {}, {}, post_barrier); vk::DependencyFlagBits::eByRegion, {}, {}, post_barrier);
}); });
} }

View File

@ -164,7 +164,7 @@ Instance::Instance(Frontend::EmuWindow& window, u32 physical_device_index)
VULKAN_HPP_DEFAULT_DISPATCHER.init(vkGetInstanceProcAddr); VULKAN_HPP_DEFAULT_DISPATCHER.init(vkGetInstanceProcAddr);
// Enable the instance extensions the backend uses // Enable the instance extensions the backend uses
auto extensions = GetInstanceExtensions(window_info.type, enable_validation); auto extensions = GetInstanceExtensions(window_info.type, false);
// Use required platform-specific flags // Use required platform-specific flags
auto flags = GetInstanceFlags(); auto flags = GetInstanceFlags();

View File

@ -787,10 +787,10 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
depth_surface); depth_surface);
} }
static int submit_threshold = 80; static int submit_threshold = 50;
submit_threshold--; submit_threshold--;
if (!submit_threshold) { if (!submit_threshold) {
submit_threshold = 80; submit_threshold = 50;
scheduler.DispatchWork(); scheduler.DispatchWork();
} }

View File

@ -16,6 +16,16 @@
namespace Vulkan { namespace Vulkan {
struct RecordParams {
vk::ImageAspectFlags aspect;
vk::Filter filter;
vk::PipelineStageFlags pipeline_flags;
vk::AccessFlags src_access;
vk::AccessFlags dst_access;
vk::Image src_image;
vk::Image dst_image;
};
[[nodiscard]] vk::ImageAspectFlags MakeAspect(VideoCore::SurfaceType type) { [[nodiscard]] vk::ImageAspectFlags MakeAspect(VideoCore::SurfaceType type) {
switch (type) { switch (type) {
case VideoCore::SurfaceType::Color: case VideoCore::SurfaceType::Color:
@ -397,14 +407,17 @@ bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClea
VideoCore::ClearValue value) { VideoCore::ClearValue value) {
renderpass_cache.ExitRenderpass(); renderpass_cache.ExitRenderpass();
const bool is_color = surface.type != VideoCore::SurfaceType::Depth && const RecordParams params = {
surface.type != VideoCore::SurfaceType::DepthStencil; .aspect = surface.alloc.aspect,
.pipeline_flags = surface.PipelineStageFlags(),
.src_access = surface.AccessFlags(),
.src_image = surface.alloc.image,
};
if (clear.texture_rect == surface.GetScaledRect()) { if (clear.texture_rect == surface.GetScaledRect()) {
scheduler.Record([aspect = MakeAspect(surface.type), image = surface.alloc.image, value, scheduler.Record([params, clear, value](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) {
is_color, clear](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) {
const vk::ImageSubresourceRange range = { const vk::ImageSubresourceRange range = {
.aspectMask = aspect, .aspectMask = params.aspect,
.baseMipLevel = clear.texture_level, .baseMipLevel = clear.texture_level,
.levelCount = 1, .levelCount = 1,
.baseArrayLayer = 0, .baseArrayLayer = 0,
@ -412,18 +425,15 @@ bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClea
}; };
const vk::ImageMemoryBarrier pre_barrier = { const vk::ImageMemoryBarrier pre_barrier = {
.srcAccessMask = vk::AccessFlagBits::eShaderWrite | .srcAccessMask = params.src_access,
vk::AccessFlagBits::eColorAttachmentWrite |
vk::AccessFlagBits::eDepthStencilAttachmentWrite |
vk::AccessFlagBits::eTransferWrite,
.dstAccessMask = vk::AccessFlagBits::eTransferWrite, .dstAccessMask = vk::AccessFlagBits::eTransferWrite,
.oldLayout = vk::ImageLayout::eGeneral, .oldLayout = vk::ImageLayout::eGeneral,
.newLayout = vk::ImageLayout::eTransferDstOptimal, .newLayout = vk::ImageLayout::eTransferDstOptimal,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = image, .image = params.src_image,
.subresourceRange{ .subresourceRange{
.aspectMask = aspect, .aspectMask = params.aspect,
.baseMipLevel = clear.texture_level, .baseMipLevel = clear.texture_level,
.levelCount = 1, .levelCount = 1,
.baseArrayLayer = 0, .baseArrayLayer = 0,
@ -433,20 +443,14 @@ bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClea
const vk::ImageMemoryBarrier post_barrier = { const vk::ImageMemoryBarrier post_barrier = {
.srcAccessMask = vk::AccessFlagBits::eTransferWrite, .srcAccessMask = vk::AccessFlagBits::eTransferWrite,
.dstAccessMask = .dstAccessMask = params.src_access,
vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite |
vk::AccessFlagBits::eColorAttachmentRead |
vk::AccessFlagBits::eColorAttachmentWrite |
vk::AccessFlagBits::eDepthStencilAttachmentRead |
vk::AccessFlagBits::eDepthStencilAttachmentWrite |
vk::AccessFlagBits::eTransferRead | vk::AccessFlagBits::eTransferWrite,
.oldLayout = vk::ImageLayout::eTransferDstOptimal, .oldLayout = vk::ImageLayout::eTransferDstOptimal,
.newLayout = vk::ImageLayout::eGeneral, .newLayout = vk::ImageLayout::eGeneral,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = image, .image = params.src_image,
.subresourceRange{ .subresourceRange{
.aspectMask = aspect, .aspectMask = params.aspect,
.baseMipLevel = clear.texture_level, .baseMipLevel = clear.texture_level,
.levelCount = 1, .levelCount = 1,
.baseArrayLayer = 0, .baseArrayLayer = 0,
@ -454,20 +458,19 @@ bool TextureRuntime::ClearTexture(Surface& surface, const VideoCore::TextureClea
}, },
}; };
render_cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eAllCommands, render_cmdbuf.pipelineBarrier(params.pipeline_flags, vk::PipelineStageFlagBits::eTransfer,
vk::PipelineStageFlagBits::eTransfer,
vk::DependencyFlagBits::eByRegion, {}, {}, pre_barrier); vk::DependencyFlagBits::eByRegion, {}, {}, pre_barrier);
const bool is_color = static_cast<bool>(params.aspect & vk::ImageAspectFlagBits::eColor);
if (is_color) { if (is_color) {
render_cmdbuf.clearColorImage(image, vk::ImageLayout::eTransferDstOptimal, render_cmdbuf.clearColorImage(params.src_image, vk::ImageLayout::eTransferDstOptimal,
MakeClearColorValue(value), range); MakeClearColorValue(value), range);
} else { } else {
render_cmdbuf.clearDepthStencilImage(image, vk::ImageLayout::eTransferDstOptimal, render_cmdbuf.clearDepthStencilImage(params.src_image, vk::ImageLayout::eTransferDstOptimal,
MakeClearDepthStencilValue(value), range); MakeClearDepthStencilValue(value), range);
} }
render_cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, render_cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, params.pipeline_flags,
vk::PipelineStageFlagBits::eAllCommands,
vk::DependencyFlagBits::eByRegion, {}, {}, post_barrier); vk::DependencyFlagBits::eByRegion, {}, {}, post_barrier);
}); });
return true; return true;
@ -518,22 +521,25 @@ void TextureRuntime::ClearTextureWithRenderpass(Surface& surface,
.clear = MakeClearValue(value), .clear = MakeClearValue(value),
}; };
const RecordParams params = {
.aspect = surface.alloc.aspect,
.pipeline_flags = surface.PipelineStageFlags(),
.src_access = surface.AccessFlags(),
.src_image = surface.alloc.image,
};
scheduler.Record( scheduler.Record(
[aspect = MakeAspect(surface.type), image = surface.alloc.image, [params, level = clear.texture_level](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) {
level = clear.texture_level](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) {
const vk::ImageMemoryBarrier pre_barrier = { const vk::ImageMemoryBarrier pre_barrier = {
.srcAccessMask = vk::AccessFlagBits::eShaderWrite | .srcAccessMask = params.src_access,
vk::AccessFlagBits::eColorAttachmentWrite |
vk::AccessFlagBits::eDepthStencilAttachmentWrite |
vk::AccessFlagBits::eTransferWrite,
.dstAccessMask = vk::AccessFlagBits::eTransferWrite, .dstAccessMask = vk::AccessFlagBits::eTransferWrite,
.oldLayout = vk::ImageLayout::eGeneral, .oldLayout = vk::ImageLayout::eGeneral,
.newLayout = vk::ImageLayout::eGeneral, .newLayout = vk::ImageLayout::eGeneral,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = image, .image = params.src_image,
.subresourceRange{ .subresourceRange{
.aspectMask = aspect, .aspectMask = params.aspect,
.baseMipLevel = level, .baseMipLevel = level,
.levelCount = 1, .levelCount = 1,
.baseArrayLayer = 0, .baseArrayLayer = 0,
@ -541,32 +547,25 @@ void TextureRuntime::ClearTextureWithRenderpass(Surface& surface,
}, },
}; };
render_cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eAllCommands, render_cmdbuf.pipelineBarrier(params.pipeline_flags, vk::PipelineStageFlagBits::eTransfer,
vk::PipelineStageFlagBits::eTransfer,
vk::DependencyFlagBits::eByRegion, {}, {}, pre_barrier); vk::DependencyFlagBits::eByRegion, {}, {}, pre_barrier);
}); });
renderpass_cache.EnterRenderpass(clear_info); renderpass_cache.EnterRenderpass(clear_info);
renderpass_cache.ExitRenderpass(); renderpass_cache.ExitRenderpass();
scheduler.Record([aspect = MakeAspect(surface.type), image = surface.alloc.image, scheduler.Record([params, level = clear.texture_level]
level = clear.texture_level](vk::CommandBuffer render_cmdbuf, (vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) {
vk::CommandBuffer) {
const vk::ImageMemoryBarrier post_barrier = { const vk::ImageMemoryBarrier post_barrier = {
.srcAccessMask = vk::AccessFlagBits::eTransferWrite, .srcAccessMask = vk::AccessFlagBits::eTransferWrite,
.dstAccessMask = vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite | .dstAccessMask = params.src_access,
vk::AccessFlagBits::eColorAttachmentRead |
vk::AccessFlagBits::eColorAttachmentWrite |
vk::AccessFlagBits::eDepthStencilAttachmentRead |
vk::AccessFlagBits::eDepthStencilAttachmentWrite |
vk::AccessFlagBits::eTransferRead | vk::AccessFlagBits::eTransferWrite,
.oldLayout = vk::ImageLayout::eGeneral, .oldLayout = vk::ImageLayout::eGeneral,
.newLayout = vk::ImageLayout::eGeneral, .newLayout = vk::ImageLayout::eGeneral,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = image, .image = params.src_image,
.subresourceRange{ .subresourceRange{
.aspectMask = aspect, .aspectMask = params.aspect,
.baseMipLevel = level, .baseMipLevel = level,
.levelCount = 1, .levelCount = 1,
.baseArrayLayer = 0, .baseArrayLayer = 0,
@ -574,8 +573,7 @@ void TextureRuntime::ClearTextureWithRenderpass(Surface& surface,
}, },
}; };
render_cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, render_cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, params.pipeline_flags,
vk::PipelineStageFlagBits::eAllCommands,
vk::DependencyFlagBits::eByRegion, {}, {}, post_barrier); vk::DependencyFlagBits::eByRegion, {}, {}, post_barrier);
}); });
} }
@ -584,22 +582,28 @@ bool TextureRuntime::CopyTextures(Surface& source, Surface& dest,
const VideoCore::TextureCopy& copy) { const VideoCore::TextureCopy& copy) {
renderpass_cache.ExitRenderpass(); renderpass_cache.ExitRenderpass();
scheduler.Record([src_image = source.alloc.image, dst_image = dest.alloc.image, const RecordParams params = {
aspect = MakeAspect(source.type), .aspect = source.alloc.aspect,
copy](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) { .filter = MakeFilter(source.pixel_format),
.pipeline_flags = source.PipelineStageFlags() | dest.PipelineStageFlags(),
.src_access = source.AccessFlags(),
.dst_access = dest.AccessFlags(),
.src_image = source.alloc.image,
.dst_image = dest.alloc.image,
};
scheduler.Record([params, copy](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) {
const vk::ImageCopy image_copy = { const vk::ImageCopy image_copy = {
.srcSubresource = .srcSubresource{
{ .aspectMask = params.aspect,
.aspectMask = aspect,
.mipLevel = copy.src_level, .mipLevel = copy.src_level,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = 1, .layerCount = 1,
}, },
.srcOffset = {static_cast<s32>(copy.src_offset.x), static_cast<s32>(copy.src_offset.y), .srcOffset = {static_cast<s32>(copy.src_offset.x), static_cast<s32>(copy.src_offset.y),
0}, 0},
.dstSubresource = .dstSubresource{
{ .aspectMask = params.aspect,
.aspectMask = aspect,
.mipLevel = copy.dst_level, .mipLevel = copy.dst_level,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = 1, .layerCount = 1,
@ -611,18 +615,15 @@ bool TextureRuntime::CopyTextures(Surface& source, Surface& dest,
const std::array pre_barriers = { const std::array pre_barriers = {
vk::ImageMemoryBarrier{ vk::ImageMemoryBarrier{
.srcAccessMask = vk::AccessFlagBits::eShaderWrite | .srcAccessMask = params.src_access,
vk::AccessFlagBits::eColorAttachmentWrite |
vk::AccessFlagBits::eDepthStencilAttachmentWrite |
vk::AccessFlagBits::eTransferWrite,
.dstAccessMask = vk::AccessFlagBits::eTransferRead, .dstAccessMask = vk::AccessFlagBits::eTransferRead,
.oldLayout = vk::ImageLayout::eGeneral, .oldLayout = vk::ImageLayout::eGeneral,
.newLayout = vk::ImageLayout::eTransferSrcOptimal, .newLayout = vk::ImageLayout::eTransferSrcOptimal,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = src_image, .image = params.src_image,
.subresourceRange{ .subresourceRange{
.aspectMask = aspect, .aspectMask = params.aspect,
.baseMipLevel = copy.src_level, .baseMipLevel = copy.src_level,
.levelCount = 1, .levelCount = 1,
.baseArrayLayer = 0, .baseArrayLayer = 0,
@ -630,18 +631,15 @@ bool TextureRuntime::CopyTextures(Surface& source, Surface& dest,
}, },
}, },
vk::ImageMemoryBarrier{ vk::ImageMemoryBarrier{
.srcAccessMask = vk::AccessFlagBits::eShaderWrite | .srcAccessMask = params.dst_access,
vk::AccessFlagBits::eColorAttachmentWrite |
vk::AccessFlagBits::eDepthStencilAttachmentWrite |
vk::AccessFlagBits::eTransferWrite,
.dstAccessMask = vk::AccessFlagBits::eTransferWrite, .dstAccessMask = vk::AccessFlagBits::eTransferWrite,
.oldLayout = vk::ImageLayout::eGeneral, .oldLayout = vk::ImageLayout::eGeneral,
.newLayout = vk::ImageLayout::eTransferDstOptimal, .newLayout = vk::ImageLayout::eTransferDstOptimal,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = dst_image, .image = params.dst_image,
.subresourceRange{ .subresourceRange{
.aspectMask = aspect, .aspectMask = params.aspect,
.baseMipLevel = copy.dst_level, .baseMipLevel = copy.dst_level,
.levelCount = 1, .levelCount = 1,
.baseArrayLayer = 0, .baseArrayLayer = 0,
@ -657,9 +655,9 @@ bool TextureRuntime::CopyTextures(Surface& source, Surface& dest,
.newLayout = vk::ImageLayout::eGeneral, .newLayout = vk::ImageLayout::eGeneral,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = src_image, .image = params.src_image,
.subresourceRange{ .subresourceRange{
.aspectMask = aspect, .aspectMask = params.aspect,
.baseMipLevel = copy.src_level, .baseMipLevel = copy.src_level,
.levelCount = 1, .levelCount = 1,
.baseArrayLayer = 0, .baseArrayLayer = 0,
@ -668,20 +666,14 @@ bool TextureRuntime::CopyTextures(Surface& source, Surface& dest,
}, },
vk::ImageMemoryBarrier{ vk::ImageMemoryBarrier{
.srcAccessMask = vk::AccessFlagBits::eTransferWrite, .srcAccessMask = vk::AccessFlagBits::eTransferWrite,
.dstAccessMask = .dstAccessMask = params.dst_access,
vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite |
vk::AccessFlagBits::eColorAttachmentRead |
vk::AccessFlagBits::eColorAttachmentWrite |
vk::AccessFlagBits::eDepthStencilAttachmentRead |
vk::AccessFlagBits::eDepthStencilAttachmentWrite |
vk::AccessFlagBits::eTransferRead | vk::AccessFlagBits::eTransferWrite,
.oldLayout = vk::ImageLayout::eTransferDstOptimal, .oldLayout = vk::ImageLayout::eTransferDstOptimal,
.newLayout = vk::ImageLayout::eGeneral, .newLayout = vk::ImageLayout::eGeneral,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = dst_image, .image = params.dst_image,
.subresourceRange{ .subresourceRange{
.aspectMask = aspect, .aspectMask = params.aspect,
.baseMipLevel = copy.dst_level, .baseMipLevel = copy.dst_level,
.levelCount = 1, .levelCount = 1,
.baseArrayLayer = 0, .baseArrayLayer = 0,
@ -690,15 +682,13 @@ bool TextureRuntime::CopyTextures(Surface& source, Surface& dest,
}, },
}; };
render_cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eAllCommands, render_cmdbuf.pipelineBarrier(params.pipeline_flags, vk::PipelineStageFlagBits::eTransfer,
vk::PipelineStageFlagBits::eTransfer,
vk::DependencyFlagBits::eByRegion, {}, {}, pre_barriers); vk::DependencyFlagBits::eByRegion, {}, {}, pre_barriers);
render_cmdbuf.copyImage(src_image, vk::ImageLayout::eTransferSrcOptimal, dst_image, render_cmdbuf.copyImage(params.src_image, vk::ImageLayout::eTransferSrcOptimal,
vk::ImageLayout::eTransferDstOptimal, image_copy); params.dst_image, vk::ImageLayout::eTransferDstOptimal, image_copy);
render_cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, render_cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, params.pipeline_flags,
vk::PipelineStageFlagBits::eAllCommands,
vk::DependencyFlagBits::eByRegion, {}, {}, post_barriers); vk::DependencyFlagBits::eByRegion, {}, {}, post_barriers);
}); });
@ -709,9 +699,17 @@ bool TextureRuntime::BlitTextures(Surface& source, Surface& dest,
const VideoCore::TextureBlit& blit) { const VideoCore::TextureBlit& blit) {
renderpass_cache.ExitRenderpass(); renderpass_cache.ExitRenderpass();
scheduler.Record([src_image = source.alloc.image, aspect = MakeAspect(source.type), const RecordParams params = {
filter = MakeFilter(source.pixel_format), dst_image = dest.alloc.image, .aspect = source.alloc.aspect,
blit](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) { .filter = MakeFilter(source.pixel_format),
.pipeline_flags = source.PipelineStageFlags() | dest.PipelineStageFlags(),
.src_access = source.AccessFlags(),
.dst_access = dest.AccessFlags(),
.src_image = source.alloc.image,
.dst_image = dest.alloc.image,
};
scheduler.Record([params, blit](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) {
const std::array source_offsets = { const std::array source_offsets = {
vk::Offset3D{static_cast<s32>(blit.src_rect.left), vk::Offset3D{static_cast<s32>(blit.src_rect.left),
static_cast<s32>(blit.src_rect.bottom), 0}, static_cast<s32>(blit.src_rect.bottom), 0},
@ -727,17 +725,15 @@ bool TextureRuntime::BlitTextures(Surface& source, Surface& dest,
}; };
const vk::ImageBlit blit_area = { const vk::ImageBlit blit_area = {
.srcSubresource = .srcSubresource{
{ .aspectMask = params.aspect,
.aspectMask = aspect,
.mipLevel = blit.src_level, .mipLevel = blit.src_level,
.baseArrayLayer = blit.src_layer, .baseArrayLayer = blit.src_layer,
.layerCount = 1, .layerCount = 1,
}, },
.srcOffsets = source_offsets, .srcOffsets = source_offsets,
.dstSubresource = .dstSubresource{
{ .aspectMask = params.aspect,
.aspectMask = aspect,
.mipLevel = blit.dst_level, .mipLevel = blit.dst_level,
.baseArrayLayer = blit.dst_layer, .baseArrayLayer = blit.dst_layer,
.layerCount = 1, .layerCount = 1,
@ -747,15 +743,15 @@ bool TextureRuntime::BlitTextures(Surface& source, Surface& dest,
const std::array read_barriers = { const std::array read_barriers = {
vk::ImageMemoryBarrier{ vk::ImageMemoryBarrier{
.srcAccessMask = vk::AccessFlagBits::eMemoryWrite, .srcAccessMask = params.src_access,
.dstAccessMask = vk::AccessFlagBits::eTransferRead, .dstAccessMask = vk::AccessFlagBits::eTransferRead,
.oldLayout = vk::ImageLayout::eGeneral, .oldLayout = vk::ImageLayout::eGeneral,
.newLayout = vk::ImageLayout::eTransferSrcOptimal, .newLayout = vk::ImageLayout::eTransferSrcOptimal,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = src_image, .image = params.src_image,
.subresourceRange{ .subresourceRange{
.aspectMask = aspect, .aspectMask = params.aspect,
.baseMipLevel = blit.src_level, .baseMipLevel = blit.src_level,
.levelCount = 1, .levelCount = 1,
.baseArrayLayer = 0, .baseArrayLayer = 0,
@ -763,35 +759,33 @@ bool TextureRuntime::BlitTextures(Surface& source, Surface& dest,
}, },
}, },
vk::ImageMemoryBarrier{ vk::ImageMemoryBarrier{
.srcAccessMask = vk::AccessFlagBits::eShaderRead | .srcAccessMask = params.dst_access,
vk::AccessFlagBits::eDepthStencilAttachmentRead |
vk::AccessFlagBits::eColorAttachmentRead |
vk::AccessFlagBits::eTransferRead,
.dstAccessMask = vk::AccessFlagBits::eTransferWrite, .dstAccessMask = vk::AccessFlagBits::eTransferWrite,
.oldLayout = vk::ImageLayout::eGeneral, .oldLayout = vk::ImageLayout::eGeneral,
.newLayout = vk::ImageLayout::eTransferDstOptimal, .newLayout = vk::ImageLayout::eTransferDstOptimal,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = dst_image, .image = params.dst_image,
.subresourceRange{ .subresourceRange{
.aspectMask = aspect, .aspectMask = params.aspect,
.baseMipLevel = blit.dst_level, .baseMipLevel = blit.dst_level,
.levelCount = 1, .levelCount = 1,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = VK_REMAINING_ARRAY_LAYERS, .layerCount = VK_REMAINING_ARRAY_LAYERS,
}, },
}}; },
};
const std::array write_barriers = { const std::array write_barriers = {
vk::ImageMemoryBarrier{ vk::ImageMemoryBarrier{
.srcAccessMask = vk::AccessFlagBits::eNone, .srcAccessMask = vk::AccessFlagBits::eNone,
.dstAccessMask = vk::AccessFlagBits::eMemoryWrite | vk::AccessFlagBits::eMemoryRead, .dstAccessMask = vk::AccessFlagBits::eNone,
.oldLayout = vk::ImageLayout::eTransferSrcOptimal, .oldLayout = vk::ImageLayout::eTransferSrcOptimal,
.newLayout = vk::ImageLayout::eGeneral, .newLayout = vk::ImageLayout::eGeneral,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = src_image, .image = params.src_image,
.subresourceRange{ .subresourceRange{
.aspectMask = aspect, .aspectMask = params.aspect,
.baseMipLevel = blit.src_level, .baseMipLevel = blit.src_level,
.levelCount = 1, .levelCount = 1,
.baseArrayLayer = 0, .baseArrayLayer = 0,
@ -800,30 +794,30 @@ bool TextureRuntime::BlitTextures(Surface& source, Surface& dest,
}, },
vk::ImageMemoryBarrier{ vk::ImageMemoryBarrier{
.srcAccessMask = vk::AccessFlagBits::eTransferWrite, .srcAccessMask = vk::AccessFlagBits::eTransferWrite,
.dstAccessMask = vk::AccessFlagBits::eMemoryWrite | vk::AccessFlagBits::eMemoryRead, .dstAccessMask = params.dst_access,
.oldLayout = vk::ImageLayout::eTransferDstOptimal, .oldLayout = vk::ImageLayout::eTransferDstOptimal,
.newLayout = vk::ImageLayout::eGeneral, .newLayout = vk::ImageLayout::eGeneral,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = dst_image, .image = params.dst_image,
.subresourceRange{ .subresourceRange{
.aspectMask = aspect, .aspectMask = params.aspect,
.baseMipLevel = blit.dst_level, .baseMipLevel = blit.dst_level,
.levelCount = 1, .levelCount = 1,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = VK_REMAINING_ARRAY_LAYERS, .layerCount = VK_REMAINING_ARRAY_LAYERS,
}, },
}}; },
};
render_cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eAllCommands, render_cmdbuf.pipelineBarrier(params.pipeline_flags, vk::PipelineStageFlagBits::eTransfer,
vk::PipelineStageFlagBits::eTransfer,
vk::DependencyFlagBits::eByRegion, {}, {}, read_barriers); vk::DependencyFlagBits::eByRegion, {}, {}, read_barriers);
render_cmdbuf.blitImage(src_image, vk::ImageLayout::eTransferSrcOptimal, dst_image, render_cmdbuf.blitImage(params.src_image, vk::ImageLayout::eTransferSrcOptimal,
vk::ImageLayout::eTransferDstOptimal, blit_area, filter); params.dst_image, vk::ImageLayout::eTransferDstOptimal, blit_area,
params.filter);
render_cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, render_cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, params.pipeline_flags,
vk::PipelineStageFlagBits::eAllCommands,
vk::DependencyFlagBits::eByRegion, {}, {}, write_barriers); vk::DependencyFlagBits::eByRegion, {}, {}, write_barriers);
}); });
@ -933,8 +927,15 @@ void Surface::Upload(const VideoCore::BufferTextureCopy& upload, const StagingDa
if (is_scaled) { if (is_scaled) {
ScaledUpload(upload, staging); ScaledUpload(upload, staging);
} else { } else {
scheduler.Record([aspect = alloc.aspect, image = alloc.image, format = alloc.format, const RecordParams params = {
staging, upload](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) { .aspect = alloc.aspect,
.pipeline_flags = PipelineStageFlags(),
.src_access = AccessFlags(),
.src_image = alloc.image,
};
scheduler.Record([format = alloc.format, params, staging,
upload](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) {
u32 num_copies = 1; u32 num_copies = 1;
std::array<vk::BufferImageCopy, 2> buffer_image_copies; std::array<vk::BufferImageCopy, 2> buffer_image_copies;
@ -943,9 +944,8 @@ void Surface::Upload(const VideoCore::BufferTextureCopy& upload, const StagingDa
.bufferOffset = staging.buffer_offset + upload.buffer_offset, .bufferOffset = staging.buffer_offset + upload.buffer_offset,
.bufferRowLength = rect.GetWidth(), .bufferRowLength = rect.GetWidth(),
.bufferImageHeight = rect.GetHeight(), .bufferImageHeight = rect.GetHeight(),
.imageSubresource = .imageSubresource{
{ .aspectMask = params.aspect,
.aspectMask = aspect,
.mipLevel = upload.texture_level, .mipLevel = upload.texture_level,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = 1, .layerCount = 1,
@ -954,7 +954,7 @@ void Surface::Upload(const VideoCore::BufferTextureCopy& upload, const StagingDa
.imageExtent = {rect.GetWidth(), rect.GetHeight(), 1}, .imageExtent = {rect.GetWidth(), rect.GetHeight(), 1},
}; };
if (aspect & vk::ImageAspectFlagBits::eStencil) { if (params.aspect & vk::ImageAspectFlagBits::eStencil) {
buffer_image_copies[0].imageSubresource.aspectMask = buffer_image_copies[0].imageSubresource.aspectMask =
vk::ImageAspectFlagBits::eDepth; vk::ImageAspectFlagBits::eDepth;
vk::BufferImageCopy& stencil_copy = buffer_image_copies[1]; vk::BufferImageCopy& stencil_copy = buffer_image_copies[1];
@ -964,24 +964,16 @@ void Surface::Upload(const VideoCore::BufferTextureCopy& upload, const StagingDa
num_copies++; num_copies++;
} }
static constexpr vk::AccessFlags WRITE_ACCESS_FLAGS =
vk::AccessFlagBits::eShaderWrite | vk::AccessFlagBits::eColorAttachmentWrite |
vk::AccessFlagBits::eDepthStencilAttachmentWrite;
static constexpr vk::AccessFlags READ_ACCESS_FLAGS =
vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eColorAttachmentRead |
vk::AccessFlagBits::eDepthStencilAttachmentRead;
const vk::ImageMemoryBarrier read_barrier = { const vk::ImageMemoryBarrier read_barrier = {
.srcAccessMask = WRITE_ACCESS_FLAGS, .srcAccessMask = params.src_access,
.dstAccessMask = vk::AccessFlagBits::eTransferWrite, .dstAccessMask = vk::AccessFlagBits::eTransferWrite,
.oldLayout = vk::ImageLayout::eGeneral, .oldLayout = vk::ImageLayout::eGeneral,
.newLayout = vk::ImageLayout::eTransferDstOptimal, .newLayout = vk::ImageLayout::eTransferDstOptimal,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = image, .image = params.src_image,
.subresourceRange = .subresourceRange{
{ .aspectMask = params.aspect,
.aspectMask = aspect,
.baseMipLevel = upload.texture_level, .baseMipLevel = upload.texture_level,
.levelCount = 1, .levelCount = 1,
.baseArrayLayer = 0, .baseArrayLayer = 0,
@ -990,15 +982,14 @@ void Surface::Upload(const VideoCore::BufferTextureCopy& upload, const StagingDa
}; };
const vk::ImageMemoryBarrier write_barrier = { const vk::ImageMemoryBarrier write_barrier = {
.srcAccessMask = vk::AccessFlagBits::eTransferWrite, .srcAccessMask = vk::AccessFlagBits::eTransferWrite,
.dstAccessMask = WRITE_ACCESS_FLAGS | READ_ACCESS_FLAGS, .dstAccessMask = params.src_access,
.oldLayout = vk::ImageLayout::eTransferDstOptimal, .oldLayout = vk::ImageLayout::eTransferDstOptimal,
.newLayout = vk::ImageLayout::eGeneral, .newLayout = vk::ImageLayout::eGeneral,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = image, .image = params.src_image,
.subresourceRange = .subresourceRange{
{ .aspectMask = params.aspect,
.aspectMask = aspect,
.baseMipLevel = upload.texture_level, .baseMipLevel = upload.texture_level,
.levelCount = 1, .levelCount = 1,
.baseArrayLayer = 0, .baseArrayLayer = 0,
@ -1006,17 +997,17 @@ void Surface::Upload(const VideoCore::BufferTextureCopy& upload, const StagingDa
}, },
}; };
render_cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eAllCommands, render_cmdbuf.pipelineBarrier(params.pipeline_flags,
vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer,
vk::DependencyFlagBits::eByRegion, {}, {}, read_barrier); vk::DependencyFlagBits::eByRegion, {}, {}, read_barrier);
render_cmdbuf.copyBufferToImage(staging.buffer, image, render_cmdbuf.copyBufferToImage(staging.buffer, params.src_image,
vk::ImageLayout::eTransferDstOptimal, num_copies, vk::ImageLayout::eTransferDstOptimal, num_copies,
buffer_image_copies.data()); buffer_image_copies.data());
render_cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, render_cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer,
vk::PipelineStageFlagBits::eAllCommands, params.pipeline_flags, vk::DependencyFlagBits::eByRegion,
vk::DependencyFlagBits::eByRegion, {}, {}, write_barrier); {}, {}, write_barrier);
}); });
runtime.upload_buffer.Commit(staging.size); runtime.upload_buffer.Commit(staging.size);
@ -1042,16 +1033,22 @@ void Surface::Download(const VideoCore::BufferTextureCopy& download, const Stagi
if (is_scaled) { if (is_scaled) {
ScaledDownload(download, staging); ScaledDownload(download, staging);
} else { } else {
scheduler.Record([aspect = alloc.aspect, image = alloc.image, staging, const RecordParams params = {
download](vk::CommandBuffer render_cmdbuf, vk::CommandBuffer) { .aspect = alloc.aspect,
.pipeline_flags = PipelineStageFlags(),
.src_access = AccessFlags(),
.src_image = alloc.image,
};
scheduler.Record([params, staging, download](vk::CommandBuffer render_cmdbuf,
vk::CommandBuffer) {
const VideoCore::Rect2D rect = download.texture_rect; const VideoCore::Rect2D rect = download.texture_rect;
const vk::BufferImageCopy buffer_image_copy = { const vk::BufferImageCopy buffer_image_copy = {
.bufferOffset = staging.buffer_offset + download.buffer_offset, .bufferOffset = staging.buffer_offset + download.buffer_offset,
.bufferRowLength = rect.GetWidth(), .bufferRowLength = rect.GetWidth(),
.bufferImageHeight = rect.GetHeight(), .bufferImageHeight = rect.GetHeight(),
.imageSubresource = .imageSubresource{
{ .aspectMask = params.aspect,
.aspectMask = aspect,
.mipLevel = download.texture_level, .mipLevel = download.texture_level,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = 1, .layerCount = 1,
@ -1067,10 +1064,9 @@ void Surface::Download(const VideoCore::BufferTextureCopy& download, const Stagi
.newLayout = vk::ImageLayout::eTransferSrcOptimal, .newLayout = vk::ImageLayout::eTransferSrcOptimal,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = image, .image = params.src_image,
.subresourceRange = .subresourceRange{
{ .aspectMask = params.aspect,
.aspectMask = aspect,
.baseMipLevel = download.texture_level, .baseMipLevel = download.texture_level,
.levelCount = 1, .levelCount = 1,
.baseArrayLayer = 0, .baseArrayLayer = 0,
@ -1084,10 +1080,9 @@ void Surface::Download(const VideoCore::BufferTextureCopy& download, const Stagi
.newLayout = vk::ImageLayout::eGeneral, .newLayout = vk::ImageLayout::eGeneral,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = image, .image = params.src_image,
.subresourceRange = .subresourceRange{
{ .aspectMask = params.aspect,
.aspectMask = aspect,
.baseMipLevel = download.texture_level, .baseMipLevel = download.texture_level,
.levelCount = 1, .levelCount = 1,
.baseArrayLayer = 0, .baseArrayLayer = 0,
@ -1099,16 +1094,16 @@ void Surface::Download(const VideoCore::BufferTextureCopy& download, const Stagi
.dstAccessMask = vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite, .dstAccessMask = vk::AccessFlagBits::eMemoryRead | vk::AccessFlagBits::eMemoryWrite,
}; };
render_cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eAllCommands, render_cmdbuf.pipelineBarrier(params.pipeline_flags,
vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer,
vk::DependencyFlagBits::eByRegion, {}, {}, read_barrier); vk::DependencyFlagBits::eByRegion, {}, {}, read_barrier);
render_cmdbuf.copyImageToBuffer(image, vk::ImageLayout::eTransferSrcOptimal, render_cmdbuf.copyImageToBuffer(params.src_image, vk::ImageLayout::eTransferSrcOptimal,
staging.buffer, buffer_image_copy); staging.buffer, buffer_image_copy);
render_cmdbuf.pipelineBarrier( render_cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer,
vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eAllCommands, params.pipeline_flags, vk::DependencyFlagBits::eByRegion,
vk::DependencyFlagBits::eByRegion, memory_write_barrier, {}, image_write_barrier); memory_write_barrier, {}, image_write_barrier);
}); });
runtime.download_buffer.Commit(staging.size); runtime.download_buffer.Commit(staging.size);
} }
@ -1124,6 +1119,33 @@ u32 Surface::GetInternalBytesPerPixel() const {
return vk::blockSize(alloc.format); return vk::blockSize(alloc.format);
} }
vk::AccessFlags Surface::AccessFlags() const noexcept {
const bool is_color = static_cast<bool>(alloc.aspect & vk::ImageAspectFlagBits::eColor);
const vk::AccessFlags attachment_flags =
is_color
? vk::AccessFlagBits::eColorAttachmentRead | vk::AccessFlagBits::eColorAttachmentWrite
: vk::AccessFlagBits::eDepthStencilAttachmentRead |
vk::AccessFlagBits::eDepthStencilAttachmentWrite;
return vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eTransferRead |
vk::AccessFlagBits::eTransferWrite |
(is_framebuffer ? attachment_flags : vk::AccessFlagBits::eNone) |
(is_storage ? vk::AccessFlagBits::eShaderWrite : vk::AccessFlagBits::eNone);
}
vk::PipelineStageFlags Surface::PipelineStageFlags() const noexcept {
const bool is_color = static_cast<bool>(alloc.aspect & vk::ImageAspectFlagBits::eColor);
const vk::PipelineStageFlags attachment_flags =
is_color ? vk::PipelineStageFlagBits::eColorAttachmentOutput
: vk::PipelineStageFlagBits::eEarlyFragmentTests |
vk::PipelineStageFlagBits::eLateFragmentTests;
return vk::PipelineStageFlagBits::eTransfer | vk::PipelineStageFlagBits::eFragmentShader |
(is_framebuffer ? attachment_flags : vk::PipelineStageFlagBits::eNone) |
(is_storage ? vk::PipelineStageFlagBits::eComputeShader
: vk::PipelineStageFlagBits::eNone);
}
void Surface::ScaledUpload(const VideoCore::BufferTextureCopy& upload, const StagingData& staging) { void Surface::ScaledUpload(const VideoCore::BufferTextureCopy& upload, const StagingData& staging) {
const u32 rect_width = upload.texture_rect.GetWidth(); const u32 rect_width = upload.texture_rect.GetWidth();
const u32 rect_height = upload.texture_rect.GetHeight(); const u32 rect_height = upload.texture_rect.GetHeight();

View File

@ -190,28 +190,35 @@ public:
/// Returns the bpp of the internal surface format /// Returns the bpp of the internal surface format
u32 GetInternalBytesPerPixel() const; u32 GetInternalBytesPerPixel() const;
/// Returns the access flags indicative of the surface
vk::AccessFlags AccessFlags() const noexcept;
/// Returns the pipeline stage flags indicative of the surface
vk::PipelineStageFlags PipelineStageFlags() const noexcept;
/// Returns an image view used to sample the surface from a shader /// Returns an image view used to sample the surface from a shader
vk::ImageView GetImageView() const { vk::ImageView GetImageView() const noexcept {
return alloc.image_view; return alloc.image_view;
} }
/// Returns an image view used to create a framebuffer /// Returns an image view used to create a framebuffer
vk::ImageView GetFramebufferView() { vk::ImageView GetFramebufferView() noexcept {
is_framebuffer = true;
return alloc.base_view; return alloc.base_view;
} }
/// Returns the depth only image view of the surface, null otherwise /// Returns the depth only image view of the surface, null otherwise
vk::ImageView GetDepthView() const { vk::ImageView GetDepthView() const noexcept {
return alloc.depth_view; return alloc.depth_view;
} }
/// Returns the stencil only image view of the surface, null otherwise /// Returns the stencil only image view of the surface, null otherwise
vk::ImageView GetStencilView() const { vk::ImageView GetStencilView() const noexcept {
return alloc.stencil_view; return alloc.stencil_view;
} }
/// Returns the R32 image view used for atomic load/store /// Returns the R32 image view used for atomic load/store
vk::ImageView GetStorageView() const { vk::ImageView GetStorageView() noexcept {
if (!alloc.storage_view) { if (!alloc.storage_view) {
LOG_CRITICAL(Render_Vulkan, LOG_CRITICAL(Render_Vulkan,
"Surface with pixel format {} and internal format {} " "Surface with pixel format {} and internal format {} "
@ -219,11 +226,12 @@ public:
VideoCore::PixelFormatAsString(pixel_format), vk::to_string(alloc.format)); VideoCore::PixelFormatAsString(pixel_format), vk::to_string(alloc.format));
UNREACHABLE(); UNREACHABLE();
} }
is_storage = true;
return alloc.storage_view; return alloc.storage_view;
} }
/// Returns the internal format of the allocated texture /// Returns the internal format of the allocated texture
vk::Format GetInternalFormat() const { vk::Format GetInternalFormat() const noexcept {
return alloc.format; return alloc.format;
} }
@ -244,6 +252,8 @@ private:
Scheduler& scheduler; Scheduler& scheduler;
public: public:
bool is_framebuffer{};
bool is_storage{};
ImageAlloc alloc; ImageAlloc alloc;
FormatTraits traits; FormatTraits traits;
}; };