Implement resume behaviour for mobile stk

This commit is contained in:
Benau 2022-04-02 13:33:08 +08:00
parent 4d2c65ade9
commit 067ac4fe01
9 changed files with 160 additions and 23 deletions

View File

@ -84,6 +84,8 @@ public class SuperTuxKartActivity extends SDLActivity
// ------------------------------------------------------------------------
private native static void addDNSSrvRecords(String name, int weight);
// ------------------------------------------------------------------------
private native static void pauseRenderingJNI();
// ------------------------------------------------------------------------
private void showExtractProgressPrivate()
{
WindowManager wm =
@ -283,6 +285,8 @@ public class SuperTuxKartActivity extends SDLActivity
{
super.onPause();
hideKeyboardNative(false/*clear_text*/);
if (SDLActivity.mSDLThread != null)
pauseRenderingJNI();
}
// ------------------------------------------------------------------------
/* SDL manually dlopen main to allow unload after main thread exit. */

View File

@ -318,6 +318,8 @@ namespace GE
void getRotatedViewport(VkViewport* vp);
const core::matrix4& getPreRotationMatrix()
{ return m_pre_rotation_matrix; }
virtual void pauseRendering();
virtual void unpauseRendering();
private:
struct SwapChainSupportDetails
{
@ -383,7 +385,8 @@ namespace GE
{
for (VkFramebuffer& framebuffer : swap_chain_framebuffers)
vkDestroyFramebuffer(device, framebuffer, NULL);
vkDestroyRenderPass(device, render_pass, NULL);
if (render_pass != VK_NULL_HANDLE)
vkDestroyRenderPass(device, render_pass, NULL);
for (unsigned i = 0; i < GVS_COUNT; i++)
vkDestroySampler(device, samplers[i], NULL);
if (!command_buffers.empty())
@ -438,6 +441,8 @@ namespace GE
video::ITexture* m_white_texture;
video::ITexture* m_transparent_texture;
SDL_Window* m_window;
void createInstance(SDL_Window* window);
void findPhysicalDevice();
bool checkDeviceExtensions(VkPhysicalDevice device);
@ -458,6 +463,8 @@ namespace GE
void initPreRotationMatrix();
std::string getVulkanVersionString() const;
std::string getDriverVersionString() const;
void destroySwapChainRelated(bool handle_surface);
void createSwapChainRelated(bool handle_surface);
};
}

View File

@ -545,11 +545,17 @@ end_cmd:
vkEndCommandBuffer(g_vk->getCurrentCommandBuffer());
end:
clear();
} // render
// ----------------------------------------------------------------------------
void GEVulkan2dRenderer::clear()
{
g_tex_map.clear();
g_tris_queue.clear();
g_tris_index_queue.clear();
g_tris_clip.clear();
} // render
} // clear
// ----------------------------------------------------------------------------
void GEVulkan2dRenderer::addVerticesIndices(irr::video::S3DVertex* vertices,

View File

@ -30,6 +30,8 @@ void createTrisBuffers();
// ----------------------------------------------------------------------------
void render();
// ----------------------------------------------------------------------------
void clear();
// ----------------------------------------------------------------------------
void addVerticesIndices(irr::video::S3DVertex* vertices,
unsigned vertices_count, uint16_t* indices,
unsigned indices_count,

View File

@ -9,11 +9,11 @@
#ifdef _IRR_COMPILE_WITH_VULKAN_
#include "SDL_vulkan.h"
#include <algorithm>
#include <atomic>
#include <limits>
#include <set>
#include <sstream>
#include <stdexcept>
#include "../source/Irrlicht/os.h"
#if !defined(__APPLE__) || defined(DLOPEN_MOLTENVK)
@ -443,6 +443,10 @@ extern "C" PFN_vkVoidFunction loader(void* user_ptr, const char* name)
namespace GE
{
std::atomic_bool g_device_created(false);
std::atomic_bool g_schedule_pausing_rendering(false);
std::atomic_bool g_paused_rendering(false);
GEVulkanDriver::GEVulkanDriver(const SIrrlichtCreationParameters& params,
io::IFileSystem* io, SDL_Window* window)
: CNullDriver(io, core::dimension2d<u32>(0, 0)),
@ -463,6 +467,11 @@ GEVulkanDriver::GEVulkanDriver(const SIrrlichtCreationParameters& params,
m_transparent_texture = NULL;
m_pre_rotation_matrix = core::matrix4(core::matrix4::EM4CONST_IDENTITY);
m_window = window;
g_schedule_pausing_rendering.store(false);
g_paused_rendering.store(false);
g_device_created.store(true);
createInstance(window);
#if !defined(__APPLE__) || defined(DLOPEN_MOLTENVK)
@ -523,6 +532,7 @@ GEVulkanDriver::GEVulkanDriver(const SIrrlichtCreationParameters& params,
// ----------------------------------------------------------------------------
GEVulkanDriver::~GEVulkanDriver()
{
g_device_created.store(false);
} // ~GEVulkanDriver
// ----------------------------------------------------------------------------
@ -923,22 +933,6 @@ void GEVulkanDriver::createSwapChain()
}
found_mode:
VkExtent2D image_extent = m_surface_capabilities.currentExtent;
if (m_surface_capabilities.currentExtent.width == std::numeric_limits<uint32_t>::max())
{
VkExtent2D max_extent = m_surface_capabilities.maxImageExtent;
VkExtent2D min_extent = m_surface_capabilities.minImageExtent;
VkExtent2D actual_extent =
{
std::max(
std::min(ScreenSize.Width, max_extent.width), min_extent.width),
std::max(
std::min(ScreenSize.Height, max_extent.height), min_extent.height)
};
image_extent = actual_extent;
}
// Try to get triple buffering by default
// https://vulkan-tutorial.com/Drawing_a_triangle/Presentation/Swap_chain
uint32_t swap_chain_images_count = m_surface_capabilities.minImageCount + 1;
@ -948,13 +942,25 @@ found_mode:
swap_chain_images_count = m_surface_capabilities.maxImageCount;
}
int w, h = 0;
SDL_Vulkan_GetDrawableSize(m_window, &w, &h);
VkExtent2D max_extent = m_surface_capabilities.maxImageExtent;
VkExtent2D min_extent = m_surface_capabilities.minImageExtent;
VkExtent2D actual_extent =
{
std::max(
std::min((unsigned)w, max_extent.width), min_extent.width),
std::max(
std::min((unsigned)h, max_extent.height), min_extent.height)
};
VkSwapchainCreateInfoKHR create_info = {};
create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
create_info.surface = m_vk->surface;
create_info.minImageCount = swap_chain_images_count;
create_info.imageFormat = surface_format.format;
create_info.imageColorSpace = surface_format.colorSpace;
create_info.imageExtent = image_extent;
create_info.imageExtent = actual_extent;
create_info.imageArrayLayers = 1;
create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
@ -979,7 +985,7 @@ found_mode:
create_info.clipped = VK_TRUE;
create_info.oldSwapchain = VK_NULL_HANDLE;
m_swap_chain_extent = image_extent;
m_swap_chain_extent = actual_extent;
ScreenSize.Width = m_swap_chain_extent.width;
ScreenSize.Height = m_swap_chain_extent.height;
m_clip = getFullscreenClip();
@ -1325,6 +1331,11 @@ void GEVulkanDriver::endSingleTimeCommands(VkCommandBuffer command_buffer)
void GEVulkanDriver::OnResize(const core::dimension2d<u32>& size)
{
CNullDriver::OnResize(size);
if (g_paused_rendering.load() == false)
{
destroySwapChainRelated(false/*handle_surface*/);
createSwapChainRelated(false/*handle_surface*/);
}
} // OnResize
// ----------------------------------------------------------------------------
@ -1332,7 +1343,14 @@ bool GEVulkanDriver::beginScene(bool backBuffer, bool zBuffer, SColor color,
const SExposedVideoData& videoData,
core::rect<s32>* sourceRect)
{
if (!video::CNullDriver::beginScene(backBuffer, zBuffer, color, videoData,
if (g_schedule_pausing_rendering.load())
{
pauseRendering();
g_schedule_pausing_rendering.store(false);
}
if (g_paused_rendering.load() ||
!video::CNullDriver::beginScene(backBuffer, zBuffer, color, videoData,
sourceRect))
return false;
@ -1353,6 +1371,12 @@ bool GEVulkanDriver::beginScene(bool backBuffer, bool zBuffer, SColor color,
// ----------------------------------------------------------------------------
bool GEVulkanDriver::endScene()
{
if (g_paused_rendering.load())
{
GEVulkan2dRenderer::clear();
return false;
}
GEVulkan2dRenderer::render();
VkSemaphore wait_semaphores[] = {m_vk->image_available_semaphores[m_current_frame]};
@ -1827,6 +1851,66 @@ void GEVulkanDriver::initPreRotationMatrix()
m_pre_rotation_matrix.setRotationAxisRadians(270.0 * pi / 180., core::vector3df(0.0f, 0.0f, 1.0f));
} // initPreRotationMatrix
// ----------------------------------------------------------------------------
void GEVulkanDriver::pauseRendering()
{
if (g_paused_rendering.load() != false)
return;
destroySwapChainRelated(true/*handle_surface*/);
g_paused_rendering.store(true);
} // pauseRendering
// ----------------------------------------------------------------------------
void GEVulkanDriver::unpauseRendering()
{
if (g_paused_rendering.load() != true)
return;
createSwapChainRelated(true/*handle_surface*/);
g_paused_rendering.store(false);
} // unpauseRendering
// ----------------------------------------------------------------------------
void GEVulkanDriver::destroySwapChainRelated(bool handle_surface)
{
vkDeviceWaitIdle(m_vk->device);
for (VkFramebuffer& framebuffer : m_vk->swap_chain_framebuffers)
vkDestroyFramebuffer(m_vk->device, framebuffer, NULL);
m_vk->swap_chain_framebuffers.clear();
if (m_vk->render_pass != VK_NULL_HANDLE)
vkDestroyRenderPass(m_vk->device, m_vk->render_pass, NULL);
m_vk->render_pass = VK_NULL_HANDLE;
for (VkImageView& image_view : m_vk->swap_chain_image_views)
vkDestroyImageView(m_vk->device, image_view, NULL);
m_vk->swap_chain_image_views.clear();
if (m_vk->swap_chain != VK_NULL_HANDLE)
vkDestroySwapchainKHR(m_vk->device, m_vk->swap_chain, NULL);
m_vk->swap_chain = VK_NULL_HANDLE;
if (handle_surface)
{
if (m_vk->surface != VK_NULL_HANDLE)
vkDestroySurfaceKHR(m_vk->instance, m_vk->surface, NULL);
m_vk->surface = VK_NULL_HANDLE;
}
} // destroySwapChainRelated
// ----------------------------------------------------------------------------
void GEVulkanDriver::createSwapChainRelated(bool handle_surface)
{
vkDeviceWaitIdle(m_vk->device);
if (handle_surface)
{
if (SDL_Vulkan_CreateSurface(m_window, m_vk->instance, &m_vk->surface) == SDL_FALSE)
throw std::runtime_error("SDL_Vulkan_CreateSurface failed");
}
updateSurfaceInformation(m_physical_device, &m_surface_capabilities,
&m_surface_formats, &m_present_modes);
createSwapChain();
createRenderPass();
createFramebuffers();
} // createSwapChainRelated
}
namespace irr
@ -1840,4 +1924,25 @@ namespace video
} // createVulkanDriver
}
}
#ifdef ANDROID
#include <jni.h>
extern "C" JNIEXPORT void JNICALL pauseRenderingJNI(JNIEnv* env, jclass cls)
{
using namespace GE;
if (g_device_created.load() == false || g_schedule_pausing_rendering.load() == true)
return;
g_schedule_pausing_rendering.store(true);
if (g_paused_rendering.load() == false)
{
while (true)
{
if (g_device_created.load() == false || g_paused_rendering.load() == true)
break;
}
}
} // pauseRenderingJNI
#endif
#endif

View File

@ -1481,6 +1481,8 @@ namespace video
virtual u32 getDefaultFramebuffer() const =0;
virtual void enableScissorTest(const core::rect<s32>& r) {}
virtual void disableScissorTest() {}
virtual void pauseRendering() {}
virtual void unpauseRendering() {}
};
} // end namespace video

View File

@ -909,6 +909,10 @@ bool CIrrDeviceSDL::run()
{
WindowHasFocus = true;
reset_network_body();
#ifdef ANDROID
if (VideoDriver)
VideoDriver->unpauseRendering();
#endif
}
else if (SDL_event.window.event == SDL_WINDOWEVENT_FOCUS_LOST)
{

View File

@ -33,6 +33,7 @@ extern int android_main(int argc, char *argv[]);
extern "C" JNIEXPORT void JNICALL debugMsg(JNIEnv* env, jclass cls, jstring msg);
extern "C" JNIEXPORT void JNICALL handlePadding(JNIEnv* env, jclass cls, jboolean val);
extern "C" JNIEXPORT void JNICALL addDNSSrvRecords(JNIEnv* env, jclass cls, jstring name, jint weight);
extern "C" JNIEXPORT void JNICALL pauseRenderingJNI(JNIEnv* env, jclass cls);
extern "C" JNIEXPORT void JNICALL editText2STKEditbox(JNIEnv* env, jclass cls, jint widget_id, jstring text, jint start, jint end, jint composing_start, jint composing_end);
extern "C" JNIEXPORT void JNICALL handleActionNext(JNIEnv* env, jclass cls, jint widget_id);
@ -48,7 +49,8 @@ void registering_natives()
{
{ "debugMsg", "(Ljava/lang/String;)V", (void*)&debugMsg },
{ "handlePadding", "(Z)V", (void*)&handlePadding },
{ "addDNSSrvRecords", "(Ljava/lang/String;I)V", (void*)&addDNSSrvRecords }
{ "addDNSSrvRecords", "(Ljava/lang/String;I)V", (void*)&addDNSSrvRecords },
{ "pauseRenderingJNI", "()V", (void*)&pauseRenderingJNI }
};
JNIEnv* env = (JNIEnv*)SDL_AndroidGetJNIEnv();
assert(env);

View File

@ -800,12 +800,17 @@ extern "C" int handle_app_event(void* userdata, SDL_Event* event)
{
if (!main_loop)
return 1;
IrrlichtDevice* dev = irr_driver->getDevice();
switch (event->type)
{
case SDL_APP_WILLENTERBACKGROUND:
if (dev && dev->getVideoDriver())
dev->getVideoDriver()->pauseRendering();
main_loop->setPaused(true);
break;
case SDL_APP_DIDENTERFOREGROUND:
if (dev && dev->getVideoDriver())
dev->getVideoDriver()->unpauseRendering();
main_loop->setPaused(false);
break;
default: