summaryrefslogtreecommitdiffstats
path: root/Graphics/GraphicsEngine/include/DeviceObjectBase.hpp
blob: c9d174dc83398e8478b2a1a6165da94273ab4bb1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
/*
 *  Copyright 2019-2021 Diligent Graphics LLC
 *  Copyright 2015-2019 Egor Yusov
 *  
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *  
 *      http://www.apache.org/licenses/LICENSE-2.0
 *  
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *  In no event and under no legal theory, whether in tort (including negligence), 
 *  contract, or otherwise, unless required by applicable law (such as deliberate 
 *  and grossly negligent acts) or agreed to in writing, shall any Contributor be
 *  liable for any damages, including any direct, indirect, special, incidental, 
 *  or consequential damages of any character arising as a result of this License or 
 *  out of the use or inability to use the software (including but not limited to damages 
 *  for loss of goodwill, work stoppage, computer failure or malfunction, or any and 
 *  all other commercial damages or losses), even if such Contributor has been advised 
 *  of the possibility of such damages.
 */

#pragma once

/// \file
/// Implementation of the Diligent::DeviceObjectBase template class

#include <cstring>
#include <cstdio>
#include "RefCntAutoPtr.hpp"
#include "ObjectBase.hpp"
#include "UniqueIdentifier.hpp"
#include "EngineMemory.h"

namespace Diligent
{

/// Template class implementing base functionality of the device object
template <class BaseInterface, typename RenderDeviceImplType, typename ObjectDescType>
class DeviceObjectBase : public ObjectBase<BaseInterface>
{
public:
    typedef ObjectBase<BaseInterface> TBase;

    /// \param pRefCounters      - Reference counters object that controls the lifetime of this device object
    /// \param pDevice           - Pointer to the render device.
    /// \param ObjDesc           - Object description.
    /// \param bIsDeviceInternal - Flag indicating if the object is an internal device object
    ///							   and must not keep a strong reference to the device.
    DeviceObjectBase(IReferenceCounters*   pRefCounters,
                     RenderDeviceImplType* pDevice,
                     const ObjectDescType& ObjDesc,
                     bool                  bIsDeviceInternal = false) :
        // clang-format off
        TBase              {pRefCounters},
        m_pDevice          {pDevice          },
        m_Desc             {ObjDesc          },
        m_bIsDeviceInternal{bIsDeviceInternal}
    //clang-format on
    {
        // Do not keep strong reference to the device if the object is an internal device object
        if (!m_bIsDeviceInternal)
        {
            m_pDevice->AddRef();
        }

        if (ObjDesc.Name != nullptr)
        {
            auto  size     = strlen(ObjDesc.Name) + 1;
            auto* NameCopy = ALLOCATE(GetStringAllocator(), "Object name copy", char, size);
            memcpy(NameCopy, ObjDesc.Name, size);
            m_Desc.Name = NameCopy;
        }
        else
        {
            size_t size       = 16 + 2 + 1; // 0x12345678
            auto*  AddressStr = ALLOCATE(GetStringAllocator(), "Object address string", char, size);
            snprintf(AddressStr, size, "0x%llX", static_cast<unsigned long long>(reinterpret_cast<size_t>(this)));
            m_Desc.Name = AddressStr;
        }

        //                        !!!WARNING!!!
        // We cannot add resource to the hash table from here, because the object
        // has not been completely created yet and the reference counters object
        // is not initialized!
        //m_pDevice->AddResourceToHash( this ); - ERROR!
    }

    // clang-format off
    DeviceObjectBase             (const DeviceObjectBase& ) = delete;
    DeviceObjectBase             (      DeviceObjectBase&&) = delete;
    DeviceObjectBase& operator = (const DeviceObjectBase& ) = delete;
    DeviceObjectBase& operator = (      DeviceObjectBase&&) = delete;
    // clang-format on

    virtual ~DeviceObjectBase()
    {
        FREE(GetStringAllocator(), const_cast<Char*>(m_Desc.Name));

        if (!m_bIsDeviceInternal)
        {
            m_pDevice->Release();
        }
    }

    inline virtual Atomics::Long DILIGENT_CALL_TYPE Release() override final
    {
        // Render device owns allocators for all types of device objects,
        // so it must be destroyed after all device objects are released.
        // Consider the following scenario: an object A owns the last strong
        // reference to the device:
        //
        // 1. A::~A() completes
        // 2. A::~DeviceObjectBase() completes
        // 3. A::m_pDevice is released
        //       Render device is destroyed, all allocators are invalid
        // 4. RefCountersImpl::ObjectWrapperBase::DestroyObject() calls
        //    m_pAllocator->Free(m_pObject) - crash!

        RefCntAutoPtr<RenderDeviceImplType> pDevice;
        return TBase::Release(
            [&]() //
            {
                // We must keep the device alive while the object is being destroyed
                // Note that internal device objects do not keep strong reference to the device
                if (!m_bIsDeviceInternal)
                {
                    pDevice = m_pDevice;
                }
            });
    }

    IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_DeviceObject, TBase)

    virtual const ObjectDescType& DILIGENT_CALL_TYPE GetDesc() const override final
    {
        return m_Desc;
    }

    /// Returns unique identifier
    virtual Int32 DILIGENT_CALL_TYPE GetUniqueID() const override final
    {
        /// \note
        /// This unique ID is used to unambiguously identify device object for
        /// tracking purposes.
        /// Niether GL handle nor pointer could be safely used for this purpose
        /// as both GL reuses released handles and the OS reuses released pointers.
        return m_UniqueID.GetID();
    }

    /// Implementation of IDeviceObject::SetUserData.
    virtual void DILIGENT_CALL_TYPE SetUserData(IObject* pUserData) override final
    {
        m_pUserData = pUserData;
    }

    /// Implementation of IDeviceObject::GetUserData.
    virtual IObject* DILIGENT_CALL_TYPE GetUserData() const override final
    {
        return m_pUserData.RawPtr<IObject>();
    }

    static bool IsSameObject(const DeviceObjectBase* pObj1, const DeviceObjectBase* pObj2)
    {
        UniqueIdentifier Id1 = (pObj1 != nullptr) ? pObj1->GetUniqueID() : 0;
        UniqueIdentifier Id2 = (pObj2 != nullptr) ? pObj2->GetUniqueID() : 0;
        return Id1 == Id2;
    }

    RenderDeviceImplType* GetDevice() const { return m_pDevice; }

protected:
    /// Pointer to the device
    RenderDeviceImplType* const m_pDevice;

    /// Object description
    ObjectDescType m_Desc;

    // Template argument is only used to separate counters for
    // different groups of objects
    UniqueIdHelper<BaseInterface> m_UniqueID;
    const bool                    m_bIsDeviceInternal;

    RefCntAutoPtr<IObject> m_pUserData;
};

} // namespace Diligent