1 
2 // Copyright (c) 2015- PPSSPP Project.
3 
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, version 2.0 or later versions.
7 
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 // GNU General Public License 2.0 for more details.
12 
13 // A copy of the GPL 2.0 should have been included with the program.
14 // If not, see http://www.gnu.org/licenses/
15 
16 // Official git repository and contact information can be found at
17 // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
18 
19 #include <thread>
20 
21 #include "Common/Profiler/Profiler.h"
22 
23 #include "Common/Log.h"
24 #include "Common/File/FileUtil.h"
25 #include "Common/GraphicsContext.h"
26 #include "Common/Serialize/Serializer.h"
27 #include "Common/TimeUtil.h"
28 
29 #include "Core/Config.h"
30 #include "Core/Debugger/Breakpoints.h"
31 #include "Core/MemMapHelpers.h"
32 #include "Core/Reporting.h"
33 #include "Core/System.h"
34 #include "Core/ELF/ParamSFO.h"
35 
36 #include "GPU/GPUState.h"
37 #include "GPU/ge_constants.h"
38 #include "GPU/GeDisasm.h"
39 #include "GPU/Common/FramebufferManagerCommon.h"
40 #include "GPU/Debugger/Debugger.h"
41 #include "GPU/Vulkan/ShaderManagerVulkan.h"
42 #include "GPU/Vulkan/GPU_Vulkan.h"
43 #include "GPU/Vulkan/FramebufferManagerVulkan.h"
44 #include "GPU/Vulkan/DrawEngineVulkan.h"
45 #include "GPU/Vulkan/TextureCacheVulkan.h"
46 #include "Common/GPU/Vulkan/VulkanRenderManager.h"
47 #include "Common/GPU/Vulkan/VulkanQueueRunner.h"
48 
49 #include "Core/MIPS/MIPS.h"
50 #include "Core/HLE/sceKernelThread.h"
51 #include "Core/HLE/sceKernelInterrupt.h"
52 #include "Core/HLE/sceGe.h"
53 
GPU_Vulkan(GraphicsContext * gfxCtx,Draw::DrawContext * draw)54 GPU_Vulkan::GPU_Vulkan(GraphicsContext *gfxCtx, Draw::DrawContext *draw)
55 	: GPUCommon(gfxCtx, draw),
56 		vulkan_((VulkanContext *)gfxCtx->GetAPIContext()),
57 		depalShaderCache_(draw, vulkan_),
58 		drawEngine_(vulkan_, draw),
59 		vulkan2D_(vulkan_) {
60 	CheckGPUFeatures();
61 
62 	shaderManagerVulkan_ = new ShaderManagerVulkan(draw, vulkan_);
63 	pipelineManager_ = new PipelineManagerVulkan(vulkan_);
64 	framebufferManagerVulkan_ = new FramebufferManagerVulkan(draw, vulkan_);
65 	framebufferManager_ = framebufferManagerVulkan_;
66 	textureCacheVulkan_ = new TextureCacheVulkan(draw, vulkan_);
67 	textureCache_ = textureCacheVulkan_;
68 	drawEngineCommon_ = &drawEngine_;
69 	shaderManager_ = shaderManagerVulkan_;
70 
71 	drawEngine_.SetTextureCache(textureCacheVulkan_);
72 	drawEngine_.SetFramebufferManager(framebufferManagerVulkan_);
73 	drawEngine_.SetShaderManager(shaderManagerVulkan_);
74 	drawEngine_.SetPipelineManager(pipelineManager_);
75 	drawEngine_.Init();
76 	framebufferManagerVulkan_->SetVulkan2D(&vulkan2D_);
77 	framebufferManagerVulkan_->SetTextureCache(textureCacheVulkan_);
78 	framebufferManagerVulkan_->SetDrawEngine(&drawEngine_);
79 	framebufferManagerVulkan_->SetShaderManager(shaderManagerVulkan_);
80 	framebufferManagerVulkan_->Init();
81 	textureCacheVulkan_->SetDepalShaderCache(&depalShaderCache_);
82 	textureCacheVulkan_->SetFramebufferManager(framebufferManagerVulkan_);
83 	textureCacheVulkan_->SetShaderManager(shaderManagerVulkan_);
84 	textureCacheVulkan_->SetDrawEngine(&drawEngine_);
85 	textureCacheVulkan_->SetVulkan2D(&vulkan2D_);
86 
87 	InitDeviceObjects();
88 
89 	// Sanity check gstate
90 	if ((int *)&gstate.transferstart - (int *)&gstate != 0xEA) {
91 		ERROR_LOG(G3D, "gstate has drifted out of sync!");
92 	}
93 
94 	BuildReportingInfo();
95 	// Update again after init to be sure of any silly driver problems.
96 	UpdateVsyncInterval(true);
97 
98 	textureCacheVulkan_->NotifyConfigChanged();
99 	if (vulkan_->GetDeviceFeatures().enabled.wideLines) {
100 		drawEngine_.SetLineWidth(PSP_CoreParameter().renderWidth / 480.0f);
101 	}
102 
103 	// Load shader cache.
104 	std::string discID = g_paramSFO.GetDiscID();
105 	if (discID.size()) {
106 		File::CreateFullPath(GetSysDirectory(DIRECTORY_APP_CACHE));
107 		shaderCachePath_ = GetSysDirectory(DIRECTORY_APP_CACHE) / (discID + ".vkshadercache");
108 		shaderCacheLoaded_ = false;
109 
110 		std::thread th([&] {
111 			LoadCache(shaderCachePath_);
112 			shaderCacheLoaded_ = true;
113 		});
114 		th.detach();
115 	} else {
116 		shaderCacheLoaded_ = true;
117 	}
118 }
119 
IsReady()120 bool GPU_Vulkan::IsReady() {
121 	return shaderCacheLoaded_;
122 }
123 
CancelReady()124 void GPU_Vulkan::CancelReady() {
125 	pipelineManager_->CancelCache();
126 }
127 
LoadCache(const Path & filename)128 void GPU_Vulkan::LoadCache(const Path &filename) {
129 	PSP_SetLoading("Loading shader cache...");
130 	// Actually precompiled by IsReady() since we're single-threaded.
131 	FILE *f = File::OpenCFile(filename, "rb");
132 	if (!f)
133 		return;
134 
135 	// First compile shaders to SPIR-V, then load the pipeline cache and recreate the pipelines.
136 	// It's when recreating the pipelines that the pipeline cache is useful - in the ideal case,
137 	// it can just memcpy the finished shader binaries out of the pipeline cache file.
138 	bool result = shaderManagerVulkan_->LoadCache(f);
139 	if (result) {
140 		// WARNING: See comment in LoadCache if you are tempted to flip the second parameter to true.
141 		result = pipelineManager_->LoadCache(f, false, shaderManagerVulkan_, draw_, drawEngine_.GetPipelineLayout());
142 	}
143 	fclose(f);
144 	if (!result) {
145 		WARN_LOG(G3D, "Incompatible Vulkan pipeline cache - rebuilding.");
146 		// Bad cache file for this GPU/Driver/etc. Delete it.
147 		File::Delete(filename);
148 	} else {
149 		INFO_LOG(G3D, "Loaded Vulkan pipeline cache.");
150 	}
151 }
152 
SaveCache(const Path & filename)153 void GPU_Vulkan::SaveCache(const Path &filename) {
154 	if (!draw_) {
155 		// Already got the lost message, we're in shutdown.
156 		WARN_LOG(G3D, "Not saving shaders - shutting down from in-game.");
157 		return;
158 	}
159 
160 	FILE *f = File::OpenCFile(filename, "wb");
161 	if (!f)
162 		return;
163 	shaderManagerVulkan_->SaveCache(f);
164 	// WARNING: See comment in LoadCache if you are tempted to flip the second parameter to true.
165 	pipelineManager_->SaveCache(f, false, shaderManagerVulkan_, draw_);
166 	INFO_LOG(G3D, "Saved Vulkan pipeline cache");
167 	fclose(f);
168 }
169 
~GPU_Vulkan()170 GPU_Vulkan::~GPU_Vulkan() {
171 	SaveCache(shaderCachePath_);
172 	// Note: We save the cache in DeviceLost
173 	DestroyDeviceObjects();
174 	framebufferManagerVulkan_->DestroyAllFBOs();
175 	depalShaderCache_.Clear();
176 	depalShaderCache_.DeviceLost();
177 	drawEngine_.DeviceLost();
178 	vulkan2D_.Shutdown();
179 	delete textureCacheVulkan_;
180 	delete pipelineManager_;
181 	delete shaderManagerVulkan_;
182 	delete framebufferManagerVulkan_;
183 }
184 
CheckGPUFeatures()185 void GPU_Vulkan::CheckGPUFeatures() {
186 	uint32_t features = 0;
187 
188 	if (!PSP_CoreParameter().compat.flags().DisableRangeCulling) {
189 		features |= GPU_SUPPORTS_VS_RANGE_CULLING;
190 	}
191 
192 	switch (vulkan_->GetPhysicalDeviceProperties().properties.vendorID) {
193 	case VULKAN_VENDOR_AMD:
194 		// Accurate depth is required on AMD (due to reverse-Z driver bug) so we ignore the compat flag to disable it on those. See #9545
195 		features |= GPU_SUPPORTS_ACCURATE_DEPTH;
196 		break;
197 	case VULKAN_VENDOR_QUALCOMM:
198 		// Accurate depth is required on Adreno too (seems to also have a reverse-Z driver bug).
199 		features |= GPU_SUPPORTS_ACCURATE_DEPTH;
200 		break;
201 	case VULKAN_VENDOR_ARM:
202 	{
203 		// This check is probably not exactly accurate. But old drivers had problems with reverse-Z, just like AMD and Qualcomm.
204 		bool driverTooOld = IsHashMaliDriverVersion(vulkan_->GetPhysicalDeviceProperties().properties)
205 			|| VK_VERSION_MAJOR(vulkan_->GetPhysicalDeviceProperties().properties.driverVersion) < 14;
206 		if (!PSP_CoreParameter().compat.flags().DisableAccurateDepth || driverTooOld) {
207 			features |= GPU_SUPPORTS_ACCURATE_DEPTH;
208 		}
209 		// These GPUs (up to some certain hardware version?) has a bug where draws where gl_Position.w == .z
210 		// corrupt the depth buffer. This is easily worked around by simply scaling Z down a tiny bit when this case
211 		// is detected. See: https://github.com/hrydgard/ppsspp/issues/11937
212 		features |= GPU_NEEDS_Z_EQUAL_W_HACK;
213 		break;
214 	}
215 	default:
216 		if (!PSP_CoreParameter().compat.flags().DisableAccurateDepth) {
217 			features |= GPU_SUPPORTS_ACCURATE_DEPTH;
218 		}
219 		break;
220 	}
221 
222 	// Might enable this later - in the first round we are mostly looking at depth/stencil/discard.
223 	// if (!g_Config.bEnableVendorBugChecks)
224 	// 	features |= GPU_SUPPORTS_ACCURATE_DEPTH;
225 
226 	// Mandatory features on Vulkan, which may be checked in "centralized" code
227 	features |= GPU_SUPPORTS_TEXTURE_LOD_CONTROL;
228 	features |= GPU_SUPPORTS_FRAMEBUFFER_BLIT;
229 	features |= GPU_SUPPORTS_BLEND_MINMAX;
230 	features |= GPU_SUPPORTS_COPY_IMAGE;
231 	features |= GPU_SUPPORTS_TEXTURE_NPOT;
232 	features |= GPU_SUPPORTS_INSTANCE_RENDERING;
233 	features |= GPU_SUPPORTS_VERTEX_TEXTURE_FETCH;
234 	features |= GPU_SUPPORTS_TEXTURE_FLOAT;
235 	features |= GPU_SUPPORTS_DEPTH_TEXTURE;
236 
237 	if (vulkan_->GetDeviceInfo().canBlitToPreferredDepthStencilFormat) {
238 		features |= GPU_SUPPORTS_FRAMEBUFFER_BLIT_TO_DEPTH;
239 	}
240 
241 	if (vulkan_->GetDeviceFeatures().enabled.wideLines) {
242 		features |= GPU_SUPPORTS_WIDE_LINES;
243 	}
244 	if (vulkan_->GetDeviceFeatures().enabled.depthClamp) {
245 		features |= GPU_SUPPORTS_DEPTH_CLAMP;
246 	}
247 	if (vulkan_->GetDeviceFeatures().enabled.dualSrcBlend) {
248 		if (!g_Config.bVendorBugChecksEnabled || !draw_->GetBugs().Has(Draw::Bugs::DUAL_SOURCE_BLENDING_BROKEN)) {
249 			features |= GPU_SUPPORTS_DUALSOURCE_BLEND;
250 		}
251 	}
252 	if (vulkan_->GetDeviceFeatures().enabled.logicOp) {
253 		features |= GPU_SUPPORTS_LOGIC_OP;
254 	}
255 	if (vulkan_->GetDeviceFeatures().enabled.samplerAnisotropy) {
256 		features |= GPU_SUPPORTS_ANISOTROPY;
257 	}
258 
259 	// These are VULKAN_4444_FORMAT and friends.
260 	uint32_t fmt4444 = draw_->GetDataFormatSupport(Draw::DataFormat::B4G4R4A4_UNORM_PACK16);
261 	uint32_t fmt1555 = draw_->GetDataFormatSupport(Draw::DataFormat::A1R5G5B5_UNORM_PACK16);
262 
263 	// Note that we are (accidentally) using B5G6R5 instead of the mandatory R5G6B5.
264 	// Support is almost as widespread, but not quite. So let's just not use any 16-bit formats
265 	// if it's not available, for simplicity.
266 	uint32_t fmt565 = draw_->GetDataFormatSupport(Draw::DataFormat::B5G6R5_UNORM_PACK16);
267 	if ((fmt4444 & Draw::FMT_TEXTURE) && (fmt565 & Draw::FMT_TEXTURE) && (fmt1555 & Draw::FMT_TEXTURE)) {
268 		features |= GPU_SUPPORTS_16BIT_FORMATS;
269 	} else {
270 		INFO_LOG(G3D, "Deficient texture format support: 4444: %d  1555: %d  565: %d", fmt4444, fmt1555, fmt565);
271 	}
272 
273 	if (PSP_CoreParameter().compat.flags().ClearToRAM) {
274 		features |= GPU_USE_CLEAR_RAM_HACK;
275 	}
276 
277 	if (!g_Config.bHighQualityDepth && (features & GPU_SUPPORTS_ACCURATE_DEPTH) != 0) {
278 		features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT;
279 	}
280 	else if (PSP_CoreParameter().compat.flags().PixelDepthRounding) {
281 		// Use fragment rounding on desktop and GLES3, most accurate.
282 		features |= GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT;
283 	}
284 	else if (PSP_CoreParameter().compat.flags().VertexDepthRounding) {
285 		features |= GPU_ROUND_DEPTH_TO_16BIT;
286 	}
287 
288 	gstate_c.featureFlags = features;
289 }
290 
BeginHostFrame()291 void GPU_Vulkan::BeginHostFrame() {
292 	drawEngine_.BeginFrame();
293 	UpdateCmdInfo();
294 
295 	if (resized_) {
296 		CheckGPUFeatures();
297 		// In case the GPU changed.
298 		BuildReportingInfo();
299 		framebufferManager_->Resized();
300 		drawEngine_.Resized();
301 		textureCacheVulkan_->NotifyConfigChanged();
302 		if (vulkan_->GetDeviceFeatures().enabled.wideLines) {
303 			drawEngine_.SetLineWidth(PSP_CoreParameter().renderWidth / 480.0f);
304 		}
305 		resized_ = false;
306 	}
307 
308 	textureCacheVulkan_->StartFrame();
309 
310 	int curFrame = vulkan_->GetCurFrame();
311 	FrameData &frame = frameData_[curFrame];
312 
313 	frame.push_->Reset();
314 	frame.push_->Begin(vulkan_);
315 
316 	framebufferManagerVulkan_->BeginFrameVulkan();
317 	framebufferManagerVulkan_->SetPushBuffer(frameData_[curFrame].push_);
318 	depalShaderCache_.SetPushBuffer(frameData_[curFrame].push_);
319 	textureCacheVulkan_->SetPushBuffer(frameData_[curFrame].push_);
320 
321 	vulkan2D_.BeginFrame();
322 
323 	shaderManagerVulkan_->DirtyShader();
324 	gstate_c.Dirty(DIRTY_ALL);
325 
326 	if (dumpNextFrame_) {
327 		NOTICE_LOG(G3D, "DUMPING THIS FRAME");
328 		dumpThisFrame_ = true;
329 		dumpNextFrame_ = false;
330 	} else if (dumpThisFrame_) {
331 		dumpThisFrame_ = false;
332 	}
333 }
334 
EndHostFrame()335 void GPU_Vulkan::EndHostFrame() {
336 	int curFrame = vulkan_->GetCurFrame();
337 	FrameData &frame = frameData_[curFrame];
338 	frame.push_->End();
339 
340 	vulkan2D_.EndFrame();
341 
342 	drawEngine_.EndFrame();
343 	framebufferManagerVulkan_->EndFrame();
344 	textureCacheVulkan_->EndFrame();
345 
346 	draw_->InvalidateCachedState();
347 }
348 
349 // Needs to be called on GPU thread, not reporting thread.
BuildReportingInfo()350 void GPU_Vulkan::BuildReportingInfo() {
351 	const auto &props = vulkan_->GetPhysicalDeviceProperties().properties;
352 	const auto &features = vulkan_->GetDeviceFeatures().available;
353 
354 #define CHECK_BOOL_FEATURE(n) do { if (features.n) { featureNames += ", " #n; } } while (false)
355 
356 	std::string featureNames = "";
357 	CHECK_BOOL_FEATURE(robustBufferAccess);
358 	CHECK_BOOL_FEATURE(fullDrawIndexUint32);
359 	CHECK_BOOL_FEATURE(imageCubeArray);
360 	CHECK_BOOL_FEATURE(independentBlend);
361 	CHECK_BOOL_FEATURE(geometryShader);
362 	CHECK_BOOL_FEATURE(tessellationShader);
363 	CHECK_BOOL_FEATURE(sampleRateShading);
364 	CHECK_BOOL_FEATURE(dualSrcBlend);
365 	CHECK_BOOL_FEATURE(logicOp);
366 	CHECK_BOOL_FEATURE(multiDrawIndirect);
367 	CHECK_BOOL_FEATURE(drawIndirectFirstInstance);
368 	CHECK_BOOL_FEATURE(depthClamp);
369 	CHECK_BOOL_FEATURE(depthBiasClamp);
370 	CHECK_BOOL_FEATURE(fillModeNonSolid);
371 	CHECK_BOOL_FEATURE(depthBounds);
372 	CHECK_BOOL_FEATURE(wideLines);
373 	CHECK_BOOL_FEATURE(largePoints);
374 	CHECK_BOOL_FEATURE(alphaToOne);
375 	CHECK_BOOL_FEATURE(multiViewport);
376 	CHECK_BOOL_FEATURE(samplerAnisotropy);
377 	CHECK_BOOL_FEATURE(textureCompressionETC2);
378 	CHECK_BOOL_FEATURE(textureCompressionASTC_LDR);
379 	CHECK_BOOL_FEATURE(textureCompressionBC);
380 	CHECK_BOOL_FEATURE(occlusionQueryPrecise);
381 	CHECK_BOOL_FEATURE(pipelineStatisticsQuery);
382 	CHECK_BOOL_FEATURE(vertexPipelineStoresAndAtomics);
383 	CHECK_BOOL_FEATURE(fragmentStoresAndAtomics);
384 	CHECK_BOOL_FEATURE(shaderTessellationAndGeometryPointSize);
385 	CHECK_BOOL_FEATURE(shaderImageGatherExtended);
386 	CHECK_BOOL_FEATURE(shaderStorageImageExtendedFormats);
387 	CHECK_BOOL_FEATURE(shaderStorageImageMultisample);
388 	CHECK_BOOL_FEATURE(shaderStorageImageReadWithoutFormat);
389 	CHECK_BOOL_FEATURE(shaderStorageImageWriteWithoutFormat);
390 	CHECK_BOOL_FEATURE(shaderUniformBufferArrayDynamicIndexing);
391 	CHECK_BOOL_FEATURE(shaderSampledImageArrayDynamicIndexing);
392 	CHECK_BOOL_FEATURE(shaderStorageBufferArrayDynamicIndexing);
393 	CHECK_BOOL_FEATURE(shaderStorageImageArrayDynamicIndexing);
394 	CHECK_BOOL_FEATURE(shaderClipDistance);
395 	CHECK_BOOL_FEATURE(shaderCullDistance);
396 	CHECK_BOOL_FEATURE(shaderFloat64);
397 	CHECK_BOOL_FEATURE(shaderInt64);
398 	CHECK_BOOL_FEATURE(shaderInt16);
399 	CHECK_BOOL_FEATURE(shaderResourceResidency);
400 	CHECK_BOOL_FEATURE(shaderResourceMinLod);
401 	CHECK_BOOL_FEATURE(sparseBinding);
402 	CHECK_BOOL_FEATURE(sparseResidencyBuffer);
403 	CHECK_BOOL_FEATURE(sparseResidencyImage2D);
404 	CHECK_BOOL_FEATURE(sparseResidencyImage3D);
405 	CHECK_BOOL_FEATURE(sparseResidency2Samples);
406 	CHECK_BOOL_FEATURE(sparseResidency4Samples);
407 	CHECK_BOOL_FEATURE(sparseResidency8Samples);
408 	CHECK_BOOL_FEATURE(sparseResidency16Samples);
409 	CHECK_BOOL_FEATURE(sparseResidencyAliased);
410 	CHECK_BOOL_FEATURE(variableMultisampleRate);
411 	CHECK_BOOL_FEATURE(inheritedQueries);
412 
413 #undef CHECK_BOOL_FEATURE
414 
415 	if (!featureNames.empty()) {
416 		featureNames = featureNames.substr(2);
417 	}
418 
419 	char temp[16384];
420 	snprintf(temp, sizeof(temp), "v%08x driver v%08x (%s), vendorID=%d, deviceID=%d (features: %s)", props.apiVersion, props.driverVersion, props.deviceName, props.vendorID, props.deviceID, featureNames.c_str());
421 	reportingPrimaryInfo_ = props.deviceName;
422 	reportingFullInfo_ = temp;
423 
424 	Reporting::UpdateConfig();
425 }
426 
Reinitialize()427 void GPU_Vulkan::Reinitialize() {
428 	GPUCommon::Reinitialize();
429 	depalShaderCache_.Clear();
430 }
431 
InitClear()432 void GPU_Vulkan::InitClear() {
433 	if (!framebufferManager_->UseBufferedRendering()) {
434 		// TODO?
435 	}
436 }
437 
SetDisplayFramebuffer(u32 framebuf,u32 stride,GEBufferFormat format)438 void GPU_Vulkan::SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format) {
439 	GPUDebug::NotifyDisplay(framebuf, stride, format);
440 	framebufferManager_->SetDisplayFramebuffer(framebuf, stride, format);
441 }
442 
CopyDisplayToOutput(bool reallyDirty)443 void GPU_Vulkan::CopyDisplayToOutput(bool reallyDirty) {
444 	// Flush anything left over.
445 	drawEngine_.Flush();
446 
447 	shaderManagerVulkan_->DirtyLastShader();
448 
449 	framebufferManagerVulkan_->CopyDisplayToOutput(reallyDirty);
450 
451 	gstate_c.Dirty(DIRTY_TEXTURE_IMAGE);
452 }
453 
FinishDeferred()454 void GPU_Vulkan::FinishDeferred() {
455 	drawEngine_.FinishDeferred();
456 }
457 
CheckFlushOp(int cmd,u32 diff)458 inline void GPU_Vulkan::CheckFlushOp(int cmd, u32 diff) {
459 	const u8 cmdFlags = cmdInfo_[cmd].flags;
460 	if (diff && (cmdFlags & FLAG_FLUSHBEFOREONCHANGE)) {
461 		if (dumpThisFrame_) {
462 			NOTICE_LOG(G3D, "================ FLUSH ================");
463 		}
464 		drawEngine_.Flush();
465 	}
466 }
467 
PreExecuteOp(u32 op,u32 diff)468 void GPU_Vulkan::PreExecuteOp(u32 op, u32 diff) {
469 	CheckFlushOp(op >> 24, diff);
470 }
471 
ExecuteOp(u32 op,u32 diff)472 void GPU_Vulkan::ExecuteOp(u32 op, u32 diff) {
473 	const u8 cmd = op >> 24;
474 	const CommandInfo info = cmdInfo_[cmd];
475 	const u8 cmdFlags = info.flags;
476 	if ((cmdFlags & FLAG_EXECUTE) || (diff && (cmdFlags & FLAG_EXECUTEONCHANGE))) {
477 		(this->*info.func)(op, diff);
478 	} else if (diff) {
479 		uint64_t dirty = info.flags >> 8;
480 		if (dirty)
481 			gstate_c.Dirty(dirty);
482 	}
483 }
484 
InitDeviceObjects()485 void GPU_Vulkan::InitDeviceObjects() {
486 	INFO_LOG(G3D, "GPU_Vulkan::InitDeviceObjects");
487 	// Initialize framedata
488 	for (int i = 0; i < VulkanContext::MAX_INFLIGHT_FRAMES; i++) {
489 		_assert_(!frameData_[i].push_);
490 		VkBufferUsageFlags usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
491 		frameData_[i].push_ = new VulkanPushBuffer(vulkan_, 64 * 1024, usage);
492 	}
493 
494 	VulkanRenderManager *rm = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
495 	uint32_t hacks = 0;
496 	if (PSP_CoreParameter().compat.flags().MGS2AcidHack)
497 		hacks |= QUEUE_HACK_MGS2_ACID;
498 	if (PSP_CoreParameter().compat.flags().SonicRivalsHack)
499 		hacks |= QUEUE_HACK_SONIC;
500 
501 	// Always on.
502 	hacks |= QUEUE_HACK_RENDERPASS_MERGE;
503 
504 	if (hacks) {
505 		rm->GetQueueRunner()->EnableHacks(hacks);
506 	}
507 }
508 
DestroyDeviceObjects()509 void GPU_Vulkan::DestroyDeviceObjects() {
510 	INFO_LOG(G3D, "GPU_Vulkan::DestroyDeviceObjects");
511 	for (int i = 0; i < VulkanContext::MAX_INFLIGHT_FRAMES; i++) {
512 		if (frameData_[i].push_) {
513 			frameData_[i].push_->Destroy(vulkan_);
514 			delete frameData_[i].push_;
515 			frameData_[i].push_ = nullptr;
516 		}
517 	}
518 
519 	// Need to turn off hacks when shutting down the GPU. Don't want them running in the menu.
520 	if (draw_) {
521 		VulkanRenderManager *rm = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
522 		if (rm)
523 			rm->GetQueueRunner()->EnableHacks(0);
524 	}
525 }
526 
DeviceLost()527 void GPU_Vulkan::DeviceLost() {
528 	CancelReady();
529 	while (!IsReady()) {
530 		sleep_ms(10);
531 	}
532 	if (shaderCachePath_.Valid()) {
533 		SaveCache(shaderCachePath_);
534 	}
535 	DestroyDeviceObjects();
536 	vulkan2D_.DeviceLost();
537 	drawEngine_.DeviceLost();
538 	pipelineManager_->DeviceLost();
539 	textureCacheVulkan_->DeviceLost();
540 	depalShaderCache_.DeviceLost();
541 	shaderManagerVulkan_->ClearShaders();
542 
543 	GPUCommon::DeviceLost();
544 }
545 
DeviceRestore()546 void GPU_Vulkan::DeviceRestore() {
547 	GPUCommon::DeviceRestore();
548 	vulkan_ = (VulkanContext *)PSP_CoreParameter().graphicsContext->GetAPIContext();
549 	InitDeviceObjects();
550 
551 	CheckGPUFeatures();
552 	BuildReportingInfo();
553 	UpdateCmdInfo();
554 
555 	vulkan2D_.DeviceRestore(vulkan_);
556 	drawEngine_.DeviceRestore(vulkan_, draw_);
557 	pipelineManager_->DeviceRestore(vulkan_);
558 	textureCacheVulkan_->DeviceRestore(vulkan_, draw_);
559 	shaderManagerVulkan_->DeviceRestore(vulkan_, draw_);
560 	depalShaderCache_.DeviceRestore(draw_, vulkan_);
561 }
562 
GetStats(char * buffer,size_t bufsize)563 void GPU_Vulkan::GetStats(char *buffer, size_t bufsize) {
564 	size_t offset = FormatGPUStatsCommon(buffer, bufsize);
565 	buffer += offset;
566 	bufsize -= offset;
567 	if ((int)bufsize < 0)
568 		return;
569 	const DrawEngineVulkanStats &drawStats = drawEngine_.GetStats();
570 	char texStats[256];
571 	textureCacheVulkan_->GetStats(texStats, sizeof(texStats));
572 	snprintf(buffer, bufsize,
573 		"Vertex, Fragment, Pipelines loaded: %i, %i, %i\n"
574 		"Pushbuffer space used: UBO %d, Vtx %d, Idx %d\n"
575 		"%s\n",
576 		shaderManagerVulkan_->GetNumVertexShaders(),
577 		shaderManagerVulkan_->GetNumFragmentShaders(),
578 		pipelineManager_->GetNumPipelines(),
579 		drawStats.pushUBOSpaceUsed,
580 		drawStats.pushVertexSpaceUsed,
581 		drawStats.pushIndexSpaceUsed,
582 		texStats
583 	);
584 }
585 
ClearCacheNextFrame()586 void GPU_Vulkan::ClearCacheNextFrame() {
587 	textureCacheVulkan_->ClearNextFrame();
588 }
589 
ClearShaderCache()590 void GPU_Vulkan::ClearShaderCache() {
591 	// TODO
592 }
593 
DoState(PointerWrap & p)594 void GPU_Vulkan::DoState(PointerWrap &p) {
595 	GPUCommon::DoState(p);
596 
597 	// TODO: Some of these things may not be necessary.
598 	// None of these are necessary when saving.
599 	// In Freeze-Frame mode, we don't want to do any of this.
600 	if (p.mode == p.MODE_READ && !PSP_CoreParameter().frozen) {
601 		textureCache_->Clear(true);
602 		depalShaderCache_.Clear();
603 
604 		gstate_c.Dirty(DIRTY_TEXTURE_IMAGE);
605 		framebufferManager_->DestroyAllFBOs();
606 	}
607 }
608 
DebugGetShaderIDs(DebugShaderType type)609 std::vector<std::string> GPU_Vulkan::DebugGetShaderIDs(DebugShaderType type) {
610 	if (type == SHADER_TYPE_VERTEXLOADER) {
611 		return drawEngine_.DebugGetVertexLoaderIDs();
612 	} else if (type == SHADER_TYPE_PIPELINE) {
613 		return pipelineManager_->DebugGetObjectIDs(type);
614 	} else if (type == SHADER_TYPE_DEPAL) {
615 		///...
616 		return std::vector<std::string>();
617 	} else if (type == SHADER_TYPE_VERTEX || type == SHADER_TYPE_FRAGMENT) {
618 		return shaderManagerVulkan_->DebugGetShaderIDs(type);
619 	} else if (type == SHADER_TYPE_SAMPLER) {
620 		return textureCacheVulkan_->DebugGetSamplerIDs();
621 	} else {
622 		return std::vector<std::string>();
623 	}
624 }
625 
DebugGetShaderString(std::string id,DebugShaderType type,DebugShaderStringType stringType)626 std::string GPU_Vulkan::DebugGetShaderString(std::string id, DebugShaderType type, DebugShaderStringType stringType) {
627 	if (type == SHADER_TYPE_VERTEXLOADER) {
628 		return drawEngine_.DebugGetVertexLoaderString(id, stringType);
629 	} else if (type == SHADER_TYPE_PIPELINE) {
630 		return pipelineManager_->DebugGetObjectString(id, type, stringType);
631 	} else if (type == SHADER_TYPE_DEPAL) {
632 		return "";
633 	} else if (type == SHADER_TYPE_SAMPLER) {
634 		return textureCacheVulkan_->DebugGetSamplerString(id, stringType);
635 	} else if (type == SHADER_TYPE_VERTEX || type == SHADER_TYPE_FRAGMENT) {
636 		return shaderManagerVulkan_->DebugGetShaderString(id, type, stringType);
637 	} else {
638 		return std::string();
639 	}
640 }
641 
GetGpuProfileString()642 std::string GPU_Vulkan::GetGpuProfileString() {
643 	VulkanRenderManager *rm = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
644 	return rm->GetGpuProfileString();
645 }
646