Skip to content
Permalink
Browse files

[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.
  • Loading branch information...
gnif committed Oct 1, 2019
1 parent 6d2c464 commit bca54ab1f6aae0a6807a0d1fc56e75cd35848b2c
@@ -1 +1 @@
fetch-4-ge93bd7a3bf+1
fetch-6-g59013b2e3f+1
@@ -21,6 +21,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA

#include <stdbool.h>
#include <stdint.h>
#include "common/framebuffer.h"

typedef enum CaptureResult
{
@@ -55,7 +56,6 @@ typedef struct CaptureFrame
unsigned int pitch;
unsigned int stride;
CaptureFormat format;
void * data;
}
CaptureFrame;

@@ -84,7 +84,8 @@ typedef struct CaptureInterface
unsigned int (*getMaxFrameSize)();

CaptureResult (*capture )();
CaptureResult (*getFrame )(CaptureFrame * frame );
CaptureResult (*waitFrame )(CaptureFrame * frame );
CaptureResult (*getFrame )(FrameBuffer frame );
CaptureResult (*getPointer)(CapturePointer * pointer);
}
CaptureInterface;
@@ -766,7 +766,7 @@ static CaptureResult dxgi_capture()
return CAPTURE_RESULT_OK;
}

static CaptureResult dxgi_getFrame(CaptureFrame * frame)
static CaptureResult dxgi_waitFrame(CaptureFrame * frame)
{
assert(this);
assert(this->initialized);
@@ -778,7 +778,6 @@ static CaptureResult dxgi_getFrame(CaptureFrame * frame)
if (this->stop)
return CAPTURE_RESULT_REINIT;

// only reset the event if we used the texture
os_resetEvent(tex->mapped);

frame->width = this->width;
@@ -787,7 +786,16 @@ static CaptureResult dxgi_getFrame(CaptureFrame * frame)
frame->stride = this->stride;
frame->format = this->format;

memcpy(frame->data, tex->map.pData, this->pitch * this->height);
return CAPTURE_RESULT_OK;
}

static CaptureResult dxgi_getFrame(FrameBuffer frame)
{
assert(this);
assert(this->initialized);

Texture * tex = &this->texture[this->texRIndex];
framebuffer_write(frame, tex->map.pData, this->pitch * this->height);
os_signalEvent(tex->free);

if (++this->texRIndex == this->maxTextures)
@@ -867,6 +875,7 @@ struct CaptureInterface Capture_DXGI =
.free = dxgi_free,
.getMaxFrameSize = dxgi_getMaxFrameSize,
.capture = dxgi_capture,
.waitFrame = dxgi_waitFrame,
.getFrame = dxgi_getFrame,
.getPointer = dxgi_getPointer
};
@@ -23,6 +23,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#include "windows/debug.h"
#include "windows/mousehook.h"
#include "common/option.h"
#include "common/framebuffer.h"
#include <assert.h>
#include <stdlib.h>
#include <windows.h>
@@ -236,7 +237,7 @@ static CaptureResult nvfbc_capture()
return CAPTURE_RESULT_OK;
}

static CaptureResult nvfbc_getFrame(CaptureFrame * frame)
static CaptureResult nvfbc_waitFrame(CaptureFrame * frame)
{
if (!os_waitEvent(this->frameEvent, 1000))
return CAPTURE_RESULT_TIMEOUT;
@@ -266,7 +267,16 @@ static CaptureResult nvfbc_getFrame(CaptureFrame * frame)
#endif

frame->format = this->grabInfo.bIsHDR ? CAPTURE_FMT_RGBA10 : CAPTURE_FMT_BGRA;
memcpy(frame->data, this->frameBuffer, frame->pitch * frame->height);
return CAPTURE_RESULT_OK;
}

static CaptureResult nvfbc_getFrame(FrameBuffer frame)
{
framebuffer_write(
frame,
this->frameBuffer,
this->grabInfo.dwHeight * this->grabInfo.dwBufferWidth * 4
);
return CAPTURE_RESULT_OK;
}

@@ -310,6 +320,7 @@ struct CaptureInterface Capture_NVFBC =
.free = nvfbc_free,
.getMaxFrameSize = nvfbc_getMaxFrameSize,
.capture = nvfbc_capture,
.waitFrame = nvfbc_waitFrame,
.getFrame = nvfbc_getFrame,
.getPointer = nvfbc_getPointer
};
@@ -49,7 +49,7 @@ struct app

uint8_t * frames;
unsigned int frameSize;
uint8_t * frame[MAX_FRAMES];
FrameBuffer frame[MAX_FRAMES];
unsigned int frameOffset[MAX_FRAMES];

bool running;
@@ -168,9 +168,7 @@ static int frameThread(void * opaque)

while(app.running)
{
frame.data = app.frame[frameIndex];

switch(app.iface->getFrame(&frame))
switch(app.iface->waitFrame(&frame))
{
case CAPTURE_RESULT_OK:
break;
@@ -226,7 +224,9 @@ static int frameThread(void * opaque)
fi->dataPos = app.frameOffset[frameIndex];
frameValid = true;

framebuffer_prepare(app.frame[frameIndex]);
INTERLOCKED_OR8(&fi->flags, KVMFR_FRAME_FLAG_UPDATE);
app.iface->getFrame(app.frame[frameIndex]);

if (++frameIndex == MAX_FRAMES)
frameIndex = 0;
@@ -369,8 +369,8 @@ int app_main(int argc, char * argv[])

for (int i = 0; i < MAX_FRAMES; ++i)
{
app.frame [i] = app.frames + i * app.frameSize;
app.frameOffset[i] = app.frame[i] - shmemMap;
app.frame [i] = (FrameBuffer)(app.frames + i * app.frameSize);
app.frameOffset[i] = (uint8_t *)app.frame[i] - shmemMap;
DEBUG_INFO("Frame %d : 0x%" PRIXPTR " (0x%08x)", i, (uintptr_t)app.frame[i], app.frameOffset[i]);
}

@@ -26,6 +26,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA

#include "app.h"
#include "common/KVMFR.h"
#include "common/framebuffer.h"

#define IS_LG_RENDERER_VALID(x) \
((x)->get_name && \
@@ -89,7 +90,7 @@ typedef void (* LG_RendererDeInitialize)(void * opaque);
typedef void (* LG_RendererOnResize )(void * opaque, const int width, const int height, const LG_RendererRect destRect);
typedef bool (* LG_RendererOnMouseShape)(void * opaque, const LG_RendererCursor cursor, const int width, const int height, const int pitch, const uint8_t * data);
typedef bool (* LG_RendererOnMouseEvent)(void * opaque, const bool visible , const int x, const int y);
typedef bool (* LG_RendererOnFrameEvent)(void * opaque, const LG_RendererFormat format, const uint8_t * data);
typedef bool (* LG_RendererOnFrameEvent)(void * opaque, const LG_RendererFormat format, const FrameBuffer frame);
typedef void (* LG_RendererOnAlert )(void * opaque, const LG_MsgAlert alert, const char * message, bool ** closeFlag);
typedef bool (* LG_RendererRender )(void * opaque, SDL_Window *window);
typedef void (* LG_RendererUpdateFPS )(void * opaque, const float avgUPS, const float avgFPS);
@@ -60,7 +60,7 @@ struct EGL_Desktop
enum EGL_PixelFormat pixFmt;
unsigned int width, height;
unsigned int pitch;
const uint8_t * data;
FrameBuffer frame;
bool update;

// night vision
@@ -181,7 +181,7 @@ void egl_desktop_free(EGL_Desktop ** desktop)
*desktop = NULL;
}

bool egl_desktop_prepare_update(EGL_Desktop * desktop, const bool sourceChanged, const LG_RendererFormat format, const uint8_t * data)
bool egl_desktop_prepare_update(EGL_Desktop * desktop, const bool sourceChanged, const LG_RendererFormat format, const FrameBuffer frame)
{
if (sourceChanged)
{
@@ -217,7 +217,7 @@ bool egl_desktop_prepare_update(EGL_Desktop * desktop, const bool sourceChanged,
desktop->width = format.width;
desktop->height = format.height;
desktop->pitch = format.pitch;
desktop->data = data;
desktop->frame = frame;
desktop->update = true;

/* defer the actual update as the format has changed and we need to issue GL commands first */
@@ -226,7 +226,7 @@ bool egl_desktop_prepare_update(EGL_Desktop * desktop, const bool sourceChanged,
}

/* update the texture now */
return egl_texture_update(desktop->texture, data);
return egl_texture_update_from_frame(desktop->texture, frame);
}

void egl_desktop_perform_update(EGL_Desktop * desktop, const bool sourceChanged)
@@ -253,7 +253,7 @@ void egl_desktop_perform_update(EGL_Desktop * desktop, const bool sourceChanged)
if (desktop->update)
{
desktop->update = false;
egl_texture_update(desktop->texture, desktop->data);
egl_texture_update_from_frame(desktop->texture, desktop->frame);
}
}

@@ -28,6 +28,6 @@ typedef struct EGL_Desktop EGL_Desktop;
bool egl_desktop_init(EGL_Desktop ** desktop);
void egl_desktop_free(EGL_Desktop ** desktop);

bool egl_desktop_prepare_update(EGL_Desktop * desktop, const bool sourceChanged, const LG_RendererFormat format, const uint8_t * data);
bool egl_desktop_prepare_update(EGL_Desktop * desktop, const bool sourceChanged, const LG_RendererFormat format, const FrameBuffer frame);
void egl_desktop_perform_update(EGL_Desktop * desktop, const bool sourceChanged);
bool egl_desktop_render(EGL_Desktop * desktop, const float x, const float y, const float scaleX, const float scaleY, const bool nearest);
@@ -296,7 +296,7 @@ bool egl_on_mouse_event(void * opaque, const bool visible, const int x, const in
return true;
}

bool egl_on_frame_event(void * opaque, const LG_RendererFormat format, const uint8_t * data)
bool egl_on_frame_event(void * opaque, const LG_RendererFormat format, const FrameBuffer frame)
{
struct Inst * this = (struct Inst *)opaque;
this->sourceChanged = (
@@ -312,7 +312,7 @@ bool egl_on_frame_event(void * opaque, const LG_RendererFormat format, const uin

this->useNearest = this->width < format.width || this->height < format.height;

if (!egl_desktop_prepare_update(this->desktop, this->sourceChanged, format, data))
if (!egl_desktop_prepare_update(this->desktop, this->sourceChanged, format, frame))
{
DEBUG_INFO("Failed to prepare to update the desktop");
return false;
@@ -20,6 +20,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#include "texture.h"
#include "common/debug.h"
#include "common/locking.h"
#include "common/framebuffer.h"
#include "debug.h"
#include "utils.h"

@@ -278,6 +279,24 @@ bool egl_texture_update(EGL_Texture * texture, const uint8_t * buffer)
return true;
}

bool egl_texture_update_from_frame(EGL_Texture * texture, const FrameBuffer frame)
{
if (!texture->streaming)
return false;

if (texture->pboCount == 2)
return true;

framebuffer_read(frame, texture->pboMap[texture->pboWIndex], texture->pboBufferSize);
texture->pboSync[texture->pboWIndex] = 0;

if (++texture->pboWIndex == 2)
texture->pboWIndex = 0;
INTERLOCKED_INC(&texture->pboCount);

return true;
}

enum EGL_TexStatus egl_texture_process(EGL_Texture * texture)
{
if (!texture->streaming)
@@ -21,6 +21,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA

#include <stdbool.h>
#include "shader.h"
#include "common/framebuffer.h"

#include <GL/gl.h>

@@ -46,6 +47,7 @@ void egl_texture_free(EGL_Texture ** tex);

bool egl_texture_setup (EGL_Texture * texture, enum EGL_PixelFormat pixfmt, size_t width, size_t height, size_t stride, bool streaming);
bool egl_texture_update (EGL_Texture * texture, const uint8_t * buffer);
bool egl_texture_update_from_frame(EGL_Texture * texture, const FrameBuffer frame);
enum EGL_TexStatus egl_texture_process(EGL_Texture * texture);
enum EGL_TexStatus egl_texture_bind (EGL_Texture * texture);
int egl_texture_count (EGL_Texture * texture);

0 comments on commit bca54ab

Please sign in to comment.
You can’t perform that action at this time.