LookingGlass/common/src/framebuffer.c
Geoffrey McRae bca54ab1f6 [client/host] added new asyncronous memory copy
This changes the method of the memory copy from the host application to
the guest. Instead of performing a full copy from the capture device
into shared memory, and then flagging the new frame, we instead set a
write pointer, flag the client that there is a new frame and then copy
in chunks of 1024 bytes until the entire frame is copied. The client
upon seeing the new frame flag begins to poll at high frequency the
write pointer and upon each update copies as much as it can into the
texture.

This should improve latency but also slightly increase CPU usage on the
client due to the high frequency polling.
2019-10-09 13:53:02 +11:00

85 lines
2.1 KiB
C

/*
KVMGFX Client - A KVM Client for VGA Passthrough
Copyright (C) 2017-2019 Geoffrey McRae <geoff@hostfission.com>
https://looking-glass.hostfission.com
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/framebuffer.h"
#include "common/debug.h"
#include <string.h>
#define FB_CHUNK_SIZE 1024
struct stFrameBuffer
{
uint64_t wp;
uint8_t data[0];
};
bool framebuffer_read(const FrameBuffer frame, void * dst, size_t size)
{
uint64_t rp = 0;
while(rp < size)
{
/* spinlock */
while(rp == frame->wp) { }
/* copy what we can */
uint64_t avail = frame->wp - rp;
memcpy(dst, frame->data + rp, avail);
rp += avail;
}
return true;
}
bool framebuffer_read_fn(const FrameBuffer frame, FrameBufferReadFn fn, size_t size, void * opaque)
{
uint64_t rp = 0;
while(rp < size)
{
/* spinlock */
while(rp == frame->wp) { }
/* copy what we can */
uint64_t avail = frame->wp - rp;
if (!fn(opaque, frame->data + rp, avail))
return false;
rp += avail;
}
return true;
}
/**
* Prepare the framebuffer for writing
*/
void framebuffer_prepare(const FrameBuffer frame)
{
frame->wp = 0;
}
bool framebuffer_write(FrameBuffer frame, const void * src, size_t size)
{
/* copy in chunks */
while(size)
{
size_t copy = size < FB_CHUNK_SIZE ? FB_CHUNK_SIZE : size;
memcpy(frame->data + frame->wp, src, copy);
__sync_fetch_and_add(&frame->wp, copy);
size -= copy;
}
return true;
}