summaryrefslogtreecommitdiff
path: root/Source/Core/VideoBackends/Vulkan/VKTexture.h
blob: 456b4fcd33a8fcc5645b8e90d869da5b49ce22ad (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
// Copyright 2017 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <memory>
#include <string>
#include <string_view>

#include "VideoBackends/Vulkan/VulkanLoader.h"
#include "VideoCommon/AbstractFramebuffer.h"
#include "VideoCommon/AbstractStagingTexture.h"
#include "VideoCommon/AbstractTexture.h"

namespace Vulkan
{
class StagingBuffer;
class Texture2D;

class VKTexture final : public AbstractTexture
{
public:
  // Custom image layouts, mainly used for switching to/from compute
  enum class ComputeImageLayout
  {
    Undefined,
    ReadOnly,
    WriteOnly,
    ReadWrite
  };

  VKTexture() = delete;
  VKTexture(const TextureConfig& tex_config, VmaAllocation alloc, VkImage image,
            std::string_view name, VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED,
            ComputeImageLayout compute_layout = ComputeImageLayout::Undefined);
  ~VKTexture() override;

  static VkFormat GetLinearFormat(VkFormat format);
  static VkFormat GetVkFormatForHostTextureFormat(AbstractTextureFormat format);
  static VkImageAspectFlags GetImageAspectForFormat(AbstractTextureFormat format);
  static VkImageAspectFlags GetImageViewAspectForFormat(AbstractTextureFormat format);

  void CopyRectangleFromTexture(const AbstractTexture* src,
                                const MathUtil::Rectangle<int>& src_rect, u32 src_layer,
                                u32 src_level, const MathUtil::Rectangle<int>& dst_rect,
                                u32 dst_layer, u32 dst_level) override;
  void ResolveFromTexture(const AbstractTexture* src, const MathUtil::Rectangle<int>& rect,
                          u32 layer, u32 level) override;
  void Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer, size_t buffer_size,
            u32 layer) override;
  void FinishedRendering() override;

  VkImage GetImage() const { return m_image; }
  VkImageView GetView() const { return m_view; }
  VkImageLayout GetLayout() const { return m_layout; }
  VkFormat GetVkFormat() const { return GetVkFormatForHostTextureFormat(m_config.format); }
  bool IsAdopted() const { return m_alloc != VmaAllocation(VK_NULL_HANDLE); }

  static std::unique_ptr<VKTexture> Create(const TextureConfig& tex_config, std::string_view name);
  static std::unique_ptr<VKTexture>
  CreateAdopted(const TextureConfig& tex_config, VkImage image,
                VkImageViewType view_type = VK_IMAGE_VIEW_TYPE_2D_ARRAY,
                VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED);

  // Used when the render pass is changing the image layout, or to force it to
  // VK_IMAGE_LAYOUT_UNDEFINED, if the existing contents of the image is
  // irrelevant and will not be loaded.
  void OverrideImageLayout(VkImageLayout new_layout);

  void TransitionToLayout(VkCommandBuffer command_buffer, VkImageLayout new_layout) const;
  void TransitionToLayout(VkCommandBuffer command_buffer, ComputeImageLayout new_layout) const;
  void PrepareForRenderPass(VkCommandBuffer command_buffer) const;

private:
  bool CreateView(VkImageViewType type);

  VmaAllocation m_alloc;
  VkImage m_image;
  VkImageView m_view = VK_NULL_HANDLE;
  mutable VkImageLayout m_layout = VK_IMAGE_LAYOUT_UNDEFINED;
  mutable ComputeImageLayout m_compute_layout = ComputeImageLayout::Undefined;
  mutable bool m_written_since_last_layout_change = false;
  std::string m_name;
};

class VKStagingTexture final : public AbstractStagingTexture
{
  struct PrivateTag
  {
  };

public:
  VKStagingTexture() = delete;
  VKStagingTexture(PrivateTag, StagingTextureType type, const TextureConfig& config,
                   std::unique_ptr<StagingBuffer> buffer, VkImage linear_image,
                   VmaAllocation linear_image_alloc);

  ~VKStagingTexture() override;

  void CopyFromTexture(const AbstractTexture* src, const MathUtil::Rectangle<int>& src_rect,
                       u32 src_layer, u32 src_level,
                       const MathUtil::Rectangle<int>& dst_rect) override;
  void CopyToTexture(const MathUtil::Rectangle<int>& src_rect, AbstractTexture* dst,
                     const MathUtil::Rectangle<int>& dst_rect, u32 dst_layer,
                     u32 dst_level) override;

  bool Map() override;
  void Unmap() override;
  void Flush() override;

  static std::unique_ptr<VKStagingTexture> Create(StagingTextureType type,
                                                  const TextureConfig& config);

  static std::pair<VkImage, VmaAllocation> CreateLinearImage(StagingTextureType type,
                                                             const TextureConfig& config);

private:
  void CopyFromTextureToLinearImage(const VKTexture* src_tex,
                                    const MathUtil::Rectangle<int>& src_rect, u32 src_layer,
                                    u32 src_level, const MathUtil::Rectangle<int>& dst_rect);

  std::unique_ptr<StagingBuffer> m_staging_buffer;
  VkImage m_linear_image = VK_NULL_HANDLE;
  VmaAllocation m_linear_image_alloc = VK_NULL_HANDLE;
  u64 m_flush_fence_counter = 0;
};

class VKFramebuffer final : public AbstractFramebuffer
{
public:
  VKFramebuffer(VKTexture* color_attachment, VKTexture* depth_attachment,
                std::vector<AbstractTexture*> additional_color_attachments, u32 width, u32 height,
                u32 layers, u32 samples, VkFramebuffer fb, VkRenderPass load_render_pass,
                VkRenderPass discard_render_pass, VkRenderPass clear_render_pass);
  ~VKFramebuffer() override;

  VkFramebuffer GetFB() const { return m_fb; }
  VkRect2D GetRect() const { return VkRect2D{{0, 0}, {m_width, m_height}}; }

  VkRenderPass GetLoadRenderPass() const { return m_load_render_pass; }
  VkRenderPass GetDiscardRenderPass() const { return m_discard_render_pass; }
  VkRenderPass GetClearRenderPass() const { return m_clear_render_pass; }

  void Unbind();
  void TransitionForRender();
  void PrepareForRenderPass();

  void SetAndClear(const VkRect2D& rect, const VkClearValue& color_value,
                   const VkClearValue& depth_value);
  std::size_t GetNumberOfAdditonalAttachments() const
  {
    return m_additional_color_attachments.size();
  }

  static std::unique_ptr<VKFramebuffer>
  Create(VKTexture* color_attachments, VKTexture* depth_attachment,
         std::vector<AbstractTexture*> additional_color_attachments);

protected:
  VkFramebuffer m_fb;
  VkRenderPass m_load_render_pass;
  VkRenderPass m_discard_render_pass;
  VkRenderPass m_clear_render_pass;
};

}  // namespace Vulkan