mirror of
https://github.com/gnif/LookingGlass.git
synced 2025-11-17 07:28:44 +00:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d9397610f3 | ||
|
|
f26d8fbd3e | ||
|
|
43b096a5e7 | ||
|
|
a08aad8009 | ||
|
|
2b66fa6136 | ||
|
|
e3a426f378 | ||
|
|
e5f86a824a | ||
|
|
c0b2c8e655 | ||
|
|
c5cbb948e2 | ||
|
|
58ed978767 | ||
|
|
c098967293 | ||
|
|
8fbacba82e | ||
|
|
0753e63644 | ||
|
|
5501d22a2d | ||
|
|
2f6b7e08f8 | ||
|
|
2fe800f502 |
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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, ¶ms , 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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
70
host/MultiMemcpy.cpp
Normal 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
48
host/MultiMemcpy.h
Normal 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);
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
72
host/Util.h
72
host/Util.h
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
Reference in New Issue
Block a user