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_framebuffer_manager.h (4054B)


      1 // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
      2 // SPDX-License-Identifier: (GPL-3.0 OR PolyForm-Strict-1.0.0)
      3 
      4 #pragma once
      5 
      6 #include "common/assert.h"
      7 
      8 #include "gpu_device.h"
      9 #include "gpu_texture.h"
     10 
     11 #include <unordered_map>
     12 
     13 class GPUFramebufferManagerBase
     14 {
     15 protected:
     16   struct Key
     17   {
     18     GPUTexture* rts[GPUDevice::MAX_RENDER_TARGETS];
     19     GPUTexture* ds;
     20     u32 num_rts;
     21     u32 flags;
     22 
     23     bool operator==(const Key& rhs) const;
     24     bool operator!=(const Key& rhs) const;
     25 
     26     bool ContainsRT(const GPUTexture* tex) const;
     27   };
     28 
     29   struct KeyHash
     30   {
     31     size_t operator()(const Key& key) const;
     32   };
     33 };
     34 
     35 template<typename FBOType, FBOType (*FactoryFunc)(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds, u32 flags),
     36          void (*DestroyFunc)(FBOType fbo)>
     37 class GPUFramebufferManager : public GPUFramebufferManagerBase
     38 {
     39 public:
     40   GPUFramebufferManager() = default;
     41   ~GPUFramebufferManager();
     42 
     43   FBOType Lookup(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds, u32 flags);
     44 
     45   void RemoveReferences(const GPUTexture* tex);
     46   void RemoveRTReferences(const GPUTexture* tex);
     47   void RemoveDSReferences(const GPUTexture* tex);
     48 
     49   void Clear();
     50 
     51 private:
     52   using MapType = std::unordered_map<Key, FBOType, KeyHash>;
     53 
     54   MapType m_map;
     55 };
     56 
     57 template<typename FBOType, FBOType (*FactoryFunc)(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds, u32 flags),
     58          void (*DestroyFunc)(FBOType fbo)>
     59 GPUFramebufferManager<FBOType, FactoryFunc, DestroyFunc>::~GPUFramebufferManager()
     60 {
     61   Clear();
     62 }
     63 
     64 template<typename FBOType, FBOType (*FactoryFunc)(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds, u32 flags),
     65          void (*DestroyFunc)(FBOType fbo)>
     66 FBOType GPUFramebufferManager<FBOType, FactoryFunc, DestroyFunc>::Lookup(GPUTexture* const* rts, u32 num_rts,
     67                                                                          GPUTexture* ds, u32 flags)
     68 {
     69   Key key;
     70   for (u32 i = 0; i < num_rts; i++)
     71     key.rts[i] = rts[i];
     72   for (u32 i = num_rts; i < GPUDevice::MAX_RENDER_TARGETS; i++)
     73     key.rts[i] = nullptr;
     74   key.ds = ds;
     75   key.num_rts = num_rts;
     76   key.flags = flags;
     77 
     78   auto it = m_map.find(key);
     79   if (it == m_map.end())
     80   {
     81     FBOType fbo = FactoryFunc(rts, num_rts, ds, flags);
     82     if (!fbo)
     83       return fbo;
     84 
     85     it = m_map.emplace(key, fbo).first;
     86   }
     87 
     88   return it->second;
     89 }
     90 
     91 template<typename FBOType, FBOType (*FactoryFunc)(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds, u32 flags),
     92          void (*DestroyFunc)(FBOType fbo)>
     93 void GPUFramebufferManager<FBOType, FactoryFunc, DestroyFunc>::RemoveRTReferences(const GPUTexture* tex)
     94 {
     95   DebugAssert(tex->IsRenderTarget() || tex->IsRWTexture());
     96   for (auto it = m_map.begin(); it != m_map.end();)
     97   {
     98     if (!it->first.ContainsRT(tex))
     99     {
    100       ++it;
    101       continue;
    102     }
    103 
    104     DestroyFunc(it->second);
    105     it = m_map.erase(it);
    106   }
    107 }
    108 
    109 template<typename FBOType, FBOType (*FactoryFunc)(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds, u32 flags),
    110          void (*DestroyFunc)(FBOType fbo)>
    111 void GPUFramebufferManager<FBOType, FactoryFunc, DestroyFunc>::RemoveDSReferences(const GPUTexture* tex)
    112 {
    113   DebugAssert(tex->IsDepthStencil());
    114   for (auto it = m_map.begin(); it != m_map.end();)
    115   {
    116     if (it->first.ds != tex)
    117     {
    118       ++it;
    119       continue;
    120     }
    121 
    122     DestroyFunc(it->second);
    123     it = m_map.erase(it);
    124   }
    125 }
    126 
    127 template<typename FBOType, FBOType (*FactoryFunc)(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds, u32 flags),
    128          void (*DestroyFunc)(FBOType fbo)>
    129 void GPUFramebufferManager<FBOType, FactoryFunc, DestroyFunc>::RemoveReferences(const GPUTexture* tex)
    130 {
    131   if (tex->IsRenderTarget())
    132     RemoveRTReferences(tex);
    133   else if (tex->IsDepthStencil())
    134     RemoveDSReferences(tex);
    135 }
    136 
    137 template<typename FBOType, FBOType (*FactoryFunc)(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds, u32 flags),
    138          void (*DestroyFunc)(FBOType fbo)>
    139 void GPUFramebufferManager<FBOType, FactoryFunc, DestroyFunc>::Clear()
    140 {
    141   for (const auto& it : m_map)
    142     DestroyFunc(it.second);
    143   m_map.clear();
    144 }