[client] implement support for RGB24 packed data

This commit is contained in:
Geoffrey McRae
2023-11-03 07:03:32 +11:00
parent 578d98fd22
commit c665044bfa
30 changed files with 548 additions and 151 deletions

View File

@@ -149,10 +149,10 @@ typedef struct KVMFRFrame
FrameType type; // the frame data type
uint32_t screenWidth; // the client's screen width
uint32_t screenHeight; // the client's screen height
uint32_t dataWidth; // the packed width of the frame data
uint32_t dataHeight; // the packed height of the frame data
uint32_t frameWidth; // the frame width
uint32_t frameHeight; // the frame height
uint32_t dataWidth; // the packed frame width
uint32_t dataHeight; // the packed frame height
uint32_t frameWidth; // the unpacked frame width
uint32_t frameHeight; // the unpacked frame height
FrameRotation rotation; // the frame rotation
uint32_t stride; // the row stride (zero if compressed data)
uint32_t pitch; // the row pitch (stride in bytes or the compressed frame size)

View File

@@ -44,6 +44,12 @@ typedef bool (*FrameBufferReadFn)(void * opaque, const void * src, size_t size);
*/
bool framebuffer_wait(const FrameBuffer * frame, size_t size);
/**
* Read `size` bytes from the KVMFRFrame into the dst buffer
*/
bool framebuffer_read_linear(const FrameBuffer * frame, void * restrict dst,
size_t size);
/**
* Read data from the KVMFRFrame into the dst buffer
*/

View File

@@ -28,23 +28,23 @@
#include "common/types.h"
inline static void rectCopyUnaligned(uint8_t * dest, const uint8_t * src,
int ystart, int yend, int dx, int dstStride, int srcStride, int width)
int ystart, int yend, int dx, int dstPitch, int srcPitch, int width)
{
for (int i = ystart; i < yend; ++i)
{
unsigned int srcOffset = i * srcStride + dx;
unsigned int dstOffset = i * dstStride + dx;
unsigned int srcOffset = i * srcPitch + dx;
unsigned int dstOffset = i * dstPitch + dx;
memcpy(dest + dstOffset, src + srcOffset, width);
}
}
void rectsBufferToFramebuffer(FrameDamageRect * rects, int count, int bpp,
FrameBuffer * frame, int dstStride, int height,
const uint8_t * src, int srcStride);
FrameBuffer * frame, int dstPitch, int height,
const uint8_t * src, int srcPitch);
void rectsFramebufferToBuffer(FrameDamageRect * rects, int count, int bpp,
uint8_t * dst, int dstStride, int height,
const FrameBuffer * frame, int srcStride);
uint8_t * dst, int dstPitch, int height,
const FrameBuffer * frame, int srcPitch);
int rectsMergeOverlapping(FrameDamageRect * rects, int count);
int rectsRejectContained(FrameDamageRect * rects, int count);

View File

@@ -55,7 +55,7 @@ typedef enum FrameType
FRAME_TYPE_RGBA , // RGBA interleaved: R,G,B,A 32bpp
FRAME_TYPE_RGBA10 , // RGBA interleaved: R,G,B,A 10,10,10,2 bpp
FRAME_TYPE_RGBA16F , // RGBA interleaved: R,G,B,A 16,16,16,16 bpp float
FRAME_TYPE_BGR , // BGR interleaved: B,G,R 24bpp
FRAME_TYPE_BGR , // BGR (DO NOT COMMIT THIS)
FRAME_TYPE_MAX , // sentinel value
}
FrameType;

View File

@@ -38,4 +38,6 @@
#define UPCAST(type, x) \
(type *)((uintptr_t)(x) - offsetof(type, base))
#define ALIGN_TO(value, align) (((value) + (align) - 1) & -(align))
#endif

View File

@@ -47,8 +47,8 @@ bool framebuffer_wait(const FrameBuffer * frame, size_t size)
return true;
}
bool framebuffer_read(const FrameBuffer * frame, void * restrict dst,
size_t dstpitch, size_t height, size_t width, size_t bpp, size_t pitch)
bool framebuffer_read_linear(const FrameBuffer * frame, void * restrict dst,
size_t size)
{
#ifdef FB_PROFILE
static RunningAvg ra = NULL;
@@ -62,34 +62,54 @@ bool framebuffer_read(const FrameBuffer * frame, void * restrict dst,
uint_least32_t rp = 0;
// copy in large 1MB chunks if the pitches match
if (dstpitch == pitch)
while(size)
{
size_t remaining = height * pitch;
while(remaining)
{
const size_t copy = remaining < FB_CHUNK_SIZE ? remaining : FB_CHUNK_SIZE;
if (!framebuffer_wait(frame, rp + copy))
return false;
const size_t copy = size < FB_CHUNK_SIZE ? size : FB_CHUNK_SIZE;
if (!framebuffer_wait(frame, rp + copy))
return false;
memcpy(d, frame->data + rp, copy);
remaining -= copy;
rp += copy;
d += copy;
}
memcpy(d, frame->data + rp, copy);
size -= copy;
rp += copy;
d += copy;
}
else
{
// copy per line to match the pitch of the destination buffer
const size_t linewidth = width * bpp;
for(size_t y = 0; y < height; ++y)
{
if (!framebuffer_wait(frame, rp + linewidth))
return false;
memcpy(d, frame->data + rp, dstpitch);
rp += pitch;
d += dstpitch;
}
#ifdef FB_PROFILE
runningavg_push(ra, microtime() - ts);
if (++raCount % 100 == 0)
DEBUG_INFO("Average Copy Time: %.2fμs", runningavg_calc(ra));
#endif
return true;
}
bool framebuffer_read(const FrameBuffer * frame, void * restrict dst,
size_t dstpitch, size_t height, size_t width, size_t bpp, size_t pitch)
{
if (dstpitch == pitch)
return framebuffer_read_linear(frame, dst, height * pitch);
#ifdef FB_PROFILE
static RunningAvg ra = NULL;
static int raCount = 0;
const uint64_t ts = microtime();
if (!ra)
ra = runningavg_new(100);
#endif
uint8_t * restrict d = (uint8_t*)dst;
uint_least32_t rp = 0;
// copy per line to match the pitch of the destination buffer
const size_t linewidth = width * bpp;
for(size_t y = 0; y < height; ++y)
{
if (!framebuffer_wait(frame, rp + linewidth))
return false;
memcpy(d, frame->data + rp, dstpitch);
rp += pitch;
d += dstpitch;
}
#ifdef FB_PROFILE

View File

@@ -194,44 +194,44 @@ inline static void rectsBufferCopy(FrameDamageRect * rects, int count, int bpp,
struct ToFramebufferData
{
FrameBuffer * frame;
int stride;
int pitch;
};
static void fbRowFinish(int y, void * opaque)
{
struct ToFramebufferData * data = opaque;
framebuffer_set_write_ptr(data->frame, y * data->stride);
framebuffer_set_write_ptr(data->frame, y * data->pitch);
}
void rectsBufferToFramebuffer(FrameDamageRect * rects, int count, int bpp,
FrameBuffer * frame, int dstStride, int height,
const uint8_t * src, int srcStride)
FrameBuffer * frame, int dstPitch, int height,
const uint8_t * src, int srcPitch)
{
struct ToFramebufferData data = { .frame = frame, .stride = dstStride };
rectsBufferCopy(rects, count, bpp, framebuffer_get_data(frame), dstStride,
height, src, srcStride, &data, NULL, fbRowFinish);
framebuffer_set_write_ptr(frame, height * dstStride);
struct ToFramebufferData data = { .frame = frame, .pitch = dstPitch };
rectsBufferCopy(rects, count, bpp, framebuffer_get_data(frame), dstPitch,
height, src, srcPitch, &data, NULL, fbRowFinish);
framebuffer_set_write_ptr(frame, height * dstPitch);
}
struct FromFramebufferData
{
const FrameBuffer * frame;
int stride;
int pitch;
};
static void fbRowStart(int y, void * opaque)
{
struct FromFramebufferData * data = opaque;
framebuffer_wait(data->frame, y * data->stride);
framebuffer_wait(data->frame, y * data->pitch);
}
void rectsFramebufferToBuffer(FrameDamageRect * rects, int count, int bpp,
uint8_t * dst, int dstStride, int height,
const FrameBuffer * frame, int srcStride)
uint8_t * dst, int dstPitch, int height,
const FrameBuffer * frame, int srcPitch)
{
struct FromFramebufferData data = { .frame = frame, .stride = srcStride };
rectsBufferCopy(rects, count, bpp, dst, dstStride, height,
framebuffer_get_buffer(frame), srcStride, &data, fbRowStart, NULL);
struct FromFramebufferData data = { .frame = frame, .pitch = srcPitch };
rectsBufferCopy(rects, count, bpp, dst, dstPitch, height,
framebuffer_get_buffer(frame), srcPitch, &data, fbRowStart, NULL);
}
int rectsMergeOverlapping(FrameDamageRect * rects, int count)