mirror of
				https://github.com/gnif/LookingGlass.git
				synced 2025-11-04 06:31:54 +00:00 
			
		
		
		
	[client] spice: added initial framework for spice display fallback
This commit is contained in:
		@@ -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);
 | 
			
		||||
		Reference in New Issue
	
	Block a user