diff options
| author | 2019-12-30 14:25:14 -0400 | |
|---|---|---|
| committer | 2019-12-30 14:25:14 -0400 | |
| commit | 7bd447355fff63313bef02045a69a88592614bf2 (patch) | |
| tree | c38d39c40be56d3227204d10f716da994c4275b7 /src | |
| parent | Merge pull request #3249 from ReinUsesLisp/vk-staging-buffer-pool (diff) | |
| parent | vk_image: Avoid unnecesary equals (diff) | |
| download | yuzu-7bd447355fff63313bef02045a69a88592614bf2.tar.gz yuzu-7bd447355fff63313bef02045a69a88592614bf2.tar.xz yuzu-7bd447355fff63313bef02045a69a88592614bf2.zip | |
Merge pull request #3248 from ReinUsesLisp/vk-image
vk_image: Add an image object abstraction
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_image.cpp | 106 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_image.h | 84 |
3 files changed, 192 insertions, 0 deletions
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index fcedad3fa..2594cd0bd 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt | |||
| @@ -159,6 +159,8 @@ if (ENABLE_VULKAN) | |||
| 159 | renderer_vulkan/vk_buffer_cache.h | 159 | renderer_vulkan/vk_buffer_cache.h |
| 160 | renderer_vulkan/vk_device.cpp | 160 | renderer_vulkan/vk_device.cpp |
| 161 | renderer_vulkan/vk_device.h | 161 | renderer_vulkan/vk_device.h |
| 162 | renderer_vulkan/vk_image.cpp | ||
| 163 | renderer_vulkan/vk_image.h | ||
| 162 | renderer_vulkan/vk_memory_manager.cpp | 164 | renderer_vulkan/vk_memory_manager.cpp |
| 163 | renderer_vulkan/vk_memory_manager.h | 165 | renderer_vulkan/vk_memory_manager.h |
| 164 | renderer_vulkan/vk_resource_manager.cpp | 166 | renderer_vulkan/vk_resource_manager.cpp |
diff --git a/src/video_core/renderer_vulkan/vk_image.cpp b/src/video_core/renderer_vulkan/vk_image.cpp new file mode 100644 index 000000000..4bcbef959 --- /dev/null +++ b/src/video_core/renderer_vulkan/vk_image.cpp | |||
| @@ -0,0 +1,106 @@ | |||
| 1 | // Copyright 2018 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <memory> | ||
| 6 | #include <vector> | ||
| 7 | |||
| 8 | #include "common/assert.h" | ||
| 9 | #include "video_core/renderer_vulkan/declarations.h" | ||
| 10 | #include "video_core/renderer_vulkan/vk_device.h" | ||
| 11 | #include "video_core/renderer_vulkan/vk_image.h" | ||
| 12 | #include "video_core/renderer_vulkan/vk_scheduler.h" | ||
| 13 | |||
| 14 | namespace Vulkan { | ||
| 15 | |||
| 16 | VKImage::VKImage(const VKDevice& device, VKScheduler& scheduler, | ||
| 17 | const vk::ImageCreateInfo& image_ci, vk::ImageAspectFlags aspect_mask) | ||
| 18 | : device{device}, scheduler{scheduler}, format{image_ci.format}, aspect_mask{aspect_mask}, | ||
| 19 | image_num_layers{image_ci.arrayLayers}, image_num_levels{image_ci.mipLevels} { | ||
| 20 | UNIMPLEMENTED_IF_MSG(image_ci.queueFamilyIndexCount != 0, | ||
| 21 | "Queue family tracking is not implemented"); | ||
| 22 | |||
| 23 | const auto dev = device.GetLogical(); | ||
| 24 | image = dev.createImageUnique(image_ci, nullptr, device.GetDispatchLoader()); | ||
| 25 | |||
| 26 | const u32 num_ranges = image_num_layers * image_num_levels; | ||
| 27 | barriers.resize(num_ranges); | ||
| 28 | subrange_states.resize(num_ranges, {{}, image_ci.initialLayout}); | ||
| 29 | } | ||
| 30 | |||
| 31 | VKImage::~VKImage() = default; | ||
| 32 | |||
| 33 | void VKImage::Transition(u32 base_layer, u32 num_layers, u32 base_level, u32 num_levels, | ||
| 34 | vk::PipelineStageFlags new_stage_mask, vk::AccessFlags new_access, | ||
| 35 | vk::ImageLayout new_layout) { | ||
| 36 | if (!HasChanged(base_layer, num_layers, base_level, num_levels, new_access, new_layout)) { | ||
| 37 | return; | ||
| 38 | } | ||
| 39 | |||
| 40 | std::size_t cursor = 0; | ||
| 41 | for (u32 layer_it = 0; layer_it < num_layers; ++layer_it) { | ||
| 42 | for (u32 level_it = 0; level_it < num_levels; ++level_it, ++cursor) { | ||
| 43 | const u32 layer = base_layer + layer_it; | ||
| 44 | const u32 level = base_level + level_it; | ||
| 45 | auto& state = GetSubrangeState(layer, level); | ||
| 46 | barriers[cursor] = vk::ImageMemoryBarrier( | ||
| 47 | state.access, new_access, state.layout, new_layout, VK_QUEUE_FAMILY_IGNORED, | ||
| 48 | VK_QUEUE_FAMILY_IGNORED, *image, {aspect_mask, level, 1, layer, 1}); | ||
| 49 | state.access = new_access; | ||
| 50 | state.layout = new_layout; | ||
| 51 | } | ||
| 52 | } | ||
| 53 | |||
| 54 | scheduler.RequestOutsideRenderPassOperationContext(); | ||
| 55 | |||
| 56 | scheduler.Record([barriers = barriers, cursor](auto cmdbuf, auto& dld) { | ||
| 57 | // TODO(Rodrigo): Implement a way to use the latest stage across subresources. | ||
| 58 | constexpr auto stage_stub = vk::PipelineStageFlagBits::eAllCommands; | ||
| 59 | cmdbuf.pipelineBarrier(stage_stub, stage_stub, {}, 0, nullptr, 0, nullptr, | ||
| 60 | static_cast<u32>(cursor), barriers.data(), dld); | ||
| 61 | }); | ||
| 62 | } | ||
| 63 | |||
| 64 | bool VKImage::HasChanged(u32 base_layer, u32 num_layers, u32 base_level, u32 num_levels, | ||
| 65 | vk::AccessFlags new_access, vk::ImageLayout new_layout) noexcept { | ||
| 66 | const bool is_full_range = base_layer == 0 && num_layers == image_num_layers && | ||
| 67 | base_level == 0 && num_levels == image_num_levels; | ||
| 68 | if (!is_full_range) { | ||
| 69 | state_diverged = true; | ||
| 70 | } | ||
| 71 | |||
| 72 | if (!state_diverged) { | ||
| 73 | auto& state = GetSubrangeState(0, 0); | ||
| 74 | if (state.access != new_access || state.layout != new_layout) { | ||
| 75 | return true; | ||
| 76 | } | ||
| 77 | } | ||
| 78 | |||
| 79 | for (u32 layer_it = 0; layer_it < num_layers; ++layer_it) { | ||
| 80 | for (u32 level_it = 0; level_it < num_levels; ++level_it) { | ||
| 81 | const u32 layer = base_layer + layer_it; | ||
| 82 | const u32 level = base_level + level_it; | ||
| 83 | auto& state = GetSubrangeState(layer, level); | ||
| 84 | if (state.access != new_access || state.layout != new_layout) { | ||
| 85 | return true; | ||
| 86 | } | ||
| 87 | } | ||
| 88 | } | ||
| 89 | return false; | ||
| 90 | } | ||
| 91 | |||
| 92 | void VKImage::CreatePresentView() { | ||
| 93 | // Image type has to be 2D to be presented. | ||
| 94 | const vk::ImageViewCreateInfo image_view_ci({}, *image, vk::ImageViewType::e2D, format, {}, | ||
| 95 | {aspect_mask, 0, 1, 0, 1}); | ||
| 96 | const auto dev = device.GetLogical(); | ||
| 97 | const auto& dld = device.GetDispatchLoader(); | ||
| 98 | present_view = dev.createImageViewUnique(image_view_ci, nullptr, dld); | ||
| 99 | } | ||
| 100 | |||
| 101 | VKImage::SubrangeState& VKImage::GetSubrangeState(u32 layer, u32 level) noexcept { | ||
| 102 | return subrange_states[static_cast<std::size_t>(layer * image_num_levels) + | ||
| 103 | static_cast<std::size_t>(level)]; | ||
| 104 | } | ||
| 105 | |||
| 106 | } // namespace Vulkan \ No newline at end of file | ||
diff --git a/src/video_core/renderer_vulkan/vk_image.h b/src/video_core/renderer_vulkan/vk_image.h new file mode 100644 index 000000000..b78242512 --- /dev/null +++ b/src/video_core/renderer_vulkan/vk_image.h | |||
| @@ -0,0 +1,84 @@ | |||
| 1 | // Copyright 2018 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <memory> | ||
| 8 | #include <vector> | ||
| 9 | |||
| 10 | #include "common/common_types.h" | ||
| 11 | #include "video_core/renderer_vulkan/declarations.h" | ||
| 12 | |||
| 13 | namespace Vulkan { | ||
| 14 | |||
| 15 | class VKDevice; | ||
| 16 | class VKScheduler; | ||
| 17 | |||
| 18 | class VKImage { | ||
| 19 | public: | ||
| 20 | explicit VKImage(const VKDevice& device, VKScheduler& scheduler, | ||
| 21 | const vk::ImageCreateInfo& image_ci, vk::ImageAspectFlags aspect_mask); | ||
| 22 | ~VKImage(); | ||
| 23 | |||
| 24 | /// Records in the passed command buffer an image transition and updates the state of the image. | ||
| 25 | void Transition(u32 base_layer, u32 num_layers, u32 base_level, u32 num_levels, | ||
| 26 | vk::PipelineStageFlags new_stage_mask, vk::AccessFlags new_access, | ||
| 27 | vk::ImageLayout new_layout); | ||
| 28 | |||
| 29 | /// Returns a view compatible with presentation, the image has to be 2D. | ||
| 30 | vk::ImageView GetPresentView() { | ||
| 31 | if (!present_view) { | ||
| 32 | CreatePresentView(); | ||
| 33 | } | ||
| 34 | return *present_view; | ||
| 35 | } | ||
| 36 | |||
| 37 | /// Returns the Vulkan image handler. | ||
| 38 | vk::Image GetHandle() const { | ||
| 39 | return *image; | ||
| 40 | } | ||
| 41 | |||
| 42 | /// Returns the Vulkan format for this image. | ||
| 43 | vk::Format GetFormat() const { | ||
| 44 | return format; | ||
| 45 | } | ||
| 46 | |||
| 47 | /// Returns the Vulkan aspect mask. | ||
| 48 | vk::ImageAspectFlags GetAspectMask() const { | ||
| 49 | return aspect_mask; | ||
| 50 | } | ||
| 51 | |||
| 52 | private: | ||
| 53 | struct SubrangeState final { | ||
| 54 | vk::AccessFlags access{}; ///< Current access bits. | ||
| 55 | vk::ImageLayout layout = vk::ImageLayout::eUndefined; ///< Current image layout. | ||
| 56 | }; | ||
| 57 | |||
| 58 | bool HasChanged(u32 base_layer, u32 num_layers, u32 base_level, u32 num_levels, | ||
| 59 | vk::AccessFlags new_access, vk::ImageLayout new_layout) noexcept; | ||
| 60 | |||
| 61 | /// Creates a presentation view. | ||
| 62 | void CreatePresentView(); | ||
| 63 | |||
| 64 | /// Returns the subrange state for a layer and layer. | ||
| 65 | SubrangeState& GetSubrangeState(u32 layer, u32 level) noexcept; | ||
| 66 | |||
| 67 | const VKDevice& device; ///< Device handler. | ||
| 68 | VKScheduler& scheduler; ///< Device scheduler. | ||
| 69 | |||
| 70 | const vk::Format format; ///< Vulkan format. | ||
| 71 | const vk::ImageAspectFlags aspect_mask; ///< Vulkan aspect mask. | ||
| 72 | const u32 image_num_layers; ///< Number of layers. | ||
| 73 | const u32 image_num_levels; ///< Number of mipmap levels. | ||
| 74 | |||
| 75 | UniqueImage image; ///< Image handle. | ||
| 76 | UniqueImageView present_view; ///< Image view compatible with presentation. | ||
| 77 | |||
| 78 | std::vector<vk::ImageMemoryBarrier> barriers; ///< Pool of barriers. | ||
| 79 | std::vector<SubrangeState> subrange_states; ///< Current subrange state. | ||
| 80 | |||
| 81 | bool state_diverged = false; ///< True when subresources mismatch in layout. | ||
| 82 | }; | ||
| 83 | |||
| 84 | } // namespace Vulkan | ||