Compare commits

..

16 Commits
a8 ... a9

Author SHA1 Message Date
arcnmx
d9397610f3 [host] compile MultiMemcpy on mingw 2017-12-21 14:42:49 +11:00
arcnmx
f26d8fbd3e [host] remove unused variables 2017-12-21 14:42:49 +11:00
Geoffrey McRae
43b096a5e7 [host] added multi-threaded memcopy for high resolutions 2017-12-21 13:49:36 +11:00
Geoffrey McRae
a08aad8009 [client] opengl: don't scale the FPS readout 2017-12-21 06:50:57 +11:00
Geoffrey McRae
2b66fa6136 [client] warn about unreliable cursor scaling
This also logs the scaling information to assist with reports about
improper mouse alignment
2017-12-21 06:39:41 +11:00
Geoffrey McRae
e3a426f378 [client] update dimension information after the first frame 2017-12-21 06:38:34 +11:00
Geoffrey McRae
e5f86a824a [client] switch back to atomic locking as the default
The prior patch to correct the mouse loop resolves the CPU load issue
with the atomic locking method. SDL mutexes are still available if
desired but full mutex locking is far slower then fast spinlocks
2017-12-21 02:12:19 +11:00
Geoffrey McRae
c0b2c8e655 [client] added missing wait to cursor update thread 2017-12-21 01:56:59 +11:00
Geoffrey McRae
c5cbb948e2 [client] report locking mode used for diagnostics 2017-12-21 01:35:36 +11:00
Geoffrey McRae
58ed978767 [client] opengl: switch to SDL_mutex locking 2017-12-21 01:23:25 +11:00
Geoffrey McRae
c098967293 [client] opengl: update FPS even when there is no updates 2017-12-21 01:17:45 +11:00
Geoffrey McRae
8fbacba82e [client] make startup sleep nicer on the CPU 2017-12-21 01:15:16 +11:00
Geoffrey McRae
0753e63644 [client] fixed unlock define 2017-12-21 01:11:42 +11:00
Geoffrey McRae
5501d22a2d [client] fixed missed usage of new locking semantics 2017-12-21 01:03:21 +11:00
Geoffrey McRae
2f6b7e08f8 [client] define locking types and semantics to allow for alt methods 2017-12-21 00:58:16 +11:00
Geoffrey McRae
2fe800f502 [host] dxgi: corrected timeout alteration left behind from debugging 2017-12-20 04:35:07 +11:00
13 changed files with 306 additions and 194 deletions

View File

@@ -1,5 +1,5 @@
BINARY = looking-glass-client
CFLAGS = -g -O3 -std=gnu99 -march=native -Wall -Werror -I./ -I../common -DDEBUG
CFLAGS = -g -O3 -std=gnu99 -march=native -Wall -Werror -I./ -I../common -DDEBUG -DATOMIC_LOCKING
LDFLAGS = -lrt
CFLAGS += -ffast-math

View File

@@ -121,6 +121,9 @@ struct AppParams params =
static inline void updatePositionInfo()
{
if (!state.started)
return;
int w, h;
SDL_GetWindowSize(state.window, &w, &h);
@@ -151,11 +154,18 @@ static inline void updatePositionInfo()
state.dstRect.h = h;
}
if (state.started)
{
state.scaleX = (float)state.srcSize.y / (float)state.dstRect.h;
state.scaleY = (float)state.srcSize.x / (float)state.dstRect.w;
}
state.scaleX = (float)state.srcSize.y / (float)state.dstRect.h;
state.scaleY = (float)state.srcSize.x / (float)state.dstRect.w;
DEBUG_INFO("client %dx%d, guest %dx%d, target %dx%d, scaleX: %.2f, scaleY %.2f",
w, h,
state.srcSize.x, state.srcSize.y,
state.dstRect.w, state.dstRect.h,
state.scaleX , state.scaleY
);
if (w != state.srcSize.x || h != state.srcSize.y)
DEBUG_WARN("Window size doesn't match guest resolution, cursor alignment may not be reliable");
if (state.lgr)
state.lgr->on_resize(state.lgrData, w, h, state.dstRect);
@@ -165,10 +175,13 @@ void mainThread()
{
while(state.running)
{
nsleep(1000);
if (state.started)
{
if (!state.lgr->render(state.lgrData, state.window))
break;
}
else
usleep(1000);
}
}
@@ -182,6 +195,13 @@ int cursorThread(void * unused)
while(state.running)
{
// poll until we have cursor data
if(!(state.shm->flags & KVMFR_HEADER_FLAG_CURSOR))
{
nsleep(100);
continue;
}
// we must take a copy of the header, both to let the guest advance and to
// prevent the contained arguments being abused to overflow buffers
memcpy(&header, (KVMFRHeader *)state.shm, sizeof(struct KVMFRHeader));
@@ -345,8 +365,8 @@ int frameThread(void * unused)
if (!state.started)
{
DEBUG_INFO("feed started");
state.started = true;
updatePositionInfo();
}
}
@@ -639,6 +659,7 @@ static bool try_renderer(const int index, const LG_RendererParams lgrParams, Uin
int run()
{
DEBUG_INFO("Looking Glass (" BUILD_VERSION ")");
DEBUG_INFO("Locking Method: " LG_LOCK_MODE);
memset(&state, 0, sizeof(state));
state.running = true;

View File

@@ -71,7 +71,7 @@ struct Inst
bool resizeWindow;
bool frameUpdate;
volatile int formatLock;
LG_Lock formatLock;
LG_RendererFormat format;
GLuint intFormat;
GLuint vboFormat;
@@ -81,7 +81,7 @@ struct Inst
bool hasBuffers;
GLuint vboID[1];
uint8_t * texPixels[BUFFER_COUNT];
volatile int syncLock;
LG_Lock syncLock;
int texIndex, wTexIndex;
int texList;
int fpsList;
@@ -99,7 +99,7 @@ struct Inst
uint64_t renderCount;
SDL_Rect fpsRect;
volatile int mouseLock;
LG_Lock mouseLock;
LG_RendererCursor mouseCursor;
int mouseWidth;
int mouseHeight;
@@ -144,6 +144,10 @@ bool opengl_create(void ** opaque, const LG_RendererParams params)
memcpy(&this->params, &params , sizeof(LG_RendererParams));
memcpy(&this->opt , &defaultOptions, sizeof(struct Options ));
LG_LOCK_INIT(this->formatLock);
LG_LOCK_INIT(this->syncLock );
LG_LOCK_INIT(this->mouseLock );
return true;
}
@@ -181,6 +185,10 @@ void opengl_deinitialize(void * opaque)
if (this->mouseData)
free(this->mouseData);
LG_LOCK_FREE(this->formatLock);
LG_LOCK_FREE(this->syncLock );
LG_LOCK_FREE(this->mouseLock );
free(this);
}
@@ -203,7 +211,7 @@ bool opengl_on_mouse_shape(void * opaque, const LG_RendererCursor cursor, const
if (!this)
return false;
while(__sync_lock_test_and_set(&this->mouseLock, 1));
LG_LOCK(this->mouseLock);
this->mouseCursor = cursor;
this->mouseWidth = width;
this->mouseHeight = height;
@@ -220,7 +228,7 @@ bool opengl_on_mouse_shape(void * opaque, const LG_RendererCursor cursor, const
memcpy(this->mouseData, data, size);
this->newShape = true;
__sync_lock_release(&this->mouseLock);
LG_UNLOCK(this->mouseLock);
return true;
}
@@ -250,10 +258,10 @@ bool opengl_on_frame_event(void * opaque, const LG_RendererFormat format, const
return false;
}
while(__sync_lock_test_and_set(&this->formatLock, 1));
LG_LOCK(this->formatLock);
if (this->reconfigure)
{
__sync_lock_release(&this->formatLock);
LG_UNLOCK(this->formatLock);
return true;
}
@@ -261,16 +269,16 @@ bool opengl_on_frame_event(void * opaque, const LG_RendererFormat format, const
{
memcpy(&this->format, &format, sizeof(LG_RendererFormat));
this->reconfigure = true;
__sync_lock_release(&this->formatLock);
LG_UNLOCK(this->formatLock);
return true;
}
__sync_lock_release(&this->formatLock);
LG_UNLOCK(this->formatLock);
// lock, perform the update, then unlock
while(__sync_lock_test_and_set(&this->syncLock, 1));
LG_LOCK(this->syncLock);
memcpySSE(this->texPixels[this->wTexIndex], data, this->texSize);
this->frameUpdate = true;
__sync_lock_release(&this->syncLock);
LG_UNLOCK(this->syncLock);
++this->frameCount;
return true;
@@ -313,6 +321,84 @@ bool opengl_render(void * opaque, SDL_Window * window)
this->resizeWindow = false;
}
if (this->params.showFPS && this->renderTime > 1e9)
{
char str[128];
const float avgFPS = 1000.0f / (((float)this->renderTime / this->frameCount ) / 1e6f);
const float renderFPS = 1000.0f / (((float)this->renderTime / this->renderCount) / 1e6f);
snprintf(str, sizeof(str), "UPS: %8.4f, FPS: %8.4f", avgFPS, renderFPS);
SDL_Color color = {0xff, 0xff, 0xff};
SDL_Surface *textSurface = NULL;
if (!(textSurface = TTF_RenderText_Blended(this->params.font, str, color)))
{
DEBUG_ERROR("Failed to render text");
LG_UNLOCK(this->formatLock);
return false;
}
glBindTexture(GL_TEXTURE_2D , this->textures[FPS_TEXTURE]);
glPixelStorei(GL_UNPACK_ALIGNMENT , 4 );
glPixelStorei(GL_UNPACK_ROW_LENGTH, textSurface->w );
glTexImage2D(
GL_TEXTURE_2D,
0,
textSurface->format->BytesPerPixel,
textSurface->w,
textSurface->h,
0,
GL_BGRA,
GL_UNSIGNED_BYTE,
textSurface->pixels
);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glBindTexture(GL_TEXTURE_2D, 0);
this->fpsRect.x = 5;
this->fpsRect.y = 5;
this->fpsRect.w = textSurface->w;
this->fpsRect.h = textSurface->h;
SDL_FreeSurface(textSurface);
this->renderTime = 0;
this->frameCount = 0;
this->renderCount = 0;
this->fpsTexture = true;
glNewList(this->fpsList, GL_COMPILE);
glPushMatrix();
glLoadIdentity();
glEnable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
glColor4f(0.0f, 0.0f, 1.0f, 0.5f);
glBegin(GL_TRIANGLE_STRIP);
glVertex2i(this->fpsRect.x , this->fpsRect.y );
glVertex2i(this->fpsRect.x + this->fpsRect.w, this->fpsRect.y );
glVertex2i(this->fpsRect.x , this->fpsRect.y + this->fpsRect.h);
glVertex2i(this->fpsRect.x + this->fpsRect.w, this->fpsRect.y + this->fpsRect.h);
glEnd();
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, this->textures[FPS_TEXTURE]);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2f(0.0f , 0.0f); glVertex2i(this->fpsRect.x , this->fpsRect.y );
glTexCoord2f(1.0f , 0.0f); glVertex2i(this->fpsRect.x + this->fpsRect.w, this->fpsRect.y );
glTexCoord2f(0.0f , 1.0f); glVertex2i(this->fpsRect.x , this->fpsRect.y + this->fpsRect.h);
glTexCoord2f(1.0f, 1.0f); glVertex2i(this->fpsRect.x + this->fpsRect.w, this->fpsRect.y + this->fpsRect.h);
glEnd();
glDisable(GL_BLEND);
glPopMatrix();
glEndList();
}
bool frameUpdate;
if (!draw_frame(this, &frameUpdate))
return false;
@@ -430,10 +516,10 @@ static bool _check_gl_error(unsigned int line, const char * name)
static bool configure(struct Inst * this, SDL_Window *window)
{
while(__sync_lock_test_and_set(&this->formatLock, 1));
LG_LOCK(this->formatLock);
if (!this->reconfigure)
{
__sync_lock_release(&this->formatLock);
LG_UNLOCK(this->formatLock);
return this->configured;
}
@@ -444,7 +530,7 @@ static bool configure(struct Inst * this, SDL_Window *window)
if (!this->glContext)
{
DEBUG_ERROR("Failed to create the OpenGL context");
__sync_lock_release(&this->formatLock);
LG_UNLOCK(this->formatLock);
return false;
}
@@ -464,7 +550,7 @@ static bool configure(struct Inst * this, SDL_Window *window)
if (!gluCheckExtension((const GLubyte *)"GL_ARB_buffer_storage", extensions))
{
DEBUG_INFO("The GPU doesn't support GL_ARB_buffer_storage");
__sync_lock_release(&this->formatLock);
LG_UNLOCK(this->formatLock);
return false;
}
@@ -483,7 +569,7 @@ static bool configure(struct Inst * this, SDL_Window *window)
default:
DEBUG_INFO("%d bpp not supported", this->format.bpp);
__sync_lock_release(&this->formatLock);
LG_UNLOCK(this->formatLock);
return false;
}
@@ -499,7 +585,7 @@ static bool configure(struct Inst * this, SDL_Window *window)
glGenBuffers(1, this->vboID);
if (check_gl_error("glGenBuffers"))
{
__sync_lock_release(&this->formatLock);
LG_UNLOCK(this->formatLock);
return false;
}
this->hasBuffers = true;
@@ -507,7 +593,7 @@ static bool configure(struct Inst * this, SDL_Window *window)
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->vboID[0]);
if (check_gl_error("glBindBuffer"))
{
__sync_lock_release(&this->formatLock);
LG_UNLOCK(this->formatLock);
return false;
}
@@ -520,7 +606,7 @@ static bool configure(struct Inst * this, SDL_Window *window)
);
if (check_gl_error("glBufferStorage"))
{
__sync_lock_release(&this->formatLock);
LG_UNLOCK(this->formatLock);
return false;
}
@@ -535,7 +621,7 @@ static bool configure(struct Inst * this, SDL_Window *window)
if (check_gl_error("glMapBufferRange"))
{
__sync_lock_release(&this->formatLock);
LG_UNLOCK(this->formatLock);
return false;
}
@@ -546,7 +632,7 @@ static bool configure(struct Inst * this, SDL_Window *window)
glGenTextures(TEXTURE_COUNT, this->textures);
if (check_gl_error("glGenTextures"))
{
__sync_lock_release(&this->formatLock);
LG_UNLOCK(this->formatLock);
return false;
}
this->hasTextures = true;
@@ -555,7 +641,7 @@ static bool configure(struct Inst * this, SDL_Window *window)
glBindTexture(GL_TEXTURE_2D, this->textures[FRAME_TEXTURE]);
if (check_gl_error("glBindTexture"))
{
__sync_lock_release(&this->formatLock);
LG_UNLOCK(this->formatLock);
return false;
}
@@ -572,7 +658,7 @@ static bool configure(struct Inst * this, SDL_Window *window)
);
if (check_gl_error("glTexImage2D"))
{
__sync_lock_release(&this->formatLock);
LG_UNLOCK(this->formatLock);
return false;
}
@@ -616,7 +702,7 @@ static bool configure(struct Inst * this, SDL_Window *window)
this->configured = true;
this->reconfigure = false;
__sync_lock_release(&this->formatLock);
LG_UNLOCK(this->formatLock);
return true;
}
@@ -648,11 +734,11 @@ static void deconfigure(struct Inst * this)
static void update_mouse_shape(struct Inst * this, bool * newShape)
{
while(__sync_lock_test_and_set(&this->mouseLock, 1));
LG_LOCK(this->mouseLock);
*newShape = this->newShape;
if (!this->newShape)
{
__sync_lock_release(&this->mouseLock);
LG_UNLOCK(this->mouseLock);
return;
}
@@ -778,16 +864,16 @@ static void update_mouse_shape(struct Inst * this, bool * newShape)
}
this->mouseUpdate = true;
__sync_lock_release(&this->mouseLock);
LG_UNLOCK(this->mouseLock);
}
static bool draw_frame(struct Inst * this, bool * frameUpdate)
{
while(__sync_lock_test_and_set(&this->syncLock, 1));
LG_LOCK(this->syncLock);
*frameUpdate = this->frameUpdate;
if (!this->frameUpdate)
{
__sync_lock_release(&this->syncLock);
LG_UNLOCK(this->syncLock);
return true;
}
@@ -795,81 +881,9 @@ static bool draw_frame(struct Inst * this, bool * frameUpdate)
if (++this->wTexIndex == BUFFER_COUNT)
this->wTexIndex = 0;
this->frameUpdate = false;
__sync_lock_release(&this->syncLock);
LG_UNLOCK(this->syncLock);
while(__sync_lock_test_and_set(&this->formatLock, 1));
if (this->params.showFPS && this->renderTime > 1e9)
{
char str[128];
const float avgFPS = 1000.0f / (((float)this->renderTime / this->frameCount ) / 1e6f);
const float renderFPS = 1000.0f / (((float)this->renderTime / this->renderCount) / 1e6f);
snprintf(str, sizeof(str), "UPS: %8.4f, FPS: %8.4f", avgFPS, renderFPS);
SDL_Color color = {0xff, 0xff, 0xff};
SDL_Surface *textSurface = NULL;
if (!(textSurface = TTF_RenderText_Blended(this->params.font, str, color)))
{
DEBUG_ERROR("Failed to render text");
__sync_lock_release(&this->formatLock);
return false;
}
glBindTexture(GL_TEXTURE_2D , this->textures[FPS_TEXTURE]);
glPixelStorei(GL_UNPACK_ALIGNMENT , 4 );
glPixelStorei(GL_UNPACK_ROW_LENGTH, textSurface->w );
glTexImage2D(
GL_TEXTURE_2D,
0,
textSurface->format->BytesPerPixel,
textSurface->w,
textSurface->h,
0,
GL_BGRA,
GL_UNSIGNED_BYTE,
textSurface->pixels
);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glBindTexture(GL_TEXTURE_2D, 0);
this->fpsRect.x = 5;
this->fpsRect.y = 5;
this->fpsRect.w = textSurface->w;
this->fpsRect.h = textSurface->h;
SDL_FreeSurface(textSurface);
this->renderTime = 0;
this->frameCount = 0;
this->renderCount = 0;
this->fpsTexture = true;
glNewList(this->fpsList, GL_COMPILE);
glEnable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
glColor4f(0.0f, 0.0f, 1.0f, 0.5f);
glBegin(GL_TRIANGLE_STRIP);
glVertex2i(this->fpsRect.x , this->fpsRect.y );
glVertex2i(this->fpsRect.x + this->fpsRect.w, this->fpsRect.y );
glVertex2i(this->fpsRect.x , this->fpsRect.y + this->fpsRect.h);
glVertex2i(this->fpsRect.x + this->fpsRect.w, this->fpsRect.y + this->fpsRect.h);
glEnd();
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, this->textures[FPS_TEXTURE]);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2f(0.0f , 0.0f); glVertex2i(this->fpsRect.x , this->fpsRect.y );
glTexCoord2f(1.0f , 0.0f); glVertex2i(this->fpsRect.x + this->fpsRect.w, this->fpsRect.y );
glTexCoord2f(0.0f , 1.0f); glVertex2i(this->fpsRect.x , this->fpsRect.y + this->fpsRect.h);
glTexCoord2f(1.0f, 1.0f); glVertex2i(this->fpsRect.x + this->fpsRect.w, this->fpsRect.y + this->fpsRect.h);
glEnd();
glDisable(GL_BLEND);
glEndList();
}
LG_LOCK(this->formatLock);
// bind the texture and update it
glBindTexture(GL_TEXTURE_2D , this->textures[FRAME_TEXTURE]);
@@ -921,7 +935,7 @@ static bool draw_frame(struct Inst * this, bool * frameUpdate)
}
glBindTexture(GL_TEXTURE_2D, 0);
__sync_lock_release(&this->formatLock);
LG_UNLOCK(this->formatLock);
return true;
}

View File

@@ -44,4 +44,20 @@ static inline void nsleep(uint64_t ns)
.tv_nsec = ns - ((ns / 1e9) * 1e9)
};
nanosleep(&ts, NULL);
}
}
#ifdef ATOMIC_LOCKING
#define LG_LOCK_MODE "Atomic"
typedef volatile int LG_Lock;
#define LG_LOCK_INIT(x) (x) = 0
#define LG_LOCK(x) while(__sync_lock_test_and_set(&(x), 1)) {nsleep(100);}
#define LG_UNLOCK(x) __sync_lock_release(&x)
#define LG_LOCK_FREE(x)
#else
#define LG_LOCK_MODE "Mutex"
typedef SDL_mutex * LG_Lock;
#define LG_LOCK_INIT(x) (x = SDL_CreateMutex())
#define LG_LOCK(x) SDL_LockMutex(x)
#define LG_UNLOCK(x) SDL_UnlockMutex(x)
#define LG_LOCK_FREE(x) SDL_DestroyMutex(x)
#endif

View File

@@ -21,7 +21,6 @@ Place, Suite 330, Boston, MA 02111-1307 USA
using namespace Capture;
#include "common/debug.h"
#include "common/memcpySSE.h"
DXGI::DXGI() :
m_options(NULL),
@@ -33,11 +32,11 @@ DXGI::DXGI() :
m_texture(),
m_pointer(NULL)
{
}
DXGI::~DXGI()
{
}
bool DXGI::Initialize(CaptureOptions * options)
@@ -297,7 +296,7 @@ GrabStatus DXGI::GrabFrame(FrameInfo & frame)
}
}
status = m_dup->AcquireNextFrame(10000, &frameInfo, &res);
status = m_dup->AcquireNextFrame(1000, &frameInfo, &res);
if (status == DXGI_ERROR_WAIT_TIMEOUT)
{
if (!m_surfaceMapped)
@@ -310,7 +309,7 @@ GrabStatus DXGI::GrabFrame(FrameInfo & frame)
frame.stride = m_mapping.RowPitch / 4;
unsigned int size = m_height * m_mapping.RowPitch;
memcpySSE(frame.buffer, m_mapping.pData, size < frame.bufferSize ? size : frame.bufferSize);
m_memcpy.Copy(frame.buffer, m_mapping.pData, size < frame.bufferSize ? size : frame.bufferSize);
return GRAB_STATUS_OK;
}
@@ -393,7 +392,6 @@ GrabStatus DXGI::GrabFrame(FrameInfo & frame)
if (SUCCEEDED(status))
break;
HDESK desktop = NULL;
switch (status)
{
// desktop switch, mode change, switch DWM on or off or Secure Desktop
@@ -448,7 +446,7 @@ GrabStatus DXGI::GrabFrame(FrameInfo & frame)
frame.stride = m_mapping.RowPitch / 4;
unsigned int size = m_height * m_mapping.RowPitch;
memcpySSE(frame.buffer, m_mapping.pData, size < frame.bufferSize ? size : frame.bufferSize);
m_memcpy.Copy(frame.buffer, m_mapping.pData, size < frame.bufferSize ? size : frame.bufferSize);
return GRAB_STATUS_OK;
}

View File

@@ -20,6 +20,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#pragma once
#include "ICapture.h"
#include "MultiMemcpy.h"
#define W32_LEAN_AND_MEAN
#include <windows.h>
@@ -75,6 +76,7 @@ namespace Capture
unsigned int m_width;
unsigned int m_height;
MultiMemcpy m_memcpy;
IDXGIFactory1Ptr m_dxgiFactory;
ID3D11DevicePtr m_device;
D3D_FEATURE_LEVEL m_featureLevel;

View File

@@ -16,11 +16,11 @@ LD = $(CXX)
BUILD ?= .build
BIN ?= bin
CFLAGS += -DBUILD_VERSION='"$(shell git describe --always --long --dirty --abbrev=10 --tags)"'
OBJS = main.o \
CrashHandler.o \
MultiMemcpy.o \
IVSHMEM.o \
Service.o \
Capture/DXGI.o

70
host/MultiMemcpy.cpp Normal file
View File

@@ -0,0 +1,70 @@
/*
Looking Glass - KVM FrameRelay (KVMFR) Client
Copyright (C) 2017 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 "MultiMemcpy.h"
#include "Util.h"
#include "common/memcpySSE.h"
MultiMemcpy::MultiMemcpy()
{
for (int i = 0; i < MULTIMEMCPY_THREADS; ++i)
{
m_workers[i].start = CreateSemaphore(NULL, 0, 1, NULL);
m_workers[i].stop = CreateSemaphore(NULL, 0, 1, NULL);
m_semaphores[i] = m_workers[i].stop;
m_workers[i].thread = CreateThread(0, 0, WorkerFunction, &m_workers[i], 0, NULL);
}
}
MultiMemcpy::~MultiMemcpy()
{
for(int i = 0; i < MULTIMEMCPY_THREADS; ++i)
{
TerminateThread(m_workers[i].thread, 0);
CloseHandle(m_workers[i].start);
CloseHandle(m_workers[i].stop );
}
}
void MultiMemcpy::Copy(void * dst, void * src, size_t size)
{
const size_t block = size / MULTIMEMCPY_THREADS;
for (int i = 0; i < MULTIMEMCPY_THREADS; ++i)
{
m_workers[i].dst = (uint8_t *)dst + i * block;
m_workers[i].src = (uint8_t *)src + i * block;
m_workers[i].size = (i + 1) * block - i * block;
ReleaseSemaphore(m_workers[i].start, 1, NULL);
}
WaitForMultipleObjects(MULTIMEMCPY_THREADS, m_semaphores, TRUE, INFINITE);
}
DWORD WINAPI MultiMemcpy::WorkerFunction(LPVOID param)
{
struct Worker * w = (struct Worker *)param;
for(;;)
{
WaitForSingleObject(w->start, INFINITE);
memcpySSE(w->dst, w->src, w->size);
ReleaseSemaphore(w->stop, 1, NULL);
}
}

48
host/MultiMemcpy.h Normal file
View File

@@ -0,0 +1,48 @@
/*
Looking Glass - KVM FrameRelay (KVMFR) Client
Copyright (C) 2017 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
*/
#define MULTIMEMCPY_THREADS 4
#include <windows.h>
#include <stdint.h>
#pragma once
class MultiMemcpy
{
public:
MultiMemcpy();
~MultiMemcpy();
void Copy(void * dst, void * src, size_t size);
private:
struct Worker
{
HANDLE start;
HANDLE stop;
HANDLE thread;
void * dst;
void * src;
size_t size;
};
HANDLE m_semaphores[MULTIMEMCPY_THREADS];
struct Worker m_workers[MULTIMEMCPY_THREADS];
static DWORD WINAPI WorkerFunction(LPVOID param);
};

View File

@@ -23,16 +23,9 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#include "common/debug.h"
#include "common/KVMFR.h"
#include "Util.h"
#include "CaptureFactory.h"
#if __MINGW32__
#define INTERLOCKED_AND8 __sync_and_and_fetch
#define INTERLOCKED_OR8 __sync_or_and_fetch
#else
#define INTERLOCKED_OR8 InterlockedOr8
#define INTERLOCKED_AND8 InterlockedAnd8
#endif
Service * Service::m_instance = NULL;
Service::Service() :
@@ -161,7 +154,6 @@ bool Service::Process()
if (!m_initialized)
return false;
bool restart = false;
struct FrameInfo frame;
ZeroMemory(&frame, sizeof(FrameInfo));
frame.buffer = m_frame[m_frameIndex];
@@ -178,7 +170,6 @@ bool Service::Process()
if (f & KVMFR_HEADER_FLAG_RESTART)
{
INTERLOCKED_AND8((volatile char *)flags, ~(KVMFR_HEADER_FLAG_RESTART));
restart = true;
break;
}

View File

@@ -29,6 +29,14 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#define min(a, b) ((a) < (b) ? (a) : (b))
#endif
#if __MINGW32__
#define INTERLOCKED_AND8 __sync_and_and_fetch
#define INTERLOCKED_OR8 __sync_or_and_fetch
#else
#define INTERLOCKED_OR8 InterlockedOr8
#define INTERLOCKED_AND8 InterlockedAnd8
#endif
class Util
{
public:
@@ -120,68 +128,4 @@ public:
_mm_stream_si128((__m128i *)&dest[32], v2);
}
}
static void DrawCursor(
const enum CursorType type,
const uint8_t * cursorData,
const POINT cursorRect,
const unsigned int cursorPitch,
const POINT cursorPos,
FrameInfo & frame
)
{
const int maxHeight = min(cursorRect.y, (int)frame.height - cursorPos.y);
const int maxWidth = min(cursorRect.x, (int)frame.width - cursorPos.x);
switch (type)
{
case CURSOR_TYPE_COLOR:
{
const unsigned int destPitch = frame.stride * 4;
for (int y = abs(min(0, cursorPos.y)); y < maxHeight; ++y)
for (int x = abs(min(0, cursorPos.x)); x < maxWidth; ++x)
{
uint8_t *src = (uint8_t *)cursorData + (cursorPitch * y) + (x * 4);
uint8_t *dst = (uint8_t *)frame.buffer + (destPitch * (y + cursorPos.y)) + ((x + cursorPos.x) * 4);
const unsigned int alpha = src[3] + 1;
const unsigned int inv = 256 - alpha;
dst[0] = (uint8_t)((alpha * src[0] + inv * dst[0]) >> 8);
dst[1] = (uint8_t)((alpha * src[1] + inv * dst[1]) >> 8);
dst[2] = (uint8_t)((alpha * src[2] + inv * dst[2]) >> 8);
}
break;
}
case CURSOR_TYPE_MASKED_COLOR:
{
for (int y = abs(min(0, cursorPos.y)); y < maxHeight; ++y)
for (int x = abs(min(0, cursorPos.x)); x < maxWidth; ++x)
{
uint32_t *src = (uint32_t *)cursorData + ((cursorPitch / 4) * y) + x;
uint32_t *dst = (uint32_t *)frame.buffer + (frame.stride * (y + cursorPos.y)) + (x + cursorPos.x);
if (*src & 0xff000000)
*dst = 0xff000000 | (*dst ^ *src);
else *dst = 0xff000000 | *src;
}
break;
}
case CURSOR_TYPE_MONOCHROME:
{
for (int y = abs(min(0, cursorPos.y)); y < maxHeight / 2; ++y)
for (int x = abs(min(0, cursorPos.x)); x < maxWidth; ++x)
{
uint8_t *srcAnd = (uint8_t *)cursorData + (cursorPitch * y) + (x / 8);
uint8_t *srcXor = srcAnd + cursorPitch * (cursorRect.y / 2);
uint32_t *dst = (uint32_t *)frame.buffer + (frame.stride * (y + cursorPos.y)) + (x + cursorPos.x);
const uint8_t mask = 0x80 >> (x % 8);
const uint32_t andMask = (*srcAnd & mask) ? 0xFFFFFFFF : 0xFF000000;
const uint32_t xorMask = (*srcXor & mask) ? 0x00FFFFFF : 0x00000000;
*dst = (*dst & andMask) ^ xorMask;
}
break;
}
}
}
};

View File

@@ -335,6 +335,7 @@
<ClCompile Include="CrashHandler.cpp" />
<ClCompile Include="ivshmem.cpp" />
<ClCompile Include="main.cpp" />
<ClCompile Include="MultiMemcpy.cpp" />
<ClCompile Include="Service.cpp" />
</ItemGroup>
<ItemGroup>
@@ -344,6 +345,7 @@
<ClInclude Include="CrashHandler.h" />
<ClInclude Include="ICapture.h" />
<ClInclude Include="ivshmem.h" />
<ClInclude Include="MultiMemcpy.h" />
<ClInclude Include="Service.h" />
<ClInclude Include="Util.h" />
</ItemGroup>

View File

@@ -42,6 +42,9 @@
<ClCompile Include="CrashHandler.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="MultiMemcpy.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="ivshmem.h">
@@ -68,5 +71,8 @@
<ClInclude Include="CrashHandler.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="MultiMemcpy.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>