android: display cutouts support. render last frame when editing vjoy

render in display cutouts
gl/vk: render last frame when editing virtual gamepad
gl: Fix background handling
gui: reset vmus when stopping game
This commit is contained in:
Flyinghead 2021-05-02 11:31:44 +02:00
parent 1ddb82f334
commit d20fc971c9
13 changed files with 81 additions and 46 deletions

View File

@ -907,12 +907,22 @@ void UpdatePaletteTexture(GLenum texture_slot)
void OSD_DRAW(bool clear_screen)
{
gui_display_osd();
#ifdef __ANDROID__
if (gl.OSD_SHADER.osd_tex == 0)
gl_load_osd_resources();
if (gl.OSD_SHADER.osd_tex != 0)
{
const std::vector<OSDVertex>& osdVertices = GetOSDVertices();
glcache.Disable(GL_SCISSOR_TEST);
glViewport(0, 0, screen_width, screen_height);
if (clear_screen)
{
glcache.ClearColor(0.7f, 0.7f, 0.7f, 1.f);
glClear(GL_COLOR_BUFFER_BIT);
render_output_framebuffer();
glViewport(0, 0, screen_width, screen_height);
}
#ifndef GLES2
if (gl.gl_major >= 3)
@ -940,6 +950,7 @@ void OSD_DRAW(bool clear_screen)
glBindFramebuffer(GL_FRAMEBUFFER, 0);
const std::vector<OSDVertex>& osdVertices = GetOSDVertices();
glBufferData(GL_ARRAY_BUFFER, osdVertices.size() * sizeof(OSDVertex), osdVertices.data(), GL_STREAM_DRAW); glCheck();
glcache.Enable(GL_BLEND);
@ -950,14 +961,6 @@ void OSD_DRAW(bool clear_screen)
glcache.DepthFunc(GL_ALWAYS);
glcache.Disable(GL_CULL_FACE);
glcache.Disable(GL_SCISSOR_TEST);
glViewport(0, 0, screen_width, screen_height);
if (clear_screen)
{
glcache.ClearColor(0.7f, 0.7f, 0.7f, 1.f);
glClear(GL_COLOR_BUFFER_BIT);
}
int dfa = osdVertices.size() / 4;
for (int i = 0; i < dfa; i++)
@ -966,7 +969,6 @@ void OSD_DRAW(bool clear_screen)
glCheck();
}
#endif
gui_display_osd();
}
bool ProcessFrame(TA_context* ctx)

View File

@ -99,7 +99,6 @@ bool ImGui_ImplOpenGL3_Init(const char* glsl_version)
IM_ASSERT((int)strlen(glsl_version) + 2 < IM_ARRAYSIZE(g_GlslVersionString));
strcpy(g_GlslVersionString, glsl_version);
strcat(g_GlslVersionString, "\n");
ImGui_ImplOpenGL3_DrawBackground();
return true;
}
@ -113,8 +112,11 @@ void ImGui_ImplOpenGL3_NewFrame()
{
if (!g_FontTexture)
ImGui_ImplOpenGL3_CreateDeviceObjects();
ImGui_ImplOpenGL3_DrawBackground();
}
extern int insetLeft, insetTop; // Android notches
// OpenGL3 Render function.
// (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop)
// Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly, in order to be able to run within any OpenGL engine that doesn't do so.
@ -155,7 +157,7 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
// Setup viewport, orthographic projection matrix
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayMin is typically (0,0) for single viewport apps.
glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height);
glViewport(insetLeft, insetTop, (GLsizei)fb_width, (GLsizei)fb_height);
float L = draw_data->DisplayPos.x;
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
float T = draw_data->DisplayPos.y;
@ -220,9 +222,9 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
{
// Apply scissor/clipping rectangle
if (clip_origin_lower_left)
glcache.Scissor((int)clip_rect.x, (int)(fb_height - clip_rect.w), (int)(clip_rect.z - clip_rect.x), (int)(clip_rect.w - clip_rect.y));
glcache.Scissor(insetLeft + (int)clip_rect.x, (int)(fb_height - clip_rect.w), insetTop + (int)(clip_rect.z - clip_rect.x), (int)(clip_rect.w - clip_rect.y));
else
glcache.Scissor((int)clip_rect.x, (int)clip_rect.y, (int)clip_rect.z, (int)clip_rect.w); // Support for GL 4.5's glClipControl(GL_UPPER_LEFT)
glcache.Scissor(insetLeft + (int)clip_rect.x, (int)clip_rect.y, insetTop + (int)clip_rect.z, (int)clip_rect.w); // Support for GL 4.5's glClipControl(GL_UPPER_LEFT)
// Bind texture, Draw
glcache.BindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId);

View File

@ -49,6 +49,7 @@ extern u8 kb_shift; // shift keys pressed (bitmask)
extern u8 kb_key[6]; // normal keys pressed
int screen_dpi = 96;
int insetLeft, insetRight, insetTop, insetBottom;
static bool inited = false;
float scaling = 1;
@ -266,8 +267,8 @@ static void ImGui_Impl_NewFrame()
{
if (config::RendererType.isOpenGL())
ImGui_ImplOpenGL3_NewFrame();
ImGui::GetIO().DisplaySize.x = screen_width;
ImGui::GetIO().DisplaySize.y = screen_height;
ImGui::GetIO().DisplaySize.x = screen_width - insetLeft - insetRight;
ImGui::GetIO().DisplaySize.y = screen_height - insetTop - insetBottom;
ImGuiIO& io = ImGui::GetIO();
@ -288,7 +289,7 @@ static void ImGui_Impl_NewFrame()
if (mo_x_phy < 0 || mo_x_phy >= screen_width || mo_y_phy < 0 || mo_y_phy >= screen_height)
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
else
io.MousePos = ImVec2(mo_x_phy, mo_y_phy);
io.MousePos = ImVec2(mo_x_phy - insetLeft, mo_y_phy - insetTop);
#ifdef __ANDROID__
// Put the "mouse" outside the screen one frame after a touch up
// This avoids buttons and the like to stay selected
@ -350,6 +351,14 @@ static void ImGui_Impl_NewFrame()
}
}
void gui_set_insets(int left, int right, int top, int bottom)
{
insetLeft = left;
insetRight = right;
insetTop = top;
insetBottom = bottom;
}
#if 0
#include "oslib/timeseries.h"
TimeSeries renderTimes;
@ -403,9 +412,6 @@ static void gui_display_commands()
{
dc_stop();
if (config::RendererType.isOpenGL())
ImGui_ImplOpenGL3_DrawBackground();
display_vmus();
centerNextWindow();
@ -477,6 +483,7 @@ static void gui_display_commands()
gui_state = GuiState::Main;
game_started = false;
settings.imgread.ImagePath[0] = '\0';
reset_vmus();
}
else
{
@ -660,11 +667,11 @@ static void detect_input_popup(int index, bool analog)
static void controller_mapping_popup(const std::shared_ptr<GamepadDevice>& gamepad)
{
ImGui::SetNextWindowPos(ImVec2(0, 0));
ImGui::SetNextWindowSize(ImVec2(screen_width, screen_height));
ImGui::SetNextWindowSize(ImGui::GetIO().DisplaySize);
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0);
if (ImGui::BeginPopupModal("Controller Mapping", NULL, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove))
{
const float width = screen_width / 2;
const float width = ImGui::GetIO().DisplaySize.x / 2;
const float col_width = (width
- ImGui::GetStyle().GrabMinSize
- (0 + ImGui::GetStyle().ItemSpacing.x)
@ -887,7 +894,7 @@ static void gui_display_settings()
RenderType pvr_rend = config::RendererType;
bool vulkan = !config::RendererType.isOpenGL();
ImGui::SetNextWindowPos(ImVec2(0, 0));
ImGui::SetNextWindowSize(ImVec2(screen_width, screen_height));
ImGui::SetNextWindowSize(ImGui::GetIO().DisplaySize);
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0);
ImGui::Begin("Settings", NULL, /*ImGuiWindowFlags_AlwaysAutoResize |*/ ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse);
@ -1682,7 +1689,7 @@ inline static void gui_display_demo()
static void gui_display_content()
{
ImGui::SetNextWindowPos(ImVec2(0, 0));
ImGui::SetNextWindowSize(ImVec2(screen_width, screen_height));
ImGui::SetNextWindowSize(ImGui::GetIO().DisplaySize);
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0);
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0);
@ -1874,9 +1881,6 @@ static void gui_network_start()
static void gui_display_loadscreen()
{
if (config::RendererType.isOpenGL())
ImGui_ImplOpenGL3_DrawBackground();
centerNextWindow();
ImGui::SetNextWindowSize(ImVec2(330 * scaling, 180 * scaling));
@ -1969,7 +1973,7 @@ void gui_display_ui()
break;
case GuiState::VJoyEditCommands:
#ifdef __ANDROID__
gui_display_vjoy_commands(screen_width, screen_height, scaling);
gui_display_vjoy_commands(scaling);
#endif
break;
case GuiState::SelectDisk:
@ -2035,8 +2039,8 @@ void gui_display_osd()
if (!message.empty())
{
ImGui::SetNextWindowBgAlpha(0);
ImGui::SetNextWindowPos(ImVec2(0, screen_height), ImGuiCond_Always, ImVec2(0.f, 1.f)); // Lower left corner
ImGui::SetNextWindowSize(ImVec2(screen_width, 0));
ImGui::SetNextWindowPos(ImVec2(0, ImGui::GetIO().DisplaySize.y), ImGuiCond_Always, ImVec2(0.f, 1.f)); // Lower left corner
ImGui::SetNextWindowSize(ImVec2(ImGui::GetIO().DisplaySize.x, 0));
ImGui::Begin("##osd", NULL, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoNav
| ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoBackground);
@ -2135,7 +2139,7 @@ static void display_vmus()
return;
ImGui::SetNextWindowBgAlpha(0);
ImGui::SetNextWindowPos(ImVec2(0, 0));
ImGui::SetNextWindowSize(ImVec2(screen_width, screen_height));
ImGui::SetNextWindowSize(ImGui::GetIO().DisplaySize);
ImGui::Begin("vmu-window", NULL, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoInputs
| ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoFocusOnAppearing);
@ -2154,7 +2158,7 @@ static void display_vmus()
if (x == 0)
pos.x = VMU_PADDING;
else
pos.x = screen_width - VMU_WIDTH - VMU_PADDING;
pos.x = ImGui::GetIO().DisplaySize.x - VMU_WIDTH - VMU_PADDING;
if (y == 0)
{
pos.y = VMU_PADDING;
@ -2163,7 +2167,7 @@ static void display_vmus()
}
else
{
pos.y = screen_height - VMU_HEIGHT - VMU_PADDING;
pos.y = ImGui::GetIO().DisplaySize.y - VMU_HEIGHT - VMU_PADDING;
if (i & 1)
pos.y -= VMU_HEIGHT + VMU_PADDING;
}
@ -2233,7 +2237,7 @@ static void displayCrosshairs()
crosshairTexId = ImGui_ImplOpenGL3_CreateCrosshairTexture(getCrosshairTextureData());
ImGui::SetNextWindowBgAlpha(0);
ImGui::SetNextWindowPos(ImVec2(0, 0));
ImGui::SetNextWindowSize(ImVec2(screen_width, screen_height));
ImGui::SetNextWindowSize(ImGui::GetIO().DisplaySize);
ImGui::Begin("xhair-window", NULL, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoInputs
| ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoFocusOnAppearing);

View File

@ -29,6 +29,7 @@ void gui_open_onboarding();
void gui_term();
void gui_refresh_files();
void gui_cheats();
void gui_set_insets(int left, int right, int top, int bottom);
extern int screen_dpi;
extern float scaling;

View File

@ -29,12 +29,12 @@
void vjoy_reset_editing();
void vjoy_stop_editing(bool canceled);
void gui_display_vjoy_commands(int screen_width, int screen_height, float scaling)
void gui_display_vjoy_commands(float scaling)
{
centerNextWindow();
ImGui::Begin("Virtual Joystick", NULL, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse
| ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize);
| ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoScrollbar);
if (ImGui::Button("Save", ImVec2(150 * scaling, 50 * scaling)))
{

View File

@ -18,5 +18,5 @@
*/
#pragma once
void gui_display_vjoy_commands(int screen_width, int screen_height, float scaling);
void gui_display_vjoy_commands(float scaling);
void vjoy_start_editing();

View File

@ -23,9 +23,6 @@
void gui_cheats()
{
if (config::RendererType.isOpenGL())
ImGui_ImplOpenGL3_DrawBackground();
centerNextWindow();
ImGui::SetNextWindowSize(ImVec2(std::min<float>(screen_width, 600 * scaling), std::min<float>(screen_height, 400 * scaling)));

View File

@ -199,6 +199,8 @@ static void CreateOrResizeBuffer(VkBuffer& buffer, VkDeviceMemory& buffer_memory
p_buffer_size = new_size;
}
extern int insetLeft, insetTop; // Android notches
// Render function
// (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop)
void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer)
@ -265,8 +267,8 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm
// Setup viewport:
{
VkViewport viewport;
viewport.x = 0;
viewport.y = 0;
viewport.x = insetLeft;
viewport.y = insetTop;
viewport.width = draw_data->DisplaySize.x;
viewport.height = draw_data->DisplaySize.y;
viewport.minDepth = 0.0f;
@ -306,8 +308,12 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm
// Apply scissor/clipping rectangle
// FIXME: We could clamp width/height based on clamped min/max values.
VkRect2D scissor;
scissor.offset.x = (int32_t)(pcmd->ClipRect.x - display_pos.x) > 0 ? (int32_t)(pcmd->ClipRect.x - display_pos.x) : 0;
scissor.offset.y = (int32_t)(pcmd->ClipRect.y - display_pos.y) > 0 ? (int32_t)(pcmd->ClipRect.y - display_pos.y) : 0;
scissor.offset.x = (int32_t)(pcmd->ClipRect.x - display_pos.x + insetLeft) > 0
? (int32_t)(pcmd->ClipRect.x - display_pos.x + insetLeft)
: 0;
scissor.offset.y = (int32_t)(pcmd->ClipRect.y - display_pos.y + insetTop) > 0
? (int32_t)(pcmd->ClipRect.y - display_pos.y + insetTop)
: 0;
scissor.extent.width = (uint32_t)(pcmd->ClipRect.z - pcmd->ClipRect.x);
scissor.extent.height = (uint32_t)(pcmd->ClipRect.w - pcmd->ClipRect.y + 1); // FIXME: Why +1 here?
vkCmdSetScissor(command_buffer, 0, 1, &scissor);

View File

@ -169,6 +169,7 @@ public:
{
GetContext()->NewFrame();
GetContext()->BeginRenderPass();
GetContext()->PresentLastFrame();
}
const float dc2s_scale_h = screen_height / 480.0f;
const float sidebarWidth = (screen_width - dc2s_scale_h * 640.0f) / 2;

View File

@ -23,6 +23,7 @@ import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.Window;
import android.view.WindowManager;
import com.reicast.emulator.config.Config;
import com.reicast.emulator.debug.GenerateLogs;
@ -71,6 +72,10 @@ public abstract class BaseGLActivity extends Activity implements ActivityCompat.
window.setNavigationBarColor(0);
window.getDecorView().setSystemUiVisibility(SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
getWindow().getAttributes().layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
}
if (!getFilesDir().exists()) {
getFilesDir().mkdir();

View File

@ -37,6 +37,7 @@ public final class JNIdc
public static native void guiOpenSettings();
public static native boolean guiIsOpen();
public static native boolean guiIsContentBrowser();
public static native void guiSetInsets(int left, int right, int top, int bottom);
public static void show_osd() {
JNIdc.vjoy(14, 1, 0, 0, 0);

View File

@ -4,15 +4,15 @@ import android.annotation.TargetApi;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.Handler;
import android.os.SystemClock;
import android.preference.PreferenceManager;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.DisplayCutout;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowInsets;
import com.reicast.emulator.Emulator;
import com.reicast.emulator.NativeGLActivity;
@ -71,6 +71,16 @@ public class NativeGLView extends SurfaceView implements SurfaceHolder.Callback
{
super.onLayout(changed, left, top, right, bottom);
vjoyDelegate.layout(getWidth(), getHeight());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
// Get the display cutouts if any
WindowInsets insets = getRootWindowInsets();
if (insets != null) {
DisplayCutout cutout = insets.getDisplayCutout();
if (cutout != null)
JNIdc.guiSetInsets(cutout.getSafeInsetLeft(), cutout.getSafeInsetRight(),
cutout.getSafeInsetTop(), cutout.getSafeInsetBottom());
}
}
}
public void resetEditMode() {

View File

@ -116,6 +116,7 @@ JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_guiOpenSettings(JNIEn
JNIEXPORT jboolean JNICALL Java_com_reicast_emulator_emu_JNIdc_guiIsOpen(JNIEnv *env,jobject obj) __attribute__((visibility("default")));
JNIEXPORT jboolean JNICALL Java_com_reicast_emulator_emu_JNIdc_guiIsContentBrowser(JNIEnv *env,jobject obj) __attribute__((visibility("default")));
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_setButtons(JNIEnv *env, jobject obj, jbyteArray data) __attribute__((visibility("default")));
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_guiSetInsets(JNIEnv *env, jobject obj, jint left, jint right, jint top, jint bottom) __attribute__((visibility("default")));
JNIEXPORT void JNICALL Java_com_reicast_emulator_periph_InputDeviceManager_init(JNIEnv *env, jobject obj) __attribute__((visibility("default")));
JNIEXPORT void JNICALL Java_com_reicast_emulator_periph_InputDeviceManager_joystickAdded(JNIEnv *env, jobject obj, jint id, jstring name, jint maple_port, jstring junique_id) __attribute__((visibility("default")));
@ -470,6 +471,11 @@ JNIEXPORT jboolean JNICALL Java_com_reicast_emulator_emu_JNIdc_guiIsContentBrows
return gui_is_content_browser();
}
JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_guiSetInsets(JNIEnv *env, jobject obj, jint left, jint right, jint top, jint bottom)
{
gui_set_insets(left, right, top, bottom);
}
// Audio Stuff
static u32 androidaudio_push(const void* frame, u32 amt, bool wait)
{