1#include "GraphicsDeviceD3D11.h"
3#include "BuffersD3D11.h"
4#include "TexturesD3D11.h"
5#include "ContextD3D11.h"
6#include "EffectsD3D11.h"
7#include "FormatsD3D11.h"
9#include "Foundation/Logging/Logger.h"
10#include "Foundation/Platform/Unicode.h"
11#include "Foundation/Platform/WindowData.h"
17 ENV_COGS_USE_DEBUG_LAYER = 0,
24 const char* env_keys[ENV_N] {
25 "COGS_USE_DEBUG_LAYER",
34#ifdef COGS_RENDERING_D3D9SUPPORT
38 struct SharedResources {
39 ResourcePointer<IDirect3D9Ex> d3D9Interface;
40 ResourcePointer<IDirect3DDevice9Ex> d3d9Device;
42 HANDLE sharedHandle = 0;
44 ResourcePointer<IDirect3DSurface9> sharedSurface;
55 assert(!memorySize &&
"Rendering resource memory leaked.");
58 void*
allocate(
size_t size,
size_t alignment, MemBlockType type = MemBlockType::Block)
override {
61 return baseAllocator->allocate(size, alignment, type);
64 void deallocate(
void* ptr,
size_t size, MemBlockType type = MemBlockType::Block)
override {
66 baseAllocator->deallocate(ptr, size, type);
70 std::atomic<size_t> memorySize = 0;
74Cogs::GraphicsDeviceD3D11::GraphicsDeviceD3D11(RenderingAllocatorInfo * allocateInfo) :
75 resourceAllocator(new ResourceAllocator(allocateInfo ? allocateInfo->resourceAllocator : nullptr)),
76#ifdef COGS_RENDERING_D3D9SUPPORT
77 sharedResources(
std::make_unique<SharedResources>()),
79 defaultSwapChain(this),
85 if (settings.ioHandler) {
86 effects.setIOHandler(settings.ioHandler);
89 renderTargets.initialize(
this, &textures);
92 if (!initializeDeviceShared()) {
97 if (!initializeDeviceAndSwapChain()) {
102 device->QueryInterface(__uuidof(ID3D11InfoQueue), infoQueue.internalVoidPointer());
105 capabilities.initialize(device5);
106 syncObjects.setDevice(device5);
109 capabilities.initialize(device1);
112 capabilities.initialize(device);
114 buffers.setDevice(device);
115 effects.setDevice(
this, device);
116 context.setDevice(device, device1);
118 buffers.initialize(&context, &effects);
119 textures.initialize(&context);
120 context.initialize(
this, &buffers, &textures, &effects, &renderTargets, &syncObjects);
127 context.frameStatisticsBeginFrame();
128 context.setDefaults();
130 defaultSwapChain.beginFrame();
133 swapChain->beginFrame();
138 static std::vector<uint8_t> buffer;
140 Logging::Category::Fatal,
141 Logging::Category::Error,
142 Logging::Category::Warning,
143 Logging::Category::Debug,
144 Logging::Category::Trace
148 swapChain->endFrame(0, presentFlags);
150 defaultSwapChain.endFrame(syncInterval, presentFlags);
154 for(uint64_t idx = 0, messageCount = infoQueue->GetNumStoredMessages(); idx < messageCount; ++idx) {
155 size_t messageSize = 0;
157 infoQueue->GetMessage(idx,
nullptr, &messageSize);
158 buffer.resize(messageSize);
160 D3D11_MESSAGE* message =
reinterpret_cast<D3D11_MESSAGE*
>(buffer.data());
162 infoQueue->GetMessage(idx, message, &messageSize);
166 infoQueue->ClearStoredMessages();
172 effects.releaseResources();
173 renderTargets.releaseResources();
174 textures.releaseResources();
175 buffers.releaseResources();
181 if (swapChain->initialize(windowData)) {
182 swapChains.push_back(swapChain);
190 auto e = swapChains.end();
191 auto i = std::find(swapChains.begin(), e, swapChain);
200 defaultSwapChain.setSize(newWidth, newHeight);
204 w = defaultSwapChain.getWidth();
205 h = defaultSwapChain.getHeight();
209bool Cogs::GraphicsDeviceD3D11::resizeSharedSurfaces()
211#ifdef COGS_RENDERING_D3D9SUPPORT
213 HRESULT hr = defaultSwapChain.getSharedBackBuffer()->QueryInterface(__uuidof(IDXGIResource), dxgiSurface.internalVoidPointer());
216 LOG_ERROR(logger,
"QueryInterface failed in resizeSharedSurfaces: %s", direct3D11ReturnCodeAsString(hr));
219 hr = dxgiSurface->GetSharedHandle(&sharedResources->sharedHandle);
222 LOG_ERROR(logger,
"GetSharedHandle failed in resizeSharedSurfaces: %s", direct3D11ReturnCodeAsString(hr));
226 sharedResources->sharedSurface = {};
228 ResourcePointer<IDirect3DTexture9> sharedTexture;
229 D3DFORMAT d3D9Format = D3DFMT_A8R8G8B8;
231 hr = sharedResources->d3d9Device->CreateTexture(defaultSwapChain.getWidth(),
232 defaultSwapChain.getHeight(),
234 D3DUSAGE_RENDERTARGET,
237 sharedTexture.internalPointer(),
238 &sharedResources->sharedHandle);
241 LOG_ERROR(logger,
"Failed to create D3D9 texture in resizeSharedSurfaces: %s", direct3D11ReturnCodeAsString(hr));
245 hr = sharedTexture->GetSurfaceLevel(0, sharedResources->sharedSurface.internalPointer());
248 LOG_ERROR(logger,
"Get surface level failed in resizeSharedSurfaces: %s", direct3D11ReturnCodeAsString(hr));
251 if (settings.sharedSurface) {
252 *settings.sharedSurface = sharedResources->sharedSurface;
258bool Cogs::GraphicsDeviceD3D11::initializeDeviceAndSwapChain() {
262 auto * tmp_p = &tmp[0];
263 auto * tmp_e = tmp_p +
sizeof(tmp);
266 for (
unsigned i = 0; i < ENV_N; i++) {
267 envvars[i] = getenv(env_keys[i]);
268 auto n = strlen(env_keys[i]);
269 if (i != 0 && tmp_p + 1 < tmp_e) *tmp_p++ =
' ';
270 for (
size_t k = 0; k < n && tmp_p + 1 < tmp_e; k++) {
271 *tmp_p++ = env_keys[i][k];
273 if (tmp_p + 1 < tmp_e) *tmp_p++ =
'=';
274 if (tmp_p + 1 < tmp_e) *tmp_p++ = envvars[i] ?
'1' :
'0';
276 assert(tmp_p < tmp_e);
278 LOG_DEBUG(logger,
"envvars: %s", tmp);
280 std::vector<ResourcePointer<IDXGIAdapter>> adapters;
282 std::vector<D3D_DRIVER_TYPE> driverTypes;
284 driverTypes.push_back(D3D_DRIVER_TYPE_WARP);
286 else if (envvars[ENV_COGS_USE_REF]) {
287 driverTypes.push_back(D3D_DRIVER_TYPE_REFERENCE);
290 driverTypes = { D3D_DRIVER_TYPE_HARDWARE, D3D_DRIVER_TYPE_WARP, D3D_DRIVER_TYPE_REFERENCE };
292 ResourcePointer<IDXGIFactory5> dxgiFactory;
294 if (SUCCEEDED(CreateDXGIFactory(__uuidof(IDXGIFactory5), dxgiFactory.internalVoidPointer()))) {
295 ResourcePointer<IDXGIAdapter> adapter;
297 for (uint32_t idx = 0; dxgiFactory->EnumAdapters(idx, adapter.internalPointer()) != DXGI_ERROR_NOT_FOUND; ++idx) {
298 DXGI_ADAPTER_DESC desc;
300 adapter->GetDesc(&desc);
302 if (desc.VendorId == 0x10DE) {
303 adapters.push_back(adapter);
309 adapters.push_back({});
311 std::vector<D3D_FEATURE_LEVEL> FeatureLevelsRequested;
312 if (envvars[ENV_COGS_USE_DX11_0]) {
313 FeatureLevelsRequested.push_back(D3D_FEATURE_LEVEL_11_0);
316 FeatureLevelsRequested = {
317 D3D_FEATURE_LEVEL_11_1,
318 D3D_FEATURE_LEVEL_11_0
323 D3D_FEATURE_LEVEL apiFeatureLevel = D3D_FEATURE_LEVEL_11_0;
325 assert(!driverTypes.empty());
326 assert(!FeatureLevelsRequested.empty());
328 for (
auto i = adapters.begin(), e = adapters.end(); (i != e) && !device; ++i) {
329 for (
auto driverType : driverTypes) {
334 hr = createDevice(*i, driverType, D3D11_CREATE_DEVICE_DEBUG, FeatureLevelsRequested, apiFeatureLevel);
337 hr = createDevice(*i, driverType, 0, FeatureLevelsRequested, apiFeatureLevel);
341 if (driverType == D3D_DRIVER_TYPE_WARP) {
342 LOG_WARNING(logger,
"Software rendering via WARP device.");
344 else if (driverType == D3D_DRIVER_TYPE_REFERENCE) {
345 LOG_WARNING(logger,
"Software rendering via reference driver.");
347 if (apiFeatureLevel == D3D_FEATURE_LEVEL_11_0) {
348 LOG_WARNING(logger,
"Got feature level 11.0");
355 LOG_FATAL(logger,
"Could not create Direct3D 11 device: %s", direct3D11ReturnCodeAsString(hr));
360 if (apiFeatureLevel != D3D_FEATURE_LEVEL_11_0) {
361 hr = device->QueryInterface(__uuidof(ID3D11Device1), (
void **)&device1);
363 LOG_DEBUG(logger,
"Got ID3D11Device1 interface");
367 if (hr = device->QueryInterface(__uuidof(ID3D11Device5), (
void**)&device5); SUCCEEDED(hr)) {
368 LOG_DEBUG(logger,
"Got ID3D11Device5 interface");
375 return defaultSwapChain.initialize(settings.windowData);
378bool Cogs::GraphicsDeviceD3D11::initializeDeviceShared() {
379#ifdef COGS_RENDERING_D3D9SUPPORT
380 LOG_DEBUG(logger,
"Initializing D3D11 with shared surface support...");
382 auto desktopHwnd = GetDesktopWindow();
384 if (FAILED(hr = Direct3DCreate9Ex(D3D_SDK_VERSION, sharedResources->d3D9Interface.internalPointer()))) {
385 LOG_ERROR(logger,
"Could not create Direct3D 9 Ex interface: %s", direct3D11ReturnCodeAsString(hr));
388 D3DPRESENT_PARAMETERS presentParameters = {};
389 presentParameters.Windowed = TRUE;
390 presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
391 presentParameters.hDeviceWindow = desktopHwnd;
392 presentParameters.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
393 if (FAILED(hr = sharedResources->d3D9Interface->CreateDeviceEx(D3DADAPTER_DEFAULT,
396 D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE,
399 sharedResources->d3d9Device.internalPointer()))) {
400 LOG_ERROR(logger,
"Could not create Direct3D 9 Ex device: %s", direct3D11ReturnCodeAsString(hr));
403 const UINT deviceFlags = isDebug() ? D3D11_CREATE_DEVICE_DEBUG : 0;
404 const D3D_FEATURE_LEVEL level = D3D_FEATURE_LEVEL_11_0;
405 if (FAILED(hr = D3D11CreateDevice(
nullptr,
406 D3D_DRIVER_TYPE_HARDWARE,
412 device.internalPointer(),
415 LOG_ERROR(logger,
"Could not create Direct3D 11 device: %s", direct3D11ReturnCodeAsString(hr));
418 if (defaultSwapChain.recreateOffscreenBuffers()) {
419 return resizeSharedSurfaces();
425void Cogs::GraphicsDeviceD3D11::setupDebugging()
428 ResourcePointer<ID3D11Debug> d3dDebug;
429 if (FAILED(hr = device->QueryInterface(__uuidof(ID3D11Debug), (
void**)&d3dDebug))) {
430 LOG_WARNING(logger,
"Could not get ID3D11Debug interface: %s", direct3D11ReturnCodeAsString(hr));
434 ResourcePointer<ID3D11InfoQueue> d3dInfoQueue;
435 if (FAILED(hr = d3dDebug->QueryInterface(__uuidof(ID3D11InfoQueue), (
void**)&d3dInfoQueue))) {
436 LOG_WARNING(logger,
"Could not get ID3D11InfoQueue interface: %s", direct3D11ReturnCodeAsString(hr));
440#ifdef COGSRENDERING_GFX_BREAK
441 d3dInfoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_CORRUPTION,
true);
442 d3dInfoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR,
true);
443 LOG_DEBUG(logger,
"Break to debugger on D3D errors.");
447 D3D11_MESSAGE_ID hide[] = {
448 D3D11_MESSAGE_ID_SETPRIVATEDATA_CHANGINGPARAMS,
451 D3D11_INFO_QUEUE_FILTER filter = {};
452 filter.DenyList.NumIDs = _countof(hide);
453 filter.DenyList.pIDList = hide;
455 if (FAILED(hr = d3dInfoQueue->AddStorageFilterEntries(&filter))) {
456 LOG_WARNING(logger,
"Could not add storage filter entries: %s", direct3D11ReturnCodeAsString(hr));
458 LOG_DEBUG(logger,
"Set up debug layer.");
462 ResourceStatistics stats{};
464 stats.bufferMemoryConsumption = buffers.bufferMemoryConsumption;
465 stats.textureMemoryConsumption = textures.textureMemoryConsumption;
466 stats.bufferCount =
static_cast<uint32_t
>(buffers.buffers.size());
467 stats.inputLayoutCount =
static_cast<uint32_t
>(buffers.inputLayouts.size());
468 stats.textureCount =
static_cast<uint32_t
>(textures.textures.size());
469 stats.samplerStateCount =
static_cast<uint32_t
>(textures.samplerStates.size());
470 stats.effectCount =
static_cast<uint32_t
>(effects.effects.size());
471 stats.blendStateCount =
static_cast<uint32_t
>(renderTargets.blendStates.size());
472 stats.rasterizerStateCount =
static_cast<uint32_t
>(renderTargets.rasterizerStates.size());
473 stats.depthStencilStateCount =
static_cast<uint32_t
>(renderTargets.depthStencilStates.size());
474 stats.rendertargetsCount =
static_cast<uint32_t
>(renderTargets.renderTargets.size());
475 stats.framebufferCount = ~0u;
480HRESULT Cogs::GraphicsDeviceD3D11::createDevice(IDXGIAdapter* adapter,
481 D3D_DRIVER_TYPE driverType,
483 const std::vector<D3D_FEATURE_LEVEL>& featureLevelsRequested,
484 D3D_FEATURE_LEVEL& apiFeatureLevel) {
486 driverType = D3D_DRIVER_TYPE_UNKNOWN;
488 HRESULT hr = D3D11CreateDevice(adapter,
492 featureLevelsRequested.data(),
493 (UINT)featureLevelsRequested.size(),
495 device.internalPointer(),
499 constexpr D3D_FEATURE_LEVEL featureLevel_11_0 = D3D_FEATURE_LEVEL_11_0;
506 hr = D3D11CreateDevice(adapter,
513 device.internalPointer(),
517 LOG_WARNING(logger,
"D3D11CreateDevice didn't recognize feature level 11.1, KB2670838 is probably missing.");
Log implementation class.
void logFileLine(const char *file, const int line, const Category category, uint32_t errorNumber, _Printf_format_string_ const char *fmt,...) const VALIDATE_ARGS(6)
Log a formatted message with file/line information.
Base allocator implementation.
static Allocator * defaultAllocator()
Gets the system default allocator.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
@ Unspecified
The default error number for legacy logger usage.
Category
Logging categories used to filter log messages.
Contains all Cogs related functionality.
@ ForceSoftwareRendering
Force software rendering.
@ Debug
If available, the device will operate in debug mode, performing additional validation of input data,...
@ UseSharedSurface
Use shared surface for D3D9 interop.
bool initialize()
Initializes the graphics device with the settings previous set through calling setSettings.
void setSize(int newWidth, int newHeight)
Set the size of the main drawing buffer used by the graphics device in pixels.
void beginFrame()
Signal the beginning of a new frame to the graphics device.
void endFrame(uint32_t syncInterval=0, uint32_t presentFlags=PresentFlags::None)
Signal the end of a frame to the graphics device.
virtual ISwapChain * createSwapChain(struct WindowData *windowData) override
Create a new swap chain for the specified window.
void releaseResources()
Release all resources allocated.
virtual void deleteSwapChain(ISwapChain *swapChain) override
Deletes the specified swap chain.
bool getSize(int &w, int &h) const override
Retrieve the size previously set by setSize.
void * allocate(size_t size, size_t alignment, MemBlockType type=MemBlockType::Block) override
Allocate raw memory.
void deallocate(void *ptr, size_t size, MemBlockType type=MemBlockType::Block) override
Deallocate the memory block at the given pointer, with the given size.