/* * 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 #include #include 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 concept Renderable = std::is_convertible_v; 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 T* As() { return static_cast(renderObject); } template operator T() { return static_cast(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 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& copy) = delete; IRenderResource(IRenderResource&& 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(*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 RenderResourceHolder { RenderResourcePtr renderResource; protected: RenderResourceHolder() = default; RenderResourceHolder(const RenderResourceHolder& ignored) noexcept {} RenderResourceHolder(RenderResourceHolder&& move) noexcept : renderResource(std::move(move.renderResource)) { if (IRenderResource* renderRes = renderResource) renderRes->UpdateAddress(static_cast(this)); } ~RenderResourceHolder() = default; public: operator RenderResourcePtr&() { return renderResource; } RenderResourcePtr& GetRenderResource() const { return const_cast(this)->renderResource; } template 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* renderRes = renderResource) renderRes->UpdateAddress(static_cast(this)); return *this; } void Swap(RenderResourceHolder& other) noexcept { RenderResourceHolder tmp(std::move(*this)); *this = std::move(other); other = std::move(tmp); } }; }