mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-20 02:47:02 +02:00
graphics: simplify image allocation
This commit is contained in:
@@ -567,6 +567,8 @@ if(BUILD_TESTING)
|
||||
|
||||
add_test(NAME texture_cache_layered_image
|
||||
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --layered-image-only)
|
||||
add_test(NAME host_image_allocation
|
||||
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --host-image-allocation-only)
|
||||
add_test(NAME texture_cache_image_views
|
||||
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --image-view-cache-only)
|
||||
add_test(NAME texture_cache_storage_sampled
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
namespace Libs::Graphics {
|
||||
|
||||
struct VulkanImage;
|
||||
struct VulkanMemory;
|
||||
|
||||
inline constexpr uint32_t VULKAN_TARGET_API_VERSION = VK_API_VERSION_1_3;
|
||||
|
||||
@@ -117,12 +116,6 @@ private:
|
||||
m_image_format_properties;
|
||||
};
|
||||
|
||||
struct VulkanMemory {
|
||||
vk::MemoryPropertyFlags property = {};
|
||||
vk::MemoryPropertyFlags preferred_property = {};
|
||||
VmaAllocation allocation = nullptr;
|
||||
};
|
||||
|
||||
struct VulkanImageState {
|
||||
vk::PipelineStageFlags2 pl_stage = vk::PipelineStageFlagBits2::eAllCommands;
|
||||
vk::AccessFlags2 access_mask = vk::AccessFlagBits2::eNone;
|
||||
@@ -144,7 +137,7 @@ struct VulkanImage {
|
||||
vk::Image image = nullptr;
|
||||
VulkanImageState state;
|
||||
std::vector<VulkanImageState> subresource_states;
|
||||
Graphics::VulkanMemory memory;
|
||||
VmaAllocation allocation = nullptr;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -661,26 +661,17 @@ Image::Image(GraphicContext& graphics, CommandScheduler& scheduler, const ImageI
|
||||
return;
|
||||
}
|
||||
|
||||
backing.format = info.pixel_format;
|
||||
backing.image_type = HostImageType(info.type);
|
||||
backing.extent = info.extent;
|
||||
backing.layers = info.IsVolume() ? 1u : info.resources.layers;
|
||||
backing.mip_levels = info.resources.levels;
|
||||
backing.samples = info.samples;
|
||||
backing.flags = ImageCreateFlags(graphics, info);
|
||||
backing.usage = ImageUsageFlags(graphics, info);
|
||||
|
||||
vk::ImageCreateInfo create {};
|
||||
create.flags = backing.flags;
|
||||
create.imageType = backing.image_type;
|
||||
create.extent = backing.extent;
|
||||
create.mipLevels = backing.mip_levels;
|
||||
create.arrayLayers = backing.layers;
|
||||
create.format = backing.format;
|
||||
create.flags = ImageCreateFlags(graphics, info);
|
||||
create.imageType = HostImageType(info.type);
|
||||
create.extent = info.extent;
|
||||
create.mipLevels = info.resources.levels;
|
||||
create.arrayLayers = info.IsVolume() ? 1u : info.resources.layers;
|
||||
create.format = info.pixel_format;
|
||||
create.tiling = vk::ImageTiling::eOptimal;
|
||||
create.initialLayout = backing.state.layout;
|
||||
create.usage = backing.usage;
|
||||
create.samples = vulkan_sample_count(backing.samples);
|
||||
create.initialLayout = vk::ImageLayout::eUndefined;
|
||||
create.usage = ImageUsageFlags(graphics, info);
|
||||
create.samples = vulkan_sample_count(info.samples);
|
||||
|
||||
vk::ImageFormatProperties properties {};
|
||||
if (graphics.GetImageFormatProperties(create.format, create.imageType, create.tiling,
|
||||
@@ -691,10 +682,9 @@ Image::Image(GraphicContext& graphics, CommandScheduler& scheduler, const ImageI
|
||||
"flags=0x%x samples=%u\n",
|
||||
static_cast<int>(create.format), static_cast<int>(create.imageType),
|
||||
static_cast<vk::ImageUsageFlags::MaskType>(create.usage),
|
||||
static_cast<vk::ImageCreateFlags::MaskType>(create.flags), backing.samples);
|
||||
static_cast<vk::ImageCreateFlags::MaskType>(create.flags), info.samples);
|
||||
}
|
||||
|
||||
backing.memory.property = vk::MemoryPropertyFlagBits::eDeviceLocal;
|
||||
if (!graphics.CreateImage(create, backing)) {
|
||||
EXIT("failed to create image: extent=%ux%ux%u format=%d layers=%u levels=%u\n",
|
||||
create.extent.width, create.extent.height, create.extent.depth,
|
||||
|
||||
@@ -130,35 +130,42 @@ uint64_t GraphicContext::GetTotalMemoryBudget() const {
|
||||
|
||||
bool GraphicContext::CreateImage(const vk::ImageCreateInfo& image_info, VulkanImage& image) {
|
||||
KYTY_PROFILER_FUNCTION();
|
||||
EXIT_IF(allocator == nullptr || image.image != nullptr || image.memory.allocation != nullptr);
|
||||
EXIT_IF(allocator == nullptr || image.image != nullptr || image.allocation != nullptr);
|
||||
|
||||
auto& memory = image.memory;
|
||||
VmaAllocationCreateInfo alloc_info {};
|
||||
alloc_info.requiredFlags = static_cast<vk::MemoryPropertyFlags::MaskType>(memory.property);
|
||||
alloc_info.preferredFlags =
|
||||
static_cast<vk::MemoryPropertyFlags::MaskType>(memory.preferred_property);
|
||||
alloc_info.requiredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
||||
|
||||
vk::Image::CType native_image = VK_NULL_HANDLE;
|
||||
const auto result = static_cast<vk::Result>(
|
||||
vmaCreateImage(allocator, static_cast<const vk::ImageCreateInfo::NativeType*>(image_info),
|
||||
&alloc_info, &native_image, &memory.allocation, nullptr));
|
||||
&alloc_info, &native_image, &image.allocation, nullptr));
|
||||
image.image = native_image;
|
||||
if (result != vk::Result::eSuccess) {
|
||||
LogMemoryBudget();
|
||||
return false;
|
||||
}
|
||||
|
||||
image.format = image_info.format;
|
||||
image.image_type = image_info.imageType;
|
||||
image.extent = image_info.extent;
|
||||
image.layers = image_info.arrayLayers;
|
||||
image.mip_levels = image_info.mipLevels;
|
||||
image.samples = static_cast<uint32_t>(image_info.samples);
|
||||
image.usage = image_info.usage;
|
||||
image.flags = image_info.flags;
|
||||
image.state = {.layout = image_info.initialLayout};
|
||||
image.subresource_states.clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GraphicContext::DeleteImage(VulkanImage& image) {
|
||||
KYTY_PROFILER_FUNCTION();
|
||||
EXIT_IF(allocator == nullptr || image.image == nullptr || image.memory.allocation == nullptr);
|
||||
EXIT_IF(allocator == nullptr || image.image == nullptr || image.allocation == nullptr);
|
||||
|
||||
auto& memory = image.memory;
|
||||
vmaDestroyImage(allocator, image.image, memory.allocation);
|
||||
image.image = nullptr;
|
||||
memory.allocation = nullptr;
|
||||
vmaDestroyImage(allocator, image.image, image.allocation);
|
||||
image.image = nullptr;
|
||||
image.allocation = nullptr;
|
||||
}
|
||||
|
||||
} // namespace Libs::Graphics
|
||||
|
||||
@@ -191,24 +191,15 @@ void Presenter::Frame::Configure(GraphicContext& graphics, vk::Extent2D extent,
|
||||
}
|
||||
if (dst.image != nullptr) {
|
||||
graphics.DeleteImage(dst);
|
||||
dst.memory = {};
|
||||
}
|
||||
|
||||
dst.extent = {extent.width, extent.height, 1};
|
||||
dst.format = format;
|
||||
dst.layers = 1;
|
||||
dst.mip_levels = 1;
|
||||
dst.state = {};
|
||||
dst.subresource_states.clear();
|
||||
dst.memory.property = vk::MemoryPropertyFlagBits::eDeviceLocal;
|
||||
|
||||
vk::ImageCreateInfo create {};
|
||||
create.sType = vk::StructureType::eImageCreateInfo;
|
||||
create.imageType = vk::ImageType::e2D;
|
||||
create.extent = {dst.extent.width, dst.extent.height, 1};
|
||||
create.extent = {extent.width, extent.height, 1};
|
||||
create.mipLevels = 1;
|
||||
create.arrayLayers = 1;
|
||||
create.format = dst.format;
|
||||
create.format = format;
|
||||
create.tiling = vk::ImageTiling::eOptimal;
|
||||
create.initialLayout = vk::ImageLayout::eUndefined;
|
||||
create.usage = vk::ImageUsageFlagBits::eTransferSrc | vk::ImageUsageFlagBits::eTransferDst;
|
||||
@@ -216,7 +207,7 @@ void Presenter::Frame::Configure(GraphicContext& graphics, vk::Extent2D extent,
|
||||
create.samples = vk::SampleCountFlagBits::e1;
|
||||
if (!graphics.CreateImage(create, dst)) {
|
||||
EXIT("failed to allocate prepared presentation image, extent=%ux%u format=%d\n",
|
||||
dst.extent.width, dst.extent.height, static_cast<int>(dst.format));
|
||||
extent.width, extent.height, static_cast<int>(format));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1762,6 +1762,73 @@ public:
|
||||
return Renderer();
|
||||
}
|
||||
|
||||
void CheckHostImageAllocation() {
|
||||
constexpr const char *name = "HostImageAllocation";
|
||||
auto &graphics = RuntimeContext();
|
||||
VulkanImage image;
|
||||
vk::ImageCreateInfo create{};
|
||||
create.flags = vk::ImageCreateFlagBits::eMutableFormat;
|
||||
create.imageType = vk::ImageType::e2D;
|
||||
create.format = vk::Format::eR8G8B8A8Unorm;
|
||||
create.extent = {16, 8, 1};
|
||||
create.mipLevels = 3;
|
||||
create.arrayLayers = 4;
|
||||
create.samples = vk::SampleCountFlagBits::e1;
|
||||
create.tiling = vk::ImageTiling::eOptimal;
|
||||
create.usage = vk::ImageUsageFlagBits::eTransferSrc |
|
||||
vk::ImageUsageFlagBits::eTransferDst |
|
||||
vk::ImageUsageFlagBits::eSampled;
|
||||
create.initialLayout = vk::ImageLayout::eUndefined;
|
||||
|
||||
for (uint32_t pass = 0; pass < 2; ++pass) {
|
||||
Require(name, "create", graphics.CreateImage(create, image),
|
||||
"could not allocate native image");
|
||||
Require(name, "allocation metadata",
|
||||
image.image != nullptr && image.allocation != nullptr &&
|
||||
image.format == create.format &&
|
||||
image.image_type == create.imageType &&
|
||||
image.extent == create.extent &&
|
||||
image.layers == create.arrayLayers &&
|
||||
image.mip_levels == create.mipLevels &&
|
||||
image.samples == static_cast<uint32_t>(create.samples) &&
|
||||
image.usage == create.usage && image.flags == create.flags,
|
||||
"native image metadata did not follow its creation descriptor");
|
||||
Require(name, "fresh synchronization state",
|
||||
image.state.layout == create.initialLayout &&
|
||||
image.state.access_mask == vk::AccessFlags2{} &&
|
||||
image.state.pl_stage == vk::PipelineStageFlagBits2::eAllCommands &&
|
||||
image.subresource_states.empty(),
|
||||
"new allocation retained synchronization state from an old image");
|
||||
VkMemoryPropertyFlags properties{};
|
||||
vmaGetAllocationMemoryProperties(graphics.allocator, image.allocation,
|
||||
&properties);
|
||||
Require(name, "allocation policy",
|
||||
(properties & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0,
|
||||
"native image lost its device-local memory requirement");
|
||||
|
||||
// A reused presentation image may still describe its previous recording.
|
||||
// No commands use this fixture; seed that bookkeeping before retirement.
|
||||
image.state = {vk::PipelineStageFlagBits2::eTransfer,
|
||||
vk::AccessFlagBits2::eTransferWrite,
|
||||
vk::ImageLayout::eTransferDstOptimal};
|
||||
image.subresource_states.assign(image.layers * image.mip_levels, image.state);
|
||||
graphics.DeleteImage(image);
|
||||
Require(name, "retirement",
|
||||
image.image == nullptr && image.allocation == nullptr,
|
||||
"retired native image retained an allocation handle");
|
||||
|
||||
create.flags = vk::ImageCreateFlagBits::e2DArrayCompatible;
|
||||
create.imageType = vk::ImageType::e3D;
|
||||
create.format = vk::Format::eR32Uint;
|
||||
create.extent = {8, 4, 2};
|
||||
create.mipLevels = 2;
|
||||
create.arrayLayers = 1;
|
||||
create.usage = vk::ImageUsageFlagBits::eTransferSrc |
|
||||
vk::ImageUsageFlagBits::eTransferDst;
|
||||
}
|
||||
std::printf("[host] %-32s ok\n", name);
|
||||
}
|
||||
|
||||
void CheckDescriptorHeapLargeSet() {
|
||||
EnsureRuntimeContext();
|
||||
std::array<vk::DescriptorSetLayoutBinding, 3> bindings{};
|
||||
@@ -28116,6 +28183,11 @@ int main(int argc, char **argv) {
|
||||
vulkan.CheckSchedulerTimeline();
|
||||
return 0;
|
||||
}
|
||||
if (argc == 2 && std::strcmp(argv[1], "--host-image-allocation-only") == 0) {
|
||||
VulkanHarness vulkan;
|
||||
vulkan.CheckHostImageAllocation();
|
||||
return 0;
|
||||
}
|
||||
if (argc == 2 && std::strcmp(argv[1], "--occlusion-dump-only") == 0) {
|
||||
VulkanHarness vulkan;
|
||||
CheckPm4SyntheticOcclusionCounterDump(vulkan.RuntimeRenderer());
|
||||
@@ -28428,6 +28500,7 @@ int main(int argc, char **argv) {
|
||||
CheckIndirectImageKeySwitch();
|
||||
CheckPs5GameExampleImageClearRuntimeShape();
|
||||
vulkan.CheckSchedulerTimeline();
|
||||
vulkan.CheckHostImageAllocation();
|
||||
vulkan.CheckDescriptorHeapLargeSet();
|
||||
vulkan.CheckGraphicsPushConstantBank();
|
||||
vulkan.CheckGpuMappedRangeLifecycle();
|
||||
|
||||
Reference in New Issue
Block a user