2021-06-06 01:26:18 +00:00
|
|
|
/**
|
|
|
|
* Looking Glass
|
2024-02-01 06:16:31 +00:00
|
|
|
* Copyright © 2017-2024 The Looking Glass Authors
|
2021-06-06 01:26:18 +00:00
|
|
|
* https://looking-glass.io
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
|
|
* under the terms of the GNU General Public License as published by the Free
|
|
|
|
* Software Foundation; either version 2 of the License, or (at your option)
|
|
|
|
* any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
|
|
* more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
* with this program; if not, write to the Free Software Foundation, Inc., 59
|
|
|
|
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
*/
|
2018-09-22 06:26:10 +00:00
|
|
|
|
2019-03-28 00:02:36 +00:00
|
|
|
#include "interface/renderer.h"
|
2018-11-19 22:50:09 +00:00
|
|
|
|
2023-11-12 07:26:08 +00:00
|
|
|
#include "common/util.h"
|
2019-04-11 01:12:59 +00:00
|
|
|
#include "common/debug.h"
|
2021-07-11 01:20:08 +00:00
|
|
|
#include "common/KVMFR.h"
|
2019-05-21 05:03:59 +00:00
|
|
|
#include "common/option.h"
|
2019-05-23 06:56:13 +00:00
|
|
|
#include "common/sysinfo.h"
|
2021-08-11 06:42:31 +00:00
|
|
|
#include "common/rects.h"
|
2020-01-17 03:35:08 +00:00
|
|
|
#include "common/time.h"
|
2020-05-21 01:44:56 +00:00
|
|
|
#include "common/locking.h"
|
2021-07-08 01:45:54 +00:00
|
|
|
#include "app.h"
|
2021-01-25 08:58:36 +00:00
|
|
|
#include "util.h"
|
2018-09-22 06:26:10 +00:00
|
|
|
|
2021-01-26 10:46:30 +00:00
|
|
|
#include <EGL/egl.h>
|
2021-07-18 09:39:28 +00:00
|
|
|
#include <GLES3/gl32.h>
|
2019-03-26 06:29:49 +00:00
|
|
|
|
2021-07-08 01:45:54 +00:00
|
|
|
#include "cimgui.h"
|
|
|
|
#include "generator/output/cimgui_impl.h"
|
|
|
|
|
2021-02-21 06:25:54 +00:00
|
|
|
#include <math.h>
|
2021-01-26 10:46:30 +00:00
|
|
|
#include <string.h>
|
2021-01-19 15:06:49 +00:00
|
|
|
|
2021-01-26 10:46:30 +00:00
|
|
|
#include "egl_dynprocs.h"
|
2019-03-28 00:02:36 +00:00
|
|
|
#include "model.h"
|
|
|
|
#include "shader.h"
|
2021-07-15 10:04:25 +00:00
|
|
|
#include "damage.h"
|
2019-03-28 00:02:36 +00:00
|
|
|
#include "desktop.h"
|
|
|
|
#include "cursor.h"
|
2021-08-11 08:53:36 +00:00
|
|
|
#include "postprocess.h"
|
2021-08-03 01:37:58 +00:00
|
|
|
#include "util.h"
|
2018-12-15 13:54:37 +00:00
|
|
|
|
2021-08-03 01:37:58 +00:00
|
|
|
#define MAX_BUFFER_AGE 3
|
|
|
|
#define DESKTOP_DAMAGE_COUNT 4
|
|
|
|
#define MAX_ACCUMULATED_DAMAGE ((KVMFR_MAX_DAMAGE_RECTS + MAX_OVERLAY_RECTS + 2) * MAX_BUFFER_AGE)
|
2021-10-15 03:57:17 +00:00
|
|
|
#define IDX_AGO(counter, i, total) (((counter) + (total) - (i)) % (total))
|
2018-09-22 06:26:10 +00:00
|
|
|
|
|
|
|
struct Options
|
|
|
|
{
|
2018-09-22 08:00:52 +00:00
|
|
|
bool vsync;
|
2020-12-31 04:31:24 +00:00
|
|
|
bool doubleBuffer;
|
2018-09-22 06:26:10 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct Inst
|
|
|
|
{
|
2021-08-08 05:32:01 +00:00
|
|
|
LG_Renderer base;
|
|
|
|
|
2020-10-29 15:32:25 +00:00
|
|
|
bool dmaSupport;
|
2018-09-22 06:26:10 +00:00
|
|
|
LG_RendererParams params;
|
|
|
|
struct Options opt;
|
|
|
|
|
2019-01-01 13:04:40 +00:00
|
|
|
EGLNativeWindowType nativeWind;
|
|
|
|
EGLDisplay display;
|
|
|
|
EGLConfig configs;
|
|
|
|
EGLSurface surface;
|
2020-05-21 01:44:56 +00:00
|
|
|
EGLContext context, frameContext;
|
2018-09-22 06:26:10 +00:00
|
|
|
|
2018-12-12 10:41:51 +00:00
|
|
|
EGL_Desktop * desktop; // the desktop
|
|
|
|
EGL_Cursor * cursor; // the mouse cursor
|
2021-07-15 10:04:25 +00:00
|
|
|
EGL_Damage * damage; // the damage display
|
2021-07-08 01:45:54 +00:00
|
|
|
bool imgui; // if imgui was initialized
|
2018-09-22 06:26:10 +00:00
|
|
|
|
2018-09-23 10:45:20 +00:00
|
|
|
LG_RendererFormat format;
|
2021-01-19 09:36:43 +00:00
|
|
|
bool formatValid;
|
2018-09-24 09:48:11 +00:00
|
|
|
|
2021-01-18 15:44:56 +00:00
|
|
|
int width, height;
|
2021-02-21 06:25:54 +00:00
|
|
|
float uiScale;
|
2021-08-03 12:27:46 +00:00
|
|
|
struct DoubleRect destRect;
|
2021-01-18 15:44:56 +00:00
|
|
|
LG_RendererRotate rotate; //client side rotation
|
2018-11-19 22:50:09 +00:00
|
|
|
|
2018-12-15 23:57:01 +00:00
|
|
|
float translateX , translateY;
|
|
|
|
float scaleX , scaleY;
|
|
|
|
float splashRatio;
|
|
|
|
float screenScaleX, screenScaleY;
|
2021-02-21 00:50:59 +00:00
|
|
|
|
|
|
|
int viewportWidth, viewportHeight;
|
|
|
|
enum EGL_DesktopScaleType scaleType;
|
2018-10-03 16:31:37 +00:00
|
|
|
|
2021-07-23 10:03:20 +00:00
|
|
|
bool cursorVisible;
|
|
|
|
int cursorX , cursorY;
|
2021-10-22 12:19:56 +00:00
|
|
|
int cursorHX , cursorHY;
|
2021-07-23 10:03:20 +00:00
|
|
|
float mouseWidth , mouseHeight;
|
|
|
|
float mouseScaleX, mouseScaleY;
|
|
|
|
bool showDamage;
|
2021-10-22 12:19:56 +00:00
|
|
|
bool scalePointer;
|
2018-11-19 22:50:09 +00:00
|
|
|
|
2021-05-11 20:49:39 +00:00
|
|
|
struct CursorState cursorLast;
|
2021-07-11 01:20:08 +00:00
|
|
|
|
2021-08-01 00:37:23 +00:00
|
|
|
bool hadOverlay;
|
2021-10-14 01:23:53 +00:00
|
|
|
bool noSwapDamage;
|
2021-08-01 00:37:23 +00:00
|
|
|
struct DesktopDamage desktopDamage[DESKTOP_DAMAGE_COUNT];
|
2021-08-01 08:24:55 +00:00
|
|
|
unsigned int desktopDamageIdx;
|
|
|
|
LG_Lock desktopDamageLock;
|
2021-07-28 05:06:06 +00:00
|
|
|
|
2021-08-03 01:37:58 +00:00
|
|
|
bool hasBufferAge;
|
|
|
|
struct Rect overlayHistory[DESKTOP_DAMAGE_COUNT][MAX_OVERLAY_RECTS + 1];
|
|
|
|
int overlayHistoryCount[DESKTOP_DAMAGE_COUNT];
|
|
|
|
unsigned int overlayHistoryIdx;
|
|
|
|
|
2021-07-28 05:06:06 +00:00
|
|
|
RingBuffer importTimings;
|
|
|
|
GraphHandle importGraph;
|
2022-05-22 08:19:58 +00:00
|
|
|
|
|
|
|
bool showSpice;
|
2022-09-19 00:22:42 +00:00
|
|
|
int spiceWidth, spiceHeight;
|
2018-09-22 06:26:10 +00:00
|
|
|
};
|
|
|
|
|
2019-05-21 05:03:59 +00:00
|
|
|
static struct Option egl_options[] =
|
|
|
|
{
|
|
|
|
{
|
|
|
|
.module = "egl",
|
|
|
|
.name = "vsync",
|
|
|
|
.description = "Enable vsync",
|
|
|
|
.type = OPTION_TYPE_BOOL,
|
[client] fix hang in eglSwapBuffers when exiting while not visible
eglSwapBuffers is allowed to block when called with a nonzero interval
parameter. On Wayland, Mesa will block until a frame callback arrives.
If an application is not visible, a compositor is free to not schedule
frame callbacks (in order to save CPU time rendering something that is
entirely invisible).
Currently, starting Looking Glass from a terminal, hiding it
entirely, and sending ^C will cause Looking Glass to hang joining the
render thread until the window is made visible again.
Calling eglDestroySurface is insufficient to unblock eglSwapBuffers, as
it attempts to grab the same underlying mutex.
Instead, this commit makes it so that we pass a 0 interval to
eglSwapBuffers when running on Wayland, such that we don't block waiting
for a frame callback. This is not entirely ideal as it *does* mean
Looking Glass submits buffers while hidden, but it seems better than
hanging on exit.
It also forces opengl:vsync and egl:vsync flags to off when running on
Wayland, as they are meaningless there.
2021-01-04 02:09:55 +00:00
|
|
|
.value.x_bool = false,
|
2019-05-21 05:03:59 +00:00
|
|
|
},
|
2019-05-27 08:39:21 +00:00
|
|
|
{
|
|
|
|
.module = "egl",
|
|
|
|
.name = "doubleBuffer",
|
|
|
|
.description = "Enable double buffering",
|
|
|
|
.type = OPTION_TYPE_BOOL,
|
2020-05-19 07:34:24 +00:00
|
|
|
.value.x_bool = false
|
2019-05-27 08:39:21 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.module = "egl",
|
|
|
|
.name = "multisample",
|
|
|
|
.description = "Enable Multisampling",
|
|
|
|
.type = OPTION_TYPE_BOOL,
|
|
|
|
.value.x_bool = true
|
|
|
|
},
|
2019-05-23 06:32:18 +00:00
|
|
|
{
|
|
|
|
.module = "egl",
|
|
|
|
.name = "nvGainMax",
|
|
|
|
.description = "The maximum night vision gain",
|
|
|
|
.type = OPTION_TYPE_INT,
|
|
|
|
.value.x_int = 1
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.module = "egl",
|
|
|
|
.name = "nvGain",
|
|
|
|
.description = "The initial night vision gain at startup",
|
|
|
|
.type = OPTION_TYPE_INT,
|
|
|
|
.value.x_int = 0
|
|
|
|
},
|
2020-11-08 19:59:54 +00:00
|
|
|
{
|
|
|
|
.module = "egl",
|
|
|
|
.name = "cbMode",
|
2020-11-08 20:42:59 +00:00
|
|
|
.description = "Color Blind Mode (0 = Off, 1 = Protanope, 2 = Deuteranope, 3 = Tritanope)",
|
2020-11-08 19:59:54 +00:00
|
|
|
.type = OPTION_TYPE_INT,
|
|
|
|
.value.x_int = 0
|
|
|
|
},
|
2021-02-22 05:03:50 +00:00
|
|
|
{
|
|
|
|
.module = "egl",
|
|
|
|
.name = "scale",
|
|
|
|
.description = "Set the scale algorithm (0 = auto, 1 = nearest, 2 = linear)",
|
|
|
|
.type = OPTION_TYPE_INT,
|
2021-08-08 07:16:10 +00:00
|
|
|
.validator = egl_desktopScaleValidate,
|
2021-02-22 05:03:50 +00:00
|
|
|
.value.x_int = 0
|
|
|
|
},
|
2021-07-18 04:14:31 +00:00
|
|
|
{
|
|
|
|
.module = "egl",
|
|
|
|
.name = "debug",
|
|
|
|
.description = "Enable debug output",
|
|
|
|
.type = OPTION_TYPE_BOOL,
|
|
|
|
.value.x_bool = false
|
|
|
|
},
|
2021-10-14 01:23:53 +00:00
|
|
|
{
|
|
|
|
.module = "egl",
|
|
|
|
.name = "noBufferAge",
|
|
|
|
.description = "Disable partial rendering based on buffer age",
|
|
|
|
.type = OPTION_TYPE_BOOL,
|
|
|
|
.value.x_bool = false
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.module = "egl",
|
|
|
|
.name = "noSwapDamage",
|
|
|
|
.description = "Disable swapping with damage",
|
|
|
|
.type = OPTION_TYPE_BOOL,
|
|
|
|
.value.x_bool = false
|
|
|
|
},
|
2021-10-22 12:19:56 +00:00
|
|
|
{
|
|
|
|
.module = "egl",
|
|
|
|
.name = "scalePointer",
|
|
|
|
.description = "Keep the pointer size 1:1 when downscaling",
|
|
|
|
.type = OPTION_TYPE_BOOL,
|
|
|
|
.value.x_bool = true
|
|
|
|
},
|
2023-10-20 04:26:27 +00:00
|
|
|
{
|
|
|
|
.module = "egl",
|
|
|
|
.name = "mapHDRtoSDR",
|
|
|
|
.description = "Map HDR content to the SDR color space",
|
|
|
|
.type = OPTION_TYPE_BOOL,
|
|
|
|
.value.x_bool = true
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.module = "egl",
|
|
|
|
.name = "peakLuminance",
|
|
|
|
.description = "The peak luminance level in nits for HDR to SDR mapping",
|
|
|
|
.type = OPTION_TYPE_INT,
|
|
|
|
.value.x_int = 250,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.module = "egl",
|
|
|
|
.name = "maxCLL",
|
|
|
|
.description = "Maximum content light level in nits for HDR to SDR mapping",
|
|
|
|
.type = OPTION_TYPE_INT,
|
|
|
|
.value.x_int = 10000,
|
|
|
|
},
|
2021-08-09 15:10:08 +00:00
|
|
|
|
2019-05-21 05:03:59 +00:00
|
|
|
{0}
|
|
|
|
};
|
|
|
|
|
2021-08-08 05:43:42 +00:00
|
|
|
static const char * egl_getName(void)
|
2018-09-22 06:26:10 +00:00
|
|
|
{
|
|
|
|
return "EGL";
|
|
|
|
}
|
|
|
|
|
2021-07-29 06:31:34 +00:00
|
|
|
static void egl_setup(void)
|
2019-05-21 05:03:59 +00:00
|
|
|
{
|
|
|
|
option_register(egl_options);
|
2021-08-11 08:53:36 +00:00
|
|
|
egl_postProcessEarlyInit();
|
2019-05-21 05:03:59 +00:00
|
|
|
}
|
|
|
|
|
2021-08-08 05:32:01 +00:00
|
|
|
static bool egl_create(LG_Renderer ** renderer, const LG_RendererParams params,
|
|
|
|
bool * needsOpenGL)
|
2018-09-22 06:26:10 +00:00
|
|
|
{
|
2020-11-29 10:43:28 +00:00
|
|
|
// check if EGL is even available
|
2021-08-15 22:16:09 +00:00
|
|
|
if (!eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS))
|
|
|
|
{
|
|
|
|
DEBUG_WARN("EGL is not available");
|
2020-11-29 10:43:28 +00:00
|
|
|
return false;
|
2021-08-15 22:16:09 +00:00
|
|
|
}
|
2020-11-29 10:43:28 +00:00
|
|
|
|
2018-09-22 06:26:10 +00:00
|
|
|
// create our local storage
|
2021-08-08 05:32:01 +00:00
|
|
|
struct Inst * this = calloc(1, sizeof(*this));
|
|
|
|
if (!this)
|
2018-09-22 06:26:10 +00:00
|
|
|
{
|
2021-08-08 05:32:01 +00:00
|
|
|
DEBUG_INFO("Failed to allocate %lu bytes", sizeof(*this));
|
2018-09-22 06:26:10 +00:00
|
|
|
return false;
|
|
|
|
}
|
2021-08-08 05:32:01 +00:00
|
|
|
*renderer = &this->base;
|
2018-09-22 06:26:10 +00:00
|
|
|
|
|
|
|
// safe off parameteres and init our default option values
|
2019-05-21 05:03:59 +00:00
|
|
|
memcpy(&this->params, ¶ms, sizeof(LG_RendererParams));
|
|
|
|
|
2020-12-31 04:31:24 +00:00
|
|
|
this->opt.vsync = option_get_bool("egl", "vsync");
|
|
|
|
this->opt.doubleBuffer = option_get_bool("egl", "doubleBuffer");
|
2018-09-22 06:26:10 +00:00
|
|
|
|
2018-12-15 23:57:01 +00:00
|
|
|
this->translateX = 0;
|
|
|
|
this->translateY = 0;
|
|
|
|
this->scaleX = 1.0f;
|
|
|
|
this->scaleY = 1.0f;
|
|
|
|
this->screenScaleX = 1.0f;
|
|
|
|
this->screenScaleY = 1.0f;
|
2021-02-21 06:25:54 +00:00
|
|
|
this->uiScale = 1.0;
|
2018-09-24 09:48:11 +00:00
|
|
|
|
2021-08-01 08:24:55 +00:00
|
|
|
LG_LOCK_INIT(this->desktopDamageLock);
|
2021-08-01 00:37:23 +00:00
|
|
|
this->desktopDamage[0].count = -1;
|
2021-07-11 01:20:08 +00:00
|
|
|
|
2021-07-28 05:06:06 +00:00
|
|
|
this->importTimings = ringbuffer_new(256, sizeof(float));
|
2022-01-17 11:08:56 +00:00
|
|
|
this->importGraph = app_registerGraph("IMPORT", this->importTimings,
|
|
|
|
0.0f, 5.0f, NULL);
|
2021-07-28 05:06:06 +00:00
|
|
|
|
2021-01-27 08:38:34 +00:00
|
|
|
*needsOpenGL = false;
|
2018-09-22 06:26:10 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-08-08 05:32:01 +00:00
|
|
|
static bool egl_initialize(LG_Renderer * renderer)
|
2018-09-22 06:26:10 +00:00
|
|
|
{
|
2021-08-08 05:32:01 +00:00
|
|
|
struct Inst * this = UPCAST(struct Inst, renderer);
|
2020-12-31 04:31:24 +00:00
|
|
|
DEBUG_INFO("Double buffering is %s", this->opt.doubleBuffer ? "on" : "off");
|
2018-09-22 06:26:10 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-08-08 05:32:01 +00:00
|
|
|
static void egl_deinitialize(LG_Renderer * renderer)
|
2018-09-22 06:26:10 +00:00
|
|
|
{
|
2021-08-08 05:32:01 +00:00
|
|
|
struct Inst * this = UPCAST(struct Inst, renderer);
|
2018-09-22 06:26:10 +00:00
|
|
|
|
2021-07-08 01:45:54 +00:00
|
|
|
if (this->imgui)
|
|
|
|
ImGui_ImplOpenGL3_Shutdown();
|
|
|
|
|
2021-07-28 05:06:06 +00:00
|
|
|
ringbuffer_free(&this->importTimings);
|
|
|
|
|
2021-08-08 07:16:10 +00:00
|
|
|
egl_desktopFree(&this->desktop);
|
|
|
|
egl_cursorFree (&this->cursor);
|
|
|
|
egl_damageFree (&this->damage);
|
2018-09-24 09:48:11 +00:00
|
|
|
|
2020-05-21 01:44:56 +00:00
|
|
|
LG_LOCK_FREE(this->lock);
|
2021-08-01 08:24:55 +00:00
|
|
|
LG_LOCK_FREE(this->desktopDamageLock);
|
2020-05-21 01:44:56 +00:00
|
|
|
|
2021-01-24 08:39:00 +00:00
|
|
|
eglMakeCurrent(this->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
|
|
|
|
|
|
|
if (this->frameContext)
|
|
|
|
eglDestroyContext(this->display, this->frameContext);
|
|
|
|
|
|
|
|
if (this->context)
|
|
|
|
eglDestroyContext(this->display, this->context);
|
|
|
|
|
|
|
|
eglTerminate(this->display);
|
|
|
|
|
2018-09-22 06:26:10 +00:00
|
|
|
free(this);
|
|
|
|
}
|
|
|
|
|
2021-08-08 05:32:01 +00:00
|
|
|
static bool egl_supports(LG_Renderer * renderer, LG_RendererSupport flag)
|
2020-10-29 15:32:25 +00:00
|
|
|
{
|
2021-08-08 05:32:01 +00:00
|
|
|
struct Inst * this = UPCAST(struct Inst, renderer);
|
2020-10-29 15:32:25 +00:00
|
|
|
|
|
|
|
switch(flag)
|
|
|
|
{
|
|
|
|
case LG_SUPPORTS_DMABUF:
|
|
|
|
return this->dmaSupport;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-08 05:43:42 +00:00
|
|
|
static void egl_onRestart(LG_Renderer * renderer)
|
2020-08-11 04:30:44 +00:00
|
|
|
{
|
2021-08-08 05:32:01 +00:00
|
|
|
struct Inst * this = UPCAST(struct Inst, renderer);
|
2020-08-11 04:30:44 +00:00
|
|
|
|
|
|
|
eglDestroyContext(this->display, this->frameContext);
|
|
|
|
this->frameContext = NULL;
|
2021-10-23 07:22:37 +00:00
|
|
|
|
|
|
|
INTERLOCKED_SECTION(this->desktopDamageLock, {
|
|
|
|
this->desktopDamage[this->desktopDamageIdx].count = -1;
|
|
|
|
});
|
2020-08-11 04:30:44 +00:00
|
|
|
}
|
|
|
|
|
2021-01-18 15:44:56 +00:00
|
|
|
static void egl_calc_mouse_size(struct Inst * this)
|
|
|
|
{
|
2022-09-19 00:22:42 +00:00
|
|
|
if (this->showSpice)
|
|
|
|
{
|
|
|
|
this->mouseScaleX = 2.0f / this->spiceWidth;
|
|
|
|
this->mouseScaleY = 2.0f / this->spiceHeight;
|
|
|
|
egl_cursorSetSize(this->cursor,
|
|
|
|
(this->mouseWidth * (1.0f / this->spiceWidth )) * this->scaleX,
|
|
|
|
(this->mouseHeight * (1.0f / this->spiceHeight)) * this->scaleY
|
|
|
|
);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-01-19 09:36:43 +00:00
|
|
|
if (!this->formatValid)
|
|
|
|
return;
|
|
|
|
|
2021-08-13 23:52:30 +00:00
|
|
|
int w, h;
|
2021-02-23 09:25:30 +00:00
|
|
|
|
2021-01-18 15:44:56 +00:00
|
|
|
switch(this->format.rotate)
|
|
|
|
{
|
|
|
|
case LG_ROTATE_0:
|
|
|
|
case LG_ROTATE_180:
|
2022-05-01 09:41:46 +00:00
|
|
|
this->mouseScaleX = 2.0f / this->format.screenWidth;
|
|
|
|
this->mouseScaleY = 2.0f / this->format.screenHeight;
|
|
|
|
w = this->format.screenWidth;
|
|
|
|
h = this->format.screenHeight;
|
2021-01-18 15:44:56 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case LG_ROTATE_90:
|
|
|
|
case LG_ROTATE_270:
|
2022-05-01 09:41:46 +00:00
|
|
|
this->mouseScaleX = 2.0f / this->format.screenHeight;
|
|
|
|
this->mouseScaleY = 2.0f / this->format.screenWidth;
|
|
|
|
w = this->format.screenHeight;
|
|
|
|
h = this->format.screenWidth;
|
2021-01-18 15:44:56 +00:00
|
|
|
break;
|
2021-01-19 15:06:49 +00:00
|
|
|
|
|
|
|
default:
|
2021-08-13 23:43:51 +00:00
|
|
|
DEBUG_UNREACHABLE();
|
2021-01-18 15:44:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
switch((this->format.rotate + this->rotate) % LG_ROTATE_MAX)
|
|
|
|
{
|
|
|
|
case LG_ROTATE_0:
|
|
|
|
case LG_ROTATE_180:
|
2021-08-08 07:16:10 +00:00
|
|
|
egl_cursorSetSize(this->cursor,
|
2021-01-18 15:44:56 +00:00
|
|
|
(this->mouseWidth * (1.0f / w)) * this->scaleX,
|
|
|
|
(this->mouseHeight * (1.0f / h)) * this->scaleY
|
|
|
|
);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LG_ROTATE_90:
|
|
|
|
case LG_ROTATE_270:
|
2021-08-08 07:16:10 +00:00
|
|
|
egl_cursorSetSize(this->cursor,
|
2021-01-18 15:44:56 +00:00
|
|
|
(this->mouseWidth * (1.0f / w)) * this->scaleY,
|
|
|
|
(this->mouseHeight * (1.0f / h)) * this->scaleX
|
|
|
|
);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void egl_calc_mouse_state(struct Inst * this)
|
|
|
|
{
|
2022-09-19 00:22:42 +00:00
|
|
|
if (this->showSpice)
|
|
|
|
{
|
|
|
|
egl_cursorSetState(
|
|
|
|
this->cursor,
|
|
|
|
this->cursorVisible,
|
|
|
|
(((float)this->cursorX * this->mouseScaleX) - 1.0f) * this->scaleX,
|
|
|
|
(((float)this->cursorY * this->mouseScaleY) - 1.0f) * this->scaleY,
|
|
|
|
((float)this->cursorHX * this->mouseScaleX) * this->scaleX,
|
|
|
|
((float)this->cursorHY * this->mouseScaleY) * this->scaleY
|
|
|
|
);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-01-19 09:36:43 +00:00
|
|
|
if (!this->formatValid)
|
|
|
|
return;
|
|
|
|
|
2021-01-18 15:44:56 +00:00
|
|
|
switch((this->format.rotate + this->rotate) % LG_ROTATE_MAX)
|
|
|
|
{
|
|
|
|
case LG_ROTATE_0:
|
|
|
|
case LG_ROTATE_180:
|
2021-08-08 07:16:10 +00:00
|
|
|
egl_cursorSetState(
|
2021-01-18 15:44:56 +00:00
|
|
|
this->cursor,
|
|
|
|
this->cursorVisible,
|
2021-10-22 12:19:56 +00:00
|
|
|
(((float)this->cursorX * this->mouseScaleX) - 1.0f) * this->scaleX,
|
|
|
|
(((float)this->cursorY * this->mouseScaleY) - 1.0f) * this->scaleY,
|
|
|
|
((float)this->cursorHX * this->mouseScaleX) * this->scaleX,
|
|
|
|
((float)this->cursorHY * this->mouseScaleY) * this->scaleY
|
2021-01-18 15:44:56 +00:00
|
|
|
);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LG_ROTATE_90:
|
|
|
|
case LG_ROTATE_270:
|
2021-08-08 07:16:10 +00:00
|
|
|
egl_cursorSetState(
|
2021-01-18 15:44:56 +00:00
|
|
|
this->cursor,
|
|
|
|
this->cursorVisible,
|
2021-10-22 12:19:56 +00:00
|
|
|
(((float)this->cursorX * this->mouseScaleX) - 1.0f) * this->scaleY,
|
|
|
|
(((float)this->cursorY * this->mouseScaleY) - 1.0f) * this->scaleX,
|
|
|
|
((float)this->cursorHX * this->mouseScaleX) * this->scaleY,
|
|
|
|
((float)this->cursorHY * this->mouseScaleY) * this->scaleX
|
2021-01-18 15:44:56 +00:00
|
|
|
);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-21 00:50:59 +00:00
|
|
|
static void egl_update_scale_type(struct Inst * this)
|
|
|
|
{
|
2021-02-21 14:38:26 +00:00
|
|
|
int width = 0, height = 0;
|
2021-02-21 00:50:59 +00:00
|
|
|
|
|
|
|
switch (this->rotate)
|
|
|
|
{
|
|
|
|
case LG_ROTATE_0:
|
|
|
|
case LG_ROTATE_180:
|
2022-05-01 09:41:46 +00:00
|
|
|
width = this->format.frameWidth;
|
|
|
|
height = this->format.frameHeight;
|
2021-02-21 00:50:59 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case LG_ROTATE_90:
|
|
|
|
case LG_ROTATE_270:
|
2022-05-01 09:41:46 +00:00
|
|
|
width = this->format.frameHeight;
|
|
|
|
height = this->format.frameWidth;
|
2021-02-21 00:50:59 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (width == this->viewportWidth || height == this->viewportHeight)
|
|
|
|
this->scaleType = EGL_DESKTOP_NOSCALE;
|
|
|
|
else if (width > this->viewportWidth || height > this->viewportHeight)
|
|
|
|
this->scaleType = EGL_DESKTOP_DOWNSCALE;
|
|
|
|
else
|
|
|
|
this->scaleType = EGL_DESKTOP_UPSCALE;
|
|
|
|
}
|
|
|
|
|
2021-08-09 04:08:10 +00:00
|
|
|
void egl_resetViewport(EGL * this)
|
|
|
|
{
|
|
|
|
glViewport(0, 0, this->width, this->height);
|
|
|
|
}
|
|
|
|
|
2021-08-08 05:43:42 +00:00
|
|
|
static void egl_onResize(LG_Renderer * renderer, const int width, const int height, const double scale,
|
2021-01-18 15:44:56 +00:00
|
|
|
const LG_RendererRect destRect, LG_RendererRotate rotate)
|
2018-09-22 06:26:10 +00:00
|
|
|
{
|
2021-08-08 05:32:01 +00:00
|
|
|
struct Inst * this = UPCAST(struct Inst, renderer);
|
2018-09-24 09:48:11 +00:00
|
|
|
|
2021-02-21 06:25:54 +00:00
|
|
|
this->width = width * scale;
|
|
|
|
this->height = height * scale;
|
|
|
|
this->uiScale = (float) scale;
|
|
|
|
this->rotate = rotate;
|
2021-01-18 15:44:56 +00:00
|
|
|
|
2021-02-21 05:47:38 +00:00
|
|
|
this->destRect.x = destRect.x * scale;
|
|
|
|
this->destRect.y = destRect.y * scale;
|
|
|
|
this->destRect.w = destRect.w * scale;
|
|
|
|
this->destRect.h = destRect.h * scale;
|
2018-11-19 22:50:09 +00:00
|
|
|
|
2021-02-21 05:47:38 +00:00
|
|
|
glViewport(0, 0, this->width, this->height);
|
2018-09-24 09:48:11 +00:00
|
|
|
|
2018-10-03 16:31:37 +00:00
|
|
|
if (destRect.valid)
|
|
|
|
{
|
2022-09-17 05:12:09 +00:00
|
|
|
this->translateX = -1.0f + (((this->destRect.w / 2) + this->destRect.x) * 2) / (float)this->width;
|
|
|
|
this->translateY = 1.0f - (((this->destRect.h / 2) + this->destRect.y) * 2) / (float)this->height;
|
2021-02-21 05:47:38 +00:00
|
|
|
this->scaleX = (float)this->destRect.w / (float)this->width;
|
|
|
|
this->scaleY = (float)this->destRect.h / (float)this->height;
|
|
|
|
this->viewportWidth = this->destRect.w;
|
|
|
|
this->viewportHeight = this->destRect.h;
|
2018-10-03 16:31:37 +00:00
|
|
|
}
|
|
|
|
|
2021-02-21 00:50:59 +00:00
|
|
|
egl_update_scale_type(this);
|
2021-01-18 15:44:56 +00:00
|
|
|
egl_calc_mouse_size(this);
|
2018-12-15 13:54:37 +00:00
|
|
|
|
2018-12-15 23:57:01 +00:00
|
|
|
this->splashRatio = (float)width / (float)height;
|
2021-02-21 05:47:38 +00:00
|
|
|
this->screenScaleX = 1.0f / this->width;
|
|
|
|
this->screenScaleY = 1.0f / this->height;
|
2019-05-28 04:06:15 +00:00
|
|
|
|
2021-01-18 15:44:56 +00:00
|
|
|
egl_calc_mouse_state(this);
|
2021-10-22 12:19:56 +00:00
|
|
|
if (this->scalePointer)
|
|
|
|
{
|
|
|
|
float scale = max(1.0f,
|
2021-12-27 00:58:00 +00:00
|
|
|
this->formatValid ?
|
2022-05-01 09:41:46 +00:00
|
|
|
max(
|
|
|
|
(float)this->format.screenWidth / this->width,
|
|
|
|
(float)this->format.screenHeight / this->height)
|
|
|
|
: 1.0f);
|
2021-10-22 12:19:56 +00:00
|
|
|
egl_cursorSetScale(this->cursor, scale);
|
|
|
|
}
|
2021-05-11 20:49:39 +00:00
|
|
|
|
2021-08-01 08:24:55 +00:00
|
|
|
INTERLOCKED_SECTION(this->desktopDamageLock, {
|
|
|
|
this->desktopDamage[this->desktopDamageIdx].count = -1;
|
|
|
|
});
|
2021-07-15 10:04:25 +00:00
|
|
|
|
2021-07-23 04:01:10 +00:00
|
|
|
// this is needed to refresh the font atlas texture
|
|
|
|
ImGui_ImplOpenGL3_Shutdown();
|
2022-01-07 13:26:12 +00:00
|
|
|
ImGui_ImplOpenGL3_Init("#version 300 es");
|
2021-07-23 04:01:10 +00:00
|
|
|
ImGui_ImplOpenGL3_NewFrame();
|
|
|
|
|
2021-08-08 07:16:10 +00:00
|
|
|
egl_damageResize(this->damage, this->translateX, this->translateY, this->scaleX, this->scaleY);
|
2021-08-10 03:08:54 +00:00
|
|
|
egl_desktopResize(this->desktop, this->width, this->height);
|
2018-09-22 06:26:10 +00:00
|
|
|
}
|
|
|
|
|
2021-08-08 05:43:42 +00:00
|
|
|
static bool egl_onMouseShape(LG_Renderer * renderer, const LG_RendererCursor cursor,
|
2021-01-18 15:44:56 +00:00
|
|
|
const int width, const int height,
|
2021-01-15 01:40:59 +00:00
|
|
|
const int pitch, const uint8_t * data)
|
2018-09-22 06:26:10 +00:00
|
|
|
{
|
2021-08-08 05:32:01 +00:00
|
|
|
struct Inst * this = UPCAST(struct Inst, renderer);
|
2021-01-18 15:44:56 +00:00
|
|
|
|
2021-08-08 07:16:10 +00:00
|
|
|
if (!egl_cursorSetShape(this->cursor, cursor, width, height, pitch, data))
|
2018-09-24 09:48:11 +00:00
|
|
|
{
|
2018-12-12 07:53:55 +00:00
|
|
|
DEBUG_ERROR("Failed to update the cursor shape");
|
|
|
|
return false;
|
2018-09-24 09:48:11 +00:00
|
|
|
}
|
|
|
|
|
2018-12-12 07:53:55 +00:00
|
|
|
this->mouseWidth = width;
|
|
|
|
this->mouseHeight = height;
|
2021-01-18 15:44:56 +00:00
|
|
|
egl_calc_mouse_size(this);
|
2018-09-24 09:48:11 +00:00
|
|
|
|
2018-09-22 06:26:10 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-10-22 12:19:56 +00:00
|
|
|
static bool egl_onMouseEvent(LG_Renderer * renderer, const bool visible,
|
|
|
|
int x, int y, const int hx, const int hy)
|
2018-09-22 06:26:10 +00:00
|
|
|
{
|
2021-08-08 05:32:01 +00:00
|
|
|
struct Inst * this = UPCAST(struct Inst, renderer);
|
2019-05-28 04:06:15 +00:00
|
|
|
this->cursorVisible = visible;
|
2021-10-22 12:19:56 +00:00
|
|
|
this->cursorX = x + hx;
|
|
|
|
this->cursorY = y + hy;
|
|
|
|
this->cursorHX = hx;
|
|
|
|
this->cursorHY = hy;
|
2021-01-18 15:44:56 +00:00
|
|
|
egl_calc_mouse_state(this);
|
2018-09-22 06:26:10 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-08-08 05:43:42 +00:00
|
|
|
static bool egl_onFrameFormat(LG_Renderer * renderer, const LG_RendererFormat format)
|
2018-09-22 06:26:10 +00:00
|
|
|
{
|
2021-08-08 05:32:01 +00:00
|
|
|
struct Inst * this = UPCAST(struct Inst, renderer);
|
2020-10-12 08:43:29 +00:00
|
|
|
memcpy(&this->format, &format, sizeof(LG_RendererFormat));
|
2021-01-19 09:36:43 +00:00
|
|
|
this->formatValid = true;
|
2019-04-19 01:23:51 +00:00
|
|
|
|
2020-05-22 07:47:19 +00:00
|
|
|
/* this event runs in a second thread so we need to init it here */
|
2023-11-12 07:26:08 +00:00
|
|
|
if (unlikely(!this->frameContext))
|
2020-05-22 07:47:19 +00:00
|
|
|
{
|
|
|
|
static EGLint attrs[] = {
|
|
|
|
EGL_CONTEXT_CLIENT_VERSION, 2,
|
|
|
|
EGL_NONE
|
|
|
|
};
|
|
|
|
|
|
|
|
if (!(this->frameContext = eglCreateContext(this->display, this->configs, this->context, attrs)))
|
|
|
|
{
|
|
|
|
DEBUG_ERROR("Failed to create the frame context");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!eglMakeCurrent(this->display, EGL_NO_SURFACE, EGL_NO_SURFACE, this->frameContext))
|
|
|
|
{
|
|
|
|
DEBUG_ERROR("Failed to make the frame context current");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-12 07:26:08 +00:00
|
|
|
if (likely(this->scalePointer))
|
2021-10-22 12:19:56 +00:00
|
|
|
{
|
2022-05-01 09:41:46 +00:00
|
|
|
float scale = max(1.0f, (float)format.screenWidth / this->width);
|
2021-10-22 12:19:56 +00:00
|
|
|
egl_cursorSetScale(this->cursor, scale);
|
|
|
|
}
|
|
|
|
|
2021-02-21 00:50:59 +00:00
|
|
|
egl_update_scale_type(this);
|
2022-05-01 09:41:46 +00:00
|
|
|
egl_damageSetup(this->damage, format.frameWidth, format.frameHeight);
|
2021-07-15 10:04:25 +00:00
|
|
|
|
2021-10-22 07:51:49 +00:00
|
|
|
/* we need full screen damage when the format changes */
|
|
|
|
INTERLOCKED_SECTION(this->desktopDamageLock, {
|
2021-10-23 07:22:37 +00:00
|
|
|
this->desktopDamage[this->desktopDamageIdx].count = -1;
|
2021-10-22 07:51:49 +00:00
|
|
|
});
|
|
|
|
|
2021-08-08 07:16:10 +00:00
|
|
|
return egl_desktopSetup(this->desktop, format);
|
2020-10-12 08:43:29 +00:00
|
|
|
}
|
|
|
|
|
2021-08-08 05:43:42 +00:00
|
|
|
static bool egl_onFrame(LG_Renderer * renderer, const FrameBuffer * frame, int dmaFd,
|
2021-07-11 01:20:08 +00:00
|
|
|
const FrameDamageRect * damageRects, int damageRectsCount)
|
2020-10-12 08:43:29 +00:00
|
|
|
{
|
2021-08-08 05:32:01 +00:00
|
|
|
struct Inst * this = UPCAST(struct Inst, renderer);
|
2020-10-12 08:43:29 +00:00
|
|
|
|
2021-07-28 05:06:06 +00:00
|
|
|
uint64_t start = nanotime();
|
2023-11-12 07:26:08 +00:00
|
|
|
if (unlikely(!egl_desktopUpdate(
|
|
|
|
this->desktop, frame, dmaFd, damageRects, damageRectsCount)))
|
2018-12-12 10:41:51 +00:00
|
|
|
{
|
2020-05-21 01:44:56 +00:00
|
|
|
DEBUG_INFO("Failed to to update the desktop");
|
2018-12-12 10:41:51 +00:00
|
|
|
return false;
|
2018-09-23 05:48:44 +00:00
|
|
|
}
|
2021-07-28 05:06:06 +00:00
|
|
|
ringbuffer_push(this->importTimings, &(float){ (nanotime() - start) * 1e-6f });
|
2018-09-23 05:48:44 +00:00
|
|
|
|
2021-08-01 08:24:55 +00:00
|
|
|
INTERLOCKED_SECTION(this->desktopDamageLock, {
|
|
|
|
struct DesktopDamage * damage = this->desktopDamage + this->desktopDamageIdx;
|
2023-11-12 07:26:08 +00:00
|
|
|
if (unlikely(
|
|
|
|
damage->count == -1 ||
|
|
|
|
damageRectsCount == 0 ||
|
|
|
|
damage->count + damageRectsCount >= KVMFR_MAX_DAMAGE_RECTS))
|
|
|
|
{
|
2021-08-01 08:24:55 +00:00
|
|
|
damage->count = -1;
|
2023-11-12 07:26:08 +00:00
|
|
|
}
|
2021-08-01 08:24:55 +00:00
|
|
|
else
|
|
|
|
{
|
2023-11-12 07:26:08 +00:00
|
|
|
memcpy(damage->rects + damage->count, damageRects,
|
|
|
|
damageRectsCount * sizeof(FrameDamageRect));
|
2021-08-01 08:24:55 +00:00
|
|
|
damage->count += damageRectsCount;
|
|
|
|
}
|
|
|
|
});
|
2021-07-11 01:20:08 +00:00
|
|
|
|
2018-09-22 06:26:10 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-07-18 03:40:03 +00:00
|
|
|
static void debugCallback(GLenum source, GLenum type, GLuint id,
|
|
|
|
GLenum severity, GLsizei length, const GLchar * message,
|
|
|
|
const void * userParam)
|
|
|
|
{
|
|
|
|
enum DebugLevel level = DEBUG_LEVEL_FIXME;
|
|
|
|
switch (severity)
|
|
|
|
{
|
|
|
|
case GL_DEBUG_SEVERITY_HIGH:
|
|
|
|
level = DEBUG_LEVEL_ERROR;
|
|
|
|
break;
|
|
|
|
case GL_DEBUG_SEVERITY_MEDIUM:
|
|
|
|
level = DEBUG_LEVEL_WARN;
|
|
|
|
break;
|
|
|
|
case GL_DEBUG_SEVERITY_LOW:
|
2021-07-18 04:14:31 +00:00
|
|
|
case GL_DEBUG_SEVERITY_NOTIFICATION:
|
2021-07-18 03:40:03 +00:00
|
|
|
level = DEBUG_LEVEL_INFO;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char * sourceName = "unknown";
|
|
|
|
switch (source)
|
|
|
|
{
|
|
|
|
case GL_DEBUG_SOURCE_API:
|
|
|
|
sourceName = "OpenGL API";
|
|
|
|
break;
|
|
|
|
case GL_DEBUG_SOURCE_WINDOW_SYSTEM:
|
|
|
|
sourceName = "window system";
|
|
|
|
break;
|
|
|
|
case GL_DEBUG_SOURCE_SHADER_COMPILER:
|
|
|
|
sourceName = "shader compiler";
|
|
|
|
break;
|
|
|
|
case GL_DEBUG_SOURCE_THIRD_PARTY:
|
|
|
|
sourceName = "third party";
|
|
|
|
break;
|
|
|
|
case GL_DEBUG_SOURCE_APPLICATION:
|
|
|
|
sourceName = "application";
|
|
|
|
break;
|
|
|
|
case GL_DEBUG_SOURCE_OTHER:
|
|
|
|
sourceName = "other";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char * typeName = "unknown";
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case GL_DEBUG_TYPE_ERROR:
|
|
|
|
typeName = "error";
|
|
|
|
break;
|
|
|
|
case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
|
|
|
|
typeName = "deprecated behaviour";
|
|
|
|
break;
|
|
|
|
case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
|
|
|
|
typeName = "undefined behaviour";
|
|
|
|
break;
|
|
|
|
case GL_DEBUG_TYPE_PORTABILITY:
|
|
|
|
typeName = "portability";
|
|
|
|
break;
|
|
|
|
case GL_DEBUG_TYPE_PERFORMANCE:
|
|
|
|
typeName = "performance";
|
|
|
|
break;
|
|
|
|
case GL_DEBUG_TYPE_MARKER:
|
|
|
|
typeName = "marker";
|
|
|
|
break;
|
|
|
|
case GL_DEBUG_TYPE_PUSH_GROUP:
|
|
|
|
typeName = "group pushing";
|
|
|
|
break;
|
|
|
|
case GL_DEBUG_TYPE_POP_GROUP:
|
|
|
|
typeName = "group popping";
|
|
|
|
break;
|
|
|
|
case GL_DEBUG_TYPE_OTHER:
|
|
|
|
typeName = "other";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
DEBUG_PRINT(level, "GL message (source: %s, type: %s): %s", sourceName, typeName, message);
|
|
|
|
}
|
|
|
|
|
2021-08-11 23:04:45 +00:00
|
|
|
static void egl_configUI(void * opaque, int * id)
|
2021-08-06 07:23:49 +00:00
|
|
|
{
|
|
|
|
struct Inst * this = opaque;
|
2021-08-08 07:16:10 +00:00
|
|
|
egl_damageConfigUI(this->damage);
|
2021-08-06 07:48:07 +00:00
|
|
|
igSeparator();
|
2021-08-08 07:16:10 +00:00
|
|
|
egl_desktopConfigUI(this->desktop);
|
2021-08-06 07:23:49 +00:00
|
|
|
}
|
|
|
|
|
2021-08-08 05:43:42 +00:00
|
|
|
static bool egl_renderStartup(LG_Renderer * renderer, bool useDMA)
|
2018-09-22 06:26:10 +00:00
|
|
|
{
|
2021-08-08 05:32:01 +00:00
|
|
|
struct Inst * this = UPCAST(struct Inst, renderer);
|
2018-09-22 06:26:10 +00:00
|
|
|
|
2021-01-26 10:46:30 +00:00
|
|
|
this->nativeWind = app_getEGLNativeWindow();
|
|
|
|
if (!this->nativeWind)
|
2021-08-14 02:04:54 +00:00
|
|
|
{
|
|
|
|
DEBUG_ERROR("Failed to get EGL native window");
|
2018-09-22 06:26:10 +00:00
|
|
|
return false;
|
2021-08-14 02:04:54 +00:00
|
|
|
}
|
2021-01-25 05:04:33 +00:00
|
|
|
|
2021-01-26 10:46:30 +00:00
|
|
|
this->display = app_getEGLDisplay();
|
2018-09-22 06:26:10 +00:00
|
|
|
if (this->display == EGL_NO_DISPLAY)
|
2021-08-14 02:04:54 +00:00
|
|
|
{
|
|
|
|
DEBUG_ERROR("Failed to get EGL display");
|
2018-09-22 06:26:10 +00:00
|
|
|
return false;
|
2021-08-14 02:04:54 +00:00
|
|
|
}
|
2018-09-22 06:26:10 +00:00
|
|
|
|
2020-10-29 15:32:25 +00:00
|
|
|
int maj, min;
|
|
|
|
if (!eglInitialize(this->display, &maj, &min))
|
2018-09-22 06:26:10 +00:00
|
|
|
{
|
|
|
|
DEBUG_ERROR("Unable to initialize EGL");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-01-15 09:30:03 +00:00
|
|
|
int maxSamples = 1;
|
|
|
|
if (option_get_bool("egl", "multisample"))
|
|
|
|
{
|
|
|
|
if (app_getProp(LG_DS_MAX_MULTISAMPLE, &maxSamples) && maxSamples > 1)
|
|
|
|
{
|
|
|
|
if (maxSamples > 4)
|
|
|
|
maxSamples = 4;
|
|
|
|
|
|
|
|
DEBUG_INFO("Multisampling enabled, max samples: %d", maxSamples);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-22 06:26:10 +00:00
|
|
|
EGLint attr[] =
|
|
|
|
{
|
2023-04-19 08:02:14 +00:00
|
|
|
EGL_BUFFER_SIZE , 30,
|
2018-09-25 13:04:29 +00:00
|
|
|
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
|
2021-01-15 09:30:03 +00:00
|
|
|
EGL_SAMPLE_BUFFERS , maxSamples > 0 ? 1 : 0,
|
|
|
|
EGL_SAMPLES , maxSamples,
|
2018-09-22 06:26:10 +00:00
|
|
|
EGL_NONE
|
|
|
|
};
|
|
|
|
|
|
|
|
EGLint num_config;
|
|
|
|
if (!eglChooseConfig(this->display, attr, &this->configs, 1, &num_config))
|
|
|
|
{
|
|
|
|
DEBUG_ERROR("Failed to choose config (eglError: 0x%x)", eglGetError());
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-12-31 04:31:24 +00:00
|
|
|
const EGLint surfattr[] =
|
|
|
|
{
|
|
|
|
EGL_RENDER_BUFFER, this->opt.doubleBuffer ? EGL_BACK_BUFFER : EGL_SINGLE_BUFFER,
|
|
|
|
EGL_NONE
|
|
|
|
};
|
|
|
|
|
|
|
|
this->surface = eglCreateWindowSurface(this->display, this->configs, this->nativeWind, surfattr);
|
2018-09-22 06:26:10 +00:00
|
|
|
if (this->surface == EGL_NO_SURFACE)
|
|
|
|
{
|
2021-10-19 02:32:58 +00:00
|
|
|
// On Nvidia proprietary drivers on Wayland, specifying EGL_RENDER_BUFFER can cause
|
|
|
|
// window creation to fail, so we try again without it.
|
|
|
|
this->surface = eglCreateWindowSurface(this->display, this->configs, this->nativeWind, NULL);
|
|
|
|
if (this->surface == EGL_NO_SURFACE)
|
|
|
|
{
|
|
|
|
DEBUG_ERROR("Failed to create EGL surface (eglError: 0x%x)", eglGetError());
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
DEBUG_WARN("EGL surface creation with EGL_RENDER_BUFFER failed, "
|
|
|
|
"egl:doubleBuffer setting may not be respected");
|
2018-09-22 06:26:10 +00:00
|
|
|
}
|
|
|
|
|
2021-08-31 23:18:21 +00:00
|
|
|
const char * client_exts = eglQueryString(this->display, EGL_EXTENSIONS);
|
2022-01-05 01:38:38 +00:00
|
|
|
if (!client_exts)
|
|
|
|
{
|
|
|
|
DEBUG_ERROR("Failed to query EGL_EXTENSIONS");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-01-26 04:42:33 +00:00
|
|
|
bool debug = option_get_bool("egl", "debug");
|
2021-08-19 11:18:11 +00:00
|
|
|
EGLint ctxattr[5];
|
|
|
|
int ctxidx = 0;
|
|
|
|
|
|
|
|
ctxattr[ctxidx++] = EGL_CONTEXT_CLIENT_VERSION;
|
|
|
|
ctxattr[ctxidx++] = 2;
|
|
|
|
|
|
|
|
if (maj > 1 || (maj == 1 && min >= 5))
|
2018-09-22 06:26:10 +00:00
|
|
|
{
|
2021-08-19 11:18:11 +00:00
|
|
|
ctxattr[ctxidx++] = EGL_CONTEXT_OPENGL_DEBUG;
|
2022-01-26 04:42:33 +00:00
|
|
|
ctxattr[ctxidx++] = debug ? EGL_TRUE : EGL_FALSE;
|
2021-08-19 11:18:11 +00:00
|
|
|
}
|
2021-08-31 23:18:21 +00:00
|
|
|
else if (util_hasGLExt(client_exts, "EGL_KHR_create_context"))
|
|
|
|
{
|
|
|
|
ctxattr[ctxidx++] = EGL_CONTEXT_FLAGS_KHR;
|
2022-01-26 04:42:33 +00:00
|
|
|
ctxattr[ctxidx++] = debug ? EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR : 0;
|
2021-08-31 23:18:21 +00:00
|
|
|
}
|
2022-01-26 04:42:33 +00:00
|
|
|
else if (debug)
|
2021-08-31 23:18:21 +00:00
|
|
|
DEBUG_WARN("Cannot create debug contexts before EGL 1.5 without EGL_KHR_create_context");
|
2021-08-19 11:18:11 +00:00
|
|
|
|
2022-03-06 23:13:54 +00:00
|
|
|
ctxattr[ctxidx] = EGL_NONE;
|
2018-09-22 06:26:10 +00:00
|
|
|
|
|
|
|
this->context = eglCreateContext(this->display, this->configs, EGL_NO_CONTEXT, ctxattr);
|
|
|
|
if (this->context == EGL_NO_CONTEXT)
|
|
|
|
{
|
|
|
|
DEBUG_ERROR("Failed to create EGL context (eglError: 0x%x)", eglGetError());
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-12-31 04:31:24 +00:00
|
|
|
EGLint rb = 0;
|
|
|
|
eglQuerySurface(this->display, this->surface, EGL_RENDER_BUFFER, &rb);
|
|
|
|
switch(rb)
|
|
|
|
{
|
|
|
|
case EGL_SINGLE_BUFFER:
|
|
|
|
DEBUG_INFO("Single buffer mode");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case EGL_BACK_BUFFER:
|
|
|
|
DEBUG_INFO("Back buffer mode");
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
DEBUG_WARN("Unknown render buffer mode: %d", rb);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2018-09-22 06:26:10 +00:00
|
|
|
eglMakeCurrent(this->display, this->surface, this->surface, this->context);
|
2021-08-31 23:18:21 +00:00
|
|
|
const char * gl_exts = (const char *)glGetString(GL_EXTENSIONS);
|
2022-01-05 01:38:38 +00:00
|
|
|
if (!gl_exts)
|
|
|
|
{
|
|
|
|
DEBUG_ERROR("Failed to query GL_EXTENSIONS");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-08-31 23:18:21 +00:00
|
|
|
const char * vendor = (const char *)glGetString(GL_VENDOR);
|
2022-01-05 01:38:38 +00:00
|
|
|
if (!vendor)
|
|
|
|
{
|
|
|
|
DEBUG_ERROR("Failed to query GL_VENDOR");
|
|
|
|
return false;
|
|
|
|
}
|
2020-10-29 15:32:25 +00:00
|
|
|
|
2021-07-18 03:40:03 +00:00
|
|
|
DEBUG_INFO("EGL : %d.%d", maj, min);
|
|
|
|
DEBUG_INFO("Vendor : %s", vendor);
|
|
|
|
DEBUG_INFO("Renderer: %s", glGetString(GL_RENDERER));
|
|
|
|
DEBUG_INFO("Version : %s", glGetString(GL_VERSION ));
|
|
|
|
DEBUG_INFO("EGL APIs: %s", eglQueryString(this->display, EGL_CLIENT_APIS));
|
2022-01-26 04:42:33 +00:00
|
|
|
|
|
|
|
if (debug)
|
|
|
|
{
|
|
|
|
DEBUG_INFO("EGL Exts: %s", client_exts);
|
|
|
|
DEBUG_INFO("GL Exts : %s", gl_exts);
|
|
|
|
}
|
2021-07-18 03:40:03 +00:00
|
|
|
|
|
|
|
GLint esMaj, esMin;
|
|
|
|
glGetIntegerv(GL_MAJOR_VERSION, &esMaj);
|
|
|
|
glGetIntegerv(GL_MINOR_VERSION, &esMin);
|
2018-09-22 06:26:10 +00:00
|
|
|
|
2021-07-18 09:39:28 +00:00
|
|
|
if (!util_hasGLExt(gl_exts, "GL_EXT_texture_format_BGRA8888"))
|
|
|
|
{
|
|
|
|
DEBUG_ERROR("GL_EXT_texture_format_BGRA8888 is needed to use EGL backend");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-08-03 01:37:58 +00:00
|
|
|
this->hasBufferAge = util_hasGLExt(client_exts, "EGL_EXT_buffer_age");
|
2021-08-03 01:43:33 +00:00
|
|
|
if (!this->hasBufferAge)
|
|
|
|
DEBUG_WARN("GL_EXT_buffer_age is not supported, will not perform as well.");
|
2021-08-03 01:37:58 +00:00
|
|
|
|
2021-10-14 01:23:53 +00:00
|
|
|
if (this->hasBufferAge && option_get_bool("egl", "noBufferAge"))
|
|
|
|
{
|
|
|
|
DEBUG_WARN("egl:noBufferAge specified, disabling buffer age.");
|
|
|
|
this->hasBufferAge = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
this->noSwapDamage = option_get_bool("egl", "noSwapDamage");
|
|
|
|
if (this->noSwapDamage)
|
|
|
|
DEBUG_WARN("egl:noSwapDamage specified, disabling swap buffers with damage.");
|
|
|
|
|
2021-10-22 12:19:56 +00:00
|
|
|
this->scalePointer = option_get_bool("egl", "scalePointer");
|
|
|
|
|
2021-09-29 01:34:42 +00:00
|
|
|
if (!g_egl_dynProcs.glEGLImageTargetTexture2DOES)
|
2021-01-24 01:05:18 +00:00
|
|
|
DEBUG_INFO("glEGLImageTargetTexture2DOES unavilable, DMA support disabled");
|
2021-09-29 01:34:42 +00:00
|
|
|
else if (!g_egl_dynProcs.eglCreateImage || !g_egl_dynProcs.eglDestroyImage)
|
|
|
|
DEBUG_INFO("eglCreateImage or eglDestroyImage unavailable, DMA support disabled");
|
|
|
|
else if (!util_hasGLExt(client_exts, "EGL_EXT_image_dma_buf_import"))
|
|
|
|
DEBUG_INFO("EGL_EXT_image_dma_buf_import unavailable, DMA support disabled");
|
|
|
|
else if ((maj < 1 || (maj == 1 && min < 5)) && !util_hasGLExt(client_exts, "EGL_KHR_image_base"))
|
|
|
|
DEBUG_INFO("Need EGL 1.5+ or EGL_KHR_image_base for eglCreateImage(KHR)");
|
|
|
|
else
|
|
|
|
this->dmaSupport = true;
|
2018-09-22 06:26:10 +00:00
|
|
|
|
2021-08-02 17:58:30 +00:00
|
|
|
if (!this->dmaSupport)
|
2021-12-14 19:10:30 +00:00
|
|
|
{
|
2021-08-02 17:58:30 +00:00
|
|
|
useDMA = false;
|
2021-12-14 19:10:30 +00:00
|
|
|
if (!util_hasGLExt(gl_exts, "GL_EXT_buffer_storage"))
|
|
|
|
{
|
|
|
|
DEBUG_ERROR("GL_EXT_buffer_storage is needed to use EGL backend");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2021-08-02 17:58:30 +00:00
|
|
|
|
2022-01-26 04:42:33 +00:00
|
|
|
if (debug)
|
2021-07-18 03:40:03 +00:00
|
|
|
{
|
2021-07-18 04:14:31 +00:00
|
|
|
if ((esMaj > 3 || (esMaj == 3 && esMin >= 2)) && g_egl_dynProcs.glDebugMessageCallback)
|
|
|
|
{
|
|
|
|
g_egl_dynProcs.glDebugMessageCallback(debugCallback, NULL);
|
|
|
|
DEBUG_INFO("Using debug message callback from OpenGL ES 3.2+");
|
|
|
|
}
|
|
|
|
else if (util_hasGLExt(gl_exts, "GL_KHR_debug") && g_egl_dynProcs.glDebugMessageCallbackKHR)
|
|
|
|
{
|
|
|
|
g_egl_dynProcs.glDebugMessageCallbackKHR(debugCallback, NULL);
|
|
|
|
DEBUG_INFO("Using debug message callback from GL_KHR_debug");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
DEBUG_INFO("Debug message callback not supported");
|
2021-07-18 03:40:03 +00:00
|
|
|
}
|
|
|
|
else
|
2021-07-18 04:14:31 +00:00
|
|
|
DEBUG_INFO("Debug messages disabled, enable with egl:debug=true");
|
2021-07-18 03:40:03 +00:00
|
|
|
|
2018-12-12 10:41:51 +00:00
|
|
|
eglSwapInterval(this->display, this->opt.vsync ? 1 : 0);
|
2018-09-23 05:48:44 +00:00
|
|
|
|
2021-08-09 04:08:10 +00:00
|
|
|
if (!egl_desktopInit(this, &this->desktop, this->display, useDMA, MAX_ACCUMULATED_DAMAGE))
|
2018-12-12 10:41:51 +00:00
|
|
|
{
|
|
|
|
DEBUG_ERROR("Failed to initialize the desktop");
|
2018-09-22 08:00:52 +00:00
|
|
|
return false;
|
2018-12-12 10:41:51 +00:00
|
|
|
}
|
2018-09-24 09:48:11 +00:00
|
|
|
|
2021-08-11 08:53:36 +00:00
|
|
|
if (!egl_cursorInit(&this->cursor))
|
2018-12-12 07:53:55 +00:00
|
|
|
{
|
|
|
|
DEBUG_ERROR("Failed to initialize the cursor");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-08-08 07:16:10 +00:00
|
|
|
if (!egl_damageInit(&this->damage))
|
2021-07-15 10:04:25 +00:00
|
|
|
{
|
|
|
|
DEBUG_ERROR("Failed to initialize the damage display");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-07-18 06:38:37 +00:00
|
|
|
if (!ImGui_ImplOpenGL3_Init("#version 300 es"))
|
2021-07-08 01:45:54 +00:00
|
|
|
{
|
|
|
|
DEBUG_ERROR("Failed to initialize ImGui");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-08-11 23:04:45 +00:00
|
|
|
app_overlayConfigRegister("EGL", egl_configUI, this);
|
2021-08-06 07:23:49 +00:00
|
|
|
|
2021-07-08 01:45:54 +00:00
|
|
|
this->imgui = true;
|
2018-09-22 06:26:10 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-10-15 03:51:56 +00:00
|
|
|
inline static EGLint egl_bufferAge(struct Inst * this)
|
2021-08-03 01:37:58 +00:00
|
|
|
{
|
|
|
|
if (!this->hasBufferAge)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
EGLint result;
|
2021-12-13 23:30:29 +00:00
|
|
|
if (eglQuerySurface(this->display, this->surface, EGL_BUFFER_AGE_EXT, &result) == EGL_FALSE)
|
|
|
|
{
|
|
|
|
DEBUG_ERROR("eglQuerySurface(EGL_BUFFER_AGE_EXT) failed");
|
|
|
|
return 0;
|
|
|
|
}
|
2021-08-03 01:37:58 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline static void renderLetterBox(struct Inst * this)
|
|
|
|
{
|
|
|
|
bool hLB = this->destRect.x > 0;
|
|
|
|
bool vLB = this->destRect.y > 0;
|
|
|
|
|
|
|
|
if (hLB || vLB)
|
|
|
|
{
|
|
|
|
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
|
|
|
glEnable(GL_SCISSOR_TEST);
|
|
|
|
|
|
|
|
if (hLB)
|
|
|
|
{
|
2022-09-17 05:12:09 +00:00
|
|
|
// left
|
|
|
|
glScissor(0, 0, this->destRect.x, this->height);
|
2021-08-03 01:37:58 +00:00
|
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
|
2022-09-17 05:12:09 +00:00
|
|
|
// right
|
2021-08-03 01:37:58 +00:00
|
|
|
float x2 = this->destRect.x + this->destRect.w;
|
2022-09-17 05:12:09 +00:00
|
|
|
glScissor(x2, 0, this->width - x2, this->height);
|
2021-08-03 01:37:58 +00:00
|
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (vLB)
|
|
|
|
{
|
2022-09-17 05:12:09 +00:00
|
|
|
// top
|
|
|
|
glScissor(0, this->height - this->destRect.y,
|
|
|
|
this->width, this->destRect.y);
|
2021-08-03 01:37:58 +00:00
|
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
|
2022-09-17 05:12:09 +00:00
|
|
|
// bottom
|
|
|
|
int y2 = this->destRect.y + this->destRect.h;
|
|
|
|
glScissor(0, 0, this->width, this->height - y2);
|
2021-08-03 01:37:58 +00:00
|
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
}
|
|
|
|
|
|
|
|
glDisable(GL_SCISSOR_TEST);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-08 05:32:01 +00:00
|
|
|
static bool egl_render(LG_Renderer * renderer, LG_RendererRotate rotate,
|
|
|
|
const bool newFrame, const bool invalidateWindow,
|
|
|
|
void (*preSwap)(void * udata), void * udata)
|
2018-09-22 06:26:10 +00:00
|
|
|
{
|
2021-08-08 05:32:01 +00:00
|
|
|
struct Inst * this = UPCAST(struct Inst, renderer);
|
2021-10-15 03:51:56 +00:00
|
|
|
EGLint bufferAge = egl_bufferAge(this);
|
2022-05-26 16:07:20 +00:00
|
|
|
bool renderAll = invalidateWindow || this->hadOverlay ||
|
2022-05-22 08:19:58 +00:00
|
|
|
bufferAge <= 0 || bufferAge > MAX_BUFFER_AGE ||
|
|
|
|
this->showSpice;
|
2018-09-22 06:26:10 +00:00
|
|
|
|
2021-07-11 07:52:41 +00:00
|
|
|
bool hasOverlay = false;
|
2021-07-19 22:36:22 +00:00
|
|
|
struct CursorState cursorState = { .visible = false };
|
2021-08-01 08:24:55 +00:00
|
|
|
struct DesktopDamage * desktopDamage;
|
|
|
|
|
2021-10-24 11:57:21 +00:00
|
|
|
struct DamageRects * accumulated = (struct DamageRects *)alloca(
|
2021-08-03 01:37:58 +00:00
|
|
|
sizeof(struct DamageRects) +
|
|
|
|
MAX_ACCUMULATED_DAMAGE * sizeof(struct FrameDamageRect)
|
2021-10-24 11:57:21 +00:00
|
|
|
);
|
2021-08-03 01:37:58 +00:00
|
|
|
accumulated->count = 0;
|
|
|
|
|
2021-08-01 08:24:55 +00:00
|
|
|
INTERLOCKED_SECTION(this->desktopDamageLock, {
|
2023-11-12 07:26:08 +00:00
|
|
|
if (likely(!renderAll))
|
2021-08-03 01:37:58 +00:00
|
|
|
{
|
|
|
|
for (int i = 0; i < bufferAge; ++i)
|
|
|
|
{
|
|
|
|
struct DesktopDamage * damage = this->desktopDamage +
|
|
|
|
IDX_AGO(this->desktopDamageIdx, i, DESKTOP_DAMAGE_COUNT);
|
|
|
|
|
2023-11-12 07:26:08 +00:00
|
|
|
if (unlikely(damage->count < 0))
|
2021-08-03 01:37:58 +00:00
|
|
|
{
|
|
|
|
renderAll = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2021-08-04 21:56:32 +00:00
|
|
|
for (int j = 0; j < damage->count; ++j)
|
|
|
|
{
|
|
|
|
struct FrameDamageRect * rect = damage->rects + j;
|
|
|
|
int x = rect->x > 0 ? rect->x - 1 : 0;
|
|
|
|
int y = rect->y > 0 ? rect->y - 1 : 0;
|
|
|
|
accumulated->rects[accumulated->count++] = (struct FrameDamageRect) {
|
|
|
|
.x = x, .y = y,
|
2022-05-01 09:41:46 +00:00
|
|
|
.width = min(this->format.frameWidth - x, rect->width + 2),
|
|
|
|
.height = min(this->format.frameHeight - y, rect->height + 2),
|
2021-08-04 21:56:32 +00:00
|
|
|
};
|
|
|
|
}
|
2021-08-03 01:37:58 +00:00
|
|
|
}
|
|
|
|
}
|
2021-08-01 08:24:55 +00:00
|
|
|
desktopDamage = this->desktopDamage + this->desktopDamageIdx;
|
|
|
|
this->desktopDamageIdx = (this->desktopDamageIdx + 1) % DESKTOP_DAMAGE_COUNT;
|
2021-08-03 01:37:58 +00:00
|
|
|
this->desktopDamage[this->desktopDamageIdx].count = 0;
|
2021-08-01 08:24:55 +00:00
|
|
|
});
|
2021-05-11 20:49:39 +00:00
|
|
|
|
2023-11-12 07:26:08 +00:00
|
|
|
if (likely(!renderAll))
|
2021-08-03 01:37:58 +00:00
|
|
|
{
|
|
|
|
double matrix[6];
|
2022-05-01 09:41:46 +00:00
|
|
|
egl_screenToDesktopMatrix(matrix,
|
|
|
|
this->format.frameWidth, this->format.frameHeight,
|
2021-08-03 01:37:58 +00:00
|
|
|
this->translateX, this->translateY, this->scaleX, this->scaleY, rotate,
|
|
|
|
this->width, this->height);
|
|
|
|
|
|
|
|
for (int i = 0; i < bufferAge; ++i)
|
|
|
|
{
|
|
|
|
int idx = IDX_AGO(this->overlayHistoryIdx, i, DESKTOP_DAMAGE_COUNT);
|
|
|
|
int count = this->overlayHistoryCount[idx];
|
|
|
|
struct Rect * damage = this->overlayHistory[idx];
|
|
|
|
|
2023-11-12 07:26:08 +00:00
|
|
|
if (unlikely(count < 0))
|
2021-08-03 01:37:58 +00:00
|
|
|
{
|
|
|
|
renderAll = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int j = 0; j < count; ++j)
|
|
|
|
accumulated->count += egl_screenToDesktop(
|
|
|
|
accumulated->rects + accumulated->count, matrix, damage + j,
|
2022-05-01 09:41:46 +00:00
|
|
|
this->format.frameWidth, this->format.frameHeight
|
2021-08-03 01:37:58 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2023-11-12 07:26:08 +00:00
|
|
|
accumulated->count = rectsMergeOverlapping(accumulated->rects,
|
|
|
|
accumulated->count);
|
2021-08-03 01:37:58 +00:00
|
|
|
}
|
2021-08-10 08:54:13 +00:00
|
|
|
++this->overlayHistoryIdx;
|
2021-08-03 01:37:58 +00:00
|
|
|
|
2023-11-12 07:26:08 +00:00
|
|
|
if (likely(this->destRect.w > 0 && this->destRect.h > 0))
|
2021-07-11 01:20:08 +00:00
|
|
|
{
|
2021-08-08 07:16:10 +00:00
|
|
|
if (egl_desktopRender(this->desktop,
|
2021-08-11 08:53:36 +00:00
|
|
|
this->destRect.w, this->destRect.h,
|
2020-08-11 04:45:08 +00:00
|
|
|
this->translateX, this->translateY,
|
|
|
|
this->scaleX , this->scaleY ,
|
2021-08-03 01:37:58 +00:00
|
|
|
this->scaleType , rotate, renderAll ? NULL : accumulated))
|
2020-07-19 04:29:29 +00:00
|
|
|
{
|
2022-09-19 00:22:42 +00:00
|
|
|
cursorState = egl_cursorRender(this->cursor,
|
|
|
|
(this->format.rotate + rotate) % LG_ROTATE_MAX,
|
|
|
|
this->width, this->height);
|
2021-07-11 01:20:08 +00:00
|
|
|
}
|
|
|
|
else
|
2021-08-03 01:37:58 +00:00
|
|
|
hasOverlay = true;
|
2019-06-12 12:36:00 +00:00
|
|
|
}
|
2018-11-19 22:50:09 +00:00
|
|
|
|
2021-08-03 12:29:04 +00:00
|
|
|
renderLetterBox(this);
|
|
|
|
|
2023-11-12 07:26:08 +00:00
|
|
|
hasOverlay |=
|
|
|
|
egl_damageRender(this->damage, rotate, newFrame ? desktopDamage : NULL) |
|
|
|
|
invalidateWindow;
|
2021-07-11 07:52:41 +00:00
|
|
|
|
2021-07-22 09:43:16 +00:00
|
|
|
struct Rect damage[KVMFR_MAX_DAMAGE_RECTS + MAX_OVERLAY_RECTS + 2];
|
|
|
|
int damageIdx = app_renderOverlay(damage, MAX_OVERLAY_RECTS);
|
2023-11-12 07:26:08 +00:00
|
|
|
if (unlikely(damageIdx != 0))
|
2021-07-22 07:27:30 +00:00
|
|
|
{
|
2023-11-12 07:26:08 +00:00
|
|
|
if (damageIdx == -1)
|
2021-07-22 07:27:30 +00:00
|
|
|
hasOverlay = true;
|
2021-07-22 08:53:21 +00:00
|
|
|
|
2023-11-12 07:26:08 +00:00
|
|
|
ImGui_ImplOpenGL3_NewFrame();
|
|
|
|
ImGui_ImplOpenGL3_RenderDrawData(igGetDrawData());
|
|
|
|
|
|
|
|
for (int i = 0; i < damageIdx; ++i)
|
|
|
|
damage[i].y = this->height - damage[i].y - damage[i].h;
|
2021-07-22 07:27:30 +00:00
|
|
|
}
|
2021-05-11 20:49:39 +00:00
|
|
|
|
2023-11-12 07:26:08 +00:00
|
|
|
if (likely(damageIdx >= 0 && cursorState.visible))
|
2021-08-03 01:37:58 +00:00
|
|
|
damage[damageIdx++] = cursorState.rect;
|
|
|
|
|
|
|
|
int overlayHistoryIdx = this->overlayHistoryIdx % DESKTOP_DAMAGE_COUNT;
|
2023-11-12 07:26:08 +00:00
|
|
|
if (unlikely(hasOverlay))
|
2021-08-03 01:37:58 +00:00
|
|
|
this->overlayHistoryCount[overlayHistoryIdx] = -1;
|
|
|
|
else
|
|
|
|
{
|
2023-11-12 07:26:08 +00:00
|
|
|
if (unlikely(damageIdx > 0))
|
|
|
|
memcpy(this->overlayHistory[overlayHistoryIdx],
|
|
|
|
damage, damageIdx * sizeof(struct Rect));
|
2021-08-03 01:37:58 +00:00
|
|
|
this->overlayHistoryCount[overlayHistoryIdx] = damageIdx;
|
|
|
|
}
|
|
|
|
|
2023-11-12 07:26:08 +00:00
|
|
|
if (unlikely(!hasOverlay && !this->hadOverlay))
|
2021-05-11 20:49:39 +00:00
|
|
|
{
|
2021-07-19 22:36:22 +00:00
|
|
|
if (this->cursorLast.visible)
|
|
|
|
damage[damageIdx++] = this->cursorLast.rect;
|
2021-05-11 20:49:39 +00:00
|
|
|
|
2021-08-01 00:37:23 +00:00
|
|
|
if (desktopDamage->count == -1)
|
|
|
|
// -1 damage count means invalidating entire window.
|
|
|
|
damageIdx = 0;
|
|
|
|
else
|
2021-07-11 01:20:08 +00:00
|
|
|
{
|
2021-08-02 22:40:19 +00:00
|
|
|
double matrix[6];
|
2022-05-01 09:41:46 +00:00
|
|
|
egl_desktopToScreenMatrix(matrix,
|
|
|
|
this->format.frameWidth, this->format.frameHeight,
|
2021-08-02 22:40:19 +00:00
|
|
|
this->translateX, this->translateY, this->scaleX, this->scaleY, rotate,
|
|
|
|
this->width, this->height);
|
|
|
|
|
2021-08-01 00:37:23 +00:00
|
|
|
for (int i = 0; i < desktopDamage->count; ++i)
|
2021-08-02 22:40:19 +00:00
|
|
|
damage[damageIdx++] = egl_desktopToScreen(matrix, desktopDamage->rects + i);
|
2021-05-11 20:49:39 +00:00
|
|
|
}
|
|
|
|
}
|
2021-07-22 08:58:32 +00:00
|
|
|
else
|
|
|
|
damageIdx = 0;
|
2021-08-01 00:37:23 +00:00
|
|
|
|
2021-07-11 07:52:41 +00:00
|
|
|
this->hadOverlay = hasOverlay;
|
2021-08-01 05:47:59 +00:00
|
|
|
this->cursorLast = cursorState;
|
2021-07-08 01:45:54 +00:00
|
|
|
|
2021-08-06 15:44:36 +00:00
|
|
|
preSwap(udata);
|
2023-11-12 07:26:08 +00:00
|
|
|
app_eglSwapBuffers(this->display, this->surface, damage,
|
|
|
|
this->noSwapDamage ? 0 : damageIdx);
|
|
|
|
|
2018-09-22 06:26:10 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-05-25 18:08:22 +00:00
|
|
|
static void * egl_createTexture(LG_Renderer * renderer,
|
|
|
|
int width, int height, uint8_t * data)
|
|
|
|
{
|
|
|
|
GLuint tex;
|
|
|
|
glGenTextures(1, &tex);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, tex);
|
|
|
|
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
|
|
|
|
|
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
|
|
|
|
glTexImage2D(
|
|
|
|
GL_TEXTURE_2D,
|
|
|
|
0,
|
|
|
|
GL_RGBA,
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
0,
|
|
|
|
GL_RGBA,
|
|
|
|
GL_UNSIGNED_BYTE,
|
|
|
|
data);
|
|
|
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
|
|
|
|
|
|
return (void*)(intptr_t)tex;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void egl_freeTexture(LG_Renderer * renderer, void * texture)
|
|
|
|
{
|
|
|
|
GLuint tex = (GLuint)(intptr_t)texture;
|
|
|
|
glDeleteTextures(1, &tex);
|
|
|
|
}
|
|
|
|
|
2022-05-22 08:19:58 +00:00
|
|
|
static void egl_spiceConfigure(LG_Renderer * renderer, int width, int height)
|
|
|
|
{
|
|
|
|
struct Inst * this = UPCAST(struct Inst, renderer);
|
2022-09-19 00:22:42 +00:00
|
|
|
this->spiceWidth = width;
|
|
|
|
this->spiceHeight = height;
|
2022-05-22 08:19:58 +00:00
|
|
|
egl_desktopSpiceConfigure(this->desktop, width, height);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void egl_spiceDrawFill(LG_Renderer * renderer, int x, int y, int width,
|
|
|
|
int height, uint32_t color)
|
|
|
|
{
|
|
|
|
struct Inst * this = UPCAST(struct Inst, renderer);
|
|
|
|
egl_desktopSpiceDrawFill(this->desktop, x, y, width, height, color);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void egl_spiceDrawBitmap(LG_Renderer * renderer, int x, int y, int width,
|
|
|
|
int height, int stride, uint8_t * data, bool topDown)
|
|
|
|
{
|
|
|
|
struct Inst * this = UPCAST(struct Inst, renderer);
|
|
|
|
egl_desktopSpiceDrawBitmap(this->desktop, x, y, width, height, stride,
|
|
|
|
data, topDown);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void egl_spiceShow(LG_Renderer * renderer, bool show)
|
|
|
|
{
|
|
|
|
struct Inst * this = UPCAST(struct Inst, renderer);
|
|
|
|
this->showSpice = show;
|
2022-09-19 01:38:20 +00:00
|
|
|
egl_calc_mouse_size(this);
|
2022-05-22 08:19:58 +00:00
|
|
|
egl_desktopSpiceShow(this->desktop, show);
|
|
|
|
}
|
|
|
|
|
2021-08-08 04:43:04 +00:00
|
|
|
struct LG_RendererOps LGR_EGL =
|
2018-09-22 06:26:10 +00:00
|
|
|
{
|
2021-08-08 05:43:42 +00:00
|
|
|
.getName = egl_getName,
|
|
|
|
.setup = egl_setup,
|
|
|
|
.create = egl_create,
|
|
|
|
.initialize = egl_initialize,
|
|
|
|
.deinitialize = egl_deinitialize,
|
|
|
|
.supports = egl_supports,
|
|
|
|
.onRestart = egl_onRestart,
|
|
|
|
.onResize = egl_onResize,
|
|
|
|
.onMouseShape = egl_onMouseShape,
|
|
|
|
.onMouseEvent = egl_onMouseEvent,
|
|
|
|
.onFrameFormat = egl_onFrameFormat,
|
|
|
|
.onFrame = egl_onFrame,
|
|
|
|
.renderStartup = egl_renderStartup,
|
2022-05-22 08:19:58 +00:00
|
|
|
.render = egl_render,
|
2022-05-25 18:08:22 +00:00
|
|
|
.createTexture = egl_createTexture,
|
|
|
|
.freeTexture = egl_freeTexture,
|
2022-05-22 08:19:58 +00:00
|
|
|
|
|
|
|
.spiceConfigure = egl_spiceConfigure,
|
|
|
|
.spiceDrawFill = egl_spiceDrawFill,
|
|
|
|
.spiceDrawBitmap = egl_spiceDrawBitmap,
|
|
|
|
.spiceShow = egl_spiceShow
|
2020-01-17 00:50:00 +00:00
|
|
|
};
|