Android: Reduce asserts during startup.

This commit is contained in:
Henrik Rydgård 2020-07-28 19:06:29 +02:00
parent aebbff55f1
commit 73166def93
9 changed files with 124 additions and 74 deletions

View file

@ -803,29 +803,34 @@ static void UIThemeInit() {
}
void RenderOverlays(UIContext *dc, void *userdata);
bool CreateGlobalPipelines();
bool NativeInitGraphics(GraphicsContext *graphicsContext) {
ILOG("NativeInitGraphics");
_assert_msg_(graphicsContext, "No graphics context!");
// We set this now so any resize during init is processed later.
resized = false;
using namespace Draw;
Core_SetGraphicsContext(graphicsContext);
g_draw = graphicsContext->GetDrawContext();
_assert_msg_(g_draw, "No draw context available!");
_assert_msg_(g_draw->GetVshaderPreset(VS_COLOR_2D) != nullptr, "Failed to compile presets");
if (!CreateGlobalPipelines()) {
ERROR_LOG(G3D, "Failed to create global pipelines");
return false;
}
// Load the atlas.
size_t atlas_data_size = 0;
if (!g_ui_atlas.IsMetadataLoaded()) {
const uint8_t *atlas_data = VFSReadFile("ui_atlas.meta", &atlas_data_size);
bool load_success = atlas_data != nullptr && g_ui_atlas.Load(atlas_data, atlas_data_size);
_assert_msg_(load_success, "Failed to load ui_atlas.meta");
if (!load_success) {
ERROR_LOG(G3D, "Failed to load ui_atlas.meta - graphics will be broken.");
// Stumble along with broken visuals instead of dying.
}
delete[] atlas_data;
}
ui_draw2d.SetAtlas(&g_ui_atlas);
ui_draw2d_front.SetAtlas(&g_ui_atlas);
@ -834,43 +839,10 @@ bool NativeInitGraphics(GraphicsContext *graphicsContext) {
uiContext = new UIContext();
uiContext->theme = &ui_theme;
Draw::InputLayout *inputLayout = ui_draw2d.CreateInputLayout(g_draw);
Draw::BlendState *blendNormal = g_draw->CreateBlendState({ true, 0xF, BlendFactor::SRC_ALPHA, BlendFactor::ONE_MINUS_SRC_ALPHA });
Draw::DepthStencilState *depth = g_draw->CreateDepthStencilState({ false, false, Comparison::LESS });
Draw::RasterState *rasterNoCull = g_draw->CreateRasterState({});
PipelineDesc colorDesc{
Primitive::TRIANGLE_LIST,
{ g_draw->GetVshaderPreset(VS_COLOR_2D), g_draw->GetFshaderPreset(FS_COLOR_2D) },
inputLayout, depth, blendNormal, rasterNoCull, &vsColBufDesc,
};
PipelineDesc texColorDesc{
Primitive::TRIANGLE_LIST,
{ g_draw->GetVshaderPreset(VS_TEXTURE_COLOR_2D), g_draw->GetFshaderPreset(FS_TEXTURE_COLOR_2D) },
inputLayout, depth, blendNormal, rasterNoCull, &vsTexColBufDesc,
};
colorPipeline = g_draw->CreateGraphicsPipeline(colorDesc);
texColorPipeline = g_draw->CreateGraphicsPipeline(texColorDesc);
_assert_(colorPipeline);
_assert_(texColorPipeline);
// Release these now, reference counting should ensure that they get completely released
// once we delete both pipelines.
inputLayout->Release();
rasterNoCull->Release();
blendNormal->Release();
depth->Release();
ui_draw2d.Init(g_draw, texColorPipeline);
ui_draw2d_front.Init(g_draw, texColorPipeline);
uiContext->Init(g_draw, texColorPipeline, colorPipeline, &ui_draw2d, &ui_draw2d_front);
RasterStateDesc desc;
desc.cull = CullMode::NONE;
desc.frontFace = Facing::CCW;
if (uiContext->Text())
uiContext->Text()->SetFont("Tahoma", 20, 0);
@ -897,13 +869,54 @@ bool NativeInitGraphics(GraphicsContext *graphicsContext) {
g_gameInfoCache = new GameInfoCache();
if (gpu)
if (gpu) {
gpu->DeviceRestore();
}
ILOG("NativeInitGraphics completed");
return true;
}
bool CreateGlobalPipelines() {
using namespace Draw;
InputLayout *inputLayout = ui_draw2d.CreateInputLayout(g_draw);
BlendState *blendNormal = g_draw->CreateBlendState({ true, 0xF, BlendFactor::SRC_ALPHA, BlendFactor::ONE_MINUS_SRC_ALPHA });
DepthStencilState *depth = g_draw->CreateDepthStencilState({ false, false, Comparison::LESS });
RasterState *rasterNoCull = g_draw->CreateRasterState({});
PipelineDesc colorDesc{
Primitive::TRIANGLE_LIST,
{ g_draw->GetVshaderPreset(VS_COLOR_2D), g_draw->GetFshaderPreset(FS_COLOR_2D) },
inputLayout, depth, blendNormal, rasterNoCull, &vsColBufDesc,
};
PipelineDesc texColorDesc{
Primitive::TRIANGLE_LIST,
{ g_draw->GetVshaderPreset(VS_TEXTURE_COLOR_2D), g_draw->GetFshaderPreset(FS_TEXTURE_COLOR_2D) },
inputLayout, depth, blendNormal, rasterNoCull, &vsTexColBufDesc,
};
colorPipeline = g_draw->CreateGraphicsPipeline(colorDesc);
if (!colorPipeline) {
// Something really critical is wrong, don't care much about correct releasing of the states.
return false;
}
texColorPipeline = g_draw->CreateGraphicsPipeline(texColorDesc);
if (!texColorPipeline) {
// Something really critical is wrong, don't care much about correct releasing of the states.
return false;
}
// Release these now, reference counting should ensure that they get completely released
// once we delete both pipelines.
inputLayout->Release();
rasterNoCull->Release();
blendNormal->Release();
depth->Release();
return true;
}
void NativeShutdownGraphics() {
screenManager->deviceLost();
@ -912,12 +925,12 @@ void NativeShutdownGraphics() {
ILOG("NativeShutdownGraphics");
#ifdef _WIN32
#if PPSSPP_PLATFORM(WINDOWS)
delete winAudioBackend;
winAudioBackend = nullptr;
#endif
#if defined(_WIN32) && !PPSSPP_PLATFORM(UWP)
#if PPSSPP_PLATFORM(WINDOWS) && !PPSSPP_PLATFORM(UWP)
if (winCamera) {
winCamera->sendMessage({ CAPTUREDEVIDE_COMMAND::SHUTDOWN, nullptr });
while (!winCamera->isShutDown()) {};// Wait for shutting down.
@ -1086,7 +1099,7 @@ void NativeRender(GraphicsContext *graphicsContext) {
screenManager->resized();
// TODO: Move this to the GraphicsContext objects for each backend.
#if !defined(_WIN32) && !defined(ANDROID)
#if !PPSSPP_PLATFORM(WINDOWS) && !defined(ANDROID)
PSP_CoreParameter().pixelWidth = pixel_xres;
PSP_CoreParameter().pixelHeight = pixel_yres;
NativeMessageReceived("gpu_resized", "");
@ -1133,7 +1146,7 @@ void HandleGlobalMessage(const std::string &msg, const std::string &value) {
if (msg == "core_powerSaving") {
if (value != "false") {
auto sy = GetI18NCategory("System");
#ifdef __ANDROID__
#if PPSSPP_PLATFORM(ANDROID)
osm.Show(sy->T("WARNING: Android battery save mode is on"), 2.0f, 0xFFFFFF, -1, true, "core_powerSaving");
#else
osm.Show(sy->T("WARNING: Battery save mode is on"), 2.0f, 0xFFFFFF, -1, true, "core_powerSaving");
@ -1142,7 +1155,7 @@ void HandleGlobalMessage(const std::string &msg, const std::string &value) {
Core_SetPowerSaving(value != "false");
}
if (msg == "permission_granted" && value == "storage") {
#ifdef __ANDROID__
#if PPSSPP_PLATFORM(ANDROID)
CreateDirectoriesAndroid();
#endif
// We must have failed to load the config before, so load it now to avoid overwriting the old config

View file

@ -399,17 +399,23 @@ bool WindowsGLContext::InitFromRenderThread(std::string *error_message) {
pauseRequested = false;
resumeRequested = false;
CheckGLExtensions();
draw_ = Draw::T3DCreateGLContext();
bool success = draw_->CreatePresets(); // if we get this far, there will always be a GLSL compiler capable of compiling these.
if (!success) {
delete draw_;
draw_ = nullptr;
ReleaseGLContext();
return false;
}
// These are auto-reset events.
pauseEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
resumeEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
CheckGLExtensions();
draw_ = Draw::T3DCreateGLContext();
renderManager_ = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
renderManager_->SetInflightFrames(g_Config.iInflightFrames);
SetGPUBackend(GPUBackend::OPENGL);
bool success = draw_->CreatePresets(); // if we get this far, there will always be a GLSL compiler capable of compiling these.
_assert_msg_(success, "Failed to compile preset shaders");
renderManager_->SetSwapFunction([&]() {::SwapBuffers(hDC); });
if (wglSwapIntervalEXT) {
// glew loads wglSwapIntervalEXT if available
@ -430,14 +436,10 @@ void WindowsGLContext::Shutdown() {
glslang::FinalizeProcess();
}
void WindowsGLContext::ShutdownFromRenderThread() {
delete draw_;
draw_ = nullptr;
CloseHandle(pauseEvent);
CloseHandle(resumeEvent);
void WindowsGLContext::ReleaseGLContext() {
if (hRC) {
// Are we able to release the DC and RC contexts?
if (!wglMakeCurrent(NULL,NULL)) {
if (!wglMakeCurrent(NULL, NULL)) {
MessageBox(NULL, L"Release of DC and RC failed.", L"SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
}
@ -458,6 +460,14 @@ void WindowsGLContext::ShutdownFromRenderThread() {
hWnd_ = NULL;
}
void WindowsGLContext::ShutdownFromRenderThread() {
delete draw_;
draw_ = nullptr;
CloseHandle(pauseEvent);
CloseHandle(resumeEvent);
ReleaseGLContext();
}
void WindowsGLContext::Resize() {
}

View file

@ -34,6 +34,8 @@ public:
Draw::DrawContext *GetDrawContext() override { return draw_; }
private:
void ReleaseGLContext();
bool renderThread_;
Draw::DrawContext *draw_;
GLRenderManager *renderManager_;

View file

@ -4,6 +4,7 @@
#include "base/display.h"
#include "base/NativeApp.h"
#include "gfx_es2/gpu_features.h"
#include "Common/Log.h"
#include "Core/ConfigValues.h"
#include "Core/System.h"
@ -17,12 +18,11 @@ bool AndroidJavaEGLGraphicsContext::InitFromRenderThread(ANativeWindow *wnd, int
// OpenGL handles rotated rendering in the driver.
g_display_rotation = DisplayRotation::ROTATE_0;
g_display_rot_matrix.setIdentity();
draw_ = Draw::T3DCreateGLContext();
draw_ = Draw::T3DCreateGLContext(); // Can't fail
renderManager_ = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
renderManager_->SetInflightFrames(g_Config.iInflightFrames);
bool success = draw_->CreatePresets();
_assert_msg_(success, "Failed to compile preset shaders");
return success;
draw_->CreatePresets();
return true;
}
void AndroidJavaEGLGraphicsContext::ShutdownFromRenderThread() {

View file

@ -71,7 +71,6 @@ bool AndroidVulkanContext::InitAPI() {
}
g_Vulkan->ChooseDevice(physicalDevice);
// Here we can enable device extensions if we like.
ILOG("Creating Vulkan device");
if (g_Vulkan->CreateDevice() != VK_SUCCESS) {
@ -82,6 +81,7 @@ bool AndroidVulkanContext::InitAPI() {
g_Vulkan = nullptr;
return false;
}
ILOG("Vulkan device created!");
return true;
}

View file

@ -4,7 +4,6 @@
// It calls a set of methods defined in NativeApp.h. These should be implemented
// by your game or app.
#include <cassert>
#include <cstdlib>
#include <cstdint>
@ -594,7 +593,6 @@ retry:
ELOG("NativeApp.init(): iGPUBackend %d not supported. Switching to OpenGL.", (int)g_Config.iGPUBackend);
g_Config.iGPUBackend = (int)GPUBackend::OPENGL;
goto retry;
// Crash();
}
if (useCPUThread) {
@ -688,7 +686,7 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeApp_shutdown(JNIEnv *, jclass) {
}
// JavaEGL
extern "C" void Java_org_ppsspp_ppsspp_NativeRenderer_displayInit(JNIEnv * env, jobject obj) {
extern "C" bool Java_org_ppsspp_ppsspp_NativeRenderer_displayInit(JNIEnv * env, jobject obj) {
// We should be running on the render thread here.
std::string errorMessage;
if (renderer_inited) {
@ -712,21 +710,34 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeRenderer_displayInit(JNIEnv * env,
ILOG("Shut down both threads. Now let's bring it up again!");
graphicsContext->InitFromRenderThread(nullptr, 0, 0, 0, 0);
if (!graphicsContext->InitFromRenderThread(nullptr, 0, 0, 0, 0)) {
SystemToast("Graphics initialization failed. Quitting.");
return false;
}
if (useCPUThread) {
EmuThreadStart();
} else {
NativeInitGraphics(graphicsContext);
if (!NativeInitGraphics(graphicsContext)) {
// Gonna be in a weird state here, not good.
SystemToast("Failed to initialize graphics.");
return false;
}
}
graphicsContext->ThreadStart();
ILOG("Restored.");
} else {
ILOG("NativeApp.displayInit() first time");
graphicsContext->InitFromRenderThread(nullptr, 0, 0, 0, 0);
if (!graphicsContext->InitFromRenderThread(nullptr, 0, 0, 0, 0)) {
SystemToast("Graphics initialization failed. Quitting.");
return false;
}
graphicsContext->ThreadStart();
renderer_inited = true;
}
NativeMessageReceived("recreateviews", "");
return true;
}
static void recalculateDpi() {
@ -1156,6 +1167,11 @@ static void ProcessFrameCommands(JNIEnv *env) {
}
extern "C" bool JNICALL Java_org_ppsspp_ppsspp_NativeActivity_runEGLRenderLoop(JNIEnv *env, jobject obj, jobject _surf) {
if (!graphicsContext) {
ELOG("runEGLRenderLoop: Tried to enter without a created graphics context.");
return false;
}
// Needed for Vulkan, even if we're not using the old EGL path.
exitRenderLoop = false;
@ -1175,10 +1191,11 @@ extern "C" bool JNICALL Java_org_ppsspp_ppsspp_NativeActivity_runEGLRenderLoop(J
auto tryInit = [&]() {
if (graphicsContext->InitFromRenderThread(wnd, desiredBackbufferSizeX, desiredBackbufferSizeY, backbuffer_format, androidVersion)) {
return true;
} else {
ELOG("Failed to initialize graphics context.");
SystemToast("Failed to initialize graphics context.");
return false;
}
ELOG("Failed to initialize graphics context.");
return false;
};
bool initSuccess = tryInit();
@ -1202,7 +1219,10 @@ extern "C" bool JNICALL Java_org_ppsspp_ppsspp_NativeActivity_runEGLRenderLoop(J
if (!exitRenderLoop) {
if (!useCPUThread) {
NativeInitGraphics(graphicsContext);
if (!NativeInitGraphics(graphicsContext)) {
ELOG("Failed to initialize graphics.");
// Gonna be in a weird state here..
}
}
graphicsContext->ThreadStart();
renderer_inited = true;

View file

@ -616,6 +616,7 @@ public abstract class NativeActivity extends Activity {
@Override
protected void onDestroy() {
super.onDestroy();
Log.i(TAG, "onDestroy");
if (javaGL) {
if (nativeRenderer.isRenderingFrame()) {
Log.i(TAG, "Waiting for renderer to finish.");
@ -628,7 +629,6 @@ public abstract class NativeActivity extends Activity {
tries--;
} while (nativeRenderer.isRenderingFrame() && tries > 0);
}
Log.i(TAG, "onDestroy");
mGLSurfaceView.onDestroy();
mGLSurfaceView = null;
} else {

View file

@ -13,6 +13,7 @@ public class NativeRenderer implements GLSurfaceView.Renderer {
private static String TAG = "NativeRenderer";
private NativeActivity mActivity;
private boolean inFrame;
private boolean failed = false;
NativeRenderer(NativeActivity act) {
mActivity = act;
@ -21,6 +22,7 @@ public class NativeRenderer implements GLSurfaceView.Renderer {
public boolean isRenderingFrame() {
return inFrame;
}
public boolean hasFailedInit() { return failed; }
public void onDrawFrame(GL10 unused /*use GLES20*/) {
inFrame = true;
@ -29,6 +31,7 @@ public class NativeRenderer implements GLSurfaceView.Renderer {
}
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
failed = false;
Log.i(TAG, "NativeRenderer: onSurfaceCreated");
EGL10 egl = (EGL10)EGLContext.getEGL();
@ -49,7 +52,10 @@ public class NativeRenderer implements GLSurfaceView.Renderer {
}
// Log.i(TAG, "onSurfaceCreated - EGL context is new or was lost");
// Actually, it seems that it is here we should recreate lost GL objects.
displayInit();
if (!displayInit()) {
Log.e(TAG, "Display init failed");
failed = true;
}
}
public void onSurfaceChanged(GL10 unused, int width, int height) {
@ -57,7 +63,7 @@ public class NativeRenderer implements GLSurfaceView.Renderer {
// Note: This also means "device lost" and you should reload
// all buffered objects.
public native void displayInit();
public native boolean displayInit();
public native void displayRender();
}

View file

@ -3,7 +3,6 @@
#include <string>
#include <algorithm>
#include <map>
#include <cassert>
#include "base/logging.h"
#include "math/dataconv.h"