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