Files
OpenVulkano/openVulkanoCpp/Base/Render/RenderResource.hpp
2024-09-21 15:28:59 +02:00

192 lines
4.7 KiB
C++

/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <concepts>
#include <utility>
#include <type_traits>
namespace OpenVulkano
{
namespace Vulkan
{
class MetalBackedTexture;
}
class RenderResourcePtr;
class IRenderResourceHelper
{
friend class RenderResourcePtr;
protected:
void UpdateRenderResource(RenderResourcePtr* resource);
void ResetRenderResource(RenderResourcePtr* resource);
virtual void DoRelease() = 0;
virtual void Release() = 0;
};
template <class T>
concept Renderable = std::is_convertible_v<T, RenderResourcePtr&>;
class RenderResourcePtr final
{
friend class IRenderResourceHelper;
friend class Vulkan::MetalBackedTexture;
IRenderResourceHelper* renderObject = nullptr;
public:
RenderResourcePtr() = default;
RenderResourcePtr(const RenderResourcePtr& ignored) noexcept { /* Do not copy, copy will be created by renderer */ }
RenderResourcePtr(RenderResourcePtr&& move) noexcept : renderObject(move.renderObject) { move.renderObject = nullptr; }
~RenderResourcePtr()
{
Release();
}
void Release()
{
if (!renderObject) return;
renderObject->DoRelease();
renderObject = nullptr;
}
template<class T>
T* As() { return static_cast<T*>(renderObject); }
template<class T>
operator T() { return static_cast<T>(renderObject); }
operator bool() const { return renderObject; }
RenderResourcePtr& operator =(RenderResourcePtr&& move) noexcept
{
if (renderObject) renderObject->Release();
renderObject = move.renderObject;
move.renderObject = nullptr;
return *this;
}
};
inline void IRenderResourceHelper::UpdateRenderResource(RenderResourcePtr* resource)
{
if (resource)
resource->renderObject = this;
}
inline void IRenderResourceHelper::ResetRenderResource(RenderResourcePtr* resource)
{
if (resource)
resource->renderObject = nullptr;
}
template<Renderable API_INDEPENDENT_CLASS>
class IRenderResource : public IRenderResourceHelper
{
API_INDEPENDENT_CLASS* m_owner;
protected:
IRenderResource(API_INDEPENDENT_CLASS* owner) : m_owner(owner)
{
if (m_owner) UpdateRenderResource(GetOwnerResource());
}
IRenderResource(const IRenderResource<API_INDEPENDENT_CLASS>& copy) = delete;
IRenderResource(IRenderResource<API_INDEPENDENT_CLASS>&& move) noexcept
: m_owner(move.m_owner)
{
if (m_owner)
{
UpdateRenderResource(GetOwnerResource());
}
move.m_owner = nullptr;
}
RenderResourcePtr* GetOwnerResource() { if (!m_owner) return nullptr; else return &static_cast<RenderResourcePtr&>(*m_owner); }
void DoRelease() final override
{
m_owner = nullptr;
Release();
}
public:
virtual ~IRenderResource()
{
if (m_owner) ResetRenderResource(GetOwnerResource());
}
void UpdateAddress(API_INDEPENDENT_CLASS* owner)
{
m_owner = owner;
}
operator API_INDEPENDENT_CLASS*() const { return m_owner; }
API_INDEPENDENT_CLASS* GetOwner() const { return m_owner; }
};
/**
* This is a convenience class to create a Renderable class.
* You can also just create a RenderResource instance a conversion operator inside your own class to make it Renderable; and you probably want to delete your move constructor in that case.
*/
template <class T>
class RenderResourceHolder
{
RenderResourcePtr renderResource;
protected:
RenderResourceHolder() = default;
RenderResourceHolder(const RenderResourceHolder& ignored) noexcept {}
RenderResourceHolder(RenderResourceHolder&& move) noexcept
: renderResource(std::move(move.renderResource))
{
if (IRenderResource<T>* renderRes = renderResource)
renderRes->UpdateAddress(static_cast<T*>(this));
}
~RenderResourceHolder() = default;
public:
operator RenderResourcePtr&() { return renderResource; }
RenderResourcePtr& GetRenderResource() const { return const_cast<RenderResourceHolder*>(this)->renderResource; }
template<Renderable RT>
operator RT() const { return renderResource; }
bool HasRenderResource() const { return renderResource; }
RenderResourceHolder& operator =(const RenderResourceHolder& copy) noexcept
{
renderResource.Release();
return *this;
}
RenderResourceHolder& operator =(RenderResourceHolder&& move) noexcept
{
renderResource = std::move(move.renderResource);
if (IRenderResource<T>* renderRes = renderResource)
renderRes->UpdateAddress(static_cast<T*>(this));
return *this;
}
void Swap(RenderResourceHolder& other) noexcept
{
RenderResourceHolder tmp(std::move(*this));
*this = std::move(other);
other = std::move(tmp);
}
};
}