diff options
Diffstat (limited to 'demo/DemoAppD3D11/appD3D11Ctx.cpp')
| -rw-r--r-- | demo/DemoAppD3D11/appD3D11Ctx.cpp | 766 |
1 files changed, 766 insertions, 0 deletions
diff --git a/demo/DemoAppD3D11/appD3D11Ctx.cpp b/demo/DemoAppD3D11/appD3D11Ctx.cpp new file mode 100644 index 0000000..959614c --- /dev/null +++ b/demo/DemoAppD3D11/appD3D11Ctx.cpp @@ -0,0 +1,766 @@ +/* + * Copyright (c) 2014-2017, NVIDIA CORPORATION. All rights reserved. + * + * NVIDIA CORPORATION and its licensors retain all intellectual property + * and proprietary rights in and to this software, related documentation + * and any modifications thereto. Any use, reproduction, disclosure or + * distribution of this software and related documentation without an express + * license agreement from NVIDIA CORPORATION is strictly prohibited. + */ + +//direct3d headers +#include <d3d11.h> +#include <dxgi.h> + +// include the Direct3D Library file +#pragma comment (lib, "d3d11.lib") +#pragma comment (lib, "DXGI.lib") + +#include "appD3D11Ctx.h" + +#include <stdio.h> + +#include <SDL.h> +#include <SDL_video.h> +#include <SDL_syswm.h> + +namespace +{ + // COM object release utilities + template <class T> + void inline COMRelease(T& t) + { + if (t) t->Release(); + t = nullptr; + } + + template <class T> + void inline COMRelease(T& t, UINT arraySize) + { + for (UINT i = 0; i < arraySize; i++) + { + if (t[i]) t[i]->Release(); + t[i] = nullptr; + } + } +} + +AppGraphProfiler* appGraphCreateProfiler(AppGraphCtx* ctx); +void appGraphProfilerFrameBegin(AppGraphProfiler* profiler); +void appGraphProfilerFrameEnd(AppGraphProfiler* profiler); +void appGraphProfilerEnable(AppGraphProfiler* profiler, bool enabled); +void appGraphProfilerBegin(AppGraphProfiler* profiler, const char* label); +void appGraphProfilerEnd(AppGraphProfiler* profiler, const char* label); +bool appGraphProfilerGet(AppGraphProfiler* profiler, const char** plabel, float* cpuTime, float* gpuTime, int index); +void appGraphReleaseProfiler(AppGraphProfiler* profiler); + +void AppGraphCtxInitRenderTarget(AppGraphCtx* context, SDL_Window* window, bool fullscreen); + +AppGraphCtx::AppGraphCtx() +{ + m_profiler = appGraphCreateProfiler(this); +} + +AppGraphCtx::~AppGraphCtx() +{ + AppGraphCtxReleaseRenderTarget(this); + + COMRelease(m_device); + COMRelease(m_deviceContext); + COMRelease(m_depthState); + + appGraphReleaseProfiler(m_profiler); + m_profiler = nullptr; +} + +AppGraphCtx* AppGraphCtxCreate(int deviceID) +{ + AppGraphCtx* context = new AppGraphCtx; + + HRESULT hr = S_OK; + + // enumerate devices + IDXGIFactory1* pFactory = NULL; + CreateDXGIFactory1(IID_PPV_ARGS(&pFactory)); + IDXGIAdapter1* pAdapterTemp = NULL; + IDXGIAdapter1* pAdapter = NULL; + DXGI_ADAPTER_DESC1 adapterDesc; + int adapterIdx = 0; + while (S_OK == pFactory->EnumAdapters1(adapterIdx, &pAdapterTemp)) + { + pAdapterTemp->GetDesc1(&adapterDesc); + + context->m_dedicatedVideoMemory = (size_t)adapterDesc.DedicatedVideoMemory; + + if (deviceID == adapterIdx) + { + pAdapter = pAdapterTemp; + break; + } + else + { + pAdapterTemp->Release(); + } + adapterIdx++; + } + + D3D_DRIVER_TYPE driverTypes[] = + { + D3D_DRIVER_TYPE_UNKNOWN, + D3D_DRIVER_TYPE_HARDWARE, + D3D_DRIVER_TYPE_WARP, + D3D_DRIVER_TYPE_REFERENCE, + }; + UINT numDriverTypes = 4; + + D3D_FEATURE_LEVEL featureLevels[] = + { + D3D_FEATURE_LEVEL_11_1, + D3D_FEATURE_LEVEL_11_0, + D3D_FEATURE_LEVEL_10_1, + D3D_FEATURE_LEVEL_10_0, + }; + UINT numFeatureLevels = 4; + + UINT createDeviceFlags = 0; +#ifdef _DEBUG + createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG; +#endif + + for (UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++) + { + D3D_FEATURE_LEVEL featureLevel; + D3D_DRIVER_TYPE driverType = driverTypes[driverTypeIndex]; + hr = D3D11CreateDevice(pAdapter, driverType, nullptr, createDeviceFlags, featureLevels, numFeatureLevels, + D3D11_SDK_VERSION, &context->m_device, &featureLevel, &context->m_deviceContext); + if (SUCCEEDED(hr)) + { + break; + } + } + if (FAILED(hr)) + { + delete context; + return nullptr; + } + + // cleanup adapter and factory + COMRelease(pAdapter); + COMRelease(pFactory); + + // create depth state + D3D11_DEPTH_STENCIL_DESC depthStateDesc = {}; + depthStateDesc.DepthEnable = TRUE; + depthStateDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; + depthStateDesc.DepthFunc = D3D11_COMPARISON_LESS_EQUAL; + + if (hr = context->m_device->CreateDepthStencilState(&depthStateDesc, &context->m_depthState)) + { + delete context; + return nullptr; + } + + return context; +} + +bool AppGraphCtxUpdateSize(AppGraphCtx* context, SDL_Window* window, bool fullscreen) +{ + // TODO: fix iflip fullscreen support + fullscreen = false; + + bool sizeChanged = false; + + // sync with window + { + HWND hWnd = nullptr; + // get Windows handle to this SDL window + SDL_SysWMinfo winInfo; + SDL_VERSION(&winInfo.version); + if (SDL_GetWindowWMInfo(window, &winInfo)) + { + if (winInfo.subsystem == SDL_SYSWM_WINDOWS) + { + hWnd = winInfo.info.win.window; + } + } + context->m_hWnd = hWnd; + context->m_fullscreen = fullscreen; + + HRESULT hr = S_OK; + + RECT rc; + GetClientRect(context->m_hWnd, &rc); + UINT width = rc.right - rc.left; + UINT height = rc.bottom - rc.top; + + if (context->m_winW != width || context->m_winH != height) + { + context->m_winW = width; + context->m_winH = height; + sizeChanged = true; + context->m_valid = (context->m_winW != 0 && context->m_winH != 0); + } + } + + if (sizeChanged) + { + AppGraphCtxReleaseRenderTarget(context); + } + if (sizeChanged && context->m_valid) + { + AppGraphCtxInitRenderTarget(context, window, fullscreen); + } + + return context->m_valid; +} + +void AppGraphCtxInitRenderTarget(AppGraphCtx* context, SDL_Window* window, bool fullscreen) +{ + HWND hWnd = nullptr; + // get Windows handle to this SDL window + SDL_SysWMinfo winInfo; + SDL_VERSION(&winInfo.version); + if (SDL_GetWindowWMInfo(window, &winInfo)) + { + if (winInfo.subsystem == SDL_SYSWM_WINDOWS) + { + hWnd = winInfo.info.win.window; + } + } + context->m_hWnd = hWnd; + context->m_fullscreen = fullscreen; + + HRESULT hr = S_OK; + + // enumerate devices + IDXGIFactory1* pFactory = NULL; + CreateDXGIFactory1(IID_PPV_ARGS(&pFactory)); + + // create the swap chain + for (int i = 0; i < 2; i++) + { + DXGI_SWAP_CHAIN_DESC desc; + ZeroMemory(&desc, sizeof(desc)); + desc.BufferCount = 1; + desc.BufferDesc.Width = context->m_winW; + desc.BufferDesc.Height = context->m_winH; + desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + desc.BufferDesc.RefreshRate.Numerator = 0; + desc.BufferDesc.RefreshRate.Denominator = 0; + desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; // DXGI_SWAP_EFFECT_FLIP_DISCARD; + desc.OutputWindow = context->m_hWnd; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Windowed = TRUE; // m_fullscreen ? FALSE : TRUE; + desc.Flags = 0u; + + if (hr = pFactory->CreateSwapChain(context->m_device, &desc, (IDXGISwapChain**)&context->m_swapChain)) + { + COMRelease(context->m_swapChain); + context->m_fullscreen = false; + continue; + } + + if (!context->m_fullscreen) + { + + } + else + { + hr = context->m_swapChain->SetFullscreenState(true, nullptr); + if (hr != S_OK) + { + COMRelease(context->m_swapChain); + context->m_fullscreen = false; + continue; + } + DXGI_SWAP_CHAIN_DESC desc = {}; + context->m_swapChain->GetDesc(&desc); + context->m_swapChain->ResizeBuffers(1, context->m_winW, context->m_winH, desc.BufferDesc.Format, desc.Flags); + } + break; + } + + // configure scissor and viewport + { + context->m_viewport.Width = float(context->m_winW); + context->m_viewport.Height = float(context->m_winH); + context->m_viewport.MaxDepth = 1.f; + } + + COMRelease(pFactory); + + // Create a render target view + ID3D11Texture2D* pBackBuffer = NULL; + hr = context->m_swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer); + if (FAILED(hr)) + { + return; + } + + hr = context->m_device->CreateRenderTargetView(pBackBuffer, NULL, &context->m_rtv); + pBackBuffer->Release(); + if (FAILED(hr)) + { + return; + } + + context->m_deviceContext->OMSetRenderTargets(1, &context->m_rtv, NULL); + + // viewport + context->m_deviceContext->RSSetViewports(1, &context->m_viewport); + + { + D3D11_TEXTURE2D_DESC texDesc = {}; + texDesc.Width = context->m_winW; + texDesc.Height = context->m_winH; + texDesc.MipLevels = 1; + texDesc.ArraySize = 1; + texDesc.Format = DXGI_FORMAT_R32_TYPELESS; // DXGI_FORMAT_R24G8_TYPELESS + texDesc.SampleDesc.Count = 1; + texDesc.SampleDesc.Quality = 0u; + texDesc.Usage = D3D11_USAGE_DEFAULT; + texDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE; + texDesc.CPUAccessFlags = 0; + texDesc.MiscFlags = 0; + + if (hr = context->m_device->CreateTexture2D(&texDesc, nullptr, &context->m_depthStencil)) + { + return; + } + + D3D11_DEPTH_STENCIL_VIEW_DESC viewDesc = {}; + viewDesc.Format = DXGI_FORMAT_D32_FLOAT; + viewDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; + viewDesc.Flags = 0u; + viewDesc.Texture2D.MipSlice = 0; + + if (hr = context->m_device->CreateDepthStencilView(context->m_depthStencil, &viewDesc, &context->m_dsv)) + { + return; + } + + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; + srvDesc.Format = DXGI_FORMAT_R32_FLOAT; + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + srvDesc.Texture2D.MipLevels = 1; + srvDesc.Texture2D.MostDetailedMip = 0; + + if (hr = context->m_device->CreateShaderResourceView(context->m_depthStencil, &srvDesc, &context->m_depthSRV)) + { + return; + } + } +} + +void AppGraphCtxReleaseRenderTarget(AppGraphCtx* context) +{ + if (context->m_swapChain == nullptr) + { + return; + } + + BOOL bFullscreen = FALSE; + context->m_swapChain->GetFullscreenState(&bFullscreen, nullptr); + if (bFullscreen == TRUE) context->m_swapChain->SetFullscreenState(FALSE, nullptr); + + COMRelease(context->m_swapChain); + COMRelease(context->m_rtv); + COMRelease(context->m_depthStencil); + COMRelease(context->m_dsv); + COMRelease(context->m_depthSRV); + + context->m_valid = false; + context->m_winW = 0u; + context->m_winH = 0u; +} + +void AppGraphCtxRelease(AppGraphCtx* context) +{ + if (context == nullptr) return; + + delete context; +} + +void AppGraphCtxFrameStart(AppGraphCtx* context, float clearColor[4]) +{ + appGraphProfilerFrameBegin(context->m_profiler); + + context->m_deviceContext->RSSetViewports(1, &context->m_viewport); + context->m_deviceContext->RSSetScissorRects(0, nullptr); + + context->m_deviceContext->OMSetRenderTargets(1, &context->m_rtv, context->m_dsv); + + context->m_deviceContext->ClearRenderTargetView(context->m_rtv, clearColor); + context->m_deviceContext->ClearDepthStencilView(context->m_dsv, D3D11_CLEAR_DEPTH, 1.f, 0u); + + context->m_deviceContext->OMSetDepthStencilState(context->m_depthState, 0u); +} + +void AppGraphCtxFramePresent(AppGraphCtx* context, bool fullsync) +{ + context->m_swapChain->Present(0, 0); + + appGraphProfilerFrameEnd(context->m_profiler); +} + +void AppGraphCtxWaitForFrames(AppGraphCtx* context, unsigned int maxFramesInFlight) +{ + // TODO: Implement +} + +void AppGraphCtxProfileEnable(AppGraphCtx* context, bool enabled) +{ + appGraphProfilerEnable(context->m_profiler, enabled); +} + +void AppGraphCtxProfileBegin(AppGraphCtx* context, const char* label) +{ + appGraphProfilerBegin(context->m_profiler, label); +} + +void AppGraphCtxProfileEnd(AppGraphCtx* context, const char* label) +{ + appGraphProfilerEnd(context->m_profiler, label); +} + +bool AppGraphCtxProfileGet(AppGraphCtx* context, const char** plabel, float* cpuTime, float* gpuTime, int index) +{ + return appGraphProfilerGet(context->m_profiler, plabel, cpuTime, gpuTime, index); +} + +// ******************************* Profiler ********************************* + +namespace +{ + struct TimerCPU + { + LARGE_INTEGER oldCount; + LARGE_INTEGER count; + LARGE_INTEGER freq; + TimerCPU() + { + QueryPerformanceCounter(&count); + QueryPerformanceFrequency(&freq); + oldCount = count; + } + double getDeltaTime() + { + QueryPerformanceCounter(&count); + double dt = double(count.QuadPart - oldCount.QuadPart) / double(freq.QuadPart); + oldCount = count; + return dt; + } + }; + + struct TimerGPU + { + ID3D11Query* m_begin = nullptr; + ID3D11Query* m_end = nullptr; + + TimerGPU() {} + ~TimerGPU() + { + COMRelease(m_begin); + COMRelease(m_end); + } + }; + + struct Timer + { + TimerCPU m_cpu; + TimerGPU m_gpu; + + const char* m_label = nullptr; + float m_cpuTime = 0.f; + float m_gpuTime = 0.f; + + Timer() {} + ~Timer() {} + }; + + struct TimerValue + { + const char* m_label = nullptr; + float m_cpuTime = 0.f; + float m_gpuTime = 0.f; + + struct Stat + { + float m_time = 0.f; + float m_maxTime = 0.f; + float m_maxTimeAge = 0.f; + + float m_smoothTime = 0.f; + float m_smoothTimeSum = 0.f; + float m_smoothTimeCount = 0.f; + + Stat() {} + void push(float time) + { + m_time = time; + + if (m_time > m_maxTime) + { + m_maxTime = m_time; + m_maxTimeAge = 0.f; + } + + if (fabsf(m_time - m_maxTime) < 0.25f * m_maxTime) + { + m_smoothTimeSum += m_time; + m_smoothTimeCount += 1.f; + m_smoothTimeSum *= 0.98f; + m_smoothTimeCount *= 0.98f; + m_smoothTime = m_smoothTimeSum / m_smoothTimeCount; + } + } + + float pull(float frameTime) + { + m_maxTimeAge += frameTime; + + if (m_maxTimeAge > 1.f) + { + m_maxTimeAge = 0.f; + m_maxTime = m_time; + m_smoothTimeSum = 0.f; + m_smoothTimeCount = 0.f; + } + return m_smoothTime; + } + }; + + Stat m_cpu; + Stat m_gpu; + + void push(float cpuTime, float gpuTime) + { + m_cpu.push(cpuTime); + m_gpu.push(gpuTime); + } + + void pull(float frameTime) + { + m_cpuTime = m_cpu.pull(frameTime); + m_gpuTime = m_gpu.pull(frameTime); + } + }; +} + +struct AppGraphProfiler +{ + AppGraphCtx* m_context; + + int m_state = 0; + bool m_enabled = false; + + TimerCPU m_frameTimer; + float m_frameTime = 0.f; + + ID3D11Query* m_disjoint = nullptr; + + static const int m_timersCap = 64; + Timer m_timers[m_timersCap]; + int m_timersSize = 0; + + TimerValue m_timerValues[m_timersCap]; + int m_timerValuesSize = 0; + + AppGraphProfiler(AppGraphCtx* context); + ~AppGraphProfiler(); +}; + +AppGraphProfiler::AppGraphProfiler(AppGraphCtx* context) : m_context(context) +{ +} + +AppGraphProfiler::~AppGraphProfiler() +{ + COMRelease(m_disjoint); +} + +AppGraphProfiler* appGraphCreateProfiler(AppGraphCtx* ctx) +{ + return new AppGraphProfiler(ctx); +} + +void appGraphReleaseProfiler(AppGraphProfiler* profiler) +{ + delete profiler; +} + +void appGraphProfilerFrameBegin(AppGraphProfiler* p) +{ + p->m_frameTime = (float)p->m_frameTimer.getDeltaTime(); + + if (p->m_state == 0 && p->m_enabled) + { + auto device = p->m_context->m_device; + auto deviceContext = p->m_context->m_deviceContext; + + if (p->m_disjoint == nullptr) + { + D3D11_QUERY_DESC queryDesc; + queryDesc.Query = D3D11_QUERY_TIMESTAMP_DISJOINT; + queryDesc.MiscFlags = 0u; + device->CreateQuery(&queryDesc, &p->m_disjoint); + } + + deviceContext->Begin(p->m_disjoint); + + p->m_timersSize = 0; + + p->m_state = 1; + } +} + +void appGraphProfilerFrameEnd(AppGraphProfiler* p) +{ + if (p->m_state == 1) + { + auto deviceContext = p->m_context->m_deviceContext; + + deviceContext->End(p->m_disjoint); + + p->m_state = 2; + } +} + +void appGraphProfilerEnable(AppGraphProfiler* p, bool enabled) +{ + p->m_enabled = enabled; +} + +void appGraphProfilerBegin(AppGraphProfiler* p, const char* label) +{ + if (p->m_state == 1 && p->m_timersSize < p->m_timersCap) + { + auto& timer = p->m_timers[p->m_timersSize++]; + timer.m_label = label; + timer.m_cpu.getDeltaTime(); + + auto device = p->m_context->m_device; + auto deviceContext = p->m_context->m_deviceContext; + + if (timer.m_gpu.m_begin == nullptr) + { + D3D11_QUERY_DESC queryDesc; + queryDesc.MiscFlags = 0u; + queryDesc.Query = D3D11_QUERY_TIMESTAMP; + device->CreateQuery(&queryDesc, &timer.m_gpu.m_begin); + device->CreateQuery(&queryDesc, &timer.m_gpu.m_end); + } + + deviceContext->End(timer.m_gpu.m_begin); + } +} + +void appGraphProfilerEnd(AppGraphProfiler* p, const char* label) +{ + if (p->m_state == 1) + { + Timer* timer = nullptr; + for (int i = 0; i < p->m_timersSize; i++) + { + if (strcmp(p->m_timers[i].m_label, label) == 0) + { + timer = &p->m_timers[i]; + break; + } + } + if (timer) + { + auto deviceContext = p->m_context->m_deviceContext; + + deviceContext->End(timer->m_gpu.m_end); + + timer->m_cpuTime = (float)timer->m_cpu.getDeltaTime(); + } + } +} + +bool appGraphProfilerFlush(AppGraphProfiler* p) +{ + if (p->m_state == 2) + { + auto deviceContext = p->m_context->m_deviceContext; + + // check disjoint for completion + if (deviceContext->GetData(p->m_disjoint, nullptr, 0u, 0u) != S_OK) + { + return false; + } + + D3D11_QUERY_DATA_TIMESTAMP_DISJOINT tsDisjoint; + deviceContext->GetData(p->m_disjoint, &tsDisjoint, sizeof(tsDisjoint), 0u); + if (tsDisjoint.Disjoint) + { + return false; + } + + for (int i = 0; i < p->m_timersSize; i++) + { + Timer& timer = p->m_timers[i]; + + UINT64 tsBegin, tsEnd; + if (deviceContext->GetData(timer.m_gpu.m_begin, &tsBegin, sizeof(UINT64), 0) != S_OK) + { + return false; + } + if (deviceContext->GetData(timer.m_gpu.m_end, &tsEnd, sizeof(UINT64), 0) != S_OK) + { + return false; + } + + timer.m_gpuTime = float(tsEnd - tsBegin) / float(tsDisjoint.Frequency); + + // update TimerValue + int j = 0; + for (; j < p->m_timerValuesSize; j++) + { + TimerValue& value = p->m_timerValues[j]; + if (strcmp(value.m_label, timer.m_label) == 0) + { + value.push(timer.m_cpuTime, timer.m_gpuTime); + break; + } + } + if (j >= p->m_timerValuesSize && p->m_timerValuesSize < p->m_timersCap) + { + TimerValue& value = p->m_timerValues[p->m_timerValuesSize++]; + value.m_label = timer.m_label; + value.push(timer.m_cpuTime, timer.m_gpuTime); + } + } + + p->m_state = 0; + } + return false; +} + +bool appGraphProfilerGet(AppGraphProfiler* p, const char** plabel, float* cpuTime, float* gpuTime, int index) +{ + appGraphProfilerFlush(p); + { + if (index < p->m_timerValuesSize) + { + TimerValue& timer = p->m_timerValues[index]; + + timer.pull(p->m_frameTime); + + if (plabel) *plabel = timer.m_label; + if (cpuTime) *cpuTime = timer.m_cpuTime; + if (gpuTime) *gpuTime = timer.m_gpuTime; + + return true; + } + } + return false; +} + +size_t AppGraphCtxDedicatedVideoMemory(AppGraphCtx* context) +{ + return context->m_dedicatedVideoMemory; +}
\ No newline at end of file |