[client] render: optimize software surface fills

This commit is contained in:
Geoffrey McRae
2026-08-12 03:31:52 +10:00
parent 5e8066609a
commit 0c21577e9e
5 changed files with 49 additions and 29 deletions

View File

@@ -28,6 +28,7 @@
#include "app.h" #include "app.h"
#include "texture.h" #include "texture.h"
#include "texture_buffer.h"
#include "shader.h" #include "shader.h"
#include "desktop_rects.h" #include "desktop_rects.h"
#include "cimgui.h" #include "cimgui.h"
@@ -705,26 +706,9 @@ void egl_desktopSwSurfaceDrawFill(EGL_Desktop * desktop,
height = (bottom > desktop->swSurfaceHeight ? height = (bottom > desktop->swSurfaceHeight ?
desktop->swSurfaceHeight : (int)bottom) - y; desktop->swSurfaceHeight : (int)bottom) - y;
/* This is a fairly hacky way to update a software surface, but it preserves if (egl_texBufferStreamFill(
* the existing incremental fill behavior. */ desktop->swSurfaceTexture, x, y, width, height, color))
atomic_store(&desktop->processFrame, true);
uint32_t * line = malloc((size_t)width * sizeof(*line));
if (!line)
{
DEBUG_ERROR("Failed to allocate software surface fill row");
return;
}
for(int i = 0; i < width; ++i)
line[i] = color;
for(int dy = 0; dy < height; ++dy)
egl_textureUpdateRect(desktop->swSurfaceTexture,
x, y + dy, width, 1, width, width * sizeof(*line),
(uint8_t *)line, false);
free(line);
atomic_store(&desktop->processFrame, true);
} }
void egl_desktopSwSurfaceDrawBitmap(EGL_Desktop * desktop, void egl_desktopSwSurfaceDrawBitmap(EGL_Desktop * desktop,

View File

@@ -390,6 +390,44 @@ static bool egl_texBufferStreamUpdate(EGL_Texture * texture,
return true; return true;
} }
bool egl_texBufferStreamFill(EGL_Texture * texture,
int x, int y, int width, int height, uint32_t color)
{
TextureBuffer * this = UPCAST(TextureBuffer, texture);
DEBUG_ASSERT(texture->format.bpp == sizeof(color));
if (texture->format.bpp != sizeof(color))
return false;
if (!egl_texBufferStreamLock(this))
return false;
uint8_t * row = this->buf[this->bufIndex].map +
texture->format.pitch * y + x * texture->format.bpp;
for (int dy = 0; dy < height; ++dy)
{
uint32_t * dst = (uint32_t *)row;
for (int dx = 0; dx < width; ++dx)
dst[dx] = color;
row += texture->format.pitch;
}
const EGL_TexUpdate update =
{
.x = x,
.y = y,
.width = width,
.height = height,
};
this->slotToken[this->bufIndex] = LG_RENDERER_FRAME_TOKEN_NONE;
this->buf[this->bufIndex].updated = true;
egl_texBufferDamageAdd(this, this->bufIndex, &update);
LG_UNLOCK(this->copyLock);
return true;
}
EGL_TexStatus egl_texBufferStreamProcess(EGL_Texture * texture, EGL_TexStatus egl_texBufferStreamProcess(EGL_Texture * texture,
LG_RendererFrameToken frameTokenLimit) LG_RendererFrameToken frameTokenLimit)
{ {

View File

@@ -70,6 +70,8 @@ bool egl_texBufferStreamSetup(EGL_Texture * texture_,
const EGL_TexSetup * setup); const EGL_TexSetup * setup);
/* Returns with copyLock held when the current upload buffer is safe to write. */ /* Returns with copyLock held when the current upload buffer is safe to write. */
bool egl_texBufferStreamLock(TextureBuffer * texture); bool egl_texBufferStreamLock(TextureBuffer * texture);
bool egl_texBufferStreamFill(EGL_Texture * texture,
int x, int y, int width, int height, uint32_t color);
EGL_TexStatus egl_texBufferStreamProcess(EGL_Texture * texture_, EGL_TexStatus egl_texBufferStreamProcess(EGL_Texture * texture_,
LG_RendererFrameToken frameTokenLimit); LG_RendererFrameToken frameTokenLimit);
EGL_TexStatus egl_texBufferStreamGet(EGL_Texture * texture_, GLuint * tex, EGL_TexStatus egl_texBufferStreamGet(EGL_Texture * texture_, GLuint * tex,

View File

@@ -721,11 +721,11 @@ static void testSurfaceEvents(void)
CHECK(f.log.configN == 1); CHECK(f.log.configN == 1);
CHECK(f.log.width == 2); CHECK(f.log.width == 2);
CHECK(f.log.height == 1); CHECK(f.log.height == 1);
CHECK(f.log.fillN == 1); CHECK(f.log.fillN == 0);
spiceSurface_drawFill( spiceSurface_drawFill(
f.transport.surface, 0, 1, 2, 3, 4, 0xaabbccdd); f.transport.surface, 0, 1, 2, 3, 4, 0xaabbccdd);
CHECK(f.log.fillN == 2); CHECK(f.log.fillN == 1);
CHECK(f.log.x == 1); CHECK(f.log.x == 1);
CHECK(f.log.y == 2); CHECK(f.log.y == 2);
CHECK(f.log.w == 3); CHECK(f.log.w == 3);
@@ -776,7 +776,7 @@ static void testSurfaceEvents(void)
spiceSurface_destroy(f.transport.surface, 0); spiceSurface_destroy(f.transport.surface, 0);
CHECK(f.log.destroyN == 1); CHECK(f.log.destroyN == 1);
spiceSurface_drawFill(f.transport.surface, 0, 0, 0, 1, 1, 0); spiceSurface_drawFill(f.transport.surface, 0, 0, 0, 1, 1, 0);
CHECK(f.log.fillN == 2); CHECK(f.log.fillN == 1);
sw->detach(&f.transport); sw->detach(&f.transport);
freeFixture(&f); freeFixture(&f);
} }
@@ -844,9 +844,9 @@ static void testSurfaceDetach(void)
CHECK(pthread_join(detachThread, NULL) == 0); CHECK(pthread_join(detachThread, NULL) == 0);
CHECK(atomic_load(&detach.done)); CHECK(atomic_load(&detach.done));
CHECK(f.log.configN == 1); CHECK(f.log.configN == 1);
CHECK(f.log.fillN == 1); CHECK(f.log.fillN == 0);
spiceSurface_drawFill(f.transport.surface, 0, 0, 0, 1, 1, 0); spiceSurface_drawFill(f.transport.surface, 0, 0, 0, 1, 1, 0);
CHECK(f.log.fillN == 1); CHECK(f.log.fillN == 0);
freeFixture(&f); freeFixture(&f);
} }

View File

@@ -199,11 +199,7 @@ void spiceSurface_create(SpiceSurface * surface, unsigned int surfaceId,
LG_LOCK_SHARED(surface->eventsLock); LG_LOCK_SHARED(surface->eventsLock);
if (surface->events) if (surface->events)
{
surface->events->configure(surface->eventOpaque, width, height); surface->events->configure(surface->eventOpaque, width, height);
surface->events->drawFill(
surface->eventOpaque, 0, 0, width, height, 0);
}
LG_UNLOCK_SHARED(surface->eventsLock); LG_UNLOCK_SHARED(surface->eventsLock);
} }