diff --git a/CMakeLists.txt b/CMakeLists.txt index 37c6da907d..54baf1a26d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -752,9 +752,11 @@ if(VULKAN) set(THIN3D_PLATFORMS ${THIN3D_PLATFORMS} ext/native/thin3d/thin3d_vulkan.cpp) endif() if(WIN32) - set(THIN3D_PLATFORMS ${THIN3D_PLATFORMS} ext/native/thin3d/thin3d_d3d9.cpp) - set(THIN3D_PLATFORMS ${THIN3D_PLATFORMS} ext/native/thin3d/d3dx9_loader.cpp) - set(THIN3D_PLATFORMS ${THIN3D_PLATFORMS} ext/native/thin3d/d3dx9_loader.h) + set(THIN3D_PLATFORMS ${THIN3D_PLATFORMS} + ext/native/thin3d/thin3d_d3d9.cpp + ext/native/thin3d/thin3d_d3d11.cpp + ext/native/thin3d/d3dx9_loader.cpp + ext/native/thin3d/d3dx9_loader.h) endif() add_library(native STATIC diff --git a/Windows/GPU/D3D11Context.cpp b/Windows/GPU/D3D11Context.cpp new file mode 100644 index 0000000000..0cd93bb11c --- /dev/null +++ b/Windows/GPU/D3D11Context.cpp @@ -0,0 +1,245 @@ +#include "Common/CommonWindows.h" +#include + +#include "base/logging.h" +#include "util/text/utf8.h" +#include "i18n/i18n.h" + +#include "Core/Config.h" +#include "Core/Reporting.h" +#include "Windows/GPU/D3D11Context.h" +#include "Windows/W32Util/Misc.h" +#include "thin3d/thin3d.h" + +void D3D11Context::SwapBuffers() { + swapChain_->Present(0, 0); +} + +Thin3DContext *D3D11Context::CreateThin3DContext() { + return T3DCreateD3D11Context(); // device_, context_); +} + +static void GetRes(HWND hWnd, int &xres, int &yres) { + RECT rc; + GetClientRect(hWnd, &rc); + xres = rc.right - rc.left; + yres = rc.bottom - rc.top; +} + +void D3D11Context::SwapInterval(int interval) { + // Dummy +} + +bool D3D11Context::Init(HINSTANCE hInst, HWND wnd, std::string *error_message) { + bool windowed = true; + hWnd_ = wnd; + HRESULT hr = S_OK; + + RECT rc; + GetClientRect(hWnd_, &rc); + UINT width = rc.right - rc.left; + UINT height = rc.bottom - rc.top; + + UINT createDeviceFlags = 0; +#ifdef _DEBUG + createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG; +#endif + + D3D_DRIVER_TYPE driverTypes[] = { + D3D_DRIVER_TYPE_HARDWARE, + D3D_DRIVER_TYPE_WARP, + D3D_DRIVER_TYPE_REFERENCE, + }; + UINT numDriverTypes = ARRAYSIZE(driverTypes); + + const 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 = ARRAYSIZE(featureLevels); + + for (UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++) { + driverType_ = driverTypes[driverTypeIndex]; + hr = D3D11CreateDevice(nullptr, driverType_, nullptr, createDeviceFlags, featureLevels, numFeatureLevels, + D3D11_SDK_VERSION, &device_, &featureLevel_, &context_); + + if (hr == E_INVALIDARG) { + // DirectX 11.0 platforms will not recognize D3D_FEATURE_LEVEL_11_1 so we need to retry without it + hr = D3D11CreateDevice(nullptr, driverType_, nullptr, createDeviceFlags, &featureLevels[1], numFeatureLevels - 1, + D3D11_SDK_VERSION, &device_, &featureLevel_, &context_); + } + + if (SUCCEEDED(hr)) + break; + } + if (FAILED(hr)) + return false; + + // Obtain DXGI factory from device (since we used nullptr for pAdapter above) + IDXGIFactory1* dxgiFactory = nullptr; + { + IDXGIDevice* dxgiDevice = nullptr; + hr = device_->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast(&dxgiDevice)); + if (SUCCEEDED(hr)) { + IDXGIAdapter* adapter = nullptr; + hr = dxgiDevice->GetAdapter(&adapter); + if (SUCCEEDED(hr)) { + hr = adapter->GetParent(__uuidof(IDXGIFactory1), reinterpret_cast(&dxgiFactory)); + adapter->Release(); + } + dxgiDevice->Release(); + } + } + if (FAILED(hr)) + return false; + + // Create swap chain + /* + IDXGIFactory2* dxgiFactory2 = nullptr; + hr = dxgiFactory->QueryInterface(__uuidof(IDXGIFactory2), reinterpret_cast(&dxgiFactory2)); + if (dxgiFactory2) + { + // DirectX 11.1 or later + hr = device_->QueryInterface(__uuidof(ID3D11Device1), reinterpret_cast(&device_1)); + if (SUCCEEDED(hr)) + { + (void)context_->QueryInterface(__uuidof(ID3D11DeviceContext1), reinterpret_cast(&context_1)); + } + + DXGI_SWAP_CHAIN_DESC1 sd; + ZeroMemory(&sd, sizeof(sd)); + sd.Width = width; + sd.Height = height; + sd.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + sd.SampleDesc.Count = 1; + sd.SampleDesc.Quality = 0; + sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + sd.BufferCount = 1; + + hr = dxgiFactory2->CreateSwapChainForHwnd(device_, g_hWnd, &sd, nullptr, nullptr, &g_pSwapChain1); + if (SUCCEEDED(hr)) + { + hr = g_pSwapChain1->QueryInterface(__uuidof(IDXGISwapChain), reinterpret_cast(&g_pSwapChain)); + } + dxgiFactory2->Release(); + } else { + */ + // DirectX 11.0 systems + DXGI_SWAP_CHAIN_DESC sd; + ZeroMemory(&sd, sizeof(sd)); + sd.BufferCount = 1; + sd.BufferDesc.Width = width; + sd.BufferDesc.Height = height; + sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + sd.BufferDesc.RefreshRate.Numerator = 60; + sd.BufferDesc.RefreshRate.Denominator = 1; + sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + sd.OutputWindow = hWnd_; + sd.SampleDesc.Count = 1; + sd.SampleDesc.Quality = 0; + sd.Windowed = TRUE; + + hr = dxgiFactory->CreateSwapChain(device_, &sd, &swapChain_); + // } + + // Note this tutorial doesn't handle full-screen swapchains so we block the ALT+ENTER shortcut + dxgiFactory->MakeWindowAssociation(hWnd_, DXGI_MWA_NO_ALT_ENTER); + + dxgiFactory->Release(); + + if (FAILED(hr)) + return false; + + // Create a render target view + ID3D11Texture2D* pBackBuffer = nullptr; + hr = swapChain_->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast(&pBackBuffer)); + if (FAILED(hr)) + return false; + + hr = device_->CreateRenderTargetView(pBackBuffer, nullptr, &renderTargetView_); + pBackBuffer->Release(); + if (FAILED(hr)) + return false; + + // Create depth stencil texture + D3D11_TEXTURE2D_DESC descDepth; + ZeroMemory(&descDepth, sizeof(descDepth)); + descDepth.Width = width; + descDepth.Height = height; + descDepth.MipLevels = 1; + descDepth.ArraySize = 1; + descDepth.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; + descDepth.SampleDesc.Count = 1; + descDepth.SampleDesc.Quality = 0; + descDepth.Usage = D3D11_USAGE_DEFAULT; + descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL; + descDepth.CPUAccessFlags = 0; + descDepth.MiscFlags = 0; + hr = device_->CreateTexture2D(&descDepth, nullptr, &depthStencilTex_); + if (FAILED(hr)) + return false; + + // Create the depth stencil view + D3D11_DEPTH_STENCIL_VIEW_DESC descDSV; + ZeroMemory(&descDSV, sizeof(descDSV)); + descDSV.Format = descDepth.Format; + descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; + descDSV.Texture2D.MipSlice = 0; + hr = device_->CreateDepthStencilView(depthStencilTex_, &descDSV, &depthStencilView_); + if (FAILED(hr)) + return false; + + context_->OMSetRenderTargets(1, &renderTargetView_, depthStencilView_); + + int xres, yres; + GetRes(hWnd_, xres, yres); + + return true; +} + +void D3D11Context::Resize() { + // This should only be called from the emu thread. + /* + int xres, yres; + GetRes(hWnd, xres, yres); + bool w_changed = pp.BackBufferWidth != xres; + bool h_changed = pp.BackBufferHeight != yres; + + if (device && (w_changed || h_changed)) { + // DX9::fbo_shutdown(); + + pp.BackBufferWidth = xres; + pp.BackBufferHeight = yres; + HRESULT hr = device_->Reset(&pp); + if (FAILED(hr)) { + // Had to remove DXGetErrorStringA calls here because dxerr.lib is deprecated and will not link with VS 2015. + ERROR_LOG_REPORT(G3D, "Unable to reset D3D device"); + PanicAlert("Unable to reset D3D11 device"); + } + // DX9::fbo_init(d3d); + } + */ +} + +void D3D11Context::Shutdown() { + context_->Release(); + context_ = nullptr; + device_->Release(); + device_ = nullptr; + /* + DX9::DestroyShaders(); + DX9::fbo_shutdown(); + device->EndScene(); + device->Release(); + d3d->Release(); + UnloadD3DXDynamic(); + DX9::pD3Ddevice = nullptr; + DX9::pD3DdeviceEx = nullptr; + DX9::pD3D = nullptr; + */ + hWnd_ = nullptr; + // FreeLibrary(hD3D11); + // hD3D11 = nullptr; +} diff --git a/Windows/GPU/D3D11Context.h b/Windows/GPU/D3D11Context.h new file mode 100644 index 0000000000..58183dd759 --- /dev/null +++ b/Windows/GPU/D3D11Context.h @@ -0,0 +1,58 @@ +// Copyright (c) 2015- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +// Modelled on OpenD3DBase. Might make a cleaner interface later. + +#pragma once + +#include "Common/CommonWindows.h" +#include "Windows/GPU/WindowsGraphicsContext.h" +#include + +class Thin3DContext; + +class D3D11Context : public WindowsGraphicsContext { +public: + D3D11Context() : adapterId(-1), hDC(nullptr), hWnd_(nullptr), hD3D11(nullptr) { + } + + bool Init(HINSTANCE hInst, HWND window, std::string *error_message) override; + void Shutdown() override; + void SwapInterval(int interval) override; + void SwapBuffers() override; + + void Resize() override; + + Thin3DContext *CreateThin3DContext() override; + +private: + ID3D11Device *device_; + ID3D11DeviceContext *context_; + IDXGISwapChain *swapChain_ = nullptr; + ID3D11RenderTargetView *renderTargetView_ = nullptr; + ID3D11Texture2D *depthStencilTex_ = nullptr; + ID3D11DepthStencilView *depthStencilView_ = nullptr; + + D3D_DRIVER_TYPE driverType_; + D3D_FEATURE_LEVEL featureLevel_ = D3D_FEATURE_LEVEL_11_0; + int adapterId; + HDC hDC; // Private GDI Device Context + HWND hWnd_; // Holds Our Window Handle + HMODULE hD3D11; + // D3DPRESENT_PARAMETERS pp; +}; + diff --git a/Windows/GPU/D3D9Context.h b/Windows/GPU/D3D9Context.h index e80d04b97c..6c43ce4cf0 100644 --- a/Windows/GPU/D3D9Context.h +++ b/Windows/GPU/D3D9Context.h @@ -27,8 +27,7 @@ class Thin3DContext; class D3D9Context : public WindowsGraphicsContext { public: - D3D9Context() : has9Ex(false), d3d(nullptr), d3dEx(nullptr), adapterId(-1), device(nullptr), deviceEx(nullptr), hDC(nullptr), hRC(nullptr), hWnd(nullptr), hD3D9(nullptr) { - memset(&pp, 0, sizeof(pp)); + D3D9Context() : has9Ex(false), d3d(nullptr), d3dEx(nullptr), adapterId(-1), device(nullptr), deviceEx(nullptr), hDC(nullptr), hWnd(nullptr), hD3D9(nullptr), pp{} { } bool Init(HINSTANCE hInst, HWND window, std::string *error_message) override; @@ -48,7 +47,6 @@ private: LPDIRECT3DDEVICE9 device; LPDIRECT3DDEVICE9EX deviceEx; HDC hDC; // Private GDI Device Context - HGLRC hRC; // Permanent Rendering Context HWND hWnd; // Holds Our Window Handle HMODULE hD3D9; D3DPRESENT_PARAMETERS pp; diff --git a/Windows/PPSSPP.vcxproj b/Windows/PPSSPP.vcxproj index 41eb13d2f5..4f14ab6171 100644 --- a/Windows/PPSSPP.vcxproj +++ b/Windows/PPSSPP.vcxproj @@ -134,7 +134,7 @@ Disabled - Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;..\ffmpeg\Windows\x86\lib\avcodec.lib;..\ffmpeg\Windows\x86\lib\avformat.lib;..\ffmpeg\Windows\x86\lib\avutil.lib;..\ffmpeg\Windows\x86\lib\swresample.lib;..\ffmpeg\Windows\x86\lib\swscale.lib;comctl32.lib;d3d9.lib;dxguid.lib;%(AdditionalDependencies) + Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;comctl32.lib;d3d9.lib;d3d11.lib;dxguid.lib;..\ffmpeg\Windows\x86\lib\avcodec.lib;..\ffmpeg\Windows\x86\lib\avformat.lib;..\ffmpeg\Windows\x86\lib\avutil.lib;..\ffmpeg\Windows\x86\lib\swresample.lib;..\ffmpeg\Windows\x86\lib\swscale.lib;%(AdditionalDependencies) true Windows MachineX86 @@ -171,7 +171,7 @@ Disabled - Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;..\ffmpeg\Windows\x86_64\lib\avcodec.lib;..\ffmpeg\Windows\x86_64\lib\avformat.lib;..\ffmpeg\Windows\x86_64\lib\avutil.lib;..\ffmpeg\Windows\x86_64\lib\swresample.lib;..\ffmpeg\Windows\x86_64\lib\swscale.lib;comctl32.lib;d3d9.lib;dxguid.lib;%(AdditionalDependencies) + Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;comctl32.lib;d3d9.lib;d3d11.lib;dxguid.lib;..\ffmpeg\Windows\x86_64\lib\avcodec.lib;..\ffmpeg\Windows\x86_64\lib\avformat.lib;..\ffmpeg\Windows\x86_64\lib\avutil.lib;..\ffmpeg\Windows\x86_64\lib\swresample.lib;..\ffmpeg\Windows\x86_64\lib\swscale.lib;%(AdditionalDependencies) true $(OutDir)$(ProjectName).pdb true @@ -206,7 +206,7 @@ false - Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;..\ffmpeg\Windows\x86\lib\avcodec.lib;..\ffmpeg\Windows\x86\lib\avformat.lib;..\ffmpeg\Windows\x86\lib\avutil.lib;..\ffmpeg\Windows\x86\lib\swresample.lib;..\ffmpeg\Windows\x86\lib\swscale.lib;comctl32.lib;d3d9.lib;dxguid.lib;%(AdditionalDependencies) + Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;comctl32.lib;d3d9.lib;d3d11.lib;dxguid.lib;..\ffmpeg\Windows\x86\lib\avcodec.lib;..\ffmpeg\Windows\x86\lib\avformat.lib;..\ffmpeg\Windows\x86\lib\avutil.lib;..\ffmpeg\Windows\x86\lib\swresample.lib;..\ffmpeg\Windows\x86\lib\swscale.lib;%(AdditionalDependencies) $(OutDir)$(TargetName)$(TargetExt) %(AdditionalLibraryDirectories) true @@ -250,7 +250,7 @@ false - Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;..\ffmpeg\Windows\x86_64\lib\avcodec.lib;..\ffmpeg\Windows\x86_64\lib\avformat.lib;..\ffmpeg\Windows\x86_64\lib\avutil.lib;..\ffmpeg\Windows\x86_64\lib\swresample.lib;..\ffmpeg\Windows\x86_64\lib\swscale.lib;comctl32.lib;d3d9.lib;dxguid.lib;%(AdditionalDependencies) + Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;comctl32.lib;d3d9.lib;d3d11.lib;dxguid.lib;..\ffmpeg\Windows\x86_64\lib\avcodec.lib;..\ffmpeg\Windows\x86_64\lib\avformat.lib;..\ffmpeg\Windows\x86_64\lib\avutil.lib;..\ffmpeg\Windows\x86_64\lib\swresample.lib;..\ffmpeg\Windows\x86_64\lib\swscale.lib;%(AdditionalDependencies) %(AdditionalLibraryDirectories) true Windows @@ -353,6 +353,7 @@ true true + @@ -419,6 +420,7 @@ + @@ -536,4 +538,4 @@ - + \ No newline at end of file diff --git a/Windows/PPSSPP.vcxproj.filters b/Windows/PPSSPP.vcxproj.filters index ba19036339..0b3d71fd31 100644 --- a/Windows/PPSSPP.vcxproj.filters +++ b/Windows/PPSSPP.vcxproj.filters @@ -189,6 +189,9 @@ Other Platforms\Qt\Debugger + + Windows\System + @@ -346,6 +349,9 @@ Other Platforms\Qt\Debugger + + Windows\System + @@ -446,4 +452,4 @@ Resource Files - + \ No newline at end of file diff --git a/ext/native/native.vcxproj b/ext/native/native.vcxproj index 6dd2ba5a32..50238de714 100644 --- a/ext/native/native.vcxproj +++ b/ext/native/native.vcxproj @@ -683,6 +683,7 @@ + @@ -743,4 +744,4 @@ - + \ No newline at end of file diff --git a/ext/native/native.vcxproj.filters b/ext/native/native.vcxproj.filters index 005f79ffbc..48b7f12f2c 100644 --- a/ext/native/native.vcxproj.filters +++ b/ext/native/native.vcxproj.filters @@ -748,6 +748,9 @@ util + + thin3d + @@ -820,4 +823,4 @@ {06c6305a-a646-485b-85b9-645a24dd6553} - + \ No newline at end of file diff --git a/ext/native/thin3d/thin3d.h b/ext/native/thin3d/thin3d.h index 4ef7ef93f1..644bc49a33 100644 --- a/ext/native/thin3d/thin3d.h +++ b/ext/native/thin3d/thin3d.h @@ -424,3 +424,4 @@ Thin3DContext *T3DCreateDX9Context(IDirect3D9 *d3d, IDirect3D9Ex *d3dEx, int ada class VulkanContext; Thin3DContext *T3DCreateVulkanContext(VulkanContext *context); +Thin3DContext *T3DCreateD3D11Context(); \ No newline at end of file diff --git a/ext/native/thin3d/thin3d_d3d11.cpp b/ext/native/thin3d/thin3d_d3d11.cpp new file mode 100644 index 0000000000..64e17ef9af --- /dev/null +++ b/ext/native/thin3d/thin3d_d3d11.cpp @@ -0,0 +1,5 @@ +#include "thin3d/thin3d.h" + +Thin3DContext *T3DCreateD3D11Context() { + return nullptr; +} \ No newline at end of file