1 // Copyright (c) 2017- PPSSPP Project.
2
3 // This program is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, version 2.0 or later versions.
6
7 // This program is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 // GNU General Public License 2.0 for more details.
11
12 // A copy of the GPL 2.0 should have been included with the program.
13 // If not, see http://www.gnu.org/licenses/
14
15 // Official git repository and contact information can be found at
16 // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
17
18 #include <set>
19
20 #include "Common/Log.h"
21 #include "Common/Serialize/Serializer.h"
22 #include "Common/GraphicsContext.h"
23 #include "Common/System/System.h"
24 #include "Common/Profiler/Profiler.h"
25 #include "Common/Data/Text/I18n.h"
26 #include "Core/Debugger/Breakpoints.h"
27 #include "Core/MemMapHelpers.h"
28 #include "Core/MIPS/MIPS.h"
29 #include "Core/Config.h"
30 #include "Core/Reporting.h"
31 #include "Core/System.h"
32
33 #include "GPU/GPUState.h"
34 #include "GPU/ge_constants.h"
35 #include "GPU/GeDisasm.h"
36
37 #include "GPU/Common/FramebufferManagerCommon.h"
38 #include "GPU/Debugger/Debugger.h"
39 #include "GPU/D3D11/ShaderManagerD3D11.h"
40 #include "GPU/D3D11/GPU_D3D11.h"
41 #include "GPU/D3D11/FramebufferManagerD3D11.h"
42 #include "GPU/D3D11/DrawEngineD3D11.h"
43 #include "GPU/D3D11/TextureCacheD3D11.h"
44 #include "GPU/D3D11/D3D11Util.h"
45
46 #include "Core/HLE/sceKernelThread.h"
47 #include "Core/HLE/sceKernelInterrupt.h"
48 #include "Core/HLE/sceGe.h"
49
GPU_D3D11(GraphicsContext * gfxCtx,Draw::DrawContext * draw)50 GPU_D3D11::GPU_D3D11(GraphicsContext *gfxCtx, Draw::DrawContext *draw)
51 : GPUCommon(gfxCtx, draw), drawEngine_(draw,
52 (ID3D11Device *)draw->GetNativeObject(Draw::NativeObject::DEVICE),
53 (ID3D11DeviceContext *)draw->GetNativeObject(Draw::NativeObject::CONTEXT)) {
54 device_ = (ID3D11Device *)draw->GetNativeObject(Draw::NativeObject::DEVICE);
55 context_ = (ID3D11DeviceContext *)draw->GetNativeObject(Draw::NativeObject::CONTEXT);
56 D3D_FEATURE_LEVEL featureLevel = (D3D_FEATURE_LEVEL)draw->GetNativeObject(Draw::NativeObject::FEATURE_LEVEL);
57
58 stockD3D11.Create(device_);
59
60 shaderManagerD3D11_ = new ShaderManagerD3D11(draw, device_, context_, featureLevel);
61 framebufferManagerD3D11_ = new FramebufferManagerD3D11(draw);
62 framebufferManager_ = framebufferManagerD3D11_;
63 textureCacheD3D11_ = new TextureCacheD3D11(draw);
64 textureCache_ = textureCacheD3D11_;
65 drawEngineCommon_ = &drawEngine_;
66 shaderManager_ = shaderManagerD3D11_;
67 depalShaderCache_ = new DepalShaderCacheD3D11(draw);
68 drawEngine_.SetShaderManager(shaderManagerD3D11_);
69 drawEngine_.SetTextureCache(textureCacheD3D11_);
70 drawEngine_.SetFramebufferManager(framebufferManagerD3D11_);
71 drawEngine_.Init();
72 framebufferManagerD3D11_->SetTextureCache(textureCacheD3D11_);
73 framebufferManagerD3D11_->SetShaderManager(shaderManagerD3D11_);
74 framebufferManagerD3D11_->SetDrawEngine(&drawEngine_);
75 framebufferManagerD3D11_->Init();
76 textureCacheD3D11_->SetFramebufferManager(framebufferManagerD3D11_);
77 textureCacheD3D11_->SetDepalShaderCache(depalShaderCache_);
78 textureCacheD3D11_->SetShaderManager(shaderManagerD3D11_);
79
80 // Sanity check gstate
81 if ((int *)&gstate.transferstart - (int *)&gstate != 0xEA) {
82 ERROR_LOG(G3D, "gstate has drifted out of sync!");
83 }
84
85 // No need to flush before the tex scale/offset commands if we are baking
86 // the tex scale/offset into the vertices anyway.
87 UpdateCmdInfo();
88 CheckGPUFeatures();
89
90 BuildReportingInfo();
91
92 // Some of our defaults are different from hw defaults, let's assert them.
93 // We restore each frame anyway, but here is convenient for tests.
94 textureCache_->NotifyConfigChanged();
95 }
96
~GPU_D3D11()97 GPU_D3D11::~GPU_D3D11() {
98 delete depalShaderCache_;
99 framebufferManagerD3D11_->DestroyAllFBOs();
100 delete framebufferManagerD3D11_;
101 shaderManagerD3D11_->ClearShaders();
102 delete shaderManagerD3D11_;
103 delete textureCacheD3D11_;
104 stockD3D11.Destroy();
105 }
106
CheckGPUFeatures()107 void GPU_D3D11::CheckGPUFeatures() {
108 u32 features = 0;
109
110 if (!PSP_CoreParameter().compat.flags().DisableRangeCulling) {
111 features |= GPU_SUPPORTS_VS_RANGE_CULLING;
112 }
113 features |= GPU_SUPPORTS_BLEND_MINMAX;
114
115 // Accurate depth is required because the Direct3D API does not support inverse Z.
116 // So we cannot incorrectly use the viewport transform as the depth range on Direct3D.
117 // TODO: Breaks text in PaRappa for some reason?
118 features |= GPU_SUPPORTS_ACCURATE_DEPTH;
119
120 #ifndef _M_ARM
121 // TODO: Do proper feature detection
122 features |= GPU_SUPPORTS_ANISOTROPY;
123 #endif
124
125 features |= GPU_SUPPORTS_DEPTH_TEXTURE;
126 features |= GPU_SUPPORTS_TEXTURE_NPOT;
127 if (draw_->GetDeviceCaps().dualSourceBlend)
128 features |= GPU_SUPPORTS_DUALSOURCE_BLEND;
129 if (draw_->GetDeviceCaps().depthClampSupported)
130 features |= GPU_SUPPORTS_DEPTH_CLAMP;
131 features |= GPU_SUPPORTS_COPY_IMAGE;
132 features |= GPU_SUPPORTS_TEXTURE_FLOAT;
133 features |= GPU_SUPPORTS_INSTANCE_RENDERING;
134 features |= GPU_SUPPORTS_TEXTURE_LOD_CONTROL;
135
136 uint32_t fmt4444 = draw_->GetDataFormatSupport(Draw::DataFormat::A4R4G4B4_UNORM_PACK16);
137 uint32_t fmt1555 = draw_->GetDataFormatSupport(Draw::DataFormat::A1R5G5B5_UNORM_PACK16);
138 uint32_t fmt565 = draw_->GetDataFormatSupport(Draw::DataFormat::R5G6B5_UNORM_PACK16);
139 if ((fmt4444 & Draw::FMT_TEXTURE) && (fmt565 & Draw::FMT_TEXTURE) && (fmt1555 & Draw::FMT_TEXTURE)) {
140 features |= GPU_SUPPORTS_16BIT_FORMATS;
141 }
142
143 if (draw_->GetDeviceCaps().logicOpSupported) {
144 features |= GPU_SUPPORTS_LOGIC_OP;
145 }
146
147 if (!g_Config.bHighQualityDepth && (features & GPU_SUPPORTS_ACCURATE_DEPTH) != 0) {
148 features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT;
149 } else if (PSP_CoreParameter().compat.flags().PixelDepthRounding) {
150 // Use fragment rounding on desktop and GLES3, most accurate.
151 features |= GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT;
152 } else if (PSP_CoreParameter().compat.flags().VertexDepthRounding) {
153 features |= GPU_ROUND_DEPTH_TO_16BIT;
154 }
155
156 // The Phantasy Star hack :(
157 if (PSP_CoreParameter().compat.flags().DepthRangeHack && (features & GPU_SUPPORTS_ACCURATE_DEPTH) == 0) {
158 features |= GPU_USE_DEPTH_RANGE_HACK;
159 }
160
161 if (PSP_CoreParameter().compat.flags().ClearToRAM) {
162 features |= GPU_USE_CLEAR_RAM_HACK;
163 }
164
165 gstate_c.featureFlags = features;
166 }
167
168 // Needs to be called on GPU thread, not reporting thread.
BuildReportingInfo()169 void GPU_D3D11::BuildReportingInfo() {
170 using namespace Draw;
171 DrawContext *thin3d = gfxCtx_->GetDrawContext();
172
173 reportingPrimaryInfo_ = thin3d->GetInfoString(InfoField::VENDORSTRING);
174 reportingFullInfo_ = reportingPrimaryInfo_ + " - " + System_GetProperty(SYSPROP_GPUDRIVER_VERSION) + " - " + thin3d->GetInfoString(InfoField::SHADELANGVERSION);
175 }
176
DeviceLost()177 void GPU_D3D11::DeviceLost() {
178 draw_->InvalidateCachedState();
179 // Simply drop all caches and textures.
180 // FBOs appear to survive? Or no?
181 shaderManagerD3D11_->ClearShaders();
182 drawEngine_.ClearInputLayoutMap();
183 textureCacheD3D11_->Clear(false);
184
185 GPUCommon::DeviceLost();
186 }
187
DeviceRestore()188 void GPU_D3D11::DeviceRestore() {
189 GPUCommon::DeviceRestore();
190 // Nothing needed.
191 }
192
InitClear()193 void GPU_D3D11::InitClear() {
194 if (!framebufferManager_->UseBufferedRendering()) {
195 // device_->Clear(0, NULL, D3DCLEAR_STENCIL | D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.f, 0);
196 }
197 }
198
BeginHostFrame()199 void GPU_D3D11::BeginHostFrame() {
200 GPUCommon::BeginHostFrame();
201 UpdateCmdInfo();
202 if (resized_) {
203 CheckGPUFeatures();
204 framebufferManager_->Resized();
205 drawEngine_.Resized();
206 textureCacheD3D11_->NotifyConfigChanged();
207 shaderManagerD3D11_->DirtyLastShader();
208 resized_ = false;
209 }
210 }
211
ReapplyGfxState()212 void GPU_D3D11::ReapplyGfxState() {
213 GPUCommon::ReapplyGfxState();
214
215 // TODO: Dirty our caches for depth states etc
216 }
217
EndHostFrame()218 void GPU_D3D11::EndHostFrame() {
219 // Probably not really necessary.
220 draw_->InvalidateCachedState();
221 }
222
BeginFrame()223 void GPU_D3D11::BeginFrame() {
224 GPUCommon::BeginFrame();
225
226 textureCacheD3D11_->StartFrame();
227 drawEngine_.BeginFrame();
228 depalShaderCache_->Decimate();
229 // fragmentTestCache_.Decimate();
230
231 shaderManagerD3D11_->DirtyLastShader();
232
233 framebufferManagerD3D11_->BeginFrame();
234 gstate_c.Dirty(DIRTY_PROJTHROUGHMATRIX);
235 }
236
SetDisplayFramebuffer(u32 framebuf,u32 stride,GEBufferFormat format)237 void GPU_D3D11::SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format) {
238 // TODO: Some games like Spongebob - Yellow Avenger, never change framebuffer, they blit to it.
239 // So breaking on frames doesn't work. Might want to move this to sceDisplay vsync.
240 GPUDebug::NotifyDisplay(framebuf, stride, format);
241 framebufferManagerD3D11_->SetDisplayFramebuffer(framebuf, stride, format);
242 }
243
CopyDisplayToOutput(bool reallyDirty)244 void GPU_D3D11::CopyDisplayToOutput(bool reallyDirty) {
245 // Flush anything left over.
246 drawEngine_.Flush();
247
248 float blendColor[4]{};
249 context_->OMSetBlendState(stockD3D11.blendStateDisabledWithColorMask[0xF], blendColor, 0xFFFFFFFF);
250
251 framebufferManagerD3D11_->CopyDisplayToOutput(reallyDirty);
252 framebufferManagerD3D11_->EndFrame();
253
254 // shaderManager_->EndFrame();
255 shaderManagerD3D11_->DirtyLastShader();
256
257 gstate_c.Dirty(DIRTY_TEXTURE_IMAGE);
258 }
259
FinishDeferred()260 void GPU_D3D11::FinishDeferred() {
261 // This finishes reading any vertex data that is pending.
262 drawEngine_.FinishDeferred();
263 }
264
CheckFlushOp(int cmd,u32 diff)265 inline void GPU_D3D11::CheckFlushOp(int cmd, u32 diff) {
266 const u8 cmdFlags = cmdInfo_[cmd].flags;
267 if (diff && (cmdFlags & FLAG_FLUSHBEFOREONCHANGE)) {
268 if (dumpThisFrame_) {
269 NOTICE_LOG(G3D, "================ FLUSH ================");
270 }
271 drawEngine_.Flush();
272 }
273 }
274
PreExecuteOp(u32 op,u32 diff)275 void GPU_D3D11::PreExecuteOp(u32 op, u32 diff) {
276 CheckFlushOp(op >> 24, diff);
277 }
278
ExecuteOp(u32 op,u32 diff)279 void GPU_D3D11::ExecuteOp(u32 op, u32 diff) {
280 const u8 cmd = op >> 24;
281 const CommandInfo info = cmdInfo_[cmd];
282 const u8 cmdFlags = info.flags;
283 if ((cmdFlags & FLAG_EXECUTE) || (diff && (cmdFlags & FLAG_EXECUTEONCHANGE))) {
284 (this->*info.func)(op, diff);
285 } else if (diff) {
286 uint64_t dirty = info.flags >> 8;
287 if (dirty)
288 gstate_c.Dirty(dirty);
289 }
290 }
291
GetStats(char * buffer,size_t bufsize)292 void GPU_D3D11::GetStats(char *buffer, size_t bufsize) {
293 size_t offset = FormatGPUStatsCommon(buffer, bufsize);
294 buffer += offset;
295 bufsize -= offset;
296 if ((int)bufsize < 0)
297 return;
298 snprintf(buffer, bufsize,
299 "Vertex, Fragment shaders loaded: %d, %d\n",
300 shaderManagerD3D11_->GetNumVertexShaders(),
301 shaderManagerD3D11_->GetNumFragmentShaders()
302 );
303 }
304
ClearCacheNextFrame()305 void GPU_D3D11::ClearCacheNextFrame() {
306 textureCacheD3D11_->ClearNextFrame();
307 }
308
ClearShaderCache()309 void GPU_D3D11::ClearShaderCache() {
310 shaderManagerD3D11_->ClearShaders();
311 drawEngine_.ClearInputLayoutMap();
312 }
313
DoState(PointerWrap & p)314 void GPU_D3D11::DoState(PointerWrap &p) {
315 GPUCommon::DoState(p);
316
317 // TODO: Some of these things may not be necessary.
318 // None of these are necessary when saving.
319 if (p.mode == p.MODE_READ && !PSP_CoreParameter().frozen) {
320 textureCache_->Clear(true);
321 depalShaderCache_->Clear();
322 drawEngine_.ClearTrackedVertexArrays();
323
324 gstate_c.Dirty(DIRTY_TEXTURE_IMAGE);
325 framebufferManager_->DestroyAllFBOs();
326 }
327 }
328
DebugGetShaderIDs(DebugShaderType type)329 std::vector<std::string> GPU_D3D11::DebugGetShaderIDs(DebugShaderType type) {
330 switch (type) {
331 case SHADER_TYPE_VERTEXLOADER:
332 return drawEngine_.DebugGetVertexLoaderIDs();
333 case SHADER_TYPE_DEPAL:
334 return depalShaderCache_->DebugGetShaderIDs(type);
335 default:
336 return shaderManagerD3D11_->DebugGetShaderIDs(type);
337 }
338 }
339
DebugGetShaderString(std::string id,DebugShaderType type,DebugShaderStringType stringType)340 std::string GPU_D3D11::DebugGetShaderString(std::string id, DebugShaderType type, DebugShaderStringType stringType) {
341 switch (type) {
342 case SHADER_TYPE_VERTEXLOADER:
343 return drawEngine_.DebugGetVertexLoaderString(id, stringType);
344 case SHADER_TYPE_DEPAL:
345 return depalShaderCache_->DebugGetShaderString(id, type, stringType);
346 default:
347 return shaderManagerD3D11_->DebugGetShaderString(id, type, stringType);
348 }
349 }
350