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
|
|
|
|
*/
|
2017-12-14 06:48:08 +00:00
|
|
|
|
2019-03-28 00:02:36 +00:00
|
|
|
#include "interface/renderer.h"
|
2017-12-05 09:33:05 +00:00
|
|
|
#include <stdint.h>
|
|
|
|
#include <stdbool.h>
|
2021-02-25 04:57:03 +00:00
|
|
|
#include <string.h>
|
2017-12-10 14:31:52 +00:00
|
|
|
#include <unistd.h>
|
2018-05-15 03:23:44 +00:00
|
|
|
#include <malloc.h>
|
2018-07-19 13:33:51 +00:00
|
|
|
#include <math.h>
|
2017-12-10 14:31:52 +00:00
|
|
|
|
2017-12-05 09:33:05 +00:00
|
|
|
#include <GL/gl.h>
|
|
|
|
|
2021-07-08 01:45:54 +00:00
|
|
|
#include "cimgui.h"
|
|
|
|
#include "generator/output/cimgui_impl.h"
|
|
|
|
|
2019-04-11 01:12:59 +00:00
|
|
|
#include "common/debug.h"
|
2019-05-21 05:03:59 +00:00
|
|
|
#include "common/option.h"
|
2019-10-01 13:17:20 +00:00
|
|
|
#include "common/framebuffer.h"
|
2020-01-17 03:35:08 +00:00
|
|
|
#include "common/locking.h"
|
2021-09-30 10:36:24 +00:00
|
|
|
#include "gl_dynprocs.h"
|
2021-08-08 05:32:01 +00:00
|
|
|
#include "util.h"
|
2017-12-10 14:31:52 +00:00
|
|
|
|
2018-05-16 07:58:36 +00:00
|
|
|
#define BUFFER_COUNT 2
|
2017-12-05 09:33:05 +00:00
|
|
|
|
2017-12-30 13:27:26 +00:00
|
|
|
#define FPS_TEXTURE 0
|
|
|
|
#define MOUSE_TEXTURE 1
|
2022-05-23 20:57:33 +00:00
|
|
|
#define SPICE_TEXTURE 2
|
|
|
|
#define TEXTURE_COUNT 3
|
2018-07-23 15:09:53 +00:00
|
|
|
|
2019-05-21 05:03:59 +00:00
|
|
|
static struct Option opengl_options[] =
|
|
|
|
{
|
|
|
|
{
|
|
|
|
.module = "opengl",
|
|
|
|
.name = "mipmap",
|
|
|
|
.description = "Enable mipmapping",
|
|
|
|
.type = OPTION_TYPE_BOOL,
|
|
|
|
.value.x_bool = true
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.module = "opengl",
|
|
|
|
.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
|
|
|
},
|
|
|
|
{
|
|
|
|
.module = "opengl",
|
|
|
|
.name = "preventBuffer",
|
|
|
|
.description = "Prevent the driver from buffering frames",
|
|
|
|
.type = OPTION_TYPE_BOOL,
|
|
|
|
.value.x_bool = true
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.module = "opengl",
|
|
|
|
.name = "amdPinnedMem",
|
|
|
|
.description = "Use GL_AMD_pinned_memory if it is available",
|
|
|
|
.type = OPTION_TYPE_BOOL,
|
|
|
|
.value.x_bool = true
|
2020-03-28 20:24:05 +00:00
|
|
|
},
|
|
|
|
{0}
|
2019-05-21 05:03:59 +00:00
|
|
|
};
|
|
|
|
|
2021-02-25 04:57:03 +00:00
|
|
|
struct IntPoint
|
|
|
|
{
|
|
|
|
int x;
|
|
|
|
int y;
|
|
|
|
};
|
|
|
|
|
2023-11-08 03:54:05 +00:00
|
|
|
struct MouseRect
|
2021-02-25 04:57:03 +00:00
|
|
|
{
|
2023-11-08 03:54:05 +00:00
|
|
|
float x;
|
|
|
|
float y;
|
2021-02-25 04:57:03 +00:00
|
|
|
int w;
|
|
|
|
int h;
|
|
|
|
};
|
|
|
|
|
2019-05-21 05:03:59 +00:00
|
|
|
struct OpenGL_Options
|
2017-12-17 11:21:59 +00:00
|
|
|
{
|
|
|
|
bool mipmap;
|
|
|
|
bool vsync;
|
2017-12-19 00:02:35 +00:00
|
|
|
bool preventBuffer;
|
2018-05-16 07:58:36 +00:00
|
|
|
bool amdPinnedMem;
|
2017-12-17 11:21:59 +00:00
|
|
|
};
|
|
|
|
|
2017-12-19 13:53:45 +00:00
|
|
|
struct Inst
|
2017-12-05 09:33:05 +00:00
|
|
|
{
|
2021-08-08 05:32:01 +00:00
|
|
|
LG_Renderer base;
|
|
|
|
|
2019-05-21 05:03:59 +00:00
|
|
|
LG_RendererParams params;
|
|
|
|
struct OpenGL_Options opt;
|
2017-12-17 11:21:59 +00:00
|
|
|
|
2018-05-15 03:23:44 +00:00
|
|
|
bool amdPinnedMemSupport;
|
2018-07-28 04:49:37 +00:00
|
|
|
bool renderStarted;
|
2017-12-14 06:42:16 +00:00
|
|
|
bool configured;
|
2017-12-19 13:53:45 +00:00
|
|
|
bool reconfigure;
|
2021-01-27 10:27:26 +00:00
|
|
|
LG_DSGLContext glContext;
|
2017-12-14 06:42:16 +00:00
|
|
|
|
2021-02-25 04:57:03 +00:00
|
|
|
struct IntPoint window;
|
2021-02-21 06:34:32 +00:00
|
|
|
float uiScale;
|
2021-07-02 11:48:31 +00:00
|
|
|
_Atomic(bool) frameUpdate;
|
2017-12-10 14:31:52 +00:00
|
|
|
|
2020-01-13 08:30:49 +00:00
|
|
|
LG_Lock formatLock;
|
|
|
|
LG_RendererFormat format;
|
|
|
|
GLuint intFormat;
|
|
|
|
GLuint vboFormat;
|
|
|
|
GLuint dataFormat;
|
|
|
|
size_t texSize;
|
|
|
|
size_t texPos;
|
2023-11-08 03:54:05 +00:00
|
|
|
float scaleX, scaleY;
|
2020-01-13 08:30:49 +00:00
|
|
|
const FrameBuffer * frame;
|
2017-12-05 09:33:05 +00:00
|
|
|
|
2017-12-10 14:31:52 +00:00
|
|
|
uint64_t drawStart;
|
2017-12-05 09:33:05 +00:00
|
|
|
bool hasBuffers;
|
2017-12-30 13:27:26 +00:00
|
|
|
GLuint vboID[BUFFER_COUNT];
|
2017-12-13 19:54:53 +00:00
|
|
|
uint8_t * texPixels[BUFFER_COUNT];
|
2021-07-02 11:48:31 +00:00
|
|
|
LG_Lock frameLock;
|
2018-05-28 05:30:04 +00:00
|
|
|
bool texReady;
|
2021-07-02 11:48:31 +00:00
|
|
|
int texWIndex, texRIndex;
|
2017-12-10 16:47:07 +00:00
|
|
|
int texList;
|
2017-12-13 02:10:32 +00:00
|
|
|
int mouseList;
|
2022-05-23 20:57:33 +00:00
|
|
|
int spiceList;
|
2017-12-10 16:47:07 +00:00
|
|
|
LG_RendererRect destRect;
|
2022-05-23 20:57:33 +00:00
|
|
|
struct IntPoint spiceSize;
|
|
|
|
bool spiceShow;
|
2017-12-05 09:33:05 +00:00
|
|
|
|
2017-12-30 13:27:26 +00:00
|
|
|
bool hasTextures, hasFrames;
|
|
|
|
GLuint frames[BUFFER_COUNT];
|
2018-05-15 03:23:44 +00:00
|
|
|
GLsync fences[BUFFER_COUNT];
|
2017-12-12 15:22:47 +00:00
|
|
|
GLuint textures[TEXTURE_COUNT];
|
2017-12-10 14:31:52 +00:00
|
|
|
|
2017-12-20 13:57:27 +00:00
|
|
|
LG_Lock mouseLock;
|
2017-12-19 13:53:45 +00:00
|
|
|
LG_RendererCursor mouseCursor;
|
|
|
|
int mouseWidth;
|
|
|
|
int mouseHeight;
|
|
|
|
int mousePitch;
|
|
|
|
uint8_t * mouseData;
|
|
|
|
size_t mouseDataSize;
|
|
|
|
|
2017-12-13 17:18:30 +00:00
|
|
|
bool mouseUpdate;
|
2017-12-15 05:53:26 +00:00
|
|
|
bool newShape;
|
2017-12-12 17:49:43 +00:00
|
|
|
LG_RendererCursor mouseType;
|
2017-12-12 15:22:47 +00:00
|
|
|
bool mouseVisible;
|
2023-11-08 03:54:05 +00:00
|
|
|
struct MouseRect mousePos;
|
2017-12-05 09:33:05 +00:00
|
|
|
};
|
|
|
|
|
2021-08-08 07:21:25 +00:00
|
|
|
static bool _checkGLError(unsigned int line, const char * name);
|
|
|
|
#define check_gl_error(name) _checkGLError(__LINE__, name)
|
2017-12-05 09:33:05 +00:00
|
|
|
|
2019-12-12 12:32:31 +00:00
|
|
|
enum ConfigStatus
|
|
|
|
{
|
|
|
|
CONFIG_STATUS_OK,
|
|
|
|
CONFIG_STATUS_ERROR,
|
|
|
|
CONFIG_STATUS_NOOP
|
|
|
|
};
|
|
|
|
|
2017-12-19 13:53:45 +00:00
|
|
|
static void deconfigure(struct Inst * this);
|
2021-01-26 10:46:30 +00:00
|
|
|
static enum ConfigStatus configure(struct Inst * this);
|
2022-05-23 20:57:33 +00:00
|
|
|
static void updateMouseShape(struct Inst * this);
|
2021-08-08 07:21:25 +00:00
|
|
|
static bool drawFrame(struct Inst * this);
|
|
|
|
static void drawMouse(struct Inst * this);
|
2017-12-05 09:33:05 +00:00
|
|
|
|
2021-08-08 05:43:42 +00:00
|
|
|
const char * opengl_getName(void)
|
2017-12-05 09:33:05 +00:00
|
|
|
{
|
|
|
|
return "OpenGL";
|
|
|
|
}
|
|
|
|
|
2021-01-14 06:05:26 +00:00
|
|
|
static void opengl_setup(void)
|
2019-05-21 05:03:59 +00:00
|
|
|
{
|
|
|
|
option_register(opengl_options);
|
|
|
|
}
|
|
|
|
|
2021-08-08 05:32:01 +00:00
|
|
|
bool opengl_create(LG_Renderer ** renderer, const LG_RendererParams params,
|
2021-01-27 08:38:34 +00:00
|
|
|
bool * needsOpenGL)
|
2017-12-05 09:33:05 +00:00
|
|
|
{
|
|
|
|
// create our local storage
|
2021-08-08 05:32:01 +00:00
|
|
|
struct Inst * this = calloc(1, sizeof(*this));
|
|
|
|
if (!this)
|
2017-12-05 09:33:05 +00:00
|
|
|
{
|
2021-08-08 05:32:01 +00:00
|
|
|
DEBUG_INFO("Failed to allocate %lu bytes", sizeof(*this));
|
2017-12-05 09:33:05 +00:00
|
|
|
return false;
|
|
|
|
}
|
2021-08-08 05:32:01 +00:00
|
|
|
*renderer = &this->base;
|
2017-12-14 06:42:16 +00:00
|
|
|
|
2019-05-21 05:03:59 +00:00
|
|
|
memcpy(&this->params, ¶ms, sizeof(LG_RendererParams));
|
|
|
|
this->opt.mipmap = option_get_bool("opengl", "mipmap" );
|
|
|
|
this->opt.vsync = option_get_bool("opengl", "vsync" );
|
|
|
|
this->opt.preventBuffer = option_get_bool("opengl", "preventBuffer");
|
|
|
|
this->opt.amdPinnedMem = option_get_bool("opengl", "amdPinnedMem" );
|
|
|
|
|
2017-12-20 13:57:27 +00:00
|
|
|
LG_LOCK_INIT(this->formatLock);
|
2021-07-02 11:48:31 +00:00
|
|
|
LG_LOCK_INIT(this->frameLock );
|
2017-12-20 13:57:27 +00:00
|
|
|
LG_LOCK_INIT(this->mouseLock );
|
|
|
|
|
2021-01-27 08:38:34 +00:00
|
|
|
*needsOpenGL = true;
|
2017-12-17 11:21:59 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-08-08 05:32:01 +00:00
|
|
|
bool opengl_initialize(LG_Renderer * renderer)
|
2017-12-17 11:21:59 +00:00
|
|
|
{
|
2022-05-26 16:07:20 +00:00
|
|
|
// struct Inst * this = UPCAST(struct Inst, renderer);
|
2021-01-27 08:38:34 +00:00
|
|
|
return true;
|
2017-12-14 06:42:16 +00:00
|
|
|
}
|
|
|
|
|
2021-08-08 05:32:01 +00:00
|
|
|
void opengl_deinitialize(LG_Renderer * renderer)
|
2017-12-19 13:53:45 +00:00
|
|
|
{
|
2021-08-08 05:32:01 +00:00
|
|
|
struct Inst * this = UPCAST(struct Inst, renderer);
|
2017-12-19 13:53:45 +00:00
|
|
|
|
2018-07-28 04:49:37 +00:00
|
|
|
if (this->renderStarted)
|
2018-07-19 14:10:29 +00:00
|
|
|
{
|
2021-07-08 01:45:54 +00:00
|
|
|
ImGui_ImplOpenGL2_Shutdown();
|
|
|
|
|
2018-07-19 15:01:16 +00:00
|
|
|
glDeleteLists(this->texList , BUFFER_COUNT);
|
|
|
|
glDeleteLists(this->mouseList, 1);
|
2022-05-23 20:57:33 +00:00
|
|
|
glDeleteLists(this->spiceList, 1);
|
2018-07-19 14:10:29 +00:00
|
|
|
}
|
|
|
|
|
2017-12-19 13:53:45 +00:00
|
|
|
deconfigure(this);
|
2021-07-02 09:50:31 +00:00
|
|
|
|
|
|
|
if (this->hasTextures)
|
|
|
|
{
|
|
|
|
glDeleteTextures(TEXTURE_COUNT, this->textures);
|
|
|
|
this->hasTextures = false;
|
|
|
|
}
|
|
|
|
|
2017-12-19 13:53:45 +00:00
|
|
|
if (this->mouseData)
|
|
|
|
free(this->mouseData);
|
|
|
|
|
2018-05-31 08:54:29 +00:00
|
|
|
if (this->glContext)
|
|
|
|
{
|
2021-01-27 10:27:26 +00:00
|
|
|
app_glDeleteContext(this->glContext);
|
2018-05-31 08:54:29 +00:00
|
|
|
this->glContext = NULL;
|
|
|
|
}
|
|
|
|
|
2017-12-20 14:23:25 +00:00
|
|
|
LG_LOCK_FREE(this->formatLock);
|
2021-07-02 11:48:31 +00:00
|
|
|
LG_LOCK_FREE(this->frameLock );
|
2017-12-20 14:23:25 +00:00
|
|
|
LG_LOCK_FREE(this->mouseLock );
|
|
|
|
|
2017-12-19 13:53:45 +00:00
|
|
|
free(this);
|
|
|
|
}
|
|
|
|
|
2021-08-08 05:43:42 +00:00
|
|
|
void opengl_onRestart(LG_Renderer * renderer)
|
2020-08-11 04:30:44 +00:00
|
|
|
{
|
2022-05-26 16:07:20 +00:00
|
|
|
// struct Inst * this = UPCAST(struct Inst, renderer);
|
2022-05-23 20:57:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void setupModelView(struct Inst * this)
|
|
|
|
{
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glLoadIdentity();
|
|
|
|
|
|
|
|
if (!this->destRect.valid)
|
|
|
|
return;
|
|
|
|
|
|
|
|
int fw, fh;
|
|
|
|
if (this->spiceShow)
|
|
|
|
{
|
|
|
|
fw = this->spiceSize.x;
|
|
|
|
fh = this->spiceSize.y;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fw = this->format.frameWidth;
|
|
|
|
fh = this->format.frameHeight;
|
|
|
|
}
|
|
|
|
glTranslatef(this->destRect.x, this->destRect.y, 0.0f);
|
|
|
|
glScalef(
|
|
|
|
(float)this->destRect.w / (float)fw,
|
|
|
|
(float)this->destRect.h / (float)fh,
|
|
|
|
1.0f
|
|
|
|
);
|
2020-08-11 04:30:44 +00:00
|
|
|
}
|
|
|
|
|
2021-08-08 05:43:42 +00:00
|
|
|
void opengl_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)
|
2017-12-19 13:53:45 +00:00
|
|
|
{
|
2021-08-08 05:32:01 +00:00
|
|
|
struct Inst * this = UPCAST(struct Inst, renderer);
|
2017-12-19 13:53:45 +00:00
|
|
|
|
2021-02-21 05:53:14 +00:00
|
|
|
this->window.x = width * scale;
|
|
|
|
this->window.y = height * scale;
|
2021-02-21 06:34:32 +00:00
|
|
|
this->uiScale = (float) scale;
|
2018-07-19 13:32:42 +00:00
|
|
|
|
|
|
|
if (destRect.valid)
|
2021-02-21 05:53:14 +00:00
|
|
|
{
|
|
|
|
this->destRect.valid = true;
|
|
|
|
this->destRect.x = destRect.x * scale;
|
|
|
|
this->destRect.y = destRect.y * scale;
|
|
|
|
this->destRect.w = destRect.w * scale;
|
|
|
|
this->destRect.h = destRect.h * scale;
|
|
|
|
}
|
2017-12-19 13:53:45 +00:00
|
|
|
|
2018-07-28 04:49:37 +00:00
|
|
|
// setup the projection matrix
|
|
|
|
glViewport(0, 0, this->window.x, this->window.y);
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
|
|
glLoadIdentity();
|
2021-02-19 02:40:05 +00:00
|
|
|
glOrtho(0, this->window.x, this->window.y, 0, -1, 1);
|
2018-07-28 04:49:37 +00:00
|
|
|
|
2021-07-23 04:01:10 +00:00
|
|
|
// this is needed to refresh the font atlas texture
|
|
|
|
ImGui_ImplOpenGL2_Shutdown();
|
2022-01-23 19:42:16 +00:00
|
|
|
ImGui_ImplOpenGL2_Init();
|
2021-07-23 04:01:10 +00:00
|
|
|
ImGui_ImplOpenGL2_NewFrame();
|
2017-12-19 13:53:45 +00:00
|
|
|
}
|
|
|
|
|
2021-08-08 05:43:42 +00:00
|
|
|
bool opengl_onMouseShape(LG_Renderer * renderer, const LG_RendererCursor cursor,
|
2021-01-18 15:44:56 +00:00
|
|
|
const int width, const int height, const int pitch, const uint8_t * data)
|
2017-12-14 06:42:16 +00:00
|
|
|
{
|
2021-08-08 05:32:01 +00:00
|
|
|
struct Inst * this = UPCAST(struct Inst, renderer);
|
2017-12-14 06:42:16 +00:00
|
|
|
|
2017-12-20 13:57:27 +00:00
|
|
|
LG_LOCK(this->mouseLock);
|
2017-12-19 13:53:45 +00:00
|
|
|
this->mouseCursor = cursor;
|
|
|
|
this->mouseWidth = width;
|
|
|
|
this->mouseHeight = height;
|
|
|
|
this->mousePitch = pitch;
|
|
|
|
|
|
|
|
const size_t size = height * pitch;
|
|
|
|
if (size > this->mouseDataSize)
|
2017-12-14 06:42:16 +00:00
|
|
|
{
|
2017-12-19 13:53:45 +00:00
|
|
|
if (this->mouseData)
|
|
|
|
free(this->mouseData);
|
2022-03-06 23:13:54 +00:00
|
|
|
|
|
|
|
this->mouseData = malloc(size);
|
|
|
|
if (!this->mouseData)
|
|
|
|
{
|
|
|
|
DEBUG_ERROR("out of memory");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-12-19 13:53:45 +00:00
|
|
|
this->mouseDataSize = size;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(this->mouseData, data, size);
|
|
|
|
this->newShape = true;
|
2017-12-20 13:57:27 +00:00
|
|
|
LG_UNLOCK(this->mouseLock);
|
2017-12-19 13:53:45 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-10-22 12:19:56 +00:00
|
|
|
bool opengl_onMouseEvent(LG_Renderer * renderer, const bool visible,
|
|
|
|
int x, int y, const int hx, const int hy)
|
2017-12-19 13:53:45 +00:00
|
|
|
{
|
2021-08-08 05:32:01 +00:00
|
|
|
struct Inst * this = UPCAST(struct Inst, renderer);
|
2017-12-19 13:53:45 +00:00
|
|
|
|
2023-11-08 03:54:05 +00:00
|
|
|
float fx = (float)x * this->scaleX;
|
|
|
|
float fy = (float)y * this->scaleY;
|
|
|
|
|
|
|
|
if (this->mousePos.x == fx &&
|
|
|
|
this->mousePos.y == fy &&
|
|
|
|
this->mouseVisible == visible)
|
2017-12-19 13:53:45 +00:00
|
|
|
return true;
|
|
|
|
|
|
|
|
this->mouseVisible = visible;
|
2023-11-08 03:54:05 +00:00
|
|
|
this->mousePos.x = fx;
|
|
|
|
this->mousePos.y = fy;
|
2017-12-19 13:53:45 +00:00
|
|
|
this->mouseUpdate = true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-08-08 05:43:42 +00:00
|
|
|
bool opengl_onFrameFormat(LG_Renderer * renderer, const LG_RendererFormat format)
|
2017-12-19 13:53:45 +00:00
|
|
|
{
|
2021-08-08 05:32:01 +00:00
|
|
|
struct Inst * this = UPCAST(struct Inst, renderer);
|
2017-12-19 13:53:45 +00:00
|
|
|
|
2017-12-20 13:57:27 +00:00
|
|
|
LG_LOCK(this->formatLock);
|
2020-10-12 08:43:29 +00:00
|
|
|
memcpy(&this->format, &format, sizeof(LG_RendererFormat));
|
2023-11-08 03:54:05 +00:00
|
|
|
|
|
|
|
this->scaleX = (float)this->format.frameWidth / this->format.screenWidth;
|
|
|
|
this->scaleY = (float)this->format.frameHeight / this->format.screenHeight;
|
|
|
|
|
2020-10-12 08:43:29 +00:00
|
|
|
this->reconfigure = true;
|
2017-12-20 14:03:21 +00:00
|
|
|
LG_UNLOCK(this->formatLock);
|
2020-10-12 08:43:29 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-08-08 05:43:42 +00:00
|
|
|
bool opengl_onFrame(LG_Renderer * renderer, const FrameBuffer * frame, int dmaFd,
|
2021-07-11 01:20:08 +00:00
|
|
|
const FrameDamageRect * damage, int damageCount)
|
2020-10-12 08:43:29 +00:00
|
|
|
{
|
2021-08-08 05:32:01 +00:00
|
|
|
struct Inst * this = UPCAST(struct Inst, renderer);
|
2017-12-19 13:53:45 +00:00
|
|
|
|
2021-07-02 11:48:31 +00:00
|
|
|
LG_LOCK(this->frameLock);
|
|
|
|
this->frame = frame;
|
|
|
|
atomic_store_explicit(&this->frameUpdate, true, memory_order_release);
|
|
|
|
LG_UNLOCK(this->frameLock);
|
2017-12-19 13:53:45 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-08-08 05:43:42 +00:00
|
|
|
bool opengl_renderStartup(LG_Renderer * renderer, bool useDMA)
|
2017-12-19 13:53:45 +00:00
|
|
|
{
|
2021-08-08 05:32:01 +00:00
|
|
|
struct Inst * this = UPCAST(struct Inst, renderer);
|
2017-12-19 13:53:45 +00:00
|
|
|
|
2021-01-27 10:27:26 +00:00
|
|
|
this->glContext = app_glCreateContext();
|
2018-07-28 04:49:37 +00:00
|
|
|
if (!this->glContext)
|
|
|
|
return false;
|
2017-12-19 13:53:45 +00:00
|
|
|
|
2021-01-27 10:27:26 +00:00
|
|
|
app_glMakeCurrent(this->glContext);
|
|
|
|
|
2018-07-28 04:49:37 +00:00
|
|
|
DEBUG_INFO("Vendor : %s", glGetString(GL_VENDOR ));
|
|
|
|
DEBUG_INFO("Renderer: %s", glGetString(GL_RENDERER));
|
|
|
|
DEBUG_INFO("Version : %s", glGetString(GL_VERSION ));
|
2018-07-19 13:32:42 +00:00
|
|
|
|
2021-09-30 10:16:25 +00:00
|
|
|
const char * exts = (const char *)glGetString(GL_EXTENSIONS);
|
|
|
|
if (util_hasGLExt(exts, "GL_AMD_pinned_memory"))
|
2018-07-28 04:49:37 +00:00
|
|
|
{
|
2021-09-30 10:16:25 +00:00
|
|
|
if (this->opt.amdPinnedMem)
|
2018-07-19 13:32:42 +00:00
|
|
|
{
|
2021-09-30 10:16:25 +00:00
|
|
|
this->amdPinnedMemSupport = true;
|
|
|
|
DEBUG_INFO("Using GL_AMD_pinned_memory");
|
2018-07-19 13:32:42 +00:00
|
|
|
}
|
2021-09-30 10:16:25 +00:00
|
|
|
else
|
|
|
|
DEBUG_INFO("GL_AMD_pinned_memory is available but not in use");
|
2018-07-28 04:49:37 +00:00
|
|
|
}
|
|
|
|
|
2021-09-30 10:36:24 +00:00
|
|
|
GLint maj, min;
|
|
|
|
glGetIntegerv(GL_MAJOR_VERSION, &maj);
|
|
|
|
glGetIntegerv(GL_MINOR_VERSION, &min);
|
|
|
|
|
|
|
|
if ((maj < 3 || (maj == 3 && min < 2)) && !util_hasGLExt(exts, "GL_ARB_sync"))
|
|
|
|
{
|
|
|
|
DEBUG_ERROR("Need OpenGL 3.2+ or GL_ARB_sync for sync objects");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (maj < 2 && !util_hasGLExt(exts, "GL_ARB_pixel_buffer_object"))
|
|
|
|
{
|
|
|
|
DEBUG_ERROR("Need OpenGL 2.0+ or GL_ARB_pixel_buffer_object");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this->opt.mipmap && maj < 3 &&
|
|
|
|
!util_hasGLExt(exts, "GL_ARB_framebuffer_object") &&
|
|
|
|
!util_hasGLExt(exts, "GL_EXT_framebuffer_object"))
|
|
|
|
{
|
|
|
|
DEBUG_WARN("Need OpenGL 3.0+ or GL_ARB_framebuffer_object or "
|
|
|
|
"GL_EXT_framebuffer_object for glGenerateMipmap, disabling mipmaps");
|
|
|
|
this->opt.mipmap = false;
|
|
|
|
}
|
|
|
|
|
2018-07-28 04:49:37 +00:00
|
|
|
glEnable(GL_TEXTURE_2D);
|
|
|
|
glEnable(GL_COLOR_MATERIAL);
|
|
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
glBlendEquation(GL_FUNC_ADD);
|
|
|
|
glEnable(GL_MULTISAMPLE);
|
2017-12-19 13:53:45 +00:00
|
|
|
|
2018-07-28 04:49:37 +00:00
|
|
|
// generate lists for drawing
|
|
|
|
this->texList = glGenLists(BUFFER_COUNT);
|
|
|
|
this->mouseList = glGenLists(1);
|
2022-05-23 20:57:33 +00:00
|
|
|
this->spiceList = glGenLists(1);
|
2018-07-28 04:49:37 +00:00
|
|
|
|
|
|
|
// create the overlay textures
|
|
|
|
glGenTextures(TEXTURE_COUNT, this->textures);
|
|
|
|
if (check_gl_error("glGenTextures"))
|
|
|
|
{
|
|
|
|
LG_UNLOCK(this->formatLock);
|
|
|
|
return false;
|
2017-12-19 13:53:45 +00:00
|
|
|
}
|
2018-07-28 04:49:37 +00:00
|
|
|
this->hasTextures = true;
|
|
|
|
|
2021-01-27 10:27:26 +00:00
|
|
|
app_glSetSwapInterval(this->opt.vsync ? 1 : 0);
|
2021-07-08 01:45:54 +00:00
|
|
|
|
|
|
|
if (!ImGui_ImplOpenGL2_Init())
|
|
|
|
{
|
|
|
|
DEBUG_ERROR("Failed to initialize ImGui");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-07-28 04:49:37 +00:00
|
|
|
this->renderStarted = true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-08-08 05:32:01 +00:00
|
|
|
bool opengl_render(LG_Renderer * renderer, LG_RendererRotate rotate, const bool newFrame,
|
2021-08-06 15:44:36 +00:00
|
|
|
const bool invalidateWindow, void (*preSwap)(void * udata), void * udata)
|
2018-07-28 04:49:37 +00:00
|
|
|
{
|
2021-08-08 05:32:01 +00:00
|
|
|
struct Inst * this = UPCAST(struct Inst, renderer);
|
2017-12-19 13:53:45 +00:00
|
|
|
|
2022-05-23 20:57:33 +00:00
|
|
|
setupModelView(this);
|
|
|
|
|
2021-01-26 10:46:30 +00:00
|
|
|
switch(configure(this))
|
2019-12-12 12:32:31 +00:00
|
|
|
{
|
|
|
|
case CONFIG_STATUS_ERROR:
|
|
|
|
DEBUG_ERROR("configure failed");
|
2018-07-19 14:10:29 +00:00
|
|
|
return false;
|
|
|
|
|
2019-12-12 12:32:31 +00:00
|
|
|
case CONFIG_STATUS_NOOP :
|
|
|
|
case CONFIG_STATUS_OK :
|
2021-08-08 07:21:25 +00:00
|
|
|
if (!drawFrame(this))
|
2021-07-02 10:05:55 +00:00
|
|
|
return false;
|
2019-12-12 12:32:31 +00:00
|
|
|
}
|
|
|
|
|
2018-07-19 15:01:16 +00:00
|
|
|
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
|
2022-09-19 02:09:54 +00:00
|
|
|
updateMouseShape(this);
|
2022-05-26 16:07:20 +00:00
|
|
|
if (this->spiceShow)
|
|
|
|
glCallList(this->spiceList);
|
2018-07-19 15:01:16 +00:00
|
|
|
else
|
2022-05-26 16:07:20 +00:00
|
|
|
glCallList(this->texList + this->texRIndex);
|
2022-09-19 02:09:54 +00:00
|
|
|
drawMouse(this);
|
2017-12-19 13:53:45 +00:00
|
|
|
|
2021-07-22 08:53:21 +00:00
|
|
|
if (app_renderOverlay(NULL, 0) != 0)
|
2021-07-08 01:45:54 +00:00
|
|
|
{
|
|
|
|
ImGui_ImplOpenGL2_NewFrame();
|
|
|
|
ImGui_ImplOpenGL2_RenderDrawData(igGetDrawData());
|
|
|
|
}
|
|
|
|
|
2021-08-06 15:44:36 +00:00
|
|
|
preSwap(udata);
|
2017-12-19 13:53:45 +00:00
|
|
|
if (this->opt.preventBuffer)
|
|
|
|
{
|
2021-01-26 10:46:30 +00:00
|
|
|
app_glSwapBuffers();
|
2018-05-21 13:16:16 +00:00
|
|
|
glFinish();
|
2017-12-19 13:53:45 +00:00
|
|
|
}
|
|
|
|
else
|
2021-01-26 10:46:30 +00:00
|
|
|
app_glSwapBuffers();
|
2017-12-19 13:53:45 +00:00
|
|
|
|
2018-11-19 18:26:51 +00:00
|
|
|
this->mouseUpdate = false;
|
2017-12-19 13:53:45 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-05-25 18:08:22 +00:00
|
|
|
static void * opengl_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 opengl_freeTexture(LG_Renderer * renderer, void * texture)
|
|
|
|
{
|
|
|
|
GLuint tex = (GLuint)(intptr_t)texture;
|
|
|
|
glDeleteTextures(1, &tex);
|
|
|
|
}
|
|
|
|
|
2022-05-23 20:57:33 +00:00
|
|
|
static void opengl_spiceConfigure(LG_Renderer * renderer, int width, int height)
|
|
|
|
{
|
|
|
|
struct Inst * this = UPCAST(struct Inst, renderer);
|
|
|
|
this->spiceSize.x = width;
|
|
|
|
this->spiceSize.y = height;
|
|
|
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, this->textures[SPICE_TEXTURE]);
|
|
|
|
glTexImage2D
|
|
|
|
(
|
|
|
|
GL_TEXTURE_2D,
|
|
|
|
0 ,
|
|
|
|
GL_RGBA,
|
|
|
|
width ,
|
|
|
|
height ,
|
|
|
|
0 ,
|
|
|
|
GL_BGRA,
|
|
|
|
GL_UNSIGNED_BYTE,
|
|
|
|
0
|
|
|
|
);
|
|
|
|
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
|
|
|
|
|
|
// create the display lists
|
|
|
|
glNewList(this->spiceList, GL_COMPILE);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, this->textures[SPICE_TEXTURE]);
|
|
|
|
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
|
|
|
glBegin(GL_TRIANGLE_STRIP);
|
|
|
|
glTexCoord2f(0.0f, 0.0f); glVertex2i(0, 0);
|
|
|
|
glTexCoord2f(1.0f, 0.0f); glVertex2i(this->spiceSize.x, 0);
|
|
|
|
glTexCoord2f(0.0f, 1.0f); glVertex2i(0, this->spiceSize.y);
|
|
|
|
glTexCoord2f(1.0f, 1.0f);
|
|
|
|
glVertex2i(this->spiceSize.x, this->spiceSize.y);
|
|
|
|
glEnd();
|
|
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
|
|
glEndList();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void opengl_spiceDrawFill(LG_Renderer * renderer, int x, int y, int width,
|
|
|
|
int height, uint32_t color)
|
|
|
|
{
|
|
|
|
struct Inst * this = UPCAST(struct Inst, renderer);
|
|
|
|
|
|
|
|
/* this is a fairly hacky way to do this, but since it's only for the fallback
|
|
|
|
* spice display it's not really an issue */
|
|
|
|
|
|
|
|
uint32_t line[width];
|
|
|
|
for(int x = 0; x < width; ++x)
|
|
|
|
line[x] = color;
|
|
|
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, this->textures[SPICE_TEXTURE]);
|
|
|
|
glPixelStorei(GL_UNPACK_ALIGNMENT , 4 );
|
|
|
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
|
|
|
|
for(; y < height; ++y)
|
|
|
|
glTexSubImage2D
|
|
|
|
(
|
|
|
|
GL_TEXTURE_2D,
|
|
|
|
0 ,
|
|
|
|
x ,
|
|
|
|
y ,
|
|
|
|
width ,
|
|
|
|
1 ,
|
|
|
|
GL_BGRA,
|
|
|
|
GL_UNSIGNED_BYTE,
|
|
|
|
line
|
|
|
|
);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void opengl_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);
|
|
|
|
|
|
|
|
if (!topDown)
|
|
|
|
{
|
|
|
|
// this is non-optimal but as spice is a fallback it's not too critical
|
|
|
|
uint8_t line[stride];
|
|
|
|
for(int y = 0; y < height / 2; ++y)
|
|
|
|
{
|
|
|
|
uint8_t * top = data + y * stride;
|
|
|
|
uint8_t * btm = data + (height - y - 1) * stride;
|
|
|
|
memcpy(line, top , stride);
|
|
|
|
memcpy(top , btm , stride);
|
|
|
|
memcpy(btm , line, stride);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, this->textures[SPICE_TEXTURE]);
|
|
|
|
glPixelStorei(GL_UNPACK_ALIGNMENT , 4 );
|
|
|
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, stride / 4);
|
|
|
|
glTexSubImage2D
|
|
|
|
(
|
|
|
|
GL_TEXTURE_2D,
|
|
|
|
0 ,
|
|
|
|
x ,
|
|
|
|
y ,
|
|
|
|
width ,
|
|
|
|
height ,
|
|
|
|
GL_BGRA,
|
|
|
|
GL_UNSIGNED_BYTE,
|
|
|
|
data
|
|
|
|
);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void opengl_spiceShow(LG_Renderer * renderer, bool show)
|
|
|
|
{
|
|
|
|
struct Inst * this = UPCAST(struct Inst, renderer);
|
|
|
|
this->spiceShow = show;
|
|
|
|
}
|
|
|
|
|
2021-08-08 04:43:04 +00:00
|
|
|
const LG_RendererOps LGR_OpenGL =
|
2017-12-19 13:53:45 +00:00
|
|
|
{
|
2021-08-08 05:43:42 +00:00
|
|
|
.getName = opengl_getName,
|
|
|
|
.setup = opengl_setup,
|
|
|
|
|
|
|
|
.create = opengl_create,
|
|
|
|
.initialize = opengl_initialize,
|
|
|
|
.deinitialize = opengl_deinitialize,
|
|
|
|
.onRestart = opengl_onRestart,
|
|
|
|
.onResize = opengl_onResize,
|
|
|
|
.onMouseShape = opengl_onMouseShape,
|
|
|
|
.onMouseEvent = opengl_onMouseEvent,
|
|
|
|
.onFrameFormat = opengl_onFrameFormat,
|
|
|
|
.onFrame = opengl_onFrame,
|
|
|
|
.renderStartup = opengl_renderStartup,
|
2022-05-23 20:57:33 +00:00
|
|
|
.render = opengl_render,
|
2022-05-25 18:08:22 +00:00
|
|
|
.createTexture = opengl_createTexture,
|
|
|
|
.freeTexture = opengl_freeTexture,
|
2022-05-23 20:57:33 +00:00
|
|
|
|
|
|
|
.spiceConfigure = opengl_spiceConfigure,
|
|
|
|
.spiceDrawFill = opengl_spiceDrawFill,
|
|
|
|
.spiceDrawBitmap = opengl_spiceDrawBitmap,
|
|
|
|
.spiceShow = opengl_spiceShow
|
2017-12-19 13:53:45 +00:00
|
|
|
};
|
|
|
|
|
2021-08-08 07:21:25 +00:00
|
|
|
static bool _checkGLError(unsigned int line, const char * name)
|
2017-12-19 13:53:45 +00:00
|
|
|
{
|
|
|
|
GLenum error = glGetError();
|
|
|
|
if (error == GL_NO_ERROR)
|
|
|
|
return false;
|
|
|
|
|
2021-02-19 02:40:05 +00:00
|
|
|
const char * errStr;
|
|
|
|
switch (error)
|
|
|
|
{
|
|
|
|
case GL_INVALID_ENUM:
|
|
|
|
errStr = "GL_INVALID_ENUM";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GL_INVALID_VALUE:
|
|
|
|
errStr = "GL_INVALID_VALUE";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GL_INVALID_OPERATION:
|
|
|
|
errStr = "GL_INVALID_OPERATION";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GL_STACK_OVERFLOW:
|
|
|
|
errStr = "GL_STACK_OVERFLOW";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GL_STACK_UNDERFLOW:
|
|
|
|
errStr = "GL_STACK_UNDERFLOW";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GL_OUT_OF_MEMORY:
|
|
|
|
errStr = "GL_OUT_OF_MEMORY";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GL_TABLE_TOO_LARGE:
|
|
|
|
errStr = "GL_TABLE_TOO_LARGE";
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
errStr = "unknown error";
|
|
|
|
}
|
2017-12-19 13:53:45 +00:00
|
|
|
DEBUG_ERROR("%d: %s = %d (%s)", line, name, error, errStr);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-01-26 10:46:30 +00:00
|
|
|
static enum ConfigStatus configure(struct Inst * this)
|
2018-05-28 05:30:04 +00:00
|
|
|
{
|
|
|
|
LG_LOCK(this->formatLock);
|
|
|
|
if (!this->reconfigure)
|
|
|
|
{
|
|
|
|
LG_UNLOCK(this->formatLock);
|
2019-12-12 12:32:31 +00:00
|
|
|
return CONFIG_STATUS_NOOP;
|
2018-05-28 05:30:04 +00:00
|
|
|
}
|
|
|
|
|
2021-07-02 09:50:15 +00:00
|
|
|
deconfigure(this);
|
2017-12-10 14:31:52 +00:00
|
|
|
|
2018-07-27 22:41:15 +00:00
|
|
|
switch(this->format.type)
|
2017-12-05 09:33:05 +00:00
|
|
|
{
|
2018-12-04 10:23:28 +00:00
|
|
|
case FRAME_TYPE_BGRA:
|
2018-12-11 23:55:18 +00:00
|
|
|
this->intFormat = GL_RGBA8;
|
|
|
|
this->vboFormat = GL_BGRA;
|
|
|
|
this->dataFormat = GL_UNSIGNED_BYTE;
|
|
|
|
break;
|
|
|
|
|
2019-10-01 13:17:20 +00:00
|
|
|
case FRAME_TYPE_RGBA:
|
2018-12-11 23:55:18 +00:00
|
|
|
this->intFormat = GL_RGBA8;
|
|
|
|
this->vboFormat = GL_RGBA;
|
|
|
|
this->dataFormat = GL_UNSIGNED_BYTE;
|
|
|
|
break;
|
|
|
|
|
2019-10-01 13:17:20 +00:00
|
|
|
case FRAME_TYPE_RGBA10:
|
2018-12-11 23:55:18 +00:00
|
|
|
this->intFormat = GL_RGB10_A2;
|
|
|
|
this->vboFormat = GL_RGBA;
|
|
|
|
this->dataFormat = GL_UNSIGNED_INT_2_10_10_10_REV;
|
2017-12-05 09:33:05 +00:00
|
|
|
break;
|
|
|
|
|
2020-10-11 09:44:22 +00:00
|
|
|
case FRAME_TYPE_RGBA16F:
|
|
|
|
this->intFormat = GL_RGB16F;
|
|
|
|
this->vboFormat = GL_RGBA;
|
|
|
|
this->dataFormat = GL_HALF_FLOAT;
|
|
|
|
break;
|
|
|
|
|
2023-11-08 05:04:58 +00:00
|
|
|
case FRAME_TYPE_RGB_24:
|
|
|
|
this->intFormat = GL_RGB8;
|
|
|
|
this->vboFormat = GL_RGB;
|
|
|
|
this->dataFormat = GL_UNSIGNED_BYTE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FRAME_TYPE_BGR_32:
|
2023-11-02 20:03:32 +00:00
|
|
|
this->intFormat = GL_RGB8;
|
|
|
|
this->vboFormat = GL_BGR;
|
|
|
|
this->dataFormat = GL_UNSIGNED_BYTE;
|
|
|
|
|
2023-11-06 03:39:34 +00:00
|
|
|
/* The data that the host returns is comes from a 32-bit RBGA texture,
|
|
|
|
* as OpenGL supports BGR directly we need to correct dimensions in order
|
|
|
|
* to make this happen.
|
2023-11-02 20:03:32 +00:00
|
|
|
*/
|
|
|
|
this->format.dataWidth = this->format.frameWidth;
|
|
|
|
this->format.dataHeight = this->format.frameHeight;
|
|
|
|
this->format.bpp = 24;
|
|
|
|
break;
|
|
|
|
|
2017-12-05 09:33:05 +00:00
|
|
|
default:
|
2019-10-01 13:17:20 +00:00
|
|
|
DEBUG_ERROR("Unknown/unsupported compression type");
|
2019-12-12 12:32:31 +00:00
|
|
|
return CONFIG_STATUS_ERROR;
|
2017-12-05 09:33:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// calculate the texture size in bytes
|
2023-11-02 20:03:32 +00:00
|
|
|
this->texSize = this->format.dataHeight * this->format.pitch;
|
2019-10-01 13:17:20 +00:00
|
|
|
this->texPos = 0;
|
2017-12-05 09:33:05 +00:00
|
|
|
|
2021-09-30 10:36:24 +00:00
|
|
|
g_gl_dynProcs.glGenBuffers(BUFFER_COUNT, this->vboID);
|
2019-10-01 13:17:20 +00:00
|
|
|
if (check_gl_error("glGenBuffers"))
|
2017-12-19 13:53:45 +00:00
|
|
|
{
|
2019-10-01 13:17:20 +00:00
|
|
|
LG_UNLOCK(this->formatLock);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
this->hasBuffers = true;
|
2017-12-05 09:33:05 +00:00
|
|
|
|
2019-10-01 13:17:20 +00:00
|
|
|
if (this->amdPinnedMemSupport)
|
|
|
|
{
|
|
|
|
const int pagesize = getpagesize();
|
|
|
|
for(int i = 0; i < BUFFER_COUNT; ++i)
|
2017-12-30 13:27:26 +00:00
|
|
|
{
|
2023-11-02 20:03:32 +00:00
|
|
|
this->texPixels[i] = aligned_alloc(pagesize,
|
|
|
|
ALIGN_TO(this->texSize, pagesize));
|
2019-12-12 12:32:31 +00:00
|
|
|
if (!this->texPixels[i])
|
|
|
|
{
|
|
|
|
DEBUG_ERROR("Failed to allocate memory for texture");
|
|
|
|
return CONFIG_STATUS_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(this->texPixels[i], 0, this->texSize);
|
2018-05-15 09:23:57 +00:00
|
|
|
|
2023-11-02 20:03:32 +00:00
|
|
|
g_gl_dynProcs.glBindBuffer(
|
|
|
|
GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, this->vboID[i]);
|
2019-10-01 13:17:20 +00:00
|
|
|
if (check_gl_error("glBindBuffer"))
|
2017-12-30 13:27:26 +00:00
|
|
|
{
|
2019-10-01 13:17:20 +00:00
|
|
|
LG_UNLOCK(this->formatLock);
|
2019-12-12 12:32:31 +00:00
|
|
|
return CONFIG_STATUS_ERROR;
|
2019-10-01 13:17:20 +00:00
|
|
|
}
|
2019-12-12 12:32:31 +00:00
|
|
|
|
2021-09-30 10:36:24 +00:00
|
|
|
g_gl_dynProcs.glBufferData(
|
2019-10-01 13:17:20 +00:00
|
|
|
GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD,
|
|
|
|
this->texSize,
|
|
|
|
this->texPixels[i],
|
2019-12-12 12:32:31 +00:00
|
|
|
GL_STREAM_DRAW
|
|
|
|
);
|
2018-05-15 03:23:44 +00:00
|
|
|
|
2019-10-01 13:17:20 +00:00
|
|
|
if (check_gl_error("glBufferData"))
|
|
|
|
{
|
|
|
|
LG_UNLOCK(this->formatLock);
|
2019-12-12 12:32:31 +00:00
|
|
|
return CONFIG_STATUS_ERROR;
|
2017-12-30 13:27:26 +00:00
|
|
|
}
|
2018-05-15 03:23:44 +00:00
|
|
|
}
|
2021-09-30 10:36:24 +00:00
|
|
|
g_gl_dynProcs.glBindBuffer(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, 0);
|
2019-10-01 13:17:20 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for(int i = 0; i < BUFFER_COUNT; ++i)
|
2018-05-15 03:23:44 +00:00
|
|
|
{
|
2021-09-30 10:36:24 +00:00
|
|
|
g_gl_dynProcs.glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->vboID[i]);
|
2019-10-01 13:17:20 +00:00
|
|
|
if (check_gl_error("glBindBuffer"))
|
2018-05-15 03:23:44 +00:00
|
|
|
{
|
2019-10-01 13:17:20 +00:00
|
|
|
LG_UNLOCK(this->formatLock);
|
2019-12-12 12:32:31 +00:00
|
|
|
return CONFIG_STATUS_ERROR;
|
2019-10-01 13:17:20 +00:00
|
|
|
}
|
2017-12-30 13:27:26 +00:00
|
|
|
|
2021-09-30 10:36:24 +00:00
|
|
|
g_gl_dynProcs.glBufferData(
|
2019-10-01 13:17:20 +00:00
|
|
|
GL_PIXEL_UNPACK_BUFFER,
|
|
|
|
this->texSize,
|
|
|
|
NULL,
|
|
|
|
GL_STREAM_DRAW
|
|
|
|
);
|
|
|
|
if (check_gl_error("glBufferData"))
|
|
|
|
{
|
|
|
|
LG_UNLOCK(this->formatLock);
|
2019-12-12 12:32:31 +00:00
|
|
|
return CONFIG_STATUS_ERROR;
|
2017-12-30 13:27:26 +00:00
|
|
|
}
|
|
|
|
}
|
2021-09-30 10:36:24 +00:00
|
|
|
g_gl_dynProcs.glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
2017-12-19 13:53:45 +00:00
|
|
|
}
|
2017-12-05 09:33:05 +00:00
|
|
|
|
2017-12-30 13:27:26 +00:00
|
|
|
// create the frame textures
|
|
|
|
glGenTextures(BUFFER_COUNT, this->frames);
|
|
|
|
if (check_gl_error("glGenTextures"))
|
2017-12-19 13:53:45 +00:00
|
|
|
{
|
2017-12-20 14:03:21 +00:00
|
|
|
LG_UNLOCK(this->formatLock);
|
2019-12-12 12:32:31 +00:00
|
|
|
return CONFIG_STATUS_ERROR;
|
2017-12-19 13:53:45 +00:00
|
|
|
}
|
2017-12-30 13:27:26 +00:00
|
|
|
this->hasFrames = true;
|
2017-12-05 09:33:05 +00:00
|
|
|
|
2017-12-30 13:27:26 +00:00
|
|
|
for(int i = 0; i < BUFFER_COUNT; ++i)
|
2017-12-19 13:53:45 +00:00
|
|
|
{
|
2017-12-30 13:27:26 +00:00
|
|
|
// bind and create the new texture
|
|
|
|
glBindTexture(GL_TEXTURE_2D, this->frames[i]);
|
|
|
|
if (check_gl_error("glBindTexture"))
|
|
|
|
{
|
|
|
|
LG_UNLOCK(this->formatLock);
|
2019-12-12 12:32:31 +00:00
|
|
|
return CONFIG_STATUS_ERROR;
|
2017-12-30 13:27:26 +00:00
|
|
|
}
|
2017-12-13 19:54:53 +00:00
|
|
|
|
2017-12-30 13:27:26 +00:00
|
|
|
glTexImage2D(
|
|
|
|
GL_TEXTURE_2D,
|
|
|
|
0,
|
|
|
|
this->intFormat,
|
2022-05-01 09:41:46 +00:00
|
|
|
this->format.frameWidth,
|
|
|
|
this->format.frameHeight,
|
2017-12-30 13:27:26 +00:00
|
|
|
0,
|
|
|
|
this->vboFormat,
|
2018-12-11 23:55:18 +00:00
|
|
|
this->dataFormat,
|
2017-12-30 13:27:26 +00:00
|
|
|
(void*)0
|
|
|
|
);
|
|
|
|
if (check_gl_error("glTexImage2D"))
|
|
|
|
{
|
|
|
|
LG_UNLOCK(this->formatLock);
|
2019-12-12 12:32:31 +00:00
|
|
|
return CONFIG_STATUS_ERROR;
|
2017-12-30 13:27:26 +00:00
|
|
|
}
|
2017-12-13 19:54:53 +00:00
|
|
|
|
2019-10-01 13:17:20 +00:00
|
|
|
// configure the texture
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
2017-12-05 09:33:05 +00:00
|
|
|
|
2017-12-13 02:10:32 +00:00
|
|
|
// create the display lists
|
|
|
|
glNewList(this->texList + i, GL_COMPILE);
|
2017-12-30 13:27:26 +00:00
|
|
|
glBindTexture(GL_TEXTURE_2D, this->frames[i]);
|
2017-12-13 02:10:32 +00:00
|
|
|
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
|
|
|
glBegin(GL_TRIANGLE_STRIP);
|
2022-05-01 09:41:46 +00:00
|
|
|
glTexCoord2f(0.0f, 0.0f); glVertex2i(0, 0);
|
|
|
|
glTexCoord2f(1.0f, 0.0f); glVertex2i(this->format.frameWidth, 0);
|
|
|
|
glTexCoord2f(0.0f, 1.0f); glVertex2i(0, this->format.frameHeight);
|
|
|
|
glTexCoord2f(1.0f, 1.0f);
|
|
|
|
glVertex2i(this->format.frameWidth, this->format.frameHeight);
|
2021-07-02 10:05:55 +00:00
|
|
|
glEnd();
|
|
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
2017-12-13 02:10:32 +00:00
|
|
|
glEndList();
|
2017-12-05 09:33:05 +00:00
|
|
|
}
|
|
|
|
|
2017-12-12 15:22:47 +00:00
|
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
2021-09-30 10:36:24 +00:00
|
|
|
g_gl_dynProcs.glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
2017-12-12 15:22:47 +00:00
|
|
|
|
2018-07-28 04:49:37 +00:00
|
|
|
this->drawStart = nanotime();
|
2017-12-19 13:53:45 +00:00
|
|
|
this->configured = true;
|
|
|
|
this->reconfigure = false;
|
|
|
|
|
2017-12-20 14:03:21 +00:00
|
|
|
LG_UNLOCK(this->formatLock);
|
2019-12-12 12:32:31 +00:00
|
|
|
return CONFIG_STATUS_OK;
|
2017-12-05 09:33:05 +00:00
|
|
|
}
|
|
|
|
|
2017-12-19 13:53:45 +00:00
|
|
|
static void deconfigure(struct Inst * this)
|
2017-12-05 09:33:05 +00:00
|
|
|
{
|
2017-12-30 13:27:26 +00:00
|
|
|
if (this->hasFrames)
|
|
|
|
{
|
|
|
|
glDeleteTextures(BUFFER_COUNT, this->frames);
|
|
|
|
this->hasFrames = false;
|
|
|
|
}
|
|
|
|
|
2017-12-05 09:33:05 +00:00
|
|
|
if (this->hasBuffers)
|
2017-12-14 06:42:16 +00:00
|
|
|
{
|
2021-09-30 10:36:24 +00:00
|
|
|
g_gl_dynProcs.glDeleteBuffers(BUFFER_COUNT, this->vboID);
|
2017-12-14 06:42:16 +00:00
|
|
|
this->hasBuffers = false;
|
|
|
|
}
|
2017-12-05 09:33:05 +00:00
|
|
|
|
2018-05-15 03:23:44 +00:00
|
|
|
if (this->amdPinnedMemSupport)
|
2018-05-15 09:25:22 +00:00
|
|
|
{
|
2018-05-15 03:23:44 +00:00
|
|
|
for(int i = 0; i < BUFFER_COUNT; ++i)
|
|
|
|
{
|
|
|
|
if (this->fences[i])
|
|
|
|
{
|
2021-09-30 10:36:24 +00:00
|
|
|
g_gl_dynProcs.glDeleteSync(this->fences[i]);
|
2018-05-15 03:23:44 +00:00
|
|
|
this->fences[i] = NULL;
|
|
|
|
}
|
2019-12-12 12:32:31 +00:00
|
|
|
|
|
|
|
if (this->texPixels[i])
|
|
|
|
{
|
|
|
|
free(this->texPixels[i]);
|
|
|
|
this->texPixels[i] = NULL;
|
|
|
|
}
|
2018-05-15 03:23:44 +00:00
|
|
|
}
|
2018-05-15 09:25:22 +00:00
|
|
|
}
|
2018-05-15 03:23:44 +00:00
|
|
|
|
2017-12-14 06:42:16 +00:00
|
|
|
this->configured = false;
|
|
|
|
}
|
|
|
|
|
2022-05-23 20:57:33 +00:00
|
|
|
static void updateMouseShape(struct Inst * this)
|
2017-12-05 09:33:05 +00:00
|
|
|
{
|
2017-12-20 14:03:21 +00:00
|
|
|
LG_LOCK(this->mouseLock);
|
2017-12-19 13:53:45 +00:00
|
|
|
if (!this->newShape)
|
|
|
|
{
|
2017-12-20 14:03:21 +00:00
|
|
|
LG_UNLOCK(this->mouseLock);
|
2017-12-10 14:31:52 +00:00
|
|
|
return;
|
2017-12-19 13:53:45 +00:00
|
|
|
}
|
2017-12-10 14:31:52 +00:00
|
|
|
|
2017-12-19 13:53:45 +00:00
|
|
|
const LG_RendererCursor cursor = this->mouseCursor;
|
|
|
|
const int width = this->mouseWidth;
|
|
|
|
const int height = this->mouseHeight;
|
|
|
|
const int pitch = this->mousePitch;
|
|
|
|
const uint8_t * data = this->mouseData;
|
2017-12-12 16:08:13 +00:00
|
|
|
|
2018-05-28 01:39:19 +00:00
|
|
|
// tmp buffer for masked colour
|
|
|
|
uint32_t tmp[width * height];
|
|
|
|
|
2017-12-12 17:49:43 +00:00
|
|
|
this->mouseType = cursor;
|
2017-12-12 16:51:25 +00:00
|
|
|
switch(cursor)
|
|
|
|
{
|
2018-05-28 01:39:19 +00:00
|
|
|
case LG_CURSOR_MASKED_COLOR:
|
|
|
|
for(int i = 0; i < width * height; ++i)
|
|
|
|
{
|
|
|
|
const uint32_t c = ((uint32_t *)data)[i];
|
|
|
|
tmp[i] = (c & ~0xFF000000) | (c & 0xFF000000 ? 0x0 : 0xFF000000);
|
|
|
|
}
|
|
|
|
data = (uint8_t *)tmp;
|
|
|
|
// fall through to LG_CURSOR_COLOR
|
|
|
|
//
|
|
|
|
// technically we should also create an XOR texture from the data but this
|
|
|
|
// usage seems very rare in modern software.
|
|
|
|
|
2017-12-12 16:51:25 +00:00
|
|
|
case LG_CURSOR_COLOR:
|
|
|
|
{
|
|
|
|
glBindTexture(GL_TEXTURE_2D, this->textures[MOUSE_TEXTURE]);
|
|
|
|
glPixelStorei(GL_UNPACK_ALIGNMENT , 4 );
|
|
|
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
|
|
|
|
glTexImage2D
|
|
|
|
(
|
|
|
|
GL_TEXTURE_2D,
|
|
|
|
0 ,
|
|
|
|
GL_RGBA,
|
|
|
|
width ,
|
|
|
|
height ,
|
|
|
|
0 ,
|
2017-12-14 23:20:20 +00:00
|
|
|
GL_BGRA, // windows cursors are in BGRA format
|
2017-12-12 16:51:25 +00:00
|
|
|
GL_UNSIGNED_BYTE,
|
|
|
|
data
|
|
|
|
);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
|
|
|
|
|
|
this->mousePos.w = width;
|
|
|
|
this->mousePos.h = height;
|
2017-12-13 02:10:32 +00:00
|
|
|
|
|
|
|
glNewList(this->mouseList, GL_COMPILE);
|
|
|
|
glEnable(GL_BLEND);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, this->textures[MOUSE_TEXTURE]);
|
|
|
|
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
|
|
|
glBegin(GL_TRIANGLE_STRIP);
|
|
|
|
glTexCoord2f(0.0f, 0.0f); glVertex2i(0 , 0 );
|
|
|
|
glTexCoord2f(1.0f, 0.0f); glVertex2i(width, 0 );
|
|
|
|
glTexCoord2f(0.0f, 1.0f); glVertex2i(0 , height);
|
|
|
|
glTexCoord2f(1.0f, 1.0f); glVertex2i(width, height);
|
|
|
|
glEnd();
|
|
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
|
|
glDisable(GL_BLEND);
|
|
|
|
glEndList();
|
2017-12-12 16:51:25 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case LG_CURSOR_MONOCHROME:
|
|
|
|
{
|
2017-12-13 02:10:32 +00:00
|
|
|
const int hheight = height / 2;
|
2017-12-12 17:49:43 +00:00
|
|
|
uint32_t d[width * height];
|
2017-12-13 02:10:32 +00:00
|
|
|
for(int y = 0; y < hheight; ++y)
|
2017-12-12 17:49:43 +00:00
|
|
|
for(int x = 0; x < width; ++x)
|
|
|
|
{
|
|
|
|
const uint8_t * srcAnd = data + (pitch * y) + (x / 8);
|
2017-12-13 02:10:32 +00:00
|
|
|
const uint8_t * srcXor = srcAnd + pitch * hheight;
|
2017-12-12 17:49:43 +00:00
|
|
|
const uint8_t mask = 0x80 >> (x % 8);
|
|
|
|
const uint32_t andMask = (*srcAnd & mask) ? 0xFFFFFFFF : 0xFF000000;
|
|
|
|
const uint32_t xorMask = (*srcXor & mask) ? 0x00FFFFFF : 0x00000000;
|
|
|
|
|
2017-12-13 02:10:32 +00:00
|
|
|
d[y * width + x ] = andMask;
|
|
|
|
d[y * width + x + width * hheight] = xorMask;
|
2017-12-12 17:49:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, this->textures[MOUSE_TEXTURE]);
|
|
|
|
glPixelStorei(GL_UNPACK_ALIGNMENT , 4 );
|
|
|
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
|
|
|
|
glTexImage2D
|
|
|
|
(
|
|
|
|
GL_TEXTURE_2D,
|
|
|
|
0 ,
|
|
|
|
GL_RGBA,
|
|
|
|
width ,
|
|
|
|
height ,
|
|
|
|
0 ,
|
|
|
|
GL_RGBA,
|
|
|
|
GL_UNSIGNED_BYTE,
|
|
|
|
d
|
|
|
|
);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
|
|
|
|
|
|
this->mousePos.w = width;
|
2017-12-13 02:10:32 +00:00
|
|
|
this->mousePos.h = hheight;
|
|
|
|
|
|
|
|
glNewList(this->mouseList, GL_COMPILE);
|
|
|
|
glEnable(GL_COLOR_LOGIC_OP);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, this->textures[MOUSE_TEXTURE]);
|
|
|
|
glLogicOp(GL_AND);
|
|
|
|
glBegin(GL_TRIANGLE_STRIP);
|
2017-12-13 09:44:58 +00:00
|
|
|
glTexCoord2f(0.0f, 0.0f); glVertex2i(0 , 0 );
|
|
|
|
glTexCoord2f(1.0f, 0.0f); glVertex2i(width, 0 );
|
2017-12-13 02:10:32 +00:00
|
|
|
glTexCoord2f(0.0f, 0.5f); glVertex2i(0 , hheight);
|
|
|
|
glTexCoord2f(1.0f, 0.5f); glVertex2i(width, hheight);
|
|
|
|
glEnd();
|
|
|
|
glLogicOp(GL_XOR);
|
|
|
|
glBegin(GL_TRIANGLE_STRIP);
|
2017-12-13 09:44:58 +00:00
|
|
|
glTexCoord2f(0.0f, 0.5f); glVertex2i(0 , 0 );
|
|
|
|
glTexCoord2f(1.0f, 0.5f); glVertex2i(width, 0 );
|
2017-12-13 02:10:32 +00:00
|
|
|
glTexCoord2f(0.0f, 1.0f); glVertex2i(0 , hheight);
|
|
|
|
glTexCoord2f(1.0f, 1.0f); glVertex2i(width, hheight);
|
|
|
|
glEnd();
|
2018-07-19 15:01:16 +00:00
|
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
2017-12-13 02:10:32 +00:00
|
|
|
glDisable(GL_COLOR_LOGIC_OP);
|
|
|
|
glEndList();
|
2017-12-12 16:51:25 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-13 17:18:30 +00:00
|
|
|
this->mouseUpdate = true;
|
2017-12-20 14:03:21 +00:00
|
|
|
LG_UNLOCK(this->mouseLock);
|
2017-12-12 16:08:13 +00:00
|
|
|
}
|
|
|
|
|
2021-08-08 07:21:25 +00:00
|
|
|
static bool opengl_bufferFn(void * opaque, const void * data, size_t size)
|
2019-10-01 13:17:20 +00:00
|
|
|
{
|
|
|
|
struct Inst * this = (struct Inst *)opaque;
|
|
|
|
|
|
|
|
// update the buffer, this performs a DMA transfer if possible
|
2021-09-30 10:36:24 +00:00
|
|
|
g_gl_dynProcs.glBufferSubData(
|
2019-10-01 13:17:20 +00:00
|
|
|
GL_PIXEL_UNPACK_BUFFER,
|
|
|
|
this->texPos,
|
|
|
|
size,
|
|
|
|
data
|
|
|
|
);
|
2023-11-11 02:02:50 +00:00
|
|
|
|
|
|
|
if (check_gl_error("glBufferSubData"))
|
|
|
|
return false;
|
2019-10-01 13:17:20 +00:00
|
|
|
|
|
|
|
this->texPos += size;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-08-08 07:21:25 +00:00
|
|
|
static bool drawFrame(struct Inst * this)
|
2017-12-12 15:22:47 +00:00
|
|
|
{
|
2021-09-30 10:36:24 +00:00
|
|
|
if (g_gl_dynProcs.glIsSync(this->fences[this->texWIndex]))
|
2017-12-14 06:42:16 +00:00
|
|
|
{
|
2021-09-30 10:36:24 +00:00
|
|
|
switch(g_gl_dynProcs.glClientWaitSync(this->fences[this->texWIndex], 0, GL_TIMEOUT_IGNORED))
|
2018-05-15 03:23:44 +00:00
|
|
|
{
|
2019-10-01 13:17:20 +00:00
|
|
|
case GL_ALREADY_SIGNALED:
|
|
|
|
break;
|
2017-12-10 16:02:45 +00:00
|
|
|
|
2019-10-01 13:17:20 +00:00
|
|
|
case GL_CONDITION_SATISFIED:
|
|
|
|
DEBUG_WARN("Had to wait for the sync");
|
|
|
|
break;
|
2018-05-15 03:23:44 +00:00
|
|
|
|
2019-10-01 13:17:20 +00:00
|
|
|
case GL_TIMEOUT_EXPIRED:
|
|
|
|
DEBUG_WARN("Timeout expired, DMA transfers are too slow!");
|
|
|
|
break;
|
2018-05-15 03:23:44 +00:00
|
|
|
|
2019-10-01 13:17:20 +00:00
|
|
|
case GL_WAIT_FAILED:
|
2021-02-19 02:40:05 +00:00
|
|
|
DEBUG_ERROR("Wait failed %d", glGetError());
|
2019-10-01 13:17:20 +00:00
|
|
|
break;
|
2018-05-15 03:23:44 +00:00
|
|
|
}
|
2017-12-13 19:54:53 +00:00
|
|
|
|
2021-09-30 10:36:24 +00:00
|
|
|
g_gl_dynProcs.glDeleteSync(this->fences[this->texWIndex]);
|
2021-07-02 11:48:31 +00:00
|
|
|
this->fences[this->texWIndex] = NULL;
|
|
|
|
|
|
|
|
this->texRIndex = this->texWIndex;
|
|
|
|
if (++this->texWIndex == BUFFER_COUNT)
|
|
|
|
this->texWIndex = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
LG_LOCK(this->frameLock);
|
|
|
|
if (!atomic_exchange_explicit(&this->frameUpdate, false, memory_order_acquire))
|
|
|
|
{
|
|
|
|
LG_UNLOCK(this->frameLock);
|
|
|
|
return true;
|
2019-10-01 13:17:20 +00:00
|
|
|
}
|
2017-12-30 13:27:26 +00:00
|
|
|
|
2021-07-02 11:48:31 +00:00
|
|
|
LG_LOCK(this->formatLock);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, this->frames[this->texWIndex]);
|
2021-09-30 10:36:24 +00:00
|
|
|
g_gl_dynProcs.glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->vboID[this->texWIndex]);
|
2018-05-15 03:23:44 +00:00
|
|
|
|
2023-11-02 20:03:32 +00:00
|
|
|
int bpp = this->format.bpp / 8;
|
2023-11-08 03:40:30 +00:00
|
|
|
glPixelStorei(GL_UNPACK_ALIGNMENT , bpp < 4 ? 1 : bpp);
|
2023-11-06 03:39:34 +00:00
|
|
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, this->format.frameWidth);
|
2018-05-15 03:23:44 +00:00
|
|
|
|
2019-10-01 13:17:20 +00:00
|
|
|
this->texPos = 0;
|
|
|
|
framebuffer_read_fn(
|
|
|
|
this->frame,
|
2023-11-02 20:03:32 +00:00
|
|
|
this->format.dataHeight,
|
|
|
|
this->format.dataWidth,
|
2020-04-14 03:27:07 +00:00
|
|
|
bpp,
|
|
|
|
this->format.pitch,
|
2021-08-08 07:21:25 +00:00
|
|
|
opengl_bufferFn,
|
2019-10-01 13:17:20 +00:00
|
|
|
this
|
|
|
|
);
|
2017-12-30 13:27:26 +00:00
|
|
|
|
2021-07-02 11:48:31 +00:00
|
|
|
LG_UNLOCK(this->frameLock);
|
|
|
|
|
2019-10-01 13:17:20 +00:00
|
|
|
// update the texture
|
|
|
|
glTexSubImage2D(
|
|
|
|
GL_TEXTURE_2D,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0,
|
2022-05-01 09:41:46 +00:00
|
|
|
this->format.frameWidth ,
|
|
|
|
this->format.frameHeight,
|
2019-10-01 13:17:20 +00:00
|
|
|
this->vboFormat,
|
|
|
|
this->dataFormat,
|
|
|
|
(void*)0
|
|
|
|
);
|
|
|
|
if (check_gl_error("glTexSubImage2D"))
|
|
|
|
{
|
2023-11-02 20:03:32 +00:00
|
|
|
DEBUG_ERROR(
|
|
|
|
"texWIndex: %u, "
|
|
|
|
"width: %u, "
|
|
|
|
"height: %u, "
|
|
|
|
"vboFormat: %x, "
|
|
|
|
"texSize: %lu",
|
|
|
|
this->texWIndex,
|
|
|
|
this->format.frameWidth,
|
|
|
|
this->format.frameHeight,
|
|
|
|
this->vboFormat,
|
|
|
|
this->texSize
|
2017-12-30 13:27:26 +00:00
|
|
|
);
|
2019-10-01 13:17:20 +00:00
|
|
|
}
|
2017-12-30 13:27:26 +00:00
|
|
|
|
2019-10-01 13:17:20 +00:00
|
|
|
// unbind the buffer
|
2021-09-30 10:36:24 +00:00
|
|
|
g_gl_dynProcs.glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
2017-12-05 09:33:05 +00:00
|
|
|
|
2017-12-17 11:21:59 +00:00
|
|
|
const bool mipmap = this->opt.mipmap && (
|
2022-05-01 09:41:46 +00:00
|
|
|
(this->format.frameWidth > this->destRect.w) ||
|
|
|
|
(this->format.frameHeight > this->destRect.h));
|
2017-12-05 09:33:05 +00:00
|
|
|
|
|
|
|
if (mipmap)
|
2017-12-16 00:25:01 +00:00
|
|
|
{
|
2021-09-30 10:36:24 +00:00
|
|
|
g_gl_dynProcs.glGenerateMipmap(GL_TEXTURE_2D);
|
2017-12-16 00:25:01 +00:00
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
|
|
}
|
2017-12-13 19:54:53 +00:00
|
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
2017-12-30 13:27:26 +00:00
|
|
|
|
2021-07-02 11:48:31 +00:00
|
|
|
// set a fence so we don't overwrite a buffer in use
|
|
|
|
this->fences[this->texWIndex] =
|
2021-09-30 10:36:24 +00:00
|
|
|
g_gl_dynProcs.glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
2021-07-02 11:48:31 +00:00
|
|
|
glFlush();
|
|
|
|
|
2017-12-20 14:03:21 +00:00
|
|
|
LG_UNLOCK(this->formatLock);
|
2018-05-28 05:30:04 +00:00
|
|
|
this->texReady = true;
|
2017-12-12 15:22:47 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-08-08 07:21:25 +00:00
|
|
|
static void drawMouse(struct Inst * this)
|
2017-12-12 15:22:47 +00:00
|
|
|
{
|
|
|
|
if (!this->mouseVisible)
|
|
|
|
return;
|
2017-12-05 09:33:05 +00:00
|
|
|
|
2017-12-12 15:22:47 +00:00
|
|
|
glPushMatrix();
|
2017-12-13 19:54:53 +00:00
|
|
|
glTranslatef(this->mousePos.x, this->mousePos.y, 0.0f);
|
2017-12-13 02:10:32 +00:00
|
|
|
glCallList(this->mouseList);
|
2017-12-12 15:22:47 +00:00
|
|
|
glPopMatrix();
|
2020-01-17 03:35:08 +00:00
|
|
|
}
|