mirror of
https://github.com/gnif/LookingGlass.git
synced 2024-11-25 14:57:20 +00:00
[client] spice: added initial framework for spice display fallback
This commit is contained in:
parent
ffd27ac82c
commit
16f39450b5
@ -134,6 +134,7 @@ set(SOURCES
|
||||
src/egl_dynprocs.c
|
||||
src/eglutil.c
|
||||
src/overlay_utils.c
|
||||
src/render_queue.c
|
||||
|
||||
src/overlay/alert.c
|
||||
src/overlay/fps.c
|
||||
|
@ -179,5 +179,9 @@ bool app_guestIsOSX(void);
|
||||
bool app_guestIsBSD(void);
|
||||
bool app_guestIsOther(void);
|
||||
|
||||
/**
|
||||
* Enable/disable the spice display
|
||||
*/
|
||||
void app_useSpiceDisplay(bool enable);
|
||||
|
||||
#endif
|
||||
|
@ -27,17 +27,21 @@
|
||||
#include "common/framebuffer.h"
|
||||
|
||||
#define IS_LG_RENDERER_VALID(x) \
|
||||
((x)->getName && \
|
||||
(x)->create && \
|
||||
(x)->initialize && \
|
||||
(x)->deinitialize && \
|
||||
(x)->onRestart && \
|
||||
(x)->onResize && \
|
||||
(x)->onMouseShape && \
|
||||
(x)->onMouseEvent && \
|
||||
(x)->renderStartup && \
|
||||
(x)->needsRender && \
|
||||
(x)->render)
|
||||
((x)->getName && \
|
||||
(x)->create && \
|
||||
(x)->initialize && \
|
||||
(x)->deinitialize && \
|
||||
(x)->onRestart && \
|
||||
(x)->onResize && \
|
||||
(x)->onMouseShape && \
|
||||
(x)->onMouseEvent && \
|
||||
(x)->renderStartup && \
|
||||
(x)->needsRender && \
|
||||
(x)->render && \
|
||||
(x)->spiceConfigure && \
|
||||
(x)->spiceDrawFill && \
|
||||
(x)->spiceDrawBitmap && \
|
||||
(x)->spiceShow)
|
||||
|
||||
typedef struct LG_RendererParams
|
||||
{
|
||||
@ -167,6 +171,20 @@ typedef struct LG_RendererOps
|
||||
bool (*render)(LG_Renderer * renderer, LG_RendererRotate rotate,
|
||||
const bool newFrame, const bool invalidateWindow,
|
||||
void (*preSwap)(void * udata), void * udata);
|
||||
|
||||
/* setup the spice display */
|
||||
void (*spiceConfigure)(LG_Renderer * renderer, int width, int height);
|
||||
|
||||
/* draw a filled rect on the spice display with the specified color */
|
||||
void (*spiceDrawFill)(LG_Renderer * renderer, int x, int y, int width,
|
||||
int height, uint32_t color);
|
||||
|
||||
/* draw an image on the spice display, data is RGBA32 */
|
||||
void (*spiceDrawBitmap)(LG_Renderer * renderer, int x, int y, int width,
|
||||
int height, int stride, uint8_t * data);
|
||||
|
||||
/* show the spice display */
|
||||
void (*spiceShow)(LG_Renderer * renderer, bool show);
|
||||
}
|
||||
LG_RendererOps;
|
||||
|
||||
|
@ -1008,3 +1008,23 @@ bool app_guestIsOther(void)
|
||||
{
|
||||
return g_state.guestOS == KVMFR_OS_OTHER;
|
||||
}
|
||||
|
||||
void app_useSpiceDisplay(bool enable)
|
||||
{
|
||||
if (!g_params.useSpice)
|
||||
return;
|
||||
|
||||
if (!purespice_hasChannel(PS_CHANNEL_DISPLAY))
|
||||
return;
|
||||
|
||||
if (enable)
|
||||
{
|
||||
purespice_connectChannel(PS_CHANNEL_DISPLAY);
|
||||
// do not call spiceShow as the surface create callback will do this
|
||||
}
|
||||
else
|
||||
{
|
||||
RENDERER(spiceShow, false);
|
||||
purespice_disconnectChannel(PS_CHANNEL_DISPLAY);
|
||||
}
|
||||
}
|
||||
|
@ -667,7 +667,7 @@ bool config_load(int argc, char * argv[])
|
||||
|
||||
g_params.minimizeOnFocusLoss = option_get_bool("win", "minimizeOnFocusLoss");
|
||||
|
||||
if (option_get_bool("spice", "enable"))
|
||||
if ((g_params.useSpice = option_get_bool("spice", "enable")))
|
||||
{
|
||||
g_params.spiceHost = option_get_string("spice", "host");
|
||||
g_params.spicePort = option_get_int ("spice", "port");
|
||||
|
@ -62,6 +62,7 @@
|
||||
#include "overlays.h"
|
||||
#include "overlay_utils.h"
|
||||
#include "util.h"
|
||||
#include "render_queue.h"
|
||||
|
||||
// forwards
|
||||
static int renderThread(void * unused);
|
||||
@ -280,6 +281,9 @@ static int renderThread(void * unused)
|
||||
|
||||
const uint64_t renderStart = nanotime();
|
||||
LG_LOCK(g_state.lgrLock);
|
||||
|
||||
renderQueue_process();
|
||||
|
||||
if (!RENDERER(render, g_params.winRotate, newFrame, invalidate,
|
||||
preSwapCallback, (void *)&renderStart))
|
||||
{
|
||||
@ -595,6 +599,9 @@ int main_frameThread(void * unused)
|
||||
break;
|
||||
}
|
||||
|
||||
// disable the spice display as we have a frame from the LG host
|
||||
app_useSpiceDisplay(false);
|
||||
|
||||
KVMFRFrame * frame = (KVMFRFrame *)msg.mem;
|
||||
|
||||
// ignore any repeated frames, this happens when a new client connects to
|
||||
@ -800,7 +807,9 @@ int main_frameThread(void * unused)
|
||||
}
|
||||
|
||||
lgmpClientUnsubscribe(&queue);
|
||||
|
||||
RENDERER(onRestart);
|
||||
app_useSpiceDisplay(true);
|
||||
|
||||
if (g_state.useDMA)
|
||||
{
|
||||
@ -809,7 +818,6 @@ int main_frameThread(void * unused)
|
||||
close(dmaInfo[i].fd);
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -862,6 +870,32 @@ void spiceReady(void)
|
||||
purespice_freeServerInfo(&info);
|
||||
}
|
||||
|
||||
static void spice_surfaceCreate(unsigned int surfaceId, PSSurfaceFormat format,
|
||||
unsigned int width, unsigned int height)
|
||||
{
|
||||
renderQueue_spiceConfigure(width, height);
|
||||
if (g_state.lgr)
|
||||
RENDERER(spiceShow, true);
|
||||
}
|
||||
|
||||
static void spice_surfaceDestroy(unsigned int surfaceId)
|
||||
{
|
||||
if (g_state.lgr)
|
||||
RENDERER(spiceShow, false);
|
||||
}
|
||||
|
||||
static void spice_drawFill(unsigned int surfaceId, int x, int y, int width,
|
||||
int height, uint32_t color)
|
||||
{
|
||||
renderQueue_spiceDrawFill(x, y, width, height, color);
|
||||
}
|
||||
|
||||
static void spice_drawBitmap(unsigned int surfaceId, PSBitmapFormat format,
|
||||
bool topDown, int x, int y, int width, int height, int stride, void * data)
|
||||
{
|
||||
renderQueue_spiceDrawBitmap(x, y, width, height, stride, data);
|
||||
}
|
||||
|
||||
int spiceThread(void * arg)
|
||||
{
|
||||
if (g_params.useSpiceAudio)
|
||||
@ -886,6 +920,14 @@ int spiceThread(void * arg)
|
||||
.release = cb_spiceRelease,
|
||||
.request = cb_spiceRequest
|
||||
},
|
||||
.display =
|
||||
{
|
||||
.enable = true,
|
||||
.surfaceCreate = spice_surfaceCreate,
|
||||
.surfaceDestroy = spice_surfaceDestroy,
|
||||
.drawFill = spice_drawFill,
|
||||
.drawBitmap = spice_drawBitmap
|
||||
},
|
||||
#if ENABLE_AUDIO
|
||||
.playback =
|
||||
{
|
||||
@ -1117,6 +1159,9 @@ static int lg_run(void)
|
||||
return -1;
|
||||
}
|
||||
|
||||
//setup the render command queue
|
||||
renderQueue_init();
|
||||
|
||||
const PSInit psInit =
|
||||
{
|
||||
.log =
|
||||
@ -1261,6 +1306,10 @@ static int lg_run(void)
|
||||
if (g_state.cbAvailable)
|
||||
g_state.cbRequestList = ll_new();
|
||||
|
||||
// fallback to the spice display
|
||||
if (g_params.useSpice && purespice_hasChannel(PS_CHANNEL_DISPLAY))
|
||||
purespice_connectChannel(PS_CHANNEL_DISPLAY);
|
||||
|
||||
LGMP_STATUS status;
|
||||
|
||||
while(g_state.state == APP_STATE_RUNNING)
|
||||
@ -1610,6 +1659,8 @@ static void lg_shutdown(void)
|
||||
|
||||
ivshmemClose(&g_state.shm);
|
||||
|
||||
renderQueue_free();
|
||||
|
||||
// free metrics ringbuffers
|
||||
ringbuffer_free(&g_state.renderTimings);
|
||||
ringbuffer_free(&g_state.uploadTimings);
|
||||
|
@ -159,6 +159,7 @@ struct AppParams
|
||||
unsigned int w, h;
|
||||
int fpsMin;
|
||||
LG_RendererRotate winRotate;
|
||||
bool useSpice;
|
||||
bool useSpiceInput;
|
||||
bool useSpiceClipboard;
|
||||
bool useSpiceAudio;
|
||||
|
121
client/src/render_queue.c
Normal file
121
client/src/render_queue.c
Normal file
@ -0,0 +1,121 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include "render_queue.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "common/ll.h"
|
||||
#include "main.h"
|
||||
|
||||
struct ll * l_renderQueue = NULL;
|
||||
|
||||
void renderQueue_init(void)
|
||||
{
|
||||
l_renderQueue = ll_new();
|
||||
}
|
||||
|
||||
void renderQueue_clear(void)
|
||||
{
|
||||
RenderCommand * cmd;
|
||||
while(ll_shift(l_renderQueue, (void **)&cmd))
|
||||
{
|
||||
if (cmd->op == SPICE_OP_DRAW_BITMAP)
|
||||
free(cmd->drawBitmap.data);
|
||||
free(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
void renderQueue_spiceConfigure(int width, int height)
|
||||
{
|
||||
RenderCommand * cmd = malloc(sizeof(*cmd));
|
||||
cmd->op = SPICE_OP_CONFIGURE;
|
||||
cmd->configure.width = width;
|
||||
cmd->configure.height = height;
|
||||
ll_push(l_renderQueue, cmd);
|
||||
app_invalidateWindow(true);
|
||||
}
|
||||
|
||||
void renderQueue_spiceDrawFill(int x, int y, int width, int height,
|
||||
uint32_t color)
|
||||
{
|
||||
RenderCommand * cmd = malloc(sizeof(*cmd));
|
||||
cmd->op = SPICE_OP_DRAW_FILL;
|
||||
cmd->fillRect.x = x;
|
||||
cmd->fillRect.y = y;
|
||||
cmd->fillRect.width = width;
|
||||
cmd->fillRect.height = height;
|
||||
cmd->fillRect.color = color;
|
||||
ll_push(l_renderQueue, cmd);
|
||||
app_invalidateWindow(true);
|
||||
}
|
||||
|
||||
void renderQueue_spiceDrawBitmap(int x, int y, int width, int height, int stride,
|
||||
void * data)
|
||||
{
|
||||
RenderCommand * cmd = malloc(sizeof(*cmd));
|
||||
cmd->op = SPICE_OP_DRAW_BITMAP;
|
||||
cmd->drawBitmap.x = x;
|
||||
cmd->drawBitmap.y = y;
|
||||
cmd->drawBitmap.width = width;
|
||||
cmd->drawBitmap.height = height;
|
||||
cmd->drawBitmap.stride = stride;
|
||||
cmd->drawBitmap.data = malloc(height * stride);
|
||||
memcpy(cmd->drawBitmap.data, data, height * stride);
|
||||
ll_push(l_renderQueue, cmd);
|
||||
app_invalidateWindow(true);
|
||||
}
|
||||
|
||||
void renderQueue_free(void)
|
||||
{
|
||||
renderQueue_clear();
|
||||
ll_free(l_renderQueue);
|
||||
}
|
||||
|
||||
void renderQueue_process(void)
|
||||
{
|
||||
RenderCommand * cmd;
|
||||
while(ll_shift(l_renderQueue, (void **)&cmd))
|
||||
{
|
||||
switch(cmd->op)
|
||||
{
|
||||
case SPICE_OP_CONFIGURE:
|
||||
RENDERER(spiceConfigure,
|
||||
cmd->configure.width, cmd->configure.height);
|
||||
break;
|
||||
|
||||
case SPICE_OP_DRAW_FILL:
|
||||
RENDERER(spiceDrawFill,
|
||||
cmd->fillRect.x , cmd->fillRect.y,
|
||||
cmd->fillRect.width, cmd->fillRect.height,
|
||||
cmd->fillRect.color);
|
||||
break;
|
||||
|
||||
case SPICE_OP_DRAW_BITMAP:
|
||||
RENDERER(spiceDrawBitmap,
|
||||
cmd->drawBitmap.x , cmd->drawBitmap.y,
|
||||
cmd->drawBitmap.width , cmd->drawBitmap.height,
|
||||
cmd->drawBitmap.stride, cmd->drawBitmap.data);
|
||||
free(cmd->drawBitmap.data);
|
||||
break;
|
||||
}
|
||||
free(cmd);
|
||||
}
|
||||
}
|
72
client/src/render_queue.h
Normal file
72
client/src/render_queue.h
Normal file
@ -0,0 +1,72 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2022 The Looking Glass Authors
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include "common/ll.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
enum
|
||||
{
|
||||
SPICE_OP_CONFIGURE,
|
||||
SPICE_OP_DRAW_FILL,
|
||||
SPICE_OP_DRAW_BITMAP
|
||||
}
|
||||
op;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
int width, height;
|
||||
}
|
||||
configure;
|
||||
|
||||
struct
|
||||
{
|
||||
int x, y;
|
||||
int width, height;
|
||||
uint32_t color;
|
||||
}
|
||||
fillRect;
|
||||
|
||||
struct
|
||||
{
|
||||
int x , y;
|
||||
int width, height;
|
||||
int stride;
|
||||
uint8_t * data;
|
||||
}
|
||||
drawBitmap;
|
||||
};
|
||||
}
|
||||
RenderCommand;
|
||||
|
||||
void renderQueue_init(void);
|
||||
void renderQueue_free(void);
|
||||
void renderQueue_clear(void);
|
||||
void renderQueue_process(void);
|
||||
|
||||
void renderQueue_spiceConfigure(int width, int height);
|
||||
|
||||
void renderQueue_spiceDrawFill(int x, int y, int width, int height,
|
||||
uint32_t color);
|
||||
|
||||
void renderQueue_spiceDrawBitmap(int x, int y, int width, int height, int stride,
|
||||
void * data);
|
Loading…
Reference in New Issue
Block a user