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