mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2025-01-22 08:15:39 +00:00
143 lines
3.9 KiB
C++
143 lines
3.9 KiB
C++
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>
|
|
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
|
|
|
#pragma once
|
|
|
|
#include "gpu_device.h"
|
|
#include "gpu_texture.h"
|
|
|
|
#include <unordered_map>
|
|
|
|
class GPUFramebufferManagerBase
|
|
{
|
|
protected:
|
|
struct Key
|
|
{
|
|
GPUTexture* rts[GPUDevice::MAX_RENDER_TARGETS];
|
|
GPUTexture* ds;
|
|
u32 num_rts;
|
|
u32 flags;
|
|
|
|
bool operator==(const Key& rhs) const;
|
|
bool operator!=(const Key& rhs) const;
|
|
|
|
bool ContainsRT(const GPUTexture* tex) const;
|
|
};
|
|
|
|
struct KeyHash
|
|
{
|
|
size_t operator()(const Key& key) const;
|
|
};
|
|
};
|
|
|
|
template<typename FBOType, FBOType (*FactoryFunc)(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds, u32 flags),
|
|
void (*DestroyFunc)(FBOType fbo)>
|
|
class GPUFramebufferManager : public GPUFramebufferManagerBase
|
|
{
|
|
public:
|
|
GPUFramebufferManager() = default;
|
|
~GPUFramebufferManager();
|
|
|
|
FBOType Lookup(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds, u32 flags);
|
|
|
|
void RemoveReferences(const GPUTexture* tex);
|
|
void RemoveRTReferences(const GPUTexture* tex);
|
|
void RemoveDSReferences(const GPUTexture* tex);
|
|
|
|
void Clear();
|
|
|
|
private:
|
|
using MapType = std::unordered_map<Key, FBOType, KeyHash>;
|
|
|
|
MapType m_map;
|
|
};
|
|
|
|
template<typename FBOType, FBOType (*FactoryFunc)(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds, u32 flags),
|
|
void (*DestroyFunc)(FBOType fbo)>
|
|
GPUFramebufferManager<FBOType, FactoryFunc, DestroyFunc>::~GPUFramebufferManager()
|
|
{
|
|
Clear();
|
|
}
|
|
|
|
template<typename FBOType, FBOType (*FactoryFunc)(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds, u32 flags),
|
|
void (*DestroyFunc)(FBOType fbo)>
|
|
FBOType GPUFramebufferManager<FBOType, FactoryFunc, DestroyFunc>::Lookup(GPUTexture* const* rts, u32 num_rts,
|
|
GPUTexture* ds, u32 flags)
|
|
{
|
|
Key key;
|
|
for (u32 i = 0; i < num_rts; i++)
|
|
key.rts[i] = rts[i];
|
|
for (u32 i = num_rts; i < GPUDevice::MAX_RENDER_TARGETS; i++)
|
|
key.rts[i] = nullptr;
|
|
key.ds = ds;
|
|
key.num_rts = num_rts;
|
|
key.flags = flags;
|
|
|
|
auto it = m_map.find(key);
|
|
if (it == m_map.end())
|
|
{
|
|
FBOType fbo = FactoryFunc(rts, num_rts, ds, flags);
|
|
if (!fbo)
|
|
return fbo;
|
|
|
|
it = m_map.emplace(key, fbo).first;
|
|
}
|
|
|
|
return it->second;
|
|
}
|
|
|
|
template<typename FBOType, FBOType (*FactoryFunc)(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds, u32 flags),
|
|
void (*DestroyFunc)(FBOType fbo)>
|
|
void GPUFramebufferManager<FBOType, FactoryFunc, DestroyFunc>::RemoveRTReferences(const GPUTexture* tex)
|
|
{
|
|
DebugAssert(tex->IsRenderTarget());
|
|
for (auto it = m_map.begin(); it != m_map.end();)
|
|
{
|
|
if (!it->first.ContainsRT(tex))
|
|
{
|
|
++it;
|
|
continue;
|
|
}
|
|
|
|
DestroyFunc(it->second);
|
|
it = m_map.erase(it);
|
|
}
|
|
}
|
|
|
|
template<typename FBOType, FBOType (*FactoryFunc)(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds, u32 flags),
|
|
void (*DestroyFunc)(FBOType fbo)>
|
|
void GPUFramebufferManager<FBOType, FactoryFunc, DestroyFunc>::RemoveDSReferences(const GPUTexture* tex)
|
|
{
|
|
DebugAssert(tex->IsDepthStencil());
|
|
for (auto it = m_map.begin(); it != m_map.end();)
|
|
{
|
|
if (it->first.ds != tex)
|
|
{
|
|
++it;
|
|
continue;
|
|
}
|
|
|
|
DestroyFunc(it->second);
|
|
it = m_map.erase(it);
|
|
}
|
|
}
|
|
|
|
template<typename FBOType, FBOType (*FactoryFunc)(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds, u32 flags),
|
|
void (*DestroyFunc)(FBOType fbo)>
|
|
void GPUFramebufferManager<FBOType, FactoryFunc, DestroyFunc>::RemoveReferences(const GPUTexture* tex)
|
|
{
|
|
if (tex->IsRenderTarget())
|
|
RemoveRTReferences(tex);
|
|
else if (tex->IsDepthStencil())
|
|
RemoveDSReferences(tex);
|
|
}
|
|
|
|
template<typename FBOType, FBOType (*FactoryFunc)(GPUTexture* const* rts, u32 num_rts, GPUTexture* ds, u32 flags),
|
|
void (*DestroyFunc)(FBOType fbo)>
|
|
void GPUFramebufferManager<FBOType, FactoryFunc, DestroyFunc>::Clear()
|
|
{
|
|
for (auto it : m_map)
|
|
DestroyFunc(it.second);
|
|
m_map.clear();
|
|
}
|