duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

gpu_texture.h (8935B)


      1 // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
      2 // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
      3 
      4 #pragma once
      5 
      6 #include "common/gsvector.h"
      7 #include "common/types.h"
      8 
      9 #include <algorithm>
     10 #include <array>
     11 #include <string_view>
     12 #include <vector>
     13 
     14 class GPUTexture
     15 {
     16 public:
     17   enum : u32
     18   {
     19     MAX_WIDTH = 65535,
     20     MAX_HEIGHT = 65535,
     21     MAX_LAYERS = 255,
     22     MAX_LEVELS = 255,
     23     MAX_SAMPLES = 255,
     24   };
     25 
     26   enum class Type : u8
     27   {
     28     Unknown,
     29     RenderTarget,
     30     DepthStencil,
     31     Texture,
     32     DynamicTexture,
     33     RWTexture,
     34   };
     35 
     36   enum class Format : u8
     37   {
     38     Unknown,
     39     RGBA8,
     40     BGRA8,
     41     RGB565,
     42     RGBA5551,
     43     R8,
     44     D16,
     45     D24S8,
     46     D32F,
     47     D32FS8,
     48     R16,
     49     R16I,
     50     R16U,
     51     R16F,
     52     R32I,
     53     R32U,
     54     R32F,
     55     RG8,
     56     RG16,
     57     RG16F,
     58     RG32F,
     59     RGBA16,
     60     RGBA16F,
     61     RGBA32F,
     62     RGB10A2,
     63     MaxCount
     64   };
     65 
     66   enum class State : u8
     67   {
     68     Dirty,
     69     Cleared,
     70     Invalidated
     71   };
     72 
     73   union ClearValue
     74   {
     75     u32 color;
     76     float depth;
     77   };
     78 
     79 public:
     80   GPUTexture(const GPUTexture&) = delete;
     81   virtual ~GPUTexture();
     82 
     83   static const char* GetFormatName(Format format);
     84   static u32 GetPixelSize(GPUTexture::Format format);
     85   static bool IsDepthFormat(GPUTexture::Format format);
     86   static bool IsDepthStencilFormat(GPUTexture::Format format);
     87   static bool IsCompressedFormat(Format format);
     88   static u32 GetCompressedBytesPerBlock(Format format);
     89   static u32 GetCompressedBlockSize(Format format);
     90   static u32 CalcUploadPitch(Format format, u32 width);
     91   static u32 CalcUploadRowLengthFromPitch(Format format, u32 pitch);
     92   static u32 CalcUploadSize(Format format, u32 height, u32 pitch);
     93 
     94   static bool ValidateConfig(u32 width, u32 height, u32 layers, u32 levels, u32 samples, Type type, Format format);
     95 
     96   static bool ConvertTextureDataToRGBA8(u32 width, u32 height, std::vector<u32>& texture_data, u32& texture_data_stride,
     97                                         GPUTexture::Format format);
     98   static void FlipTextureDataRGBA8(u32 width, u32 height, u8* texture_data, u32 texture_data_stride);
     99 
    100   ALWAYS_INLINE u32 GetWidth() const { return m_width; }
    101   ALWAYS_INLINE u32 GetHeight() const { return m_height; }
    102   ALWAYS_INLINE u32 GetLayers() const { return m_layers; }
    103   ALWAYS_INLINE u32 GetLevels() const { return m_levels; }
    104   ALWAYS_INLINE u32 GetSamples() const { return m_samples; }
    105   ALWAYS_INLINE Type GetType() const { return m_type; }
    106   ALWAYS_INLINE Format GetFormat() const { return m_format; }
    107   ALWAYS_INLINE GSVector4i GetRect() const
    108   {
    109     return GSVector4i(0, 0, static_cast<s32>(m_width), static_cast<s32>(m_height));
    110   }
    111 
    112   ALWAYS_INLINE bool IsTextureArray() const { return m_layers > 1; }
    113   ALWAYS_INLINE bool IsMultisampled() const { return m_samples > 1; }
    114 
    115   ALWAYS_INLINE u32 GetPixelSize() const { return GetPixelSize(m_format); }
    116   ALWAYS_INLINE u32 GetMipWidth(u32 level) const { return std::max<u32>(m_width >> level, 1u); }
    117   ALWAYS_INLINE u32 GetMipHeight(u32 level) const { return std::max<u32>(m_height >> level, 1u); }
    118 
    119   ALWAYS_INLINE State GetState() const { return m_state; }
    120   ALWAYS_INLINE void SetState(State state) { m_state = state; }
    121   ALWAYS_INLINE bool IsDirty() const { return (m_state == State::Dirty); }
    122   ALWAYS_INLINE bool IsClearedOrInvalidated() const { return (m_state != State::Dirty); }
    123 
    124   ALWAYS_INLINE bool IsRenderTargetOrDepthStencil() const
    125   {
    126     return (m_type >= Type::RenderTarget && m_type <= Type::DepthStencil);
    127   }
    128   ALWAYS_INLINE bool IsRenderTarget() const { return (m_type == Type::RenderTarget); }
    129   ALWAYS_INLINE bool IsDepthStencil() const { return (m_type == Type::DepthStencil); }
    130   ALWAYS_INLINE bool IsTexture() const { return (m_type == Type::Texture || m_type == Type::DynamicTexture); }
    131   ALWAYS_INLINE bool IsDynamicTexture() const { return (m_type == Type::DynamicTexture); }
    132   ALWAYS_INLINE bool IsRWTexture() const { return (m_type == Type::RWTexture); }
    133 
    134   ALWAYS_INLINE const ClearValue& GetClearValue() const { return m_clear_value; }
    135   ALWAYS_INLINE u32 GetClearColor() const { return m_clear_value.color; }
    136   ALWAYS_INLINE float GetClearDepth() const { return m_clear_value.depth; }
    137   std::array<float, 4> GetUNormClearColor() const;
    138 
    139   ALWAYS_INLINE void SetClearColor(u32 color)
    140   {
    141     m_state = State::Cleared;
    142     m_clear_value.color = color;
    143   }
    144   ALWAYS_INLINE void SetClearDepth(float depth)
    145   {
    146     m_state = State::Cleared;
    147     m_clear_value.depth = depth;
    148   }
    149 
    150   size_t GetVRAMUsage() const;
    151 
    152   u32 GetCompressedBytesPerBlock() const;
    153   u32 GetCompressedBlockSize() const;
    154   u32 CalcUploadPitch(u32 width) const;
    155   u32 CalcUploadRowLengthFromPitch(u32 pitch) const;
    156   u32 CalcUploadSize(u32 height, u32 pitch) const;
    157 
    158   GPUTexture& operator=(const GPUTexture&) = delete;
    159 
    160   virtual bool Update(u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch, u32 layer = 0,
    161                       u32 level = 0) = 0;
    162   virtual bool Map(void** map, u32* map_stride, u32 x, u32 y, u32 width, u32 height, u32 layer = 0, u32 level = 0) = 0;
    163   virtual void Unmap() = 0;
    164 
    165   // Instructs the backend that we're finished rendering to this texture. It may transition it to a new layout.
    166   virtual void MakeReadyForSampling();
    167 
    168   virtual void SetDebugName(std::string_view name) = 0;
    169 
    170 protected:
    171   GPUTexture(u16 width, u16 height, u8 layers, u8 levels, u8 samples, Type type, Format format);
    172 
    173   u16 m_width = 0;
    174   u16 m_height = 0;
    175   u8 m_layers = 0;
    176   u8 m_levels = 0;
    177   u8 m_samples = 0;
    178   Type m_type = Type::Unknown;
    179   Format m_format = Format::Unknown;
    180 
    181   State m_state = State::Dirty;
    182 
    183   ClearValue m_clear_value = {};
    184 };
    185 
    186 class GPUDownloadTexture
    187 {
    188 public:
    189   GPUDownloadTexture(u32 width, u32 height, GPUTexture::Format format, bool is_imported);
    190   virtual ~GPUDownloadTexture();
    191 
    192   /// Basically, this has dimensions only because of DX11.
    193   ALWAYS_INLINE u32 GetWidth() const { return m_width; }
    194   ALWAYS_INLINE u32 GetHeight() const { return m_height; }
    195   ALWAYS_INLINE GPUTexture::Format GetFormat() const { return m_format; }
    196   ALWAYS_INLINE bool NeedsFlush() const { return m_needs_flush; }
    197   ALWAYS_INLINE bool IsMapped() const { return (m_map_pointer != nullptr); }
    198   ALWAYS_INLINE bool IsImported() const { return m_is_imported; }
    199   ALWAYS_INLINE const u8* GetMapPointer() const { return m_map_pointer; }
    200   ALWAYS_INLINE u32 GetMapPitch() const { return m_current_pitch; }
    201 
    202   /// Calculates the pitch of a transfer.
    203   u32 GetTransferPitch(u32 width, u32 pitch_align) const;
    204 
    205   /// Calculates the size of the data you should transfer.
    206   void GetTransferSize(u32 x, u32 y, u32 width, u32 height, u32 pitch, u32* copy_offset, u32* copy_size,
    207                        u32* copy_rows) const;
    208 
    209   /// Queues a copy from the specified texture to this buffer.
    210   /// Does not complete immediately, you should flush before accessing the buffer.
    211   /// use_transfer_pitch should be true if there's only a single texture being copied to this buffer before
    212   /// it will be used. This allows the image to be packed tighter together, and buffer reuse.
    213   virtual void CopyFromTexture(u32 dst_x, u32 dst_y, GPUTexture* src, u32 src_x, u32 src_y, u32 width, u32 height,
    214                                u32 src_layer, u32 src_level, bool use_transfer_pitch = true) = 0;
    215 
    216   /// Maps the texture into the CPU address space, enabling it to read the contents.
    217   /// The Map call may not perform synchronization. If the contents of the staging texture
    218   /// has been updated by a CopyFromTexture() call, you must call Flush() first.
    219   /// If persistent mapping is supported in the backend, this may be a no-op.
    220   virtual bool Map(u32 x, u32 y, u32 width, u32 height) = 0;
    221 
    222   /// Unmaps the CPU-readable copy of the texture. May be a no-op on backends which
    223   /// support persistent-mapped buffers.
    224   virtual void Unmap() = 0;
    225 
    226   /// Flushes pending writes from the CPU to the GPU, and reads from the GPU to the CPU.
    227   /// This may cause a command buffer submit depending on if one has occurred between the last
    228   /// call to CopyFromTexture() and the Flush() call.
    229   virtual void Flush() = 0;
    230 
    231   /// Sets object name that will be displayed in graphics debuggers.
    232   virtual void SetDebugName(std::string_view name) = 0;
    233 
    234   /// Reads the specified rectangle from the staging texture to out_ptr, with the specified stride
    235   /// (length in bytes of each row). CopyFromTexture() must be called first. The contents of any
    236   /// texels outside of the rectangle used for CopyFromTexture is undefined.
    237   bool ReadTexels(u32 x, u32 y, u32 width, u32 height, void* out_ptr, u32 out_stride);
    238 
    239   /// Returns what the size of the specified texture would be, in bytes.
    240   static u32 GetBufferSize(u32 width, u32 height, GPUTexture::Format format, u32 pitch_align = 1);
    241 
    242 protected:
    243   u32 m_width;
    244   u32 m_height;
    245   GPUTexture::Format m_format;
    246 
    247   const u8* m_map_pointer = nullptr;
    248   u32 m_current_pitch = 0;
    249 
    250   bool m_is_imported = false;
    251   bool m_needs_flush = false;
    252 };