[client] egl: implemented SPICE display support

This commit is contained in:
Geoffrey McRae 2022-05-22 18:19:58 +10:00
parent 6699018ed1
commit 247e867f18
17 changed files with 273 additions and 86 deletions

View File

@ -181,7 +181,7 @@ typedef struct LG_RendererOps
/* 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);
int height, int stride, uint8_t * data, bool topDown);
/* show the spice display */
void (*spiceShow)(LG_Renderer * renderer, bool show);

View File

@ -87,7 +87,7 @@ static bool cursorTexInit(struct CursorTex * t,
const char * vertex_code , size_t vertex_size,
const char * fragment_code, size_t fragment_size)
{
if (!egl_textureInit(&t->texture, NULL, EGL_TEXTYPE_BUFFER, false))
if (!egl_textureInit(&t->texture, NULL, EGL_TEXTYPE_BUFFER))
{
DEBUG_ERROR("Failed to initialize the cursor texture");
return false;
@ -278,7 +278,7 @@ struct CursorState egl_cursorRender(EGL_Cursor * cursor,
egl_textureSetup(cursor->mono.texture, EGL_PF_BGRA,
cursor->width, cursor->height, sizeof(xor[0]));
egl_textureUpdate(cursor->mono.texture, (uint8_t *)xor);
egl_textureUpdate(cursor->mono.texture, (uint8_t *)xor, true);
}
// fall through
@ -286,7 +286,7 @@ struct CursorState egl_cursorRender(EGL_Cursor * cursor,
{
egl_textureSetup(cursor->norm.texture, EGL_PF_BGRA,
cursor->width, cursor->height, cursor->stride);
egl_textureUpdate(cursor->norm.texture, data);
egl_textureUpdate(cursor->norm.texture, data, true);
break;
}
@ -314,8 +314,8 @@ struct CursorState egl_cursorRender(EGL_Cursor * cursor,
cursor->width, cursor->height, sizeof(and[0]));
egl_textureSetup(cursor->mono.texture, EGL_PF_BGRA,
cursor->width, cursor->height, sizeof(xor[0]));
egl_textureUpdate(cursor->norm.texture, (uint8_t *)and);
egl_textureUpdate(cursor->mono.texture, (uint8_t *)xor);
egl_textureUpdate(cursor->norm.texture, (uint8_t *)and, true);
egl_textureUpdate(cursor->mono.texture, (uint8_t *)xor, true);
break;
}
}

View File

@ -65,6 +65,10 @@ struct EGL_Desktop
int width, height;
LG_RendererRotate rotate;
bool useSpice;
int spiceWidth, spiceHeight;
EGL_Texture * spiceTexture;
// scale algorithm
int scaleAlgo;
@ -125,7 +129,7 @@ bool egl_desktopInit(EGL * egl, EGL_Desktop ** desktop_, EGLDisplay * display,
desktop->display = display;
if (!egl_textureInit(&desktop->texture, display,
useDMA ? EGL_TEXTYPE_DMABUF : EGL_TEXTYPE_FRAMEBUFFER, true))
useDMA ? EGL_TEXTYPE_DMABUF : EGL_TEXTYPE_FRAMEBUFFER))
{
DEBUG_ERROR("Failed to initialize the desktop texture");
return false;
@ -202,6 +206,7 @@ void egl_desktopFree(EGL_Desktop ** desktop)
return;
egl_textureFree (&(*desktop)->texture );
egl_textureFree (&(*desktop)->spiceTexture );
egl_shaderFree (&(*desktop)->shader.shader);
egl_desktopRectsFree(&(*desktop)->mesh );
countedBufferRelease(&(*desktop)->matrix );
@ -329,7 +334,7 @@ bool egl_desktopUpdate(EGL_Desktop * desktop, const FrameBuffer * frame, int dma
egl_textureFree(&desktop->texture);
if (!egl_textureInit(&desktop->texture, desktop->display,
EGL_TEXTYPE_FRAMEBUFFER, true))
EGL_TEXTYPE_FRAMEBUFFER))
{
DEBUG_ERROR("Failed to initialize the desktop texture");
return false;
@ -359,11 +364,27 @@ bool egl_desktopRender(EGL_Desktop * desktop, unsigned int outputWidth,
const float scaleX, const float scaleY, enum EGL_DesktopScaleType scaleType,
LG_RendererRotate rotate, const struct DamageRects * rects)
{
EGL_Texture * tex;
int width, height;
if (desktop->useSpice)
{
tex = desktop->spiceTexture;
width = desktop->spiceWidth;
height = desktop->spiceHeight;
}
else
{
tex = desktop->texture;
width = desktop->width;
height = desktop->height;
}
if (outputWidth == 0 && outputHeight == 0)
DEBUG_FATAL("outputWidth || outputHeight == 0");
enum EGL_TexStatus status;
if ((status = egl_textureProcess(desktop->texture)) != EGL_TEX_STATUS_OK)
if ((status = egl_textureProcess(tex)) != EGL_TEX_STATUS_OK)
{
if (status != EGL_TEX_STATUS_NOTREADY)
DEBUG_ERROR("Failed to process the desktop texture");
@ -372,13 +393,13 @@ bool egl_desktopRender(EGL_Desktop * desktop, unsigned int outputWidth,
int scaleAlgo = EGL_SCALE_NEAREST;
egl_desktopRectsMatrix((float *)desktop->matrix->data,
desktop->width, desktop->height, x, y, scaleX, scaleY, rotate);
egl_desktopRectsUpdate(desktop->mesh, rects, desktop->width, desktop->height);
width, height, x, y, scaleX, scaleY, rotate);
egl_desktopRectsUpdate(desktop->mesh, rects, width, height);
if (atomic_exchange(&desktop->processFrame, false) ||
egl_postProcessConfigModified(desktop->pp))
egl_postProcessRun(desktop->pp, desktop->texture, desktop->mesh,
desktop->width, desktop->height, outputWidth, outputHeight);
egl_postProcessRun(desktop->pp, tex, desktop->mesh,
width, height, outputWidth, outputHeight);
unsigned int finalSizeX, finalSizeY;
GLuint texture = egl_postProcessGetOutput(desktop->pp,
@ -389,9 +410,9 @@ bool egl_desktopRender(EGL_Desktop * desktop, unsigned int outputWidth,
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glBindSampler(0, desktop->texture->sampler);
glBindSampler(0, tex->sampler);
if (finalSizeX > desktop->width || finalSizeY > desktop->height)
if (finalSizeX > width || finalSizeY > height)
scaleType = EGL_DESKTOP_DOWNSCALE;
switch (desktop->scaleAlgo)
@ -425,7 +446,7 @@ bool egl_desktopRender(EGL_Desktop * desktop, unsigned int outputWidth,
{
.type = EGL_UNIFORM_TYPE_2F,
.location = shader->uDesktopSize,
.f = { desktop->width, desktop->height },
.f = { width, height },
},
{
.type = EGL_UNIFORM_TYPE_M3x2FV,
@ -451,3 +472,47 @@ bool egl_desktopRender(EGL_Desktop * desktop, unsigned int outputWidth,
glBindTexture(GL_TEXTURE_2D, 0);
return true;
}
void egl_desktopSpiceConfigure(EGL_Desktop * desktop, int width, int height)
{
if (!desktop->spiceTexture)
if (!egl_textureInit(&desktop->spiceTexture, desktop->display,
EGL_TEXTYPE_BUFFER_MAP))
{
DEBUG_ERROR("Failed to initialize the spice desktop texture");
return;
}
if (!egl_textureSetup(
desktop->spiceTexture,
EGL_PF_BGRA,
width,
height,
width * 4
))
{
DEBUG_ERROR("Failed to setup the spice desktop texture");
return;
}
desktop->spiceWidth = width;
desktop->spiceHeight = height;
}
void egl_desktopSpiceDrawFill(EGL_Desktop * desktop, int x, int y, int width,
int height, uint32_t color)
{
}
void egl_desktopSpiceDrawBitmap(EGL_Desktop * desktop, int x, int y, int width,
int height, int stride, uint8_t * data, bool topDown)
{
egl_textureUpdateRect(desktop->spiceTexture,
x, y, width, height, stride, data, topDown);
atomic_store(&desktop->processFrame, true);
}
void egl_desktopSpiceShow(EGL_Desktop * desktop, bool show)
{
desktop->useSpice = show;
}

View File

@ -50,3 +50,10 @@ bool egl_desktopRender(EGL_Desktop * desktop, unsigned int outputWidth,
unsigned int outputHeight, const float x, const float y,
const float scaleX, const float scaleY, enum EGL_DesktopScaleType scaleType,
LG_RendererRotate rotate, const struct DamageRects * rects);
void egl_desktopSpiceConfigure(EGL_Desktop * desktop, int width, int height);
void egl_desktopSpiceDrawFill(EGL_Desktop * desktop, int x, int y, int width,
int height, uint32_t color);
void egl_desktopSpiceDrawBitmap(EGL_Desktop * desktop, int x, int y, int width,
int height, int stride, uint8_t * data, bool topDown);
void egl_desktopSpiceShow(EGL_Desktop * desktop, bool show);

View File

@ -123,6 +123,8 @@ struct Inst
RingBuffer importTimings;
GraphHandle importGraph;
bool showSpice;
};
static struct Option egl_options[] =
@ -1012,7 +1014,8 @@ static bool egl_render(LG_Renderer * renderer, LG_RendererRotate rotate,
struct Inst * this = UPCAST(struct Inst, renderer);
EGLint bufferAge = egl_bufferAge(this);
bool renderAll = invalidateWindow || !this->start || this->hadOverlay ||
bufferAge <= 0 || bufferAge > MAX_BUFFER_AGE;
bufferAge <= 0 || bufferAge > MAX_BUFFER_AGE ||
this->showSpice;
bool hasOverlay = false;
struct CursorState cursorState = { .visible = false };
@ -1103,9 +1106,10 @@ static bool egl_render(LG_Renderer * renderer, LG_RendererRotate rotate,
this->waitDone = true;
}
cursorState = egl_cursorRender(this->cursor,
(this->format.rotate + rotate) % LG_ROTATE_MAX,
this->width, this->height);
if (!this->showSpice)
cursorState = egl_cursorRender(this->cursor,
(this->format.rotate + rotate) % LG_ROTATE_MAX,
this->width, this->height);
}
else
hasOverlay = true;
@ -1207,6 +1211,36 @@ static bool egl_render(LG_Renderer * renderer, LG_RendererRotate rotate,
return true;
}
static void egl_spiceConfigure(LG_Renderer * renderer, int width, int height)
{
struct Inst * this = UPCAST(struct Inst, renderer);
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;
egl_desktopSpiceShow(this->desktop, show);
if (show)
this->start = true;
}
struct LG_RendererOps LGR_EGL =
{
.getName = egl_getName,
@ -1223,5 +1257,10 @@ struct LG_RendererOps LGR_EGL =
.onFrame = egl_onFrame,
.renderStartup = egl_renderStartup,
.needsRender = egl_needsRender,
.render = egl_render
.render = egl_render,
.spiceConfigure = egl_spiceConfigure,
.spiceDrawFill = egl_spiceDrawFill,
.spiceDrawBitmap = egl_spiceDrawBitmap,
.spiceShow = egl_spiceShow
};

View File

@ -25,6 +25,8 @@
typedef enum EGL_TexType
{
EGL_TEXTYPE_BUFFER,
EGL_TEXTYPE_BUFFER_MAP,
EGL_TEXTYPE_BUFFER_STREAM,
EGL_TEXTYPE_FRAMEBUFFER,
EGL_TEXTYPE_DMABUF
}

View File

@ -40,7 +40,7 @@ bool egl_framebufferInit(EGL_Framebuffer ** fb)
return false;
}
if (!egl_textureInit(&this->tex, NULL, EGL_TEXTYPE_BUFFER, false))
if (!egl_textureInit(&this->tex, NULL, EGL_TEXTYPE_BUFFER))
{
DEBUG_ERROR("Failed to initialize the texture");
return false;

View File

@ -37,23 +37,26 @@ extern const EGL_TextureOps EGL_TextureFrameBuffer;
extern const EGL_TextureOps EGL_TextureDMABUF;
bool egl_textureInit(EGL_Texture ** texture_, EGLDisplay * display,
EGL_TexType type, bool streaming)
EGL_TexType type)
{
const EGL_TextureOps * ops;
switch(type)
{
case EGL_TEXTYPE_BUFFER:
ops = streaming ? &EGL_TextureBufferStream : &EGL_TextureBuffer;
ops = &EGL_TextureBuffer;
break;
case EGL_TEXTYPE_BUFFER_MAP:
case EGL_TEXTYPE_BUFFER_STREAM:
ops = &EGL_TextureBufferStream;
break;
case EGL_TEXTYPE_FRAMEBUFFER:
DEBUG_ASSERT(streaming);
ops = &EGL_TextureFrameBuffer;
break;
case EGL_TEXTYPE_DMABUF:
DEBUG_ASSERT(streaming);
ops = &EGL_TextureDMABUF;
break;
@ -62,7 +65,7 @@ bool egl_textureInit(EGL_Texture ** texture_, EGLDisplay * display,
}
*texture_ = NULL;
if (!ops->init(texture_, display))
if (!ops->init(texture_, type, display))
return false;
EGL_Texture * this = *texture_;
@ -105,18 +108,19 @@ bool egl_textureSetup(EGL_Texture * this, enum EGL_PixelFormat pixFmt,
return this->ops.setup(this, &setup);
}
bool egl_textureUpdate(EGL_Texture * this, const uint8_t * buffer)
bool egl_textureUpdate(EGL_Texture * this, const uint8_t * buffer, bool topDown)
{
const struct EGL_TexUpdate update =
{
.type = EGL_TEXTYPE_BUFFER,
.x = 0,
.y = 0,
.width = this->format.width,
.height = this->format.height,
.pitch = this->format.pitch,
.stride = this->format.stride,
.buffer = buffer
.type = EGL_TEXTYPE_BUFFER,
.x = 0,
.y = 0,
.width = this->format.width,
.height = this->format.height,
.pitch = this->format.pitch,
.stride = this->format.stride,
.topDown = topDown,
.buffer = buffer
};
return this->ops.update(this, &update);
@ -124,7 +128,7 @@ bool egl_textureUpdate(EGL_Texture * this, const uint8_t * buffer)
bool egl_textureUpdateRect(EGL_Texture * this,
int x, int y, int width, int height, int stride,
const uint8_t * buffer)
const uint8_t * buffer, bool topDown)
{
x = clamp(x , 0, this->format.width );
y = clamp(y , 0, this->format.height );
@ -136,14 +140,15 @@ bool egl_textureUpdateRect(EGL_Texture * this,
const struct EGL_TexUpdate update =
{
.type = EGL_TEXTYPE_BUFFER,
.x = x,
.y = y,
.width = width,
.height = height,
.pitch = stride / (stride / width),
.stride = stride,
.buffer = buffer
.type = EGL_TEXTYPE_BUFFER,
.x = x,
.y = y,
.width = width,
.height = height,
.pitch = stride / this->format.bpp,
.stride = stride,
.topDown = topDown,
.buffer = buffer
};
return this->ops.update(this, &update);
@ -175,14 +180,14 @@ bool egl_textureUpdateFromDMA(EGL_Texture * this,
{
const struct EGL_TexUpdate update =
{
.type = EGL_TEXTYPE_DMABUF,
.x = 0,
.y = 0,
.width = this->format.width,
.height = this->format.height,
.pitch = this->format.pitch,
.stride = this->format.stride,
.dmaFD = dmaFd
.type = EGL_TEXTYPE_DMABUF,
.x = 0,
.y = 0,
.width = this->format.width,
.height = this->format.height,
.pitch = this->format.pitch,
.stride = this->format.stride,
.dmaFD = dmaFd
};
/* wait for completion */

View File

@ -50,10 +50,15 @@ typedef struct EGL_TexUpdate
union
{
/* EGL_TEXTURE_BUFFER */
const uint8_t * buffer;
/* EGL_TEXTYPE_BUFFER */
struct
{
// true if row 0 is the top of the image
bool topDown;
const uint8_t * buffer;
};
/* EGL_TEXTURE_FRAMEBUFFER */
/* EGL_TEXTYPE_FRAMEBUFFER */
struct
{
const FrameBuffer * frame;
@ -61,7 +66,7 @@ typedef struct EGL_TexUpdate
int rectCount;
};
/* EGL_TEXTURE_DMABUF */
/* EGL_TEXTYPE_DMABUF */
int dmaFD;
};
}
@ -72,7 +77,7 @@ typedef struct EGL_Texture EGL_Texture;
typedef struct EGL_TextureOps
{
/* allocate & initialize an EGL_Texture */
bool (*init)(EGL_Texture ** texture, EGLDisplay * display);
bool (*init)(EGL_Texture ** texture, EGL_TexType type, EGLDisplay * display);
/* free the EGL_Texture */
void (*free)(EGL_Texture * texture);
@ -94,23 +99,25 @@ EGL_TextureOps;
struct EGL_Texture
{
struct EGL_TextureOps ops;
EGL_TexType type;
GLuint sampler;
EGL_TexFormat format;
};
bool egl_textureInit(EGL_Texture ** texture, EGLDisplay * display,
EGL_TexType type, bool streaming);
EGL_TexType type);
void egl_textureFree(EGL_Texture ** tex);
bool egl_textureSetup(EGL_Texture * texture, enum EGL_PixelFormat pixFmt,
size_t width, size_t height, size_t stride);
bool egl_textureUpdate(EGL_Texture * texture, const uint8_t * buffer);
bool egl_textureUpdate(EGL_Texture * texture, const uint8_t * buffer,
bool topDown);
bool egl_textureUpdateRect(EGL_Texture * texture,
int x, int y, int width, int height, int stride,
const uint8_t * buffer);
const uint8_t * buffer, bool topDown);
bool egl_textureUpdateFromFrame(EGL_Texture * texture,
const FrameBuffer * frame, const FrameDamageRect * damageRects,

View File

@ -46,7 +46,8 @@ static void egl_texBuffer_cleanup(TextureBuffer * this)
// common functions
bool egl_texBufferInit(EGL_Texture ** texture, EGLDisplay * display)
bool egl_texBufferInit(EGL_Texture ** texture, EGL_TexType type,
EGLDisplay * display)
{
TextureBuffer * this;
if (!*texture)
@ -140,14 +141,29 @@ EGL_TexStatus egl_texBufferGet(EGL_Texture * texture, GLuint * tex)
// streaming functions
bool egl_texBufferStreamInit(EGL_Texture ** texture, EGLDisplay * display)
bool egl_texBufferStreamInit(EGL_Texture ** texture, EGL_TexType type,
EGLDisplay * display)
{
if (!egl_texBufferInit(texture, display))
if (!egl_texBufferInit(texture, type, display))
return false;
TextureBuffer * this = UPCAST(TextureBuffer, *texture);
this->texCount = 2;
switch(type)
{
case EGL_TEXTYPE_BUFFER_STREAM:
case EGL_TEXTYPE_DMABUF:
this->texCount = 2;
break;
case EGL_TEXTYPE_BUFFER_MAP:
this->texCount = 1;
break;
default:
DEBUG_UNREACHABLE();
}
LG_LOCK_INIT(this->copyLock);
return true;
}
@ -168,8 +184,32 @@ static bool egl_texBufferStreamUpdate(EGL_Texture * texture,
DEBUG_ASSERT(update->type == EGL_TEXTYPE_BUFFER);
LG_LOCK(this->copyLock);
memcpy(this->buf[this->bufIndex].map, update->buffer,
texture->format.bufferSize);
uint8_t * dst = this->buf[this->bufIndex].map +
texture->format.stride * update->y +
update->x * texture->format.bpp;
if (update->topDown)
{
const uint8_t * src = update->buffer;
for(int y = 0; y < update->height; ++y)
{
memcpy(dst, src, update->stride);
dst += texture->format.stride;
src += update->stride;
}
}
else
{
const uint8_t * src = update->buffer + update->stride * update->height;
for(int y = 0; y < update->height; ++y)
{
src -= update->stride;
memcpy(dst, src, update->stride);
dst += texture->format.stride;
}
}
this->buf[this->bufIndex].updated = true;
LG_UNLOCK(this->copyLock);

View File

@ -42,13 +42,15 @@ typedef struct TextureBuffer
}
TextureBuffer;
bool egl_texBufferInit(EGL_Texture ** texture_, EGLDisplay * display);
bool egl_texBufferInit(EGL_Texture ** texture_, EGL_TexType type,
EGLDisplay * display);
void egl_texBufferFree(EGL_Texture * texture_);
bool egl_texBufferSetup(EGL_Texture * texture_, const EGL_TexSetup * setup);
EGL_TexStatus egl_texBufferProcess(EGL_Texture * texture_);
EGL_TexStatus egl_texBufferGet(EGL_Texture * texture_, GLuint * tex);
bool egl_texBufferStreamInit(EGL_Texture ** texture_, EGLDisplay * display);
bool egl_texBufferStreamInit(EGL_Texture ** texture_, EGL_TexType type,
EGLDisplay * display);
bool egl_texBufferStreamSetup(EGL_Texture * texture_,
const EGL_TexSetup * setup);
EGL_TexStatus egl_texBufferStreamProcess(EGL_Texture * texture_);

View File

@ -54,7 +54,8 @@ static void egl_texDMABUFCleanup(TexDMABUF * this)
// dmabuf functions
static bool egl_texDMABUFInit(EGL_Texture ** texture, EGLDisplay * display)
static bool egl_texDMABUFInit(EGL_Texture ** texture, EGL_TexType type,
EGLDisplay * display)
{
TexDMABUF * this = calloc(1, sizeof(*this));
*texture = &this->base.base;
@ -67,7 +68,7 @@ static bool egl_texDMABUFInit(EGL_Texture ** texture, EGLDisplay * display)
}
EGL_Texture * parent = &this->base.base;
if (!egl_texBufferStreamInit(&parent, display))
if (!egl_texBufferStreamInit(&parent, type, display))
{
vector_destroy(&this->images);
free(this);

View File

@ -38,13 +38,14 @@ typedef struct TexFB
}
TexFB;
static bool egl_texFBInit(EGL_Texture ** texture, EGLDisplay * display)
static bool egl_texFBInit(EGL_Texture ** texture, EGL_TexType type,
EGLDisplay * display)
{
TexFB * this = calloc(1, sizeof(*this));
*texture = &this->base.base;
EGL_Texture * parent = &this->base.base;
if (!egl_texBufferStreamInit(&parent, display))
if (!egl_texBufferStreamInit(&parent, type, display))
{
free(this);
*texture = NULL;

View File

@ -35,7 +35,7 @@ typedef struct EGL_TexFormat
unsigned int fourcc;
size_t bufferSize;
size_t width, height;
size_t width , height;
size_t stride, pitch;
}
EGL_TexFormat;

View File

@ -50,6 +50,7 @@
#include "common/version.h"
#include "common/paths.h"
#include "common/cpuinfo.h"
#include "common/ll.h"
#include "core.h"
#include "app.h"
@ -809,7 +810,9 @@ int main_frameThread(void * unused)
lgmpClientUnsubscribe(&queue);
RENDERER(onRestart);
app_useSpiceDisplay(true);
if (g_state.state != APP_STATE_SHUTDOWN)
app_useSpiceDisplay(true);
if (g_state.useDMA)
{
@ -873,6 +876,14 @@ void spiceReady(void)
static void spice_surfaceCreate(unsigned int surfaceId, PSSurfaceFormat format,
unsigned int width, unsigned int height)
{
DEBUG_INFO("Create SPICE surface: id: %d, size: %dx%d",
surfaceId, width, height);
g_state.srcSize.x = width;
g_state.srcSize.y = height;
g_state.haveSrcSize = true;
core_updatePositionInfo();
renderQueue_spiceConfigure(width, height);
if (g_state.lgr)
RENDERER(spiceShow, true);
@ -880,6 +891,7 @@ static void spice_surfaceCreate(unsigned int surfaceId, PSSurfaceFormat format,
static void spice_surfaceDestroy(unsigned int surfaceId)
{
DEBUG_INFO("Destroy spice surface %d", surfaceId);
if (g_state.lgr)
RENDERER(spiceShow, false);
}
@ -893,7 +905,7 @@ static void spice_drawFill(unsigned int surfaceId, int x, int y, int width,
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);
renderQueue_spiceDrawBitmap(x, y, width, height, stride, data, topDown);
}
int spiceThread(void * arg)
@ -1579,8 +1591,8 @@ restart:
{
if (!lgmpClientSessionValid(g_state.lgmp))
{
g_state.state = APP_STATE_RESTART;
DEBUG_INFO("Waiting for the host to restart...");
g_state.state = APP_STATE_RESTART;
break;
}
g_state.ds->wait(100);

View File

@ -32,6 +32,15 @@ void renderQueue_init(void)
l_renderQueue = ll_new();
}
void renderQueue_free(void)
{
if (!l_renderQueue)
return;
renderQueue_clear();
ll_free(l_renderQueue);
}
void renderQueue_clear(void)
{
RenderCommand * cmd;
@ -68,7 +77,7 @@ void renderQueue_spiceDrawFill(int x, int y, int width, int height,
}
void renderQueue_spiceDrawBitmap(int x, int y, int width, int height, int stride,
void * data)
void * data, bool topDown)
{
RenderCommand * cmd = malloc(sizeof(*cmd));
cmd->op = SPICE_OP_DRAW_BITMAP;
@ -78,17 +87,12 @@ void renderQueue_spiceDrawBitmap(int x, int y, int width, int height, int stride
cmd->drawBitmap.height = height;
cmd->drawBitmap.stride = stride;
cmd->drawBitmap.data = malloc(height * stride);
cmd->drawBitmap.topDown = topDown;
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;
@ -112,7 +116,8 @@ void renderQueue_process(void)
RENDERER(spiceDrawBitmap,
cmd->drawBitmap.x , cmd->drawBitmap.y,
cmd->drawBitmap.width , cmd->drawBitmap.height,
cmd->drawBitmap.stride, cmd->drawBitmap.data);
cmd->drawBitmap.stride, cmd->drawBitmap.data,
cmd->drawBitmap.topDown);
free(cmd->drawBitmap.data);
break;
}

View File

@ -52,6 +52,7 @@ typedef struct
int width, height;
int stride;
uint8_t * data;
bool topDown;
}
drawBitmap;
};
@ -69,4 +70,4 @@ 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);
void * data, bool topDown);