#include "AndroidVulkanContext.h"
#include "Common/System/Display.h"
#include "Common/System/NativeApp.h"
#include "Common/System/System.h"
#include "Common/Log.h"
#include "Common/GPU/Vulkan/VulkanContext.h"
#include "Common/GPU/Vulkan/VulkanDebug.h"
#include "Common/GPU/Vulkan/VulkanLoader.h"
#include "Common/GPU/Vulkan/VulkanRenderManager.h"
#include "Common/GPU/thin3d_create.h"
#include "Common/Data/Text/Parsers.h"
#include "Core/Config.h"
#include "Core/ConfigValues.h"
#include "Core/System.h"
#include "GPU/Vulkan/VulkanUtil.h"
AndroidVulkanContext::AndroidVulkanContext() {}
AndroidVulkanContext::~AndroidVulkanContext() {
delete g_Vulkan;
g_Vulkan = nullptr;
}
bool AndroidVulkanContext::InitAPI() {
INFO_LOG(Log::G3D, "AndroidVulkanContext::Init");
init_glslang();
g_LogOptions.breakOnError = true;
g_LogOptions.breakOnWarning = true;
g_LogOptions.msgBoxOnError = false;
std::string errorStr;
if (!VulkanLoad(&errorStr)) {
ERROR_LOG(Log::G3D, "Failed to load Vulkan driver library: %s", errorStr.c_str());
state_ = GraphicsContextState::FAILED_INIT;
return false;
}
if (!g_Vulkan) {
INFO_LOG(Log::G3D, "Creating Vulkan context.");
g_Vulkan = new VulkanContext();
} else {
INFO_LOG(Log::G3D, "Reusing existing Vulkan context.");
}
VulkanContext::CreateInfo info{};
InitVulkanCreateInfoFromConfig(&info);
if (!g_Vulkan->CreateInstanceAndDevice(info)) {
delete g_Vulkan;
g_Vulkan = nullptr;
state_ = GraphicsContextState::FAILED_INIT;
return false;
}
INFO_LOG(Log::G3D, "Vulkan device created!");
state_ = GraphicsContextState::INITIALIZED;
return true;
}
bool AndroidVulkanContext::InitFromRenderThread(ANativeWindow *wnd, int desiredBackbufferSizeX, int desiredBackbufferSizeY, int backbufferFormat, int androidVersion) {
INFO_LOG(Log::G3D, "AndroidVulkanContext::InitFromRenderThread: desiredwidth=%d desiredheight=%d", desiredBackbufferSizeX, desiredBackbufferSizeY);
if (!g_Vulkan) {
ERROR_LOG(Log::G3D, "AndroidVulkanContext::InitFromRenderThread: No Vulkan context");
return false;
}
VkResult res = g_Vulkan->InitSurface(WINDOWSYSTEM_ANDROID, (void *)wnd, nullptr);
if (res != VK_SUCCESS) {
ERROR_LOG(Log::G3D, "g_Vulkan->InitSurface failed: '%s'", VulkanResultToString(res));
return false;
}
bool useMultiThreading = g_Config.bRenderMultiThreading;
if (g_Config.iInflightFrames == 1) {
useMultiThreading = false;
}
draw_ = Draw::T3DCreateVulkanContext(g_Vulkan, useMultiThreading);
VkPresentModeKHR presentMode = ConfigPresentModeToVulkan(draw_);
if (!g_Vulkan->InitSwapchain(presentMode)) {
g_Vulkan->DestroySurface();
return false;
}
SetGPUBackend(GPUBackend::VULKAN);
bool success = draw_->CreatePresets();
_assert_msg_(success, "Failed to compile preset shaders");
draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight());
VulkanRenderManager *renderManager = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
renderManager->SetInflightFrames(g_Config.iInflightFrames);
if (!renderManager->HasBackbuffers()) {
ERROR_LOG(Log::G3D, "VulkanRenderManager has no backbuffers after InitFromRenderThread");
g_Vulkan->DestroySwapchain();
g_Vulkan->DestroySurface();
delete draw_;
draw_ = nullptr;
return false;
}
INFO_LOG(Log::G3D, "AndroidVulkanContext::Init completed successfully");
return true;
}
void AndroidVulkanContext::ShutdownFromRenderThread() {
INFO_LOG(Log::G3D, "AndroidVulkanContext::Shutdown");
draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight());
delete draw_;
draw_ = nullptr;
g_Vulkan->WaitUntilQueueIdle();
g_Vulkan->PerformPendingDeletes();
g_Vulkan->DestroySwapchain();
g_Vulkan->DestroySurface();
INFO_LOG(Log::G3D, "Done with ShutdownFromRenderThread");
}
void AndroidVulkanContext::Shutdown() {
INFO_LOG(Log::G3D, "Calling NativeShutdownGraphics");
g_Vulkan->DestroyDevice();
g_Vulkan->DestroyInstance();
finalize_glslang();
INFO_LOG(Log::G3D, "AndroidVulkanContext::Shutdown completed");
}
void AndroidVulkanContext::Resize() {
INFO_LOG(Log::G3D, "AndroidVulkanContext::Resize begin (oldsize: %dx%d)", g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight());
draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight());
g_Vulkan->DestroySwapchain();
g_Vulkan->DestroySurface();
g_Vulkan->ReinitSurface();
VkPresentModeKHR presentMode = ConfigPresentModeToVulkan(draw_);
g_Vulkan->InitSwapchain(presentMode);
draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight());
INFO_LOG(Log::G3D, "AndroidVulkanContext::Resize end (final size: %dx%d)", g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight());
}