CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/Windows/GPU/WindowsVulkanContext.cpp
Views: 1401
// Copyright (c) 2015- PPSSPP Project.12// This program is free software: you can redistribute it and/or modify3// it under the terms of the GNU General Public License as published by4// the Free Software Foundation, version 2.0 or later versions.56// This program is distributed in the hope that it will be useful,7// but WITHOUT ANY WARRANTY; without even the implied warranty of8// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the9// GNU General Public License 2.0 for more details.1011// A copy of the GPL 2.0 should have been included with the program.12// If not, see http://www.gnu.org/licenses/1314// Official git repository and contact information can be found at15// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.161718// Initializing a Vulkan context is quite a complex task!19// That's not really a strange thing though - you really do have control over everything,20// and everything needs to be specified. There are no nebulous defaults.2122// We create a swapchain, and two framebuffers that we can point to two of the images23// we got from the swap chain. These will be used as backbuffers.24//25// We also create a depth buffer. The swap chain will not allocate one for us so we need26// to manage the memory for it ourselves.27// The depth buffer will not really be used unless we do "non-buffered" rendering, which will happen28// directly to one of the backbuffers.29//30// Render pass usage31//32// In normal buffered rendering mode, we do not begin the "UI" render pass until after we have rendered33// a frame of PSP graphics. The render pass that we will use then will be the simple "uiPass" that does not34// bother attaching the depth buffer, and discards all input (no need to even bother clearing as we will35// draw over the whole backbuffer anyway).36//37// However, in non-buffered, we will have to use the depth buffer, and we must begin the rendering pass38// before we start rendering PSP graphics, and end it only after we have completed rendering the UI on top.39// We will also use clearing.40//41// So it all turns into a single rendering pass, which might be good for performance on some GPUs, but it42// will complicate things a little.43//44// In a first iteration, we will not distinguish between these two cases - we will always create a depth buffer45// and use the same render pass configuration (clear to black). However, we can later change this so we switch46// to a non-clearing render pass in buffered mode, which might be a tiny bit faster.4748#include <crtdbg.h>49#include <sstream>5051#include "Core/Config.h"52#include "Core/ConfigValues.h"53#include "Core/System.h"54#include "Common/GPU/Vulkan/VulkanLoader.h"55#include "Common/GPU/Vulkan/VulkanContext.h"5657#include "Common/GPU/thin3d.h"58#include "Common/GPU/thin3d_create.h"59#include "Common/GPU/Vulkan/VulkanRenderManager.h"60#include "Common/Data/Text/Parsers.h"61#include "Windows/GPU/WindowsVulkanContext.h"6263#ifdef _DEBUG64static const bool g_validate_ = true;65#else66static const bool g_validate_ = false;67#endif6869static uint32_t FlagsFromConfig() {70uint32_t flags = 0;71flags = g_Config.bVSync ? VULKAN_FLAG_PRESENT_FIFO : VULKAN_FLAG_PRESENT_MAILBOX;72if (g_validate_) {73flags |= VULKAN_FLAG_VALIDATE;74}75return flags;76}7778bool WindowsVulkanContext::Init(HINSTANCE hInst, HWND hWnd, std::string *error_message) {79*error_message = "N/A";8081if (vulkan_) {82*error_message = "Already initialized";83return false;84}8586init_glslang();8788g_LogOptions.breakOnError = true;89g_LogOptions.breakOnWarning = true;90g_LogOptions.msgBoxOnError = false;9192Version gitVer(PPSSPP_GIT_VERSION);9394std::string errorStr;95if (!VulkanLoad(&errorStr)) {96*error_message = "Failed to load Vulkan driver library: ";97(*error_message) += errorStr;98return false;99}100101vulkan_ = new VulkanContext();102103VulkanContext::CreateInfo info{};104info.app_name = "PPSSPP";105info.app_ver = gitVer.ToInteger();106info.flags = FlagsFromConfig();107if (VK_SUCCESS != vulkan_->CreateInstance(info)) {108*error_message = vulkan_->InitError();109delete vulkan_;110vulkan_ = nullptr;111return false;112}113int deviceNum = vulkan_->GetPhysicalDeviceByName(g_Config.sVulkanDevice);114if (deviceNum < 0) {115deviceNum = vulkan_->GetBestPhysicalDevice();116if (!g_Config.sVulkanDevice.empty())117g_Config.sVulkanDevice = vulkan_->GetPhysicalDeviceProperties(deviceNum).properties.deviceName;118}119120if (vulkan_->CreateDevice(deviceNum) != VK_SUCCESS) {121*error_message = vulkan_->InitError();122delete vulkan_;123vulkan_ = nullptr;124return false;125}126127vulkan_->InitSurface(WINDOWSYSTEM_WIN32, (void *)hInst, (void *)hWnd);128if (!vulkan_->InitSwapchain()) {129*error_message = vulkan_->InitError();130Shutdown();131return false;132}133134bool useMultiThreading = g_Config.bRenderMultiThreading;135if (g_Config.iInflightFrames == 1) {136useMultiThreading = false;137}138139draw_ = Draw::T3DCreateVulkanContext(vulkan_, useMultiThreading);140SetGPUBackend(GPUBackend::VULKAN, vulkan_->GetPhysicalDeviceProperties(deviceNum).properties.deviceName);141bool success = draw_->CreatePresets();142_assert_msg_(success, "Failed to compile preset shaders");143draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight());144145renderManager_ = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);146renderManager_->SetInflightFrames(g_Config.iInflightFrames);147if (!renderManager_->HasBackbuffers()) {148Shutdown();149return false;150}151return true;152}153154void WindowsVulkanContext::Shutdown() {155if (draw_)156draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight());157158delete draw_;159draw_ = nullptr;160161vulkan_->WaitUntilQueueIdle();162vulkan_->DestroySwapchain();163vulkan_->DestroySurface();164vulkan_->DestroyDevice();165vulkan_->DestroyInstance();166167delete vulkan_;168vulkan_ = nullptr;169renderManager_ = nullptr;170171finalize_glslang();172}173174void WindowsVulkanContext::Resize() {175draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight());176vulkan_->DestroySwapchain();177vulkan_->UpdateFlags(FlagsFromConfig());178vulkan_->InitSwapchain();179draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight());180}181182void WindowsVulkanContext::Poll() {183// Check for existing swapchain to avoid issues during shutdown.184if (vulkan_->GetSwapchain() && renderManager_->NeedsSwapchainRecreate()) {185Resize();186}187}188189void *WindowsVulkanContext::GetAPIContext() {190return vulkan_;191}192193194