DirectXTK12/Inc/GraphicsMemory.h

228 строки
9.1 KiB
C++

//--------------------------------------------------------------------------------------
// File: GraphicsMemory.h
//
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
//
// http://go.microsoft.com/fwlink/?LinkID=615561
//--------------------------------------------------------------------------------------
#pragma once
#ifdef _GAMING_XBOX_SCARLETT
#include <d3d12_xs.h>
#elif (defined(_XBOX_ONE) && defined(_TITLE)) || defined(_GAMING_XBOX)
#include <d3d12_x.h>
#elif defined(USING_DIRECTX_HEADERS)
#include <directx/d3d12.h>
#include <dxguids/dxguids.h>
#else
#include <d3d12.h>
#endif
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <memory>
#ifdef _GAMING_XBOX
#include <gxdk.h>
#endif
#if defined(_GAMING_XBOX) && (defined(_DEBUG) || defined(PROFILE)) && (_GXDK_VER >= 0x585D073C) /* GDK Edition 221000 */
#define USING_PIX_CUSTOM_MEMORY_EVENTS
#include <tuple>
#endif
namespace DirectX
{
class LinearAllocatorPage;
inline namespace DX12
{
// Works a little like a smart pointer. The memory will only be fenced by the GPU once the pointer
// has been invalidated or the user explicitly marks it for fencing.
class GraphicsResource
{
public:
GraphicsResource() noexcept;
GraphicsResource(
_In_ LinearAllocatorPage* page,
_In_ D3D12_GPU_VIRTUAL_ADDRESS gpuAddress,
_In_ ID3D12Resource* resource,
_In_ void* memory,
_In_ size_t offset,
_In_ size_t size) noexcept;
GraphicsResource(GraphicsResource&& other) noexcept;
GraphicsResource&& operator= (GraphicsResource&&) noexcept;
GraphicsResource(const GraphicsResource&) = delete;
GraphicsResource& operator= (const GraphicsResource&) = delete;
~GraphicsResource();
D3D12_GPU_VIRTUAL_ADDRESS GpuAddress() const noexcept { return mGpuAddress; }
ID3D12Resource* Resource() const noexcept { return mResource; }
void* Memory() const noexcept { return mMemory; }
size_t ResourceOffset() const noexcept { return mBufferOffset; }
size_t Size() const noexcept { return mSize; }
explicit operator bool() const noexcept { return mResource != nullptr; }
// Clear the pointer. Using operator -> will produce bad results.
void __cdecl Reset() noexcept;
void __cdecl Reset(GraphicsResource&&) noexcept;
private:
LinearAllocatorPage* mPage;
D3D12_GPU_VIRTUAL_ADDRESS mGpuAddress;
ID3D12Resource* mResource;
void* mMemory;
size_t mBufferOffset;
size_t mSize;
};
class SharedGraphicsResource
{
public:
SharedGraphicsResource() noexcept;
SharedGraphicsResource(SharedGraphicsResource&&) noexcept;
SharedGraphicsResource&& operator= (SharedGraphicsResource&&) noexcept;
SharedGraphicsResource(GraphicsResource&&);
SharedGraphicsResource&& operator= (GraphicsResource&&);
SharedGraphicsResource(const SharedGraphicsResource&) noexcept;
SharedGraphicsResource& operator= (const SharedGraphicsResource&) noexcept;
SharedGraphicsResource(const GraphicsResource&) = delete;
SharedGraphicsResource& operator= (const GraphicsResource&) = delete;
~SharedGraphicsResource();
D3D12_GPU_VIRTUAL_ADDRESS GpuAddress() const noexcept { return mSharedResource->GpuAddress(); }
ID3D12Resource* Resource() const noexcept { return mSharedResource->Resource(); }
void* Memory() const noexcept { return mSharedResource->Memory(); }
size_t ResourceOffset() const noexcept { return mSharedResource->ResourceOffset(); }
size_t Size() const noexcept { return mSharedResource->Size(); }
explicit operator bool() const noexcept { return mSharedResource != nullptr; }
bool operator == (const SharedGraphicsResource& other) const noexcept { return mSharedResource.get() == other.mSharedResource.get(); }
bool operator != (const SharedGraphicsResource& other) const noexcept { return mSharedResource.get() != other.mSharedResource.get(); }
// Clear the pointer. Using operator -> will produce bad results.
void __cdecl Reset() noexcept;
void __cdecl Reset(GraphicsResource&&);
void __cdecl Reset(SharedGraphicsResource&&) noexcept;
void __cdecl Reset(const SharedGraphicsResource& resource) noexcept;
private:
std::shared_ptr<GraphicsResource> mSharedResource;
};
//------------------------------------------------------------------------------
struct GraphicsMemoryStatistics
{
size_t committedMemory; // Bytes of memory currently committed/in-flight
size_t totalMemory; // Total bytes of memory used by the allocators
size_t totalPages; // Total page count
size_t peakCommitedMemory; // Peak commited memory value since last reset
size_t peakTotalMemory; // Peak total bytes
size_t peakTotalPages; // Peak total page count
};
//------------------------------------------------------------------------------
class GraphicsMemory
{
public:
enum Tag : uint32_t
{
TAG_GENERIC = 0,
TAG_CONSTANT,
TAG_VERTEX,
TAG_INDEX,
TAG_SPRITES,
TAG_TEXTURE,
TAG_COMPUTE,
};
explicit GraphicsMemory(_In_ ID3D12Device* device);
GraphicsMemory(GraphicsMemory&&) noexcept;
GraphicsMemory& operator= (GraphicsMemory&&) noexcept;
GraphicsMemory(GraphicsMemory const&) = delete;
GraphicsMemory& operator=(GraphicsMemory const&) = delete;
virtual ~GraphicsMemory();
// Make sure to keep the GraphicsResource handle alive as long as you need to access
// the memory on the CPU. For example, do not simply cache GpuAddress() and discard
// the GraphicsResource object, or your memory may be overwritten later.
GraphicsResource __cdecl Allocate(size_t size, size_t alignment = 16, uint32_t tag = TAG_GENERIC)
{
auto alloc = AllocateImpl(size, alignment);
#ifdef USING_PIX_CUSTOM_MEMORY_EVENTS
std::ignore = ReportCustomMemoryAlloc(alloc.Memory(), alloc.Size(), tag);
#else
UNREFERENCED_PARAMETER(tag);
#endif
return alloc;
}
// Version of Allocate that aligns to D3D12 constant buffer requirements
template<typename T> GraphicsResource AllocateConstant()
{
constexpr size_t alignment = D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT;
constexpr size_t alignedSize = (sizeof(T) + alignment - 1) & ~(alignment - 1);
auto alloc = AllocateImpl(alignedSize, alignment);
#ifdef USING_PIX_CUSTOM_MEMORY_EVENTS
// This cast is needed to capture the type information in the PDB
std::ignore = reinterpret_cast<T*>(ReportCustomMemoryAlloc(alloc.Memory(), alloc.Size(), TAG_CONSTANT));
#endif
return alloc;
}
template<typename T> GraphicsResource AllocateConstant(const T& setData)
{
GraphicsResource alloc = AllocateConstant<T>();
memcpy(alloc.Memory(), &setData, sizeof(T));
return alloc;
}
// Submits all the pending one-shot memory to the GPU.
// The memory will be recycled once the GPU is done with it.
void __cdecl Commit(_In_ ID3D12CommandQueue* commandQueue);
// This frees up any unused memory.
// If you want to make sure all memory is reclaimed, idle the GPU before calling this.
// It is not recommended that you call this unless absolutely necessary (e.g. your
// memory budget changes at run-time, or perhaps you're changing levels in your game.)
void __cdecl GarbageCollect();
// Memory statistics
GraphicsMemoryStatistics __cdecl GetStatistics();
void __cdecl ResetStatistics();
// Singleton
// Should only use nullptr for single GPU scenarios; mGPU requires a specific device
static GraphicsMemory& __cdecl Get(_In_opt_ ID3D12Device* device = nullptr);
private:
// Private implementation.
class Impl;
GraphicsResource __cdecl AllocateImpl(size_t size, size_t alignment);
#ifdef USING_PIX_CUSTOM_MEMORY_EVENTS
// The declspec is required to ensure the proper information is captured in the PDB
__declspec(allocator) static void* __cdecl ReportCustomMemoryAlloc(void* pMem, size_t size, UINT64 metadata);
#endif
std::unique_ptr<Impl> pImpl;
};
}
}