summaryrefslogtreecommitdiffstats
path: root/Graphics/GraphicsEngine/include/BufferBase.hpp
blob: 217dd109163bf8b0c3fddd7d2b97b28b0b4844cc (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
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
/*
 *  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::BufferBase template class

#include <memory>

#include "Buffer.h"
#include "GraphicsTypes.h"
#include "DeviceObjectBase.hpp"
#include "GraphicsAccessories.hpp"
#include "STDAllocator.hpp"
#include "FormatString.hpp"

namespace Diligent
{

/// Validates buffer description and throws an exception in case of an error.
void ValidateBufferDesc(const BufferDesc& Desc, const DeviceCaps& deviceCaps) noexcept(false);

/// Validates initial buffer data parameters and throws an exception in case of an error.
void ValidateBufferInitData(const BufferDesc& Desc, const BufferData* pBuffData) noexcept(false);

/// Validates and corrects buffer view description; throws an exception in case of an error.
void ValidateAndCorrectBufferViewDesc(const BufferDesc& BuffDesc, BufferViewDesc& ViewDesc) noexcept(false);


/// Template class implementing base functionality of the buffer object

/// \tparam EngineImplTraits - Engine implementation type traits.
template <typename EngineImplTraits>
class BufferBase : public DeviceObjectBase<typename EngineImplTraits::BufferInterface, typename EngineImplTraits::RenderDeviceImplType, BufferDesc>
{
public:
    // Base interface that this class inherits (IBufferD3D12, IBufferVk, etc.).
    using BaseInterface = typename EngineImplTraits::BufferInterface;

    // Render device implementation type (RenderDeviceD3D12Impl, RenderDeviceVkImpl, etc.).
    using RenderDeviceImplType = typename EngineImplTraits::RenderDeviceImplType;

    // Buffer view implementation type (BufferViewD3D12Impl, BufferViewVkImpl, etc.).
    using BufferViewImplType = typename EngineImplTraits::BufferViewImplType;

    // The type of the allocator that is used to allocate memory for the buffer view object instances.
    using TBuffViewObjAllocator = typename EngineImplTraits::BuffViewObjAllocatorType;

    using TDeviceObjectBase = DeviceObjectBase<BaseInterface, RenderDeviceImplType, BufferDesc>;

    /// \param pRefCounters         - Reference counters object that controls the lifetime of this buffer.
    /// \param BuffViewObjAllocator - Allocator that is used to allocate memory for the buffer view instances.
    ///                               This parameter is only used for debug purposes.
    /// \param pDevice              - Pointer to the device.
    /// \param BuffDesc             - Buffer description.
    /// \param bIsDeviceInternal    - Flag indicating if the buffer is an internal device object and
    ///							      must not keep a strong reference to the device.
    BufferBase(IReferenceCounters*    pRefCounters,
               TBuffViewObjAllocator& BuffViewObjAllocator,
               RenderDeviceImplType*  pDevice,
               const BufferDesc&      BuffDesc,
               bool                   bIsDeviceInternal) :
        TDeviceObjectBase{pRefCounters, pDevice, BuffDesc, bIsDeviceInternal},
#ifdef DILIGENT_DEBUG
        m_dbgBuffViewAllocator{BuffViewObjAllocator},
#endif
        m_pDefaultUAV{nullptr, STDDeleter<BufferViewImplType, TBuffViewObjAllocator>(BuffViewObjAllocator)},
        m_pDefaultSRV{nullptr, STDDeleter<BufferViewImplType, TBuffViewObjAllocator>(BuffViewObjAllocator)}
    {
        ValidateBufferDesc(this->m_Desc, pDevice->GetDeviceCaps());

        Uint64 DeviceQueuesMask = pDevice->GetCommandQueueMask();
        DEV_CHECK_ERR((this->m_Desc.CommandQueueMask & DeviceQueuesMask) != 0, "No bits in the command queue mask (0x", std::hex, this->m_Desc.CommandQueueMask, ") correspond to one of ", pDevice->GetCommandQueueCount(), " available device command queues");
        this->m_Desc.CommandQueueMask &= DeviceQueuesMask;
    }

    IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_Buffer, TDeviceObjectBase)

    /// Implementation of IBuffer::CreateView(); calls CreateViewInternal() virtual function
    /// that creates buffer view for the specific engine implementation.
    virtual void DILIGENT_CALL_TYPE CreateView(const struct BufferViewDesc& ViewDesc, IBufferView** ppView) override
    {
        DEV_CHECK_ERR(ViewDesc.ViewType != BUFFER_VIEW_UNDEFINED, "Buffer view type is not specified");
        if (ViewDesc.ViewType == BUFFER_VIEW_SHADER_RESOURCE)
            DEV_CHECK_ERR(this->m_Desc.BindFlags & BIND_SHADER_RESOURCE, "Attempting to create SRV for buffer '", this->m_Desc.Name, "' that was not created with BIND_SHADER_RESOURCE flag");
        else if (ViewDesc.ViewType == BUFFER_VIEW_UNORDERED_ACCESS)
            DEV_CHECK_ERR(this->m_Desc.BindFlags & BIND_UNORDERED_ACCESS, "Attempting to create UAV for buffer '", this->m_Desc.Name, "' that was not created with BIND_UNORDERED_ACCESS flag");
        else
            UNEXPECTED("Unexpected buffer view type");

        CreateViewInternal(ViewDesc, ppView, false);
    }


    /// Implementation of IBuffer::GetDefaultView().
    virtual IBufferView* DILIGENT_CALL_TYPE GetDefaultView(BUFFER_VIEW_TYPE ViewType) override
    {
        switch (ViewType)
        {
            case BUFFER_VIEW_SHADER_RESOURCE: return m_pDefaultSRV.get();
            case BUFFER_VIEW_UNORDERED_ACCESS: return m_pDefaultUAV.get();
            default: UNEXPECTED("Unknown view type"); return nullptr;
        }
    }


    /// Creates default buffer views.

    ///
    /// - Creates default shader resource view addressing the entire buffer if Diligent::BIND_SHADER_RESOURCE flag is set
    /// - Creates default unordered access view addressing the entire buffer if Diligent::BIND_UNORDERED_ACCESS flag is set
    ///
    /// The function calls CreateViewInternal().
    void CreateDefaultViews()
    {
        // Create default views for structured and raw buffers. For formatted buffers we do not know the view format, so
        // cannot create views.

        auto CreateDefaultView = [&](BUFFER_VIEW_TYPE ViewType) //
        {
            BufferViewDesc ViewDesc;
            ViewDesc.ViewType = ViewType;

            std::string ViewName;
            switch (ViewType)
            {
                case BUFFER_VIEW_UNORDERED_ACCESS:
                    ViewName = "Default UAV of buffer '";
                    break;

                case BUFFER_VIEW_SHADER_RESOURCE:
                    ViewName = "Default SRV of buffer '";
                    break;

                default:
                    UNEXPECTED("Unexpected buffer view type");
            }

            ViewName += this->m_Desc.Name;
            ViewName += '\'';
            ViewDesc.Name = ViewName.c_str();

            IBufferView* pView = nullptr;
            CreateViewInternal(ViewDesc, &pView, true);
            VERIFY(pView != nullptr, "Failed to create default view for buffer '", this->m_Desc.Name, "'");
            VERIFY(pView->GetDesc().ViewType == ViewType, "Unexpected view type");

            return static_cast<BufferViewImplType*>(pView);
        };

        if (this->m_Desc.BindFlags & BIND_UNORDERED_ACCESS && (this->m_Desc.Mode == BUFFER_MODE_STRUCTURED || this->m_Desc.Mode == BUFFER_MODE_RAW))
        {
            m_pDefaultUAV.reset(CreateDefaultView(BUFFER_VIEW_UNORDERED_ACCESS));
        }

        if (this->m_Desc.BindFlags & BIND_SHADER_RESOURCE && (this->m_Desc.Mode == BUFFER_MODE_STRUCTURED || this->m_Desc.Mode == BUFFER_MODE_RAW))
        {
            m_pDefaultSRV.reset(CreateDefaultView(BUFFER_VIEW_SHADER_RESOURCE));
        }
    }

    virtual void DILIGENT_CALL_TYPE SetState(RESOURCE_STATE State) override final
    {
        this->m_State = State;
    }

    virtual RESOURCE_STATE DILIGENT_CALL_TYPE GetState() const override final
    {
        return this->m_State;
    }

    bool IsInKnownState() const
    {
        return this->m_State != RESOURCE_STATE_UNKNOWN;
    }

    bool CheckState(RESOURCE_STATE State) const
    {
        DEV_CHECK_ERR((State & (State - 1)) == 0, "Single state is expected");
        DEV_CHECK_ERR(IsInKnownState(), "Buffer state is unknown");
        return (this->m_State & State) == State;
    }

protected:
    /// Pure virtual function that creates buffer view for the specific engine implementation.
    virtual void CreateViewInternal(const struct BufferViewDesc& ViewDesc, IBufferView** ppView, bool bIsDefaultView) = 0;

#ifdef DILIGENT_DEBUG
    TBuffViewObjAllocator& m_dbgBuffViewAllocator;
#endif

    RESOURCE_STATE m_State = RESOURCE_STATE_UNKNOWN;

    /// Default UAV addressing the entire buffer
    std::unique_ptr<BufferViewImplType, STDDeleter<BufferViewImplType, TBuffViewObjAllocator>> m_pDefaultUAV;

    /// Default SRV addressing the entire buffer
    std::unique_ptr<BufferViewImplType, STDDeleter<BufferViewImplType, TBuffViewObjAllocator>> m_pDefaultSRV;
};

} // namespace Diligent