DirectXTK/Src/GraphicsMemory.cpp

326 строки
7.8 KiB
C++
Исходник Обычный вид История

2017-07-11 06:58:49 +03:00
//--------------------------------------------------------------------------------------
// File: GraphicsMemory.cpp
//
2021-02-27 10:00:12 +03:00
// Copyright (c) Microsoft Corporation.
2018-02-23 22:49:48 +03:00
// Licensed under the MIT License.
2017-07-11 06:58:49 +03:00
//
// http://go.microsoft.com/fwlink/?LinkId=248929
//--------------------------------------------------------------------------------------
#include "pch.h"
#include "GraphicsMemory.h"
2018-02-16 05:04:57 +03:00
#include "DirectXHelpers.h"
2017-07-11 06:58:49 +03:00
#include "PlatformHelpers.h"
using namespace DirectX;
using Microsoft::WRL::ComPtr;
#if defined(_XBOX_ONE) && defined(_TITLE)
//======================================================================================
// Xbox One Direct3D 11.x
//======================================================================================
class GraphicsMemory::Impl
{
public:
Impl(GraphicsMemory* owner) :
mOwner(owner),
mCurrentFrame(0)
{
if (s_graphicsMemory)
{
2021-01-06 00:01:34 +03:00
throw std::logic_error("GraphicsMemory is a singleton");
2017-07-11 06:58:49 +03:00
}
s_graphicsMemory = this;
}
~Impl()
{
if (mDevice && mDeviceContext)
{
UINT64 finalFence = mDeviceContext->InsertFence(0);
while (mDevice->IsFencePending(finalFence))
{
SwitchToThread();
}
mDeviceContext.Reset();
mDevice.Reset();
}
s_graphicsMemory = nullptr;
}
void Initialize(_In_ ID3D11DeviceX* device, unsigned int backBufferCount)
2017-07-11 06:58:49 +03:00
{
assert(device != nullptr);
2017-07-11 06:58:49 +03:00
mDevice = device;
2018-03-16 21:33:06 +03:00
device->GetImmediateContextX(mDeviceContext.GetAddressOf());
2017-07-11 06:58:49 +03:00
2018-03-16 21:33:06 +03:00
mFrames.resize(backBufferCount);
2017-07-11 06:58:49 +03:00
}
void* Allocate(_In_opt_ ID3D11DeviceContext* deviceContext, size_t size, int alignment)
{
// Currently use a single global allocator instead of a per-context allocator
UNREFERENCED_PARAMETER(deviceContext);
std::lock_guard<std::mutex> lock(mGuard);
return mFrames[mCurrentFrame].Allocate(size, alignment);
}
void Commit()
{
std::lock_guard<std::mutex> lock(mGuard);
mFrames[mCurrentFrame].mFence = mDeviceContext->InsertFence(D3D11_INSERT_FENCE_NO_KICKOFF);
++mCurrentFrame;
if (mCurrentFrame >= mFrames.size())
{
mCurrentFrame = 0;
}
mFrames[mCurrentFrame].WaitOnFence(mDevice.Get());
mFrames[mCurrentFrame].Clear();
}
GraphicsMemory* mOwner;
std::mutex mGuard;
struct MemoryPage
{
2018-07-11 00:39:58 +03:00
MemoryPage() noexcept : mPageSize(0), mGrfxMemory(nullptr) {}
2017-07-11 06:58:49 +03:00
void Initialize(size_t reqSize)
{
mPageSize = 0x100000; // 1 MB general pages for Xbox One
if (mPageSize < reqSize)
{
mPageSize = AlignUp(reqSize, 65536);
}
mGrfxMemory = VirtualAlloc(nullptr, mPageSize,
MEM_LARGE_PAGES | MEM_GRAPHICS | MEM_RESERVE | MEM_COMMIT,
PAGE_WRITECOMBINE | PAGE_READWRITE | PAGE_GPU_READONLY);
if (!mGrfxMemory)
2021-01-06 00:01:34 +03:00
throw std::bad_alloc();
2017-07-11 06:58:49 +03:00
}
size_t mPageSize;
void* mGrfxMemory;
};
struct MemoryFrame
{
2018-07-11 00:39:58 +03:00
MemoryFrame() noexcept : mCurOffset(0), mFence(0) {}
2017-07-11 06:58:49 +03:00
~MemoryFrame() { Clear(); }
UINT mCurOffset;
UINT64 mFence;
void* Allocate(size_t size, size_t alignment)
{
size_t alignedSize = AlignUp(size, alignment);
if (mPages.empty())
{
MemoryPage newPage;
newPage.Initialize(alignedSize);
mCurOffset = 0;
mPages.emplace_back(newPage);
}
else
{
mCurOffset = AlignUp(mCurOffset, alignment);
if (mCurOffset + alignedSize > mPages.front().mPageSize)
{
MemoryPage newPage;
newPage.Initialize(alignedSize);
mCurOffset = 0;
mPages.emplace_front(newPage);
}
}
void* ptr = static_cast<uint8_t*>(mPages.front().mGrfxMemory) + mCurOffset;
2018-03-16 21:33:06 +03:00
mCurOffset += static_cast<UINT>(alignedSize);
2017-07-11 06:58:49 +03:00
return ptr;
}
void WaitOnFence(ID3D11DeviceX* device)
{
if (mFence)
{
while (device->IsFencePending(mFence))
{
SwitchToThread();
}
mFence = 0;
}
}
void Clear()
{
2021-08-27 03:06:53 +03:00
for (auto& it : mPages)
2017-07-11 06:58:49 +03:00
{
2021-08-27 03:06:53 +03:00
if (it.mGrfxMemory)
2017-07-11 06:58:49 +03:00
{
2021-08-27 03:28:29 +03:00
VirtualFree(it.mGrfxMemory, 0, MEM_RELEASE);
2021-08-27 03:06:53 +03:00
it.mGrfxMemory = nullptr;
2017-07-11 06:58:49 +03:00
}
}
mPages.clear();
mCurOffset = 0;
}
std::list<MemoryPage> mPages;
};
UINT mCurrentFrame;
std::vector<MemoryFrame> mFrames;
ComPtr<ID3D11DeviceX> mDevice;
ComPtr<ID3D11DeviceContextX> mDeviceContext;
2018-03-16 21:33:06 +03:00
2017-07-11 06:58:49 +03:00
static GraphicsMemory::Impl* s_graphicsMemory;
};
GraphicsMemory::Impl* GraphicsMemory::Impl::s_graphicsMemory = nullptr;
#else
//======================================================================================
// Null allocator for standard Direct3D
//======================================================================================
class GraphicsMemory::Impl
{
public:
Impl(GraphicsMemory* owner) :
mOwner(owner)
{
if (s_graphicsMemory)
{
2021-01-06 00:01:34 +03:00
throw std::logic_error("GraphicsMemory is a singleton");
2017-07-11 06:58:49 +03:00
}
s_graphicsMemory = this;
}
Impl(Impl&&) = default;
Impl& operator= (Impl&&) = default;
Impl(Impl const&) = delete;
Impl& operator= (Impl const&) = delete;
2017-07-11 06:58:49 +03:00
~Impl()
{
s_graphicsMemory = nullptr;
}
void Initialize(_In_ ID3D11Device* device, unsigned int backBufferCount) noexcept
2017-07-11 06:58:49 +03:00
{
UNREFERENCED_PARAMETER(device);
UNREFERENCED_PARAMETER(backBufferCount);
}
2019-12-13 03:23:30 +03:00
void* Allocate(_In_opt_ ID3D11DeviceContext* context, size_t size, int alignment) noexcept
2017-07-11 06:58:49 +03:00
{
UNREFERENCED_PARAMETER(context);
UNREFERENCED_PARAMETER(size);
UNREFERENCED_PARAMETER(alignment);
return nullptr;
}
2019-12-13 03:23:30 +03:00
void Commit() noexcept
2017-07-11 06:58:49 +03:00
{
}
GraphicsMemory* mOwner;
static GraphicsMemory::Impl* s_graphicsMemory;
};
GraphicsMemory::Impl* GraphicsMemory::Impl::s_graphicsMemory = nullptr;
#endif
//--------------------------------------------------------------------------------------
#pragma warning( disable : 4355 )
// Public constructor.
#if defined(_XBOX_ONE) && defined(_TITLE)
GraphicsMemory::GraphicsMemory(_In_ ID3D11DeviceX* device, unsigned int backBufferCount)
2017-07-11 06:58:49 +03:00
#else
GraphicsMemory::GraphicsMemory(_In_ ID3D11Device* device, unsigned int backBufferCount)
2017-07-11 06:58:49 +03:00
#endif
2018-04-13 21:34:06 +03:00
: pImpl(std::make_unique<Impl>(this))
2017-07-11 06:58:49 +03:00
{
pImpl->Initialize(device, backBufferCount);
}
// Move constructor.
GraphicsMemory::GraphicsMemory(GraphicsMemory&& moveFrom) noexcept
2017-07-11 06:58:49 +03:00
: pImpl(std::move(moveFrom.pImpl))
{
pImpl->mOwner = this;
}
// Move assignment.
GraphicsMemory& GraphicsMemory::operator= (GraphicsMemory&& moveFrom) noexcept
2017-07-11 06:58:49 +03:00
{
pImpl = std::move(moveFrom.pImpl);
pImpl->mOwner = this;
return *this;
}
// Public destructor.
GraphicsMemory::~GraphicsMemory() = default;
2017-07-11 06:58:49 +03:00
void* GraphicsMemory::Allocate(_In_opt_ ID3D11DeviceContext* context, size_t size, int alignment)
{
return pImpl->Allocate(context, size, alignment);
}
void GraphicsMemory::Commit()
{
pImpl->Commit();
}
GraphicsMemory& GraphicsMemory::Get()
{
if (!Impl::s_graphicsMemory || !Impl::s_graphicsMemory->mOwner)
2021-01-06 00:01:34 +03:00
throw std::logic_error("GraphicsMemory singleton not created");
2017-07-11 06:58:49 +03:00
return *Impl::s_graphicsMemory->mOwner;
}