CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: hrydgard/ppsspp
Path: blob/master/Windows/GPU/D3D11Context.cpp
Views: 1401
1
#include "ppsspp_config.h"
2
3
#include "Common/CommonWindows.h"
4
#include <d3d11.h>
5
#include <WinError.h>
6
7
#include "Common/Log.h"
8
#include "Common/System/Display.h"
9
#include "Common/Data/Encoding/Utf8.h"
10
#include "Common/Data/Text/I18n.h"
11
12
#include "Core/Config.h"
13
#include "Core/ConfigValues.h"
14
#include "Core/System.h"
15
#include "Windows/GPU/D3D11Context.h"
16
#include "Windows/W32Util/Misc.h"
17
#include "Common/GPU/thin3d.h"
18
#include "Common/GPU/thin3d_create.h"
19
#include "Common/GPU/D3D11/D3D11Loader.h"
20
21
#ifdef __MINGW32__
22
#undef __uuidof
23
#define __uuidof(type) IID_##type
24
#endif
25
26
#ifndef DXGI_ERROR_NOT_FOUND
27
#define _FACDXGI 0x87a
28
#define MAKE_DXGI_HRESULT(code) MAKE_HRESULT(1, _FACDXGI, code)
29
#define DXGI_ERROR_NOT_FOUND MAKE_DXGI_HRESULT(2)
30
#endif
31
32
#if PPSSPP_PLATFORM(UWP)
33
#error This file should not be compiled for UWP.
34
#endif
35
36
HRESULT D3D11Context::CreateTheDevice(IDXGIAdapter *adapter) {
37
bool windowed = true;
38
// D3D11 has no need for display rotation.
39
g_display.rotation = DisplayRotation::ROTATE_0;
40
g_display.rot_matrix.setIdentity();
41
#if defined(_DEBUG) && !PPSSPP_ARCH(ARM) && !PPSSPP_ARCH(ARM64)
42
UINT createDeviceFlags = D3D11_CREATE_DEVICE_DEBUG;
43
#else
44
UINT createDeviceFlags = 0;
45
#endif
46
47
static const D3D_FEATURE_LEVEL featureLevels[] = {
48
D3D_FEATURE_LEVEL_12_1,
49
D3D_FEATURE_LEVEL_12_0,
50
D3D_FEATURE_LEVEL_11_1,
51
D3D_FEATURE_LEVEL_11_0,
52
D3D_FEATURE_LEVEL_10_1,
53
D3D_FEATURE_LEVEL_10_0,
54
};
55
const UINT numFeatureLevels = ARRAYSIZE(featureLevels);
56
57
HRESULT hr = S_OK;
58
D3D_DRIVER_TYPE driverType = D3D_DRIVER_TYPE_UNKNOWN;
59
hr = ptr_D3D11CreateDevice(adapter, driverType, nullptr, createDeviceFlags, (D3D_FEATURE_LEVEL *)featureLevels, numFeatureLevels,
60
D3D11_SDK_VERSION, &device_, &featureLevel_, &context_);
61
if (hr == E_INVALIDARG) {
62
// DirectX 11.0 platforms will not recognize D3D_FEATURE_LEVEL_11_1 so we need to retry without it
63
hr = ptr_D3D11CreateDevice(adapter, driverType, nullptr, createDeviceFlags, (D3D_FEATURE_LEVEL *)&featureLevels[3], numFeatureLevels - 3,
64
D3D11_SDK_VERSION, &device_, &featureLevel_, &context_);
65
}
66
return hr;
67
}
68
69
bool D3D11Context::Init(HINSTANCE hInst, HWND wnd, std::string *error_message) {
70
hWnd_ = wnd;
71
LoadD3D11Error result = LoadD3D11();
72
73
HRESULT hr = E_FAIL;
74
std::vector<std::string> adapterNames;
75
std::string chosenAdapterName;
76
if (result == LoadD3D11Error::SUCCESS) {
77
std::vector<IDXGIAdapter *> adapters;
78
int chosenAdapter = 0;
79
IDXGIFactory* pFactory = nullptr;
80
81
hr = ptr_CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)&pFactory);
82
if (SUCCEEDED(hr)) {
83
IDXGIAdapter* pAdapter;
84
for (UINT i = 0; pFactory->EnumAdapters(i, &pAdapter) != DXGI_ERROR_NOT_FOUND; i++) {
85
adapters.push_back(pAdapter);
86
DXGI_ADAPTER_DESC desc;
87
pAdapter->GetDesc(&desc);
88
std::string str = ConvertWStringToUTF8(desc.Description);
89
adapterNames.push_back(str);
90
if (str == g_Config.sD3D11Device) {
91
chosenAdapter = i;
92
}
93
}
94
if (!adapters.empty()) {
95
chosenAdapterName = adapterNames[chosenAdapter];
96
hr = CreateTheDevice(adapters[chosenAdapter]);
97
for (int i = 0; i < (int)adapters.size(); i++) {
98
adapters[i]->Release();
99
}
100
} else {
101
// No adapters found. Trip the error path below.
102
hr = E_FAIL;
103
}
104
pFactory->Release();
105
}
106
}
107
108
if (FAILED(hr)) {
109
const char *defaultError = "Your GPU does not appear to support Direct3D 11.\n\nWould you like to try again using Direct3D 9 instead?";
110
auto err = GetI18NCategory(I18NCat::ERRORS);
111
112
std::wstring error;
113
114
if (result == LoadD3D11Error::FAIL_NO_COMPILER) {
115
error = ConvertUTF8ToWString(err->T("D3D11CompilerMissing", "D3DCompiler_47.dll not found. Please install. Or press Yes to try again using Direct3D9 instead."));
116
} else if (result == LoadD3D11Error::FAIL_NO_D3D11) {
117
error = ConvertUTF8ToWString(err->T("D3D11Missing", "Your operating system version does not include D3D11. Please run Windows Update.\n\nPress Yes to try again using Direct3D9 instead."));
118
}
119
120
error = ConvertUTF8ToWString(err->T("D3D11NotSupported", defaultError));
121
std::wstring title = ConvertUTF8ToWString(err->T("D3D11InitializationError", "Direct3D 11 initialization error"));
122
bool yes = IDYES == MessageBox(hWnd_, error.c_str(), title.c_str(), MB_ICONERROR | MB_YESNO);
123
if (yes) {
124
// Change the config to D3D9 and restart.
125
g_Config.iGPUBackend = (int)GPUBackend::DIRECT3D9;
126
g_Config.sFailedGPUBackends.clear();
127
g_Config.Save("save_d3d9_fallback");
128
129
W32Util::ExitAndRestart();
130
}
131
return false;
132
}
133
134
if (FAILED(device_->QueryInterface(__uuidof (ID3D11Device1), (void **)&device1_))) {
135
device1_ = nullptr;
136
}
137
138
if (FAILED(context_->QueryInterface(__uuidof (ID3D11DeviceContext1), (void **)&context1_))) {
139
context1_ = nullptr;
140
}
141
142
#ifdef _DEBUG
143
if (SUCCEEDED(device_->QueryInterface(__uuidof(ID3D11Debug), (void**)&d3dDebug_))) {
144
if (SUCCEEDED(d3dDebug_->QueryInterface(__uuidof(ID3D11InfoQueue), (void**)&d3dInfoQueue_))) {
145
d3dInfoQueue_->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_CORRUPTION, true);
146
d3dInfoQueue_->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, true);
147
d3dInfoQueue_->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_WARNING, true);
148
}
149
}
150
#endif
151
152
153
int width;
154
int height;
155
W32Util::GetWindowRes(hWnd_, &width, &height);
156
157
// Obtain DXGI factory from device (since we used nullptr for pAdapter above)
158
IDXGIFactory1 *dxgiFactory = nullptr;
159
IDXGIDevice *dxgiDevice = nullptr;
160
IDXGIAdapter *adapter = nullptr;
161
hr = device_->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void**>(&dxgiDevice));
162
if (SUCCEEDED(hr)) {
163
hr = dxgiDevice->GetAdapter(&adapter);
164
if (SUCCEEDED(hr)) {
165
hr = adapter->GetParent(__uuidof(IDXGIFactory1), reinterpret_cast<void**>(&dxgiFactory));
166
DXGI_ADAPTER_DESC desc;
167
adapter->GetDesc(&desc);
168
adapter->Release();
169
}
170
dxgiDevice->Release();
171
}
172
173
// DirectX 11.0 systems
174
DXGI_SWAP_CHAIN_DESC sd;
175
ZeroMemory(&sd, sizeof(sd));
176
sd.BufferCount = 1;
177
sd.BufferDesc.Width = width;
178
sd.BufferDesc.Height = height;
179
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
180
sd.BufferDesc.RefreshRate.Numerator = 60;
181
sd.BufferDesc.RefreshRate.Denominator = 1;
182
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
183
sd.OutputWindow = hWnd_;
184
sd.SampleDesc.Count = 1;
185
sd.SampleDesc.Quality = 0;
186
sd.Windowed = TRUE;
187
188
hr = dxgiFactory->CreateSwapChain(device_, &sd, &swapChain_);
189
dxgiFactory->MakeWindowAssociation(hWnd_, DXGI_MWA_NO_ALT_ENTER);
190
dxgiFactory->Release();
191
192
draw_ = Draw::T3DCreateD3D11Context(device_, context_, device1_, context1_, swapChain_, featureLevel_, hWnd_, adapterNames, g_Config.iInflightFrames);
193
SetGPUBackend(GPUBackend::DIRECT3D11, chosenAdapterName);
194
bool success = draw_->CreatePresets(); // If we can run D3D11, there's a compiler installed. I think.
195
_assert_msg_(success, "Failed to compile preset shaders");
196
197
GotBackbuffer();
198
return true;
199
}
200
201
void D3D11Context::LostBackbuffer() {
202
draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, width, height, nullptr);
203
bbRenderTargetTex_->Release();
204
bbRenderTargetTex_ = nullptr;
205
bbRenderTargetView_->Release();
206
bbRenderTargetView_ = nullptr;
207
}
208
209
void D3D11Context::GotBackbuffer() {
210
// Create a render target view
211
ID3D11Texture2D* pBackBuffer = nullptr;
212
HRESULT hr = swapChain_->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&bbRenderTargetTex_));
213
if (FAILED(hr))
214
return;
215
216
D3D11_TEXTURE2D_DESC bbDesc{};
217
bbRenderTargetTex_->GetDesc(&bbDesc);
218
width = bbDesc.Width;
219
height = bbDesc.Height;
220
221
hr = device_->CreateRenderTargetView(bbRenderTargetTex_, nullptr, &bbRenderTargetView_);
222
if (FAILED(hr))
223
return;
224
draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, width, height, bbRenderTargetView_, bbRenderTargetTex_);
225
}
226
227
void D3D11Context::Resize() {
228
LostBackbuffer();
229
int width;
230
int height;
231
W32Util::GetWindowRes(hWnd_, &width, &height);
232
swapChain_->ResizeBuffers(0, width, height, DXGI_FORMAT_UNKNOWN, 0);
233
GotBackbuffer();
234
}
235
236
void D3D11Context::Shutdown() {
237
LostBackbuffer();
238
239
delete draw_;
240
draw_ = nullptr;
241
242
swapChain_->Release();
243
swapChain_ = nullptr;
244
if (context1_)
245
context1_->Release();
246
if (device1_)
247
device1_->Release();
248
device1_ = nullptr;
249
device_->Release();
250
device_ = nullptr;
251
252
context_->ClearState();
253
context_->Flush();
254
context_->Release();
255
context_ = nullptr;
256
257
#ifdef _DEBUG
258
if (d3dInfoQueue_) {
259
d3dInfoQueue_->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_CORRUPTION, false);
260
d3dInfoQueue_->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, false);
261
d3dInfoQueue_->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_WARNING, false);
262
}
263
if (d3dDebug_) {
264
d3dDebug_->ReportLiveDeviceObjects(D3D11_RLDO_SUMMARY | D3D11_RLDO_DETAIL);
265
d3dDebug_->Release();
266
d3dDebug_ = nullptr;
267
}
268
if (d3dInfoQueue_) {
269
d3dInfoQueue_->Release();
270
d3dInfoQueue_ = nullptr;
271
}
272
#endif
273
274
hWnd_ = nullptr;
275
UnloadD3D11();
276
}
277
278