Compare commits

..

34 Commits

Author SHA1 Message Date
Geoffrey McRae
163a2e5d0a [client] fix failure to build due to broken symlink, fixes #173 2019-07-23 11:06:51 +10:00
Geoffrey McRae
b979752989 [client] added missing include 2019-07-15 18:30:39 +10:00
orcephrye
8ad2d5f949 [client] autodetect monitor refresh rate for fps limit 2019-07-10 05:04:29 +10:00
Rokas Kupstys
745ba66119 Implement option to disable minimizing window on focus loss. Default behavior is not changed - not configuring these options unfocused window is minimized.
* Added config entry win:minimizeOnFocusLoss (default true).
2019-07-09 21:57:47 +10:00
Geoffrey McRae
4cf6dec592 [all] allow disable of backtrace support during build 2019-06-19 09:13:03 +10:00
Geoffrey McRae
d7fa0aeff9 [client] fix typo in SDL_VIDEODRIVER from prior patch, whoops :) 2019-06-19 09:03:15 +10:00
Geoffrey McRae
2def6346e6 [client] don't override SDL_VIDEODRIVER if it is already set 2019-06-19 09:01:28 +10:00
Geoffrey McRae
607539a2af [client] improve streaming texture performance 2019-06-13 08:54:51 +10:00
Geoffrey McRae
6d24dd52d6 [c-host] not all versions of mingw support wcstombs_s
While the _s functions are for security as they avoid exceeding the
supplied buffer, in our case they are not really required as we are
allocating a buffer large enough to store the entire result.

Fixes #171
2019-06-12 15:31:18 +10:00
Omar Pakker
e3343cbd01 Rewrite dkms.conf
1) With the change to the Makefile, this update allows dkms to build and install the module for different kernels.
2) As per dkms documentation, no use of ${dkms_tree}.
3) Removed the use of REMAKE_INITRD as this module is not needed that early in the boot process.
4) Updated version to match what's defined in the module
2019-06-06 13:40:06 +10:00
Omar Pakker
71ffa0a137 Update makefile to allow kernel override 2019-06-06 13:40:06 +10:00
Geoffrey McRae
2b4f8091f9 [client] README.md cosmetics 2019-05-31 16:45:55 +10:00
Geoffrey McRae
113da121e9 [client] updated documentation for new keybinds 2019-05-31 16:44:08 +10:00
Geoffrey McRae
dd7413f973 [client] added keybinds to send Ctrl+Alt+Fn
Fixes #165
2019-05-31 16:39:55 +10:00
Geoffrey McRae
0851fd13e6 [all] made a nicer icon, hopefully just a placeholder for now 2019-05-30 22:21:53 +10:00
Geoffrey McRae
97024041f3 [client] allow the screensaver to run 2019-05-30 20:54:39 +10:00
Geoffrey McRae
22238c3200 [client] fix invalid access on early termination 2019-05-30 20:24:51 +10:00
Geoffrey McRae
780bb248f7 [c-host] dxgi: fix invalid cursor type define 2019-05-28 15:17:11 +10:00
Geoffrey McRae
026bdb00f2 [c-host] take just the ivshmem headers and omit the kvm-guest submodule 2019-05-28 14:51:47 +10:00
Geoffrey McRae
373d4ac932 [host] removed old host application from the project, see c-host 2019-05-28 14:47:09 +10:00
Geoffrey McRae
7d26027752 [c-host] resend the last on client reconnect if a timeout occurs 2019-05-28 14:24:48 +10:00
Geoffrey McRae
3d426ccef8 [all] fix missing cursor when client reconnects 2019-05-28 14:06:15 +10:00
Geoffrey McRae
b31e8e1cee [client] egl: remove accidental commit of debug code 2019-05-27 18:46:05 +10:00
Geoffrey McRae
f0923c4ed7 [client] egl: expose a few new tuneables 2019-05-27 18:42:46 +10:00
Geoffrey McRae
aabf19e63b [client] main: properly shutdown if renderer fails to init 2019-05-27 18:40:36 +10:00
Geoffrey McRae
f4fc1eb5f6 [client] typo in config help text 2019-05-27 18:40:36 +10:00
Geoffrey McRae
5e201a32ca [c-host] dxgi: allow out of order frame mapping 2019-05-27 15:26:58 +10:00
Geoffrey McRae
438e9e0969 [common] option: fixed missing null terminator 2019-05-27 01:56:55 +10:00
Geoffrey McRae
9554e82c47 [common] fix failure to initialize structure 2019-05-27 01:50:38 +10:00
Geoffrey McRae
4cf2c7a350 [client] check for failure to map pbo memory 2019-05-27 01:39:01 +10:00
Geoffrey McRae
664d7dccdb [client] fix the binary path when debugging 2019-05-27 01:38:50 +10:00
Geoffrey McRae
21b02efb4d [c-host] dxgi: don't stall the GPU pipeline to map textures to ram
ID3D11DeviceContext_Map by default will force a CPU sync if the prior call to
CopyResource has not completed, this change defers the mapping and sets the
D3D11_MAP_FLAG_DO_NOT_WAIT when attempting to map the texture allowing the
capture to continue without incurring an expensive CPU/GPU sync.

A new tuneable has also been added

  * dxgi:maxTextures
2019-05-26 23:36:17 +10:00
Jonathan (JJRcop) Rubenstein
d07aa4b29e [client] Add win:maximize to maximize on startup 2019-05-26 20:47:59 +10:00
JJRcop
9f33043d17 [client] Fix typo in example of README.md 2019-05-25 10:25:57 +10:00
71 changed files with 629 additions and 6124 deletions

3
.gitmodules vendored
View File

@@ -1,3 +0,0 @@
[submodule "vendor/kvm-guest-drivers-windows"]
path = vendor/kvm-guest-drivers-windows
url = https://github.com/virtio-win/kvm-guest-drivers-windows.git

View File

@@ -1 +1 @@
B1-rc1-0-g83c5df2c47+1
B1-rc6-6-gb979752989+1

View File

@@ -14,6 +14,9 @@ if(OPTIMIZE_FOR_NATIVE)
endif()
endif()
option(ENABLE_BACKTRACE "Enable backtrace support on crash" ON)
add_feature_info(ENABLE_BACKTRACE ENABLE_BACKTRACE "Backtrace support.")
add_compile_options(
"-Wall"
"-Werror"
@@ -38,7 +41,7 @@ get_filename_component(PROJECT_TOP "${PROJECT_SOURCE_DIR}/.." ABSOLUTE)
include_directories(
${PROJECT_SOURCE_DIR}/include
${CMAKE_BINARY_DIR}/include
${PROJECT_TOP}/vendor/kvm-guest-drivers-windows
${PROJECT_TOP}/vendor/ivshmem
${PKGCONFIG_INCLUDE_DIRS}
${GMP_INCLUDE_DIR}
)

View File

@@ -30,13 +30,20 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#include "dxgi_extra.h"
#define MAX_TEXTURES 2
enum TextureState
{
TEXTURE_STATE_UNUSED,
TEXTURE_STATE_PENDING_MAP,
TEXTURE_STATE_MAPPED
};
typedef struct Texture
{
enum TextureState state;
ID3D11Texture2D * tex;
D3D11_MAPPED_SUBRESOURCE map;
osEventHandle * evt;
osEventHandle * mapped;
osEventHandle * free;
}
Texture;
@@ -64,11 +71,11 @@ struct iface
ID3D11DeviceContext * deviceContext;
D3D_FEATURE_LEVEL featureLevel;
IDXGIOutputDuplication * dup;
Texture texture[MAX_TEXTURES];
int maxTextures;
Texture * texture;
int texRIndex;
int texWIndex;
bool needsRelease;
osEventHandle * frameEvent;
osEventHandle * pointerEvent;
unsigned int width;
@@ -120,6 +127,13 @@ static void dxgi_initOptions()
.type = OPTION_TYPE_STRING,
.value.x_string = NULL
},
{
.module = "dxgi",
.name = "maxTextures",
.description = "The maximum number of frames to buffer before skipping",
.type = OPTION_TYPE_INT,
.value.x_int = 3
},
{0}
};
@@ -136,23 +150,19 @@ static bool dxgi_create()
return false;
}
this->frameEvent = os_createEvent(true);
if (!this->frameEvent)
{
DEBUG_ERROR("failed to create the frame event");
free(this);
return false;
}
this->pointerEvent = os_createEvent(true);
if (!this->pointerEvent)
{
DEBUG_ERROR("failed to create the pointer event");
os_freeEvent(this->frameEvent);
free(this);
return false;
}
this->maxTextures = option_get_int("dxgi", "maxTextures");
if (this->maxTextures <= 0)
this->maxTextures = 1;
this->texture = calloc(sizeof(struct Texture), this->maxTextures);
return true;
}
@@ -186,7 +196,6 @@ static bool dxgi_init(void * pointerShape, const unsigned int pointerSize)
this->stop = false;
this->texRIndex = 0;
this->texWIndex = 0;
os_resetEvent(this->frameEvent);
status = CreateDXGIFactory1(&IID_IDXGIFactory1, (void **)&this->factory);
if (FAILED(status))
@@ -206,9 +215,8 @@ static bool dxgi_init(void * pointerShape, const unsigned int pointerSize)
IDXGIAdapter1_GetDesc1(this->adapter, &adapterDesc);
const size_t s = (wcslen(adapterDesc.Description)+1) * 2;
size_t unused;
char * desc = malloc(s);
wcstombs_s(&unused, desc, s, adapterDesc.Description, _TRUNCATE);
wcstombs(desc, adapterDesc.Description, s);
if (strstr(desc, optAdapter) == NULL)
{
@@ -229,9 +237,8 @@ static bool dxgi_init(void * pointerShape, const unsigned int pointerSize)
if (optOutput)
{
const size_t s = (wcslen(outputDesc.DeviceName)+1) * 2;
size_t unused;
char * desc = malloc(s);
wcstombs_s(&unused, desc, s, outputDesc.DeviceName, _TRUNCATE);
wcstombs(desc, outputDesc.DeviceName, s);
if (strstr(desc, optOutput) == NULL)
{
@@ -434,7 +441,7 @@ static bool dxgi_init(void * pointerShape, const unsigned int pointerSize)
texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
texDesc.MiscFlags = 0;
for(int i = 0; i < MAX_TEXTURES; ++i)
for(int i = 0; i < this->maxTextures; ++i)
{
status = ID3D11Device_CreateTexture2D(this->device, &texDesc, NULL, &this->texture[i].tex);
if (FAILED(status))
@@ -443,15 +450,22 @@ static bool dxgi_init(void * pointerShape, const unsigned int pointerSize)
goto fail;
}
this->texture[i].evt = os_createEvent(true);
if (!this->texture[i].evt)
this->texture[i].free = os_createEvent(true);
if (!this->texture[i].free)
{
DEBUG_ERROR("Failed to create the texture event");
DEBUG_ERROR("Failed to create the texture free event");
goto fail;
}
// pre-signal the events to flag as unused
os_signalEvent(this->texture[i].evt);
// pre-signal the free events to flag as unused
os_signalEvent(this->texture[i].free);
this->texture[i].mapped = os_createEvent(false);
if (!this->texture[i].mapped)
{
DEBUG_ERROR("Failed to create the texture mapped event");
goto fail;
}
}
// map the texture simply to get the pitch and stride
@@ -477,7 +491,8 @@ fail:
static void dxgi_stop()
{
this->stop = true;
os_signalEvent(this->frameEvent );
os_signalEvent(this->texture[this->texRIndex].mapped);
os_signalEvent(this->pointerEvent);
}
@@ -485,8 +500,10 @@ static bool dxgi_deinit()
{
assert(this);
for(int i = 0; i < MAX_TEXTURES; ++i)
for(int i = 0; i < this->maxTextures; ++i)
{
this->texture[i].state = TEXTURE_STATE_UNUSED;
if (this->texture[i].map.pData)
{
ID3D11DeviceContext_Unmap(this->deviceContext, (ID3D11Resource*)this->texture[i].tex, 0);
@@ -499,11 +516,18 @@ static bool dxgi_deinit()
this->texture[i].tex = NULL;
}
if (this->texture[i].evt)
if (this->texture[i].free)
{
os_signalEvent(this->texture[i].evt);
os_freeEvent(this->texture[i].evt);
this->texture[i].evt = NULL;
os_signalEvent(this->texture[i].free);
os_freeEvent(this->texture[i].free);
this->texture[i].free = NULL;
}
if (this->texture[i].mapped)
{
os_signalEvent(this->texture[i].mapped);
os_freeEvent(this->texture[i].mapped);
this->texture[i].mapped = NULL;
}
}
@@ -561,8 +585,8 @@ static void dxgi_free()
if (this->initialized)
dxgi_deinit();
os_freeEvent(this->frameEvent );
os_freeEvent(this->pointerEvent);
free(this->texture);
free(this);
this = NULL;
@@ -586,11 +610,38 @@ static CaptureResult dxgi_capture()
DXGI_OUTDUPL_FRAME_INFO frameInfo;
IDXGIResource * res;
// if the read texture is pending a mapping
for(int i = 0; i < this->maxTextures; ++i)
{
if (this->texture[i].state != TEXTURE_STATE_PENDING_MAP)
continue;
Texture * tex = &this->texture[i];
// try to map the resource, but don't wait for it
status = ID3D11DeviceContext_Map(this->deviceContext, (ID3D11Resource*)tex->tex, 0, D3D11_MAP_READ, 0x100000L, &tex->map);
if (status != DXGI_ERROR_WAS_STILL_DRAWING)
{
if (FAILED(status))
{
DEBUG_WINERROR("Failed to map the texture", status);
IDXGIResource_Release(res);
return CAPTURE_RESULT_ERROR;
}
// successful map, set the state and signal that there is a frame available
tex->state = TEXTURE_STATE_MAPPED;
os_signalEvent(tex->mapped);
}
}
// release the prior frame
result = dxgi_releaseFrame();
if (result != CAPTURE_RESULT_OK)
return result;
status = IDXGIOutputDuplication_AcquireNextFrame(this->dup, 1000, &frameInfo, &res);
status = IDXGIOutputDuplication_AcquireNextFrame(this->dup, 1, &frameInfo, &res);
switch(status)
{
case S_OK:
@@ -614,9 +665,14 @@ static CaptureResult dxgi_capture()
Texture * tex = &this->texture[this->texWIndex];
// check if the texture is free, if not skip the frame to keep up
if (!os_waitEvent(tex->evt, 0))
if (!os_waitEvent(tex->free, 0))
{
DEBUG_WARN("Frame skipped");
/*
NOTE: This is only informational for when debugging, skipping frames is
OK as we are likely getting frames faster then the client can render
them (ie, vsync off in a title)
*/
//DEBUG_WARN("Frame skipped");
}
else
{
@@ -630,33 +686,23 @@ static CaptureResult dxgi_capture()
}
// if the texture was mapped, unmap it
if (tex->map.pData)
if (tex->state == TEXTURE_STATE_MAPPED)
{
ID3D11DeviceContext_Unmap(this->deviceContext, (ID3D11Resource*)tex->tex, 0);
tex->map.pData = NULL;
}
// issue the copy from GPU to CPU RAM
// issue the copy from GPU to CPU RAM and release the src
ID3D11DeviceContext_CopyResource(this->deviceContext,
(ID3D11Resource *)tex->tex, (ID3D11Resource *)src);
ID3D11Texture2D_Release(src);
// map the resource (this must be done here as ID3D11DeviceContext is not thread safe)
status = ID3D11DeviceContext_Map(this->deviceContext, (ID3D11Resource*)tex->tex, 0, D3D11_MAP_READ, 0, &tex->map);
if (FAILED(status))
{
DEBUG_WINERROR("Failed to map the texture", status);
IDXGIResource_Release(res);
return CAPTURE_RESULT_ERROR;
}
// signal that a frame is available
os_signalEvent(this->frameEvent);
// pending map
tex->state = TEXTURE_STATE_PENDING_MAP;
// advance our write pointer
if (++this->texWIndex == MAX_TEXTURES)
if (++this->texWIndex == this->maxTextures)
this->texWIndex = 0;
ID3D11Texture2D_Release(src);
}
}
@@ -725,16 +771,15 @@ static CaptureResult dxgi_getFrame(CaptureFrame * frame)
assert(this);
assert(this->initialized);
if (!os_waitEvent(this->frameEvent, TIMEOUT_INFINITE))
{
DEBUG_ERROR("Failed to wait on the frame event");
return CAPTURE_RESULT_ERROR;
}
Texture * tex = &this->texture[this->texRIndex];
if (!os_waitEvent(tex->mapped, 1000))
return CAPTURE_RESULT_TIMEOUT;
if (this->stop)
return CAPTURE_RESULT_REINIT;
Texture * tex = &this->texture[this->texRIndex];
// only reset the event if we used the texture
os_resetEvent(tex->mapped);
frame->width = this->width;
frame->height = this->height;
@@ -743,9 +788,9 @@ static CaptureResult dxgi_getFrame(CaptureFrame * frame)
frame->format = this->format;
memcpy(frame->data, tex->map.pData, this->pitch * this->height);
os_signalEvent(tex->evt);
os_signalEvent(tex->free);
if (++this->texRIndex == MAX_TEXTURES)
if (++this->texRIndex == this->maxTextures)
this->texRIndex = 0;
return CAPTURE_RESULT_OK;
@@ -756,11 +801,8 @@ static CaptureResult dxgi_getPointer(CapturePointer * pointer)
assert(this);
assert(this->initialized);
if (!os_waitEvent(this->pointerEvent, TIMEOUT_INFINITE))
{
DEBUG_ERROR("Failed to wait on the pointer event");
return CAPTURE_RESULT_ERROR;
}
if (!os_waitEvent(this->pointerEvent, 1000))
return CAPTURE_RESULT_TIMEOUT;
if (this->stop)
return CAPTURE_RESULT_REINIT;

View File

@@ -35,9 +35,9 @@ HRESULT __stdcall CreateDXGIFactory1(REFIID riid, void **factory);
#endif
enum DXGI_OUTDUPL_POINTER_SHAPE_TYPE {
DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME = 1,
DXGI_OUTDUPL_POINTER_SHAPE_TYPE_COLOR,
DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR
DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME = 0x1,
DXGI_OUTDUPL_POINTER_SHAPE_TYPE_COLOR = 0x2,
DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR = 0x4
};
typedef struct DXGI_OUTDUPL_DESC {

View File

@@ -238,11 +238,8 @@ static CaptureResult nvfbc_capture()
static CaptureResult nvfbc_getFrame(CaptureFrame * frame)
{
if (!os_waitEvent(this->frameEvent, TIMEOUT_INFINITE))
{
DEBUG_ERROR("Failed to wait on the frame event");
return CAPTURE_RESULT_ERROR;
}
if (!os_waitEvent(this->frameEvent, 1000))
return CAPTURE_RESULT_TIMEOUT;
if (this->stop)
return CAPTURE_RESULT_REINIT;
@@ -277,11 +274,8 @@ static CaptureResult nvfbc_getPointer(CapturePointer * pointer)
{
osEventHandle * events[2];
memcpy(&events, &this->cursorEvents, sizeof(osEventHandle *) * 2);
if (!os_waitEvents(events, this->seperateCursor ? 2 : 1, false, TIMEOUT_INFINITE))
{
DEBUG_ERROR("Failed to wait on the cursor events");
return CAPTURE_RESULT_ERROR;
}
if (!os_waitEvents(events, this->seperateCursor ? 2 : 1, false, 1000))
return CAPTURE_RESULT_TIMEOUT;
if (this->stop)
return CAPTURE_RESULT_REINIT;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1,4 +1,4 @@
#include "winuser.h"
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "app.manifest"
IDI_APPLICATION ICON "icon.ico"
IDI_APPLICATION ICON "../../../resources/icon.ico"

View File

@@ -29,7 +29,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#include "common/debug.h"
#include "common/option.h"
#include "windows/debug.h"
#include "ivshmem/Public.h"
#include "ivshmem.h"
#define ID_MENU_OPEN_LOG 3000
#define ID_MENU_EXIT 3001
@@ -194,9 +194,8 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
for(int i = 0; i < app.argc; ++i)
{
const size_t s = (wcslen(wargv[i])+1) * 2;
size_t unused;
app.argv[i] = malloc(s);
wcstombs_s(&unused, app.argv[i], s, wargv[i], _TRUNCATE);
wcstombs(app.argv[i], wargv[i], s);
}
LocalFree(wargv);

View File

@@ -38,6 +38,8 @@ Place, Suite 330, Boston, MA 02111-1307 USA
struct app
{
unsigned int clientInstance;
KVMFRHeader * shmHeader;
uint8_t * pointerData;
unsigned int pointerDataSize;
@@ -63,25 +65,54 @@ static int pointerThread(void * opaque)
DEBUG_INFO("Pointer thread started");
volatile KVMFRCursor * ci = &(app.shmHeader->cursor);
uint8_t flags;
uint8_t flags;
bool pointerValid = false;
bool shapeValid = false;
unsigned int clientInstance = 0;
CapturePointer pointer = { 0 };
while(app.running)
{
CaptureResult result;
CapturePointer pointer = { 0 };
bool resend = false;
result = app.iface->getPointer(&pointer);
if (result == CAPTURE_RESULT_REINIT)
pointer.shapeUpdate = false;
switch(app.iface->getPointer(&pointer))
{
app.reinit = true;
break;
case CAPTURE_RESULT_OK:
{
pointerValid = true;
break;
}
case CAPTURE_RESULT_REINIT:
{
app.reinit = true;
DEBUG_INFO("Pointer thread reinit");
return 0;
}
case CAPTURE_RESULT_ERROR:
{
DEBUG_ERROR("Failed to get the pointer");
return 0;
}
case CAPTURE_RESULT_TIMEOUT:
{
// if the pointer is valid and the client has restarted, send it
if (pointerValid && clientInstance != app.clientInstance)
{
resend = true;
break;
}
continue;
}
}
if (result == CAPTURE_RESULT_ERROR)
{
DEBUG_ERROR("Failed to get the pointer");
break;
}
clientInstance = app.clientInstance;
// wait for the client to finish with the previous update
while((ci->flags & ~KVMFR_CURSOR_FLAG_UPDATE) != 0 && app.running)
@@ -95,7 +126,7 @@ static int pointerThread(void * opaque)
flags |= KVMFR_CURSOR_FLAG_VISIBLE;
// if we have shape data
if (pointer.shapeUpdate)
if (pointer.shapeUpdate || (shapeValid && resend))
{
switch(pointer.format)
{
@@ -112,6 +143,7 @@ static int pointerThread(void * opaque)
ci->pitch = pointer.pitch;
ci->dataPos = app.pointerOffset;
++ci->version;
shapeValid = true;
flags |= KVMFR_CURSOR_FLAG_SHAPE;
}
@@ -127,29 +159,50 @@ static int frameThread(void * opaque)
{
DEBUG_INFO("Frame thread started");
int frameIndex = 0;
volatile KVMFRFrame * fi = &(app.shmHeader->frame);
bool frameValid = false;
int frameIndex = 0;
unsigned int clientInstance = 0;
CaptureFrame frame = { 0 };
while(app.running)
{
CaptureResult result;
CaptureFrame frame =
{
.data = app.frame[frameIndex]
};
frame.data = app.frame[frameIndex];
result = app.iface->getFrame(&frame);
if (result == CAPTURE_RESULT_REINIT)
switch(app.iface->getFrame(&frame))
{
app.reinit = true;
break;
case CAPTURE_RESULT_OK:
break;
case CAPTURE_RESULT_REINIT:
{
app.reinit = true;
DEBUG_INFO("Frame thread reinit");
return 0;
}
case CAPTURE_RESULT_ERROR:
{
DEBUG_ERROR("Failed to get the frame");
return 0;
}
case CAPTURE_RESULT_TIMEOUT:
{
if (frameValid && clientInstance != app.clientInstance)
{
// resend the last frame
if (--frameIndex < 0)
frameIndex = MAX_FRAMES - 1;
break;
}
continue;
}
}
if (result == CAPTURE_RESULT_ERROR)
{
DEBUG_ERROR("Failed to get the frame");
break;
}
clientInstance = app.clientInstance;
// wait for the client to finish with the previous frame
while(fi->flags & KVMFR_FRAME_FLAG_UPDATE && app.running)
@@ -171,6 +224,7 @@ static int frameThread(void * opaque)
fi->stride = frame.stride;
fi->pitch = frame.pitch;
fi->dataPos = app.frameOffset[frameIndex];
frameValid = true;
INTERLOCKED_OR8(&fi->flags, KVMFR_FRAME_FLAG_UPDATE);
@@ -367,7 +421,11 @@ int app_main(int argc, char * argv[])
while(app.running)
{
INTERLOCKED_AND8(flags, ~(KVMFR_HEADER_FLAG_RESTART));
if (INTERLOCKED_AND8(flags, ~(KVMFR_HEADER_FLAG_RESTART)) & KVMFR_HEADER_FLAG_RESTART)
{
DEBUG_INFO("Client restarted");
++app.clientInstance;
}
if (app.reinit && !captureRestart())
{

View File

@@ -24,6 +24,9 @@ add_feature_info(ENABLE_EGL ENABLE_EGL "EGL renderer.")
option(ENABLE_CB_X11 "Enable X11 clipboard integration" ON)
add_feature_info(ENABLE_CB_X11 ENABLE_CB_X11 "X11 Clipboard Integration.")
option(ENABLE_BACKTRACE "Enable backtrace support on crash" ON)
add_feature_info(ENABLE_BACKTRACE ENABLE_BACKTRACE "Backtrace support.")
add_compile_options(
"-Wall"
"-Werror"

View File

@@ -48,12 +48,26 @@ Below are a list of current key bindings:
| <kbd>ScrLk</kbd>+<kbd>N</kbd> | Toggle night vision mode (EGL renderer only!) |
| <kbd>ScrLk</kbd>+<kbd>Insert</kbd> | Increase mouse sensitivity (in capture mode only) |
| <kbd>ScrLk</kbd>+<kbd>Del</kbd> | Decrease mouse sensitivity (in capture mode only) |
| <kbd>ScrLk</kbd>+<kbd>F1</kbd> | Send <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>F1</kbd> to the guest |
| <kbd>ScrLk</kbd>+<kbd>F2</kbd> | Send <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>F2</kbd> to the guest |
| <kbd>ScrLk</kbd>+<kbd>F3</kbd> | Send <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>F3</kbd> to the guest |
| <kbd>ScrLk</kbd>+<kbd>F4</kbd> | Send <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>F4</kbd> to the guest |
| <kbd>ScrLk</kbd>+<kbd>F5</kbd> | Send <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>F5</kbd> to the guest |
| <kbd>ScrLk</kbd>+<kbd>F6</kbd> | Send <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>F6</kbd> to the guest |
| <kbd>ScrLk</kbd>+<kbd>F7</kbd> | Send <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>F7</kbd> to the guest |
| <kbd>ScrLk</kbd>+<kbd>F8</kbd> | Send <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>F8</kbd> to the guest |
| <kbd>ScrLk</kbd>+<kbd>F9</kbd> | Send <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>F9</kbd> to the guest |
| <kbd>ScrLk</kbd>+<kbd>F10</kbd> | Send <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>F10</kbd> to the guest |
| <kbd>ScrLk</kbd>+<kbd>F11</kbd> | Send <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>F11</kbd> to the guest |
| <kbd>ScrLk</kbd>+<kbd>F12</kbd> | Send <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>F12</kbd> to the guest |
### Setting options via command line arguments
The syntax is simple: `module:name=value`, for example:
./looking-glass-host win:fullScreen=yes egl:nvGain=1
./looking-glass-client win:fullScreen=yes egl:nvGain=1
### Setting options via configuration files
@@ -87,23 +101,25 @@ Command line arguments will override any options loaded from the config files.
| app:framePollInterval | | 1000 | How often to check for a frame update in microseconds |
|-------------------------------------------------------------------------------------------------------------------------|
|-------------------------------------------------------------------------------------------------------|
| Long | Short | Value | Description |
|-------------------------------------------------------------------------------------------------------|
| win:title | | Looking Glass (client) | The window title |
| win:position | | center | Initial window position at startup |
| win:size | | 1024x768 | Initial window size at startup |
| win:autoResize | -a | no | Auto resize the window to the guest |
| win:allowResize | -n | yes | Aallow the window to be manually resized |
| win:keepAspect | -r | yes | Maintain the correct aspect ratio |
| win:borderless | -d | no | Borderless mode |
| win:fullScreen | -F | no | Launch in fullscreen borderless mode |
| win:fpsLimit | -K | 200 | Frame rate limit (0 = disable - not recommended) |
| win:showFPS | -k | no | Enable the FPS & UPS display |
| win:ignoreQuit | -Q | no | Ignore requests to quit (ie: Alt+F4) |
| win:noScreensaver | -S | no | Prevent the screensaver from starting |
| win:alerts | -q | yes | Show on screen alert messages |
|-------------------------------------------------------------------------------------------------------|
|-------------------------------------------------------------------------------------------------------------|
| Long | Short | Value | Description |
|-------------------------------------------------------------------------------------------------------------|
| win:title | | Looking Glass (client) | The window title |
| win:position | | center | Initial window position at startup |
| win:size | | 1024x768 | Initial window size at startup |
| win:autoResize | -a | no | Auto resize the window to the guest |
| win:allowResize | -n | yes | Aallow the window to be manually resized |
| win:keepAspect | -r | yes | Maintain the correct aspect ratio |
| win:borderless | -d | no | Borderless mode |
| win:fullScreen | -F | no | Launch in fullscreen borderless mode |
| win:maximize | -T | no | Launch window maximized |
| win:minimizeOnFocusLoss | | yes | Minimize window on focus loss |
| win:fpsLimit | -K | 200 | Frame rate limit (0 = disable - not recommended) |
| win:showFPS | -k | no | Enable the FPS & UPS display |
| win:ignoreQuit | -Q | no | Ignore requests to quit (ie: Alt+F4) |
| win:noScreensaver | -S | no | Prevent the screensaver from starting |
| win:alerts | -q | yes | Show on screen alert messages |
|-------------------------------------------------------------------------------------------------------------|
|---------------------------------------------------------------------------------------------------------------------------------------|
| Long | Short | Value | Description |

View File

@@ -56,6 +56,7 @@ struct EGL_Desktop
struct DesktopShader shader_yuv;
// internals
LG_Lock updateLock;
enum EGL_PixelFormat pixFmt;
unsigned int width, height;
unsigned int pitch;
@@ -140,6 +141,8 @@ bool egl_desktop_init(EGL_Desktop ** desktop)
egl_model_set_default((*desktop)->model);
egl_model_set_texture((*desktop)->model, (*desktop)->texture);
LG_LOCK_INIT((*desktop)->updateLock);
(*desktop)->kbNV = app_register_keybind(SDL_SCANCODE_N, egl_desktop_toggle_nv, *desktop);
(*desktop)->nvMax = option_get_int("egl", "nvGainMax");
@@ -165,6 +168,8 @@ void egl_desktop_free(EGL_Desktop ** desktop)
if (!*desktop)
return;
LG_LOCK_FREE((*desktop)->updateLock);
egl_texture_free(&(*desktop)->texture );
egl_shader_free (&(*desktop)->shader_generic.shader);
egl_shader_free (&(*desktop)->shader_yuv.shader );
@@ -180,6 +185,7 @@ bool egl_desktop_prepare_update(EGL_Desktop * desktop, const bool sourceChanged,
{
if (sourceChanged)
{
LG_LOCK(desktop->updateLock);
switch(format.type)
{
case FRAME_TYPE_BGRA:
@@ -204,24 +210,30 @@ bool egl_desktop_prepare_update(EGL_Desktop * desktop, const bool sourceChanged,
default:
DEBUG_ERROR("Unsupported frame format");
LG_UNLOCK(desktop->updateLock);
return false;
}
desktop->width = format.width;
desktop->height = format.height;
desktop->pitch = format.pitch;
desktop->data = data;
desktop->update = true;
/* defer the actual update as the format has changed and we need to issue GL commands first */
LG_UNLOCK(desktop->updateLock);
return true;
}
desktop->data = data;
desktop->update = true;
return true;
/* update the texture now */
return egl_texture_update(desktop->texture, data);
}
bool egl_desktop_perform_update(EGL_Desktop * desktop, const bool sourceChanged)
void egl_desktop_perform_update(EGL_Desktop * desktop, const bool sourceChanged)
{
if (sourceChanged)
{
LG_LOCK(desktop->updateLock);
if (!egl_texture_setup(
desktop->texture,
desktop->pixFmt,
@@ -232,27 +244,26 @@ bool egl_desktop_perform_update(EGL_Desktop * desktop, const bool sourceChanged)
))
{
DEBUG_ERROR("Failed to setup the desktop texture");
return false;
LG_UNLOCK(desktop->updateLock);
return;
}
LG_UNLOCK(desktop->updateLock);
}
if (!desktop->update)
return true;
if (!egl_texture_update(desktop->texture, desktop->data))
if (desktop->update)
{
DEBUG_ERROR("Failed to update the desktop texture");
return false;
desktop->update = false;
egl_texture_update(desktop->texture, desktop->data);
}
desktop->update = false;
return true;
}
void egl_desktop_render(EGL_Desktop * desktop, const float x, const float y, const float scaleX, const float scaleY, const bool nearest)
bool egl_desktop_render(EGL_Desktop * desktop, const float x, const float y, const float scaleX, const float scaleY, const bool nearest)
{
if (!desktop->shader)
return;
return false;
if (egl_texture_process(desktop->texture) != EGL_TEX_STATUS_OK)
return false;
const struct DesktopShader * shader = desktop->shader;
egl_shader_use(shader->shader);
@@ -269,4 +280,5 @@ void egl_desktop_render(EGL_Desktop * desktop, const float x, const float y, con
glUniform1i(shader->uNV, 0);
egl_model_render(desktop->model);
return true;
}

View File

@@ -29,5 +29,5 @@ 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_perform_update(EGL_Desktop * desktop, const bool sourceChanged);
void egl_desktop_render(EGL_Desktop * desktop, const float x, const float y, const float scaleX, const float scaleY, const bool nearest);
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);

View File

@@ -85,6 +85,8 @@ struct Inst
float screenScaleX, screenScaleY;
bool useNearest;
bool cursorVisible;
int cursorX , cursorY;
float mouseWidth , mouseHeight;
float mouseScaleX, mouseScaleY;
@@ -102,6 +104,20 @@ static struct Option egl_options[] =
.type = OPTION_TYPE_BOOL,
.value.x_bool = false
},
{
.module = "egl",
.name = "doubleBuffer",
.description = "Enable double buffering",
.type = OPTION_TYPE_BOOL,
.value.x_bool = true
},
{
.module = "egl",
.name = "multisample",
.description = "Enable Multisampling",
.type = OPTION_TYPE_BOOL,
.value.x_bool = true
},
{
.module = "egl",
.name = "nvGainMax",
@@ -167,18 +183,25 @@ bool egl_create(void ** opaque, const LG_RendererParams params)
bool egl_initialize(void * opaque, Uint32 * sdlFlags)
{
const bool doubleBuffer = option_get_bool("egl", "doubleBuffer");
DEBUG_INFO("Double buffering is %s", doubleBuffer ? "on" : "off");
*sdlFlags = SDL_WINDOW_OPENGL;
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER , 1);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER , doubleBuffer ? 1 : 0);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
int maxSamples = sysinfo_gfx_max_multisample();
if (maxSamples > 1)
if (option_get_bool("egl", "multisample"))
{
if (maxSamples > 4)
maxSamples = 4;
int maxSamples = sysinfo_gfx_max_multisample();
if (maxSamples > 1)
{
if (maxSamples > 4)
maxSamples = 4;
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, maxSamples);
DEBUG_INFO("Multsampling enabled, max samples: %d", maxSamples);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, maxSamples);
}
}
return true;
@@ -228,6 +251,13 @@ void egl_on_resize(void * opaque, const int width, const int height, const LG_Re
this->splashRatio = (float)width / (float)height;
this->screenScaleX = 1.0f / width;
this->screenScaleY = 1.0f / height;
egl_cursor_set_state(
this->cursor,
this->cursorVisible,
(((float)this->cursorX * this->mouseScaleX) - 1.0f) * this->scaleX,
(((float)this->cursorY * this->mouseScaleY) - 1.0f) * this->scaleY
);
}
bool egl_on_mouse_shape(void * opaque, const LG_RendererCursor cursor, const int width, const int height, const int pitch, const uint8_t * data)
@@ -249,15 +279,18 @@ bool egl_on_mouse_shape(void * opaque, const LG_RendererCursor cursor, const int
return true;
}
bool egl_on_mouse_event(void * opaque, const bool visible , const int x, const int y)
bool egl_on_mouse_event(void * opaque, const bool visible, const int x, const int y)
{
struct Inst * this = (struct Inst *)opaque;
this->cursorVisible = visible;
this->cursorX = x;
this->cursorY = y;
egl_cursor_set_state(
this->cursor,
visible,
(((float)x * this->mouseScaleX) - 1.0f) * this->scaleX,
(((float)y * this->mouseScaleY) - 1.0f) * this->scaleY
this->cursorVisible,
(((float)this->cursorX * this->mouseScaleX) - 1.0f) * this->scaleX,
(((float)this->cursorY * this->mouseScaleY) - 1.0f) * this->scaleY
);
return true;
@@ -285,9 +318,6 @@ bool egl_on_frame_event(void * opaque, const LG_RendererFormat format, const uin
return false;
}
if (!this->waitFadeTime)
this->waitFadeTime = microtime() + SPLASH_FADE_TIME;
return true;
}
@@ -378,10 +408,10 @@ bool egl_render_startup(void * opaque, SDL_Window * window)
EGLint attr[] =
{
EGL_BUFFER_SIZE , 16,
EGL_BUFFER_SIZE , 32,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_SAMPLE_BUFFERS , 1,
EGL_SAMPLES , 8,
EGL_SAMPLES , 4,
EGL_NONE
};
@@ -460,8 +490,12 @@ bool egl_render(void * opaque, SDL_Window * window)
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
egl_desktop_render(this->desktop, this->translateX, this->translateY, this->scaleX, this->scaleY, this->useNearest);
egl_cursor_render(this->cursor);
if (egl_desktop_render(this->desktop, this->translateX, this->translateY, this->scaleX, this->scaleY, this->useNearest))
{
if (!this->waitFadeTime)
this->waitFadeTime = microtime() + SPLASH_FADE_TIME;
egl_cursor_render(this->cursor);
}
if (!this->waitDone)
{
@@ -502,13 +536,9 @@ bool egl_render(void * opaque, SDL_Window * window)
eglSwapBuffers(this->display, this->surface);
// defer texture uploads until after the flip to avoid stalling
if (!egl_desktop_perform_update(this->desktop, this->sourceChanged))
{
DEBUG_ERROR("Failed to perform the desktop update");
return false;
}
this->sourceChanged = false;
egl_desktop_perform_update(this->desktop, this->sourceChanged);
this->sourceChanged = false;
return true;
}

View File

@@ -20,6 +20,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#pragma once
#include <stdbool.h>
#include <stddef.h>
#include <GL/gl.h>

View File

@@ -32,6 +32,7 @@ struct EGL_Texture
enum EGL_PixelFormat pixFmt;
size_t width, height;
bool streaming;
bool ready;
int textureCount;
GLuint textures[3];
@@ -44,10 +45,12 @@ struct EGL_Texture
bool hasPBO;
GLuint pbo[2];
int pboIndex;
bool needsUpdate;
int pboRIndex;
int pboWIndex;
int pboCount;
size_t pboBufferSize;
void * pboMap[2];
GLsync pboSync[2];
};
bool egl_texture_init(EGL_Texture ** texture)
@@ -81,6 +84,9 @@ void egl_texture_free(EGL_Texture ** texture)
{
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, (*texture)->pbo[i]);
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
if ((*texture)->pboSync[i])
glDeleteSync((*texture)->pboSync[i]);
}
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
glDeleteBuffers(2, (*texture)->pbo);
@@ -98,6 +104,7 @@ bool egl_texture_setup(EGL_Texture * texture, enum EGL_PixelFormat pixFmt, size_
texture->width = width;
texture->height = height;
texture->streaming = streaming;
texture->ready = false;
switch(pixFmt)
{
@@ -210,8 +217,7 @@ bool egl_texture_setup(EGL_Texture * texture, enum EGL_PixelFormat pixFmt, size_
texture->pboBufferSize,
NULL,
GL_MAP_PERSISTENT_BIT |
GL_MAP_WRITE_BIT |
GL_MAP_COHERENT_BIT
GL_MAP_WRITE_BIT
);
texture->pboMap[i] = glMapBufferRange(
@@ -221,8 +227,15 @@ bool egl_texture_setup(EGL_Texture * texture, enum EGL_PixelFormat pixFmt, size_
GL_MAP_PERSISTENT_BIT |
GL_MAP_WRITE_BIT |
GL_MAP_UNSYNCHRONIZED_BIT |
GL_MAP_INVALIDATE_BUFFER_BIT
GL_MAP_INVALIDATE_BUFFER_BIT |
GL_MAP_FLUSH_EXPLICIT_BIT
);
if (!texture->pboMap[i])
{
DEBUG_ERROR("glMapBufferRange failed for %d of %lu bytes", i, texture->pboBufferSize);
return false;
}
}
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
}
@@ -234,22 +247,23 @@ bool egl_texture_update(EGL_Texture * texture, const uint8_t * buffer)
{
if (texture->streaming)
{
if (texture->needsUpdate)
{
DEBUG_ERROR("Previous frame was not consumed");
return false;
}
/* NOTE: DO NOT use any gl commands here as streaming must be thread safe */
if (++texture->pboIndex == 2)
texture->pboIndex = 0;
if (texture->pboCount == 2)
return true;
/* update the GPU buffer */
memcpy(texture->pboMap[texture->pboIndex], buffer, texture->pboBufferSize);
memcpy(texture->pboMap[texture->pboWIndex], buffer, texture->pboBufferSize);
texture->pboSync[texture->pboWIndex] = 0;
texture->needsUpdate = true;
if (++texture->pboWIndex == 2)
texture->pboWIndex = 0;
++texture->pboCount;
}
else
{
/* Non streaming, this is NOT thread safe */
for(int i = 0; i < texture->textureCount; ++i)
{
glBindTexture(GL_TEXTURE_2D, texture->textures[i]);
@@ -262,23 +276,78 @@ bool egl_texture_update(EGL_Texture * texture, const uint8_t * buffer)
return true;
}
void egl_texture_bind(EGL_Texture * texture)
enum EGL_TexStatus egl_texture_process(EGL_Texture * texture)
{
if (texture->streaming && texture->needsUpdate)
{
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, texture->pbo[texture->pboIndex]);
for(int i = 0; i < texture->textureCount; ++i)
{
glBindTexture(GL_TEXTURE_2D, texture->textures[i]);
glPixelStorei(GL_UNPACK_ROW_LENGTH, texture->planes[i][2]);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, texture->planes[i][0], texture->planes[i][1],
texture->format, texture->dataType, (const void *)texture->offsets[i]);
}
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
glBindTexture(GL_TEXTURE_2D, 0);
if (!texture->streaming)
return EGL_TEX_STATUS_OK;
texture->needsUpdate = false;
if (texture->pboCount == 0)
return texture->ready ? EGL_TEX_STATUS_OK : EGL_TEX_STATUS_NOTREADY;
/* process any buffers that have not yet been flushed */
int pos = texture->pboRIndex;
for(int i = 0; i < texture->pboCount; ++i)
{
if (texture->pboSync[pos] == 0)
{
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, texture->pbo[pos]);
glFlushMappedBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, texture->pboBufferSize);
texture->pboSync[pos] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
}
if (++pos == 2)
pos = 0;
}
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
/* wait for the buffer to be ready */
pos = texture->pboRIndex;
switch(glClientWaitSync(texture->pboSync[pos], GL_SYNC_FLUSH_COMMANDS_BIT, 0))
{
case GL_ALREADY_SIGNALED:
case GL_CONDITION_SATISFIED:
break;
case GL_TIMEOUT_EXPIRED:
return texture->ready ? EGL_TEX_STATUS_OK : EGL_TEX_STATUS_NOTREADY;
case GL_WAIT_FAILED:
glDeleteSync(texture->pboSync[pos]);
DEBUG_ERROR("glClientWaitSync failed");
return EGL_TEX_STATUS_ERROR;
}
/* delete the sync and bind the buffer */
glDeleteSync(texture->pboSync[pos]);
texture->pboSync[pos] = 0;
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, texture->pbo[pos]);
/* update the textures */
for(int i = 0; i < texture->textureCount; ++i)
{
glBindTexture(GL_TEXTURE_2D, texture->textures[i]);
glPixelStorei(GL_UNPACK_ROW_LENGTH, texture->planes[i][2]);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, texture->planes[i][0], texture->planes[i][1],
texture->format, texture->dataType, (const void *)texture->offsets[i]);
}
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
glBindTexture(GL_TEXTURE_2D, 0);
/* advance the read index */
if (++texture->pboRIndex == 2)
texture->pboRIndex = 0;
--texture->pboCount;
texture->ready = true;
return EGL_TEX_STATUS_OK;
}
enum EGL_TexStatus egl_texture_bind(EGL_Texture * texture)
{
/* if there are no new buffers ready, then just bind the textures */
if (texture->streaming && !texture->ready)
return EGL_TEX_STATUS_NOTREADY;
for(int i = 0; i < texture->textureCount; ++i)
{
@@ -286,6 +355,8 @@ void egl_texture_bind(EGL_Texture * texture)
glBindTexture(GL_TEXTURE_2D, texture->textures[i]);
glBindSampler(i, texture->samplers[i]);
}
return EGL_TEX_STATUS_OK;
}
int egl_texture_count(EGL_Texture * texture)

View File

@@ -34,10 +34,18 @@ enum EGL_PixelFormat
EGL_PF_YUV420
};
enum EGL_TexStatus
{
EGL_TEX_STATUS_NOTREADY,
EGL_TEX_STATUS_OK,
EGL_TEX_STATUS_ERROR
};
bool egl_texture_init(EGL_Texture ** tex);
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);
void egl_texture_bind (EGL_Texture * texture);
int egl_texture_count (EGL_Texture * texture);
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);
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);

View File

@@ -1 +0,0 @@
.

View File

@@ -17,7 +17,7 @@ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "spice.h"
#include "spice/spice.h"
#include "utils.h"
#include "common/debug.h"

View File

@@ -66,7 +66,7 @@ KeybindHandle app_register_keybind(SDL_Scancode key, SuperEventFn callback, void
void app_release_keybind(KeybindHandle * handle)
{
if (!handle)
if (!*handle)
return;
state.bindings[(*handle)->key] = NULL;

View File

@@ -138,7 +138,7 @@ static struct Option options[] =
{
.module = "win",
.name = "allowResize",
.description = "Aallow the window to be manually resized",
.description = "Allow the window to be manually resized",
.shortopt = 'n',
.type = OPTION_TYPE_BOOL,
.value.x_bool = true,
@@ -167,13 +167,28 @@ static struct Option options[] =
.type = OPTION_TYPE_BOOL,
.value.x_bool = false,
},
{
.module = "win",
.name = "maximize",
.description = "Launch window maximized",
.shortopt = 'T',
.type = OPTION_TYPE_BOOL,
.value.x_bool = false,
},
{
.module = "win",
.name = "minimizeOnFocusLoss",
.description = "Minimize window on focus loss",
.type = OPTION_TYPE_BOOL,
.value.x_bool = true,
},
{
.module = "win",
.name = "fpsLimit",
.description = "Frame rate limit (0 = disable - not recommended)",
.description = "Frame rate limit (0 = disable - not recommended, -1 = auto detect)",
.shortopt = 'K',
.type = OPTION_TYPE_INT,
.value.x_int = 200,
.value.x_int = -1,
},
{
.module = "win",
@@ -376,6 +391,7 @@ bool config_load(int argc, char * argv[])
params.keepAspect = option_get_bool ("win", "keepAspect" );
params.borderless = option_get_bool ("win", "borderless" );
params.fullscreen = option_get_bool ("win", "fullScreen" );
params.maximize = option_get_bool ("win", "maximize" );
params.fpsLimit = option_get_int ("win", "fpsLimit" );
params.showFPS = option_get_bool ("win", "showFPS" );
params.ignoreQuit = option_get_bool ("win", "ignoreQuit" );
@@ -387,6 +403,8 @@ bool config_load(int argc, char * argv[])
params.hideMouse = option_get_bool ("input", "hideCursor" );
params.mouseSens = option_get_int ("input", "mouseSens" );
params.minimizeOnFocusLoss = option_get_bool("win", "minimizeOnFocusLoss");
if (option_get_bool("spice", "enable"))
{
params.spiceHost = option_get_string("spice", "host");
@@ -550,4 +568,4 @@ static char * optScancodeToString(struct Option * opt)
char * str;
alloc_sprintf(&str, "%d = %s", opt->value.x_int, SDL_GetScancodeName(opt->value.x_int));
return str;
}
}

View File

@@ -95,7 +95,10 @@ static void updatePositionInfo()
static int renderThread(void * unused)
{
if (!state.lgr->render_startup(state.lgrData, state.window))
{
state.running = false;
return 1;
}
// start the cursor thread after render startup to prevent a race condition
SDL_Thread *t_cursor = NULL;
@@ -944,18 +947,48 @@ static void mouse_sens_dec(SDL_Scancode key, void * opaque)
free(msg);
}
static void ctrl_alt_fn(SDL_Scancode key, void * opaque)
{
const uint32_t ctrl = mapScancode(SDL_SCANCODE_LCTRL);
const uint32_t alt = mapScancode(SDL_SCANCODE_LALT );
const uint32_t fn = mapScancode(key);
spice_key_down(ctrl);
spice_key_down(alt );
spice_key_down(fn );
spice_key_up(ctrl);
spice_key_up(alt );
spice_key_up(fn );
}
static void register_key_binds()
{
state.kbFS = app_register_keybind(SDL_SCANCODE_F , toggle_fullscreen, NULL);
state.kbInput = app_register_keybind(SDL_SCANCODE_I , toggle_input , NULL);
state.kbMouseSensInc = app_register_keybind(SDL_SCANCODE_INSERT, mouse_sens_inc , NULL);
state.kbMouseSensDec = app_register_keybind(SDL_SCANCODE_DELETE, mouse_sens_dec , NULL);
state.kbCtrlAltFn[0 ] = app_register_keybind(SDL_SCANCODE_F1 , ctrl_alt_fn, NULL);
state.kbCtrlAltFn[1 ] = app_register_keybind(SDL_SCANCODE_F2 , ctrl_alt_fn, NULL);
state.kbCtrlAltFn[2 ] = app_register_keybind(SDL_SCANCODE_F3 , ctrl_alt_fn, NULL);
state.kbCtrlAltFn[3 ] = app_register_keybind(SDL_SCANCODE_F4 , ctrl_alt_fn, NULL);
state.kbCtrlAltFn[4 ] = app_register_keybind(SDL_SCANCODE_F5 , ctrl_alt_fn, NULL);
state.kbCtrlAltFn[5 ] = app_register_keybind(SDL_SCANCODE_F6 , ctrl_alt_fn, NULL);
state.kbCtrlAltFn[6 ] = app_register_keybind(SDL_SCANCODE_F7 , ctrl_alt_fn, NULL);
state.kbCtrlAltFn[7 ] = app_register_keybind(SDL_SCANCODE_F8 , ctrl_alt_fn, NULL);
state.kbCtrlAltFn[8 ] = app_register_keybind(SDL_SCANCODE_F9 , ctrl_alt_fn, NULL);
state.kbCtrlAltFn[9 ] = app_register_keybind(SDL_SCANCODE_F10, ctrl_alt_fn, NULL);
state.kbCtrlAltFn[10] = app_register_keybind(SDL_SCANCODE_F11, ctrl_alt_fn, NULL);
state.kbCtrlAltFn[11] = app_register_keybind(SDL_SCANCODE_F12, ctrl_alt_fn, NULL);
}
static void release_key_binds()
{
app_release_keybind(&state.kbFS);
app_release_keybind(&state.kbInput);
for(int i = 0; i < 12; ++i)
app_release_keybind(&state.kbCtrlAltFn[i]);
}
int run()
@@ -967,7 +1000,6 @@ int run()
state.running = true;
state.scaleX = 1.0f;
state.scaleY = 1.0f;
state.frameTime = 1e9 / params.fpsLimit;
state.mouseSens = params.mouseSens;
if (state.mouseSens < -9) state.mouseSens = -9;
@@ -981,13 +1013,16 @@ int run()
if (strcmp(XDG_SESSION_TYPE, "wayland") == 0)
{
DEBUG_INFO("Wayland detected");
int err = setenv("SDL_VIDEODRIVER", "wayland", 1);
if (err < 0)
if (getenv("SDL_VIDEODRIVER") == NULL)
{
DEBUG_ERROR("Unable to set the env variable SDL_VIDEODRIVER: %d", err);
return -1;
int err = setenv("SDL_VIDEODRIVER", "wayland", 1);
if (err < 0)
{
DEBUG_ERROR("Unable to set the env variable SDL_VIDEODRIVER: %d", err);
return -1;
}
DEBUG_INFO("SDL_VIDEODRIVER has been set to wayland");
}
DEBUG_INFO("SDL_VIDEODRIVER has been set to wayland");
}
// warn about using FPS display until we can fix the font rendering to prevent lag spikes
@@ -1055,6 +1090,7 @@ int run()
(params.fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0) |
(params.allowResize ? SDL_WINDOW_RESIZABLE : 0) |
(params.borderless ? SDL_WINDOW_BORDERLESS : 0) |
(params.maximize ? SDL_WINDOW_MAXIMIZED : 0) |
sdlFlags
)
);
@@ -1065,11 +1101,14 @@ int run()
return 1;
}
if (params.fullscreen)
if (params.fullscreen || !params.minimizeOnFocusLoss)
SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0");
if (!params.noScreensaver)
{
SDL_SetHint(SDL_HINT_VIDEO_ALLOW_SCREENSAVER, "1");
SDL_EnableScreenSaver();
}
if (!params.center)
SDL_SetWindowPosition(state.window, params.x, params.y);
@@ -1080,6 +1119,26 @@ int run()
// ensure renderer viewport is aware of the current window size
updatePositionInfo();
//Auto detect active monitor refresh rate for FPS Limit if no FPS Limit was passed.
if (params.fpsLimit == -1)
{
SDL_DisplayMode current;
if (SDL_GetCurrentDisplayMode(SDL_GetWindowDisplayIndex(state.window), &current) == 0)
{
state.frameTime = 1e9 / (current.refresh_rate * 2);
}
else
{
DEBUG_WARN("Unable to capture monitor refresh rate using the default FPS Limit: 200");
state.frameTime = 1e9 / 200;
}
}
else
{
DEBUG_INFO("Using the FPS Limit from args: %d", params.fpsLimit);
state.frameTime = 1e9 / params.fpsLimit;
}
register_key_binds();
// set the compositor hint to bypass for low latency
@@ -1317,7 +1376,7 @@ int run()
int main(int argc, char * argv[])
{
if (!installCrashHandler(argv[0]))
if (!installCrashHandler("/proc/self/exe"))
DEBUG_WARN("Failed to install the crash handler");
config_init();
@@ -1337,4 +1396,4 @@ int main(int argc, char * argv[])
config_free();
return ret;
}
}

View File

@@ -68,6 +68,7 @@ struct AppState
KeybindHandle kbInput;
KeybindHandle kbMouseSensInc;
KeybindHandle kbMouseSensDec;
KeybindHandle kbCtrlAltFn[12];
int mouseSens;
float sensX, sensY;
@@ -80,6 +81,8 @@ struct AppParams
bool keepAspect;
bool borderless;
bool fullscreen;
bool maximize;
bool minimizeOnFocusLoss;
bool center;
int x, y;
unsigned int w, h;
@@ -127,4 +130,4 @@ struct KeybindHandle
// forwards
extern struct AppState state;
extern struct AppParams params;
extern struct AppParams params;

View File

@@ -5,6 +5,10 @@ include_directories(
${PROJECT_SOURCE_DIR}/include
)
if(ENABLE_BACKTRACE)
add_definitions(-DENABLE_BACKTRACE)
endif()
set(COMMON_SOURCES
src/stringutils.c
src/stringlist.c
@@ -27,7 +31,9 @@ if(WIN32)
else()
set(SOURCES ${COMMON_SOURCES} ${LINUX_SOURCES})
add_library(lg_common STATIC ${SOURCES})
target_link_libraries(lg_common bfd)
if(ENABLE_BACKTRACE)
target_link_libraries(lg_common bfd)
endif()
endif()
target_include_directories(lg_common

View File

@@ -19,8 +19,8 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#pragma once
#if defined(__GCC__) || defined(__GNUC__)
#define INTERLOCKED_AND8 __sync_and_and_fetch
#define INTERLOCKED_OR8 __sync_or_and_fetch
#define INTERLOCKED_AND8 __sync_fetch_and_and
#define INTERLOCKED_OR8 __sync_fetch_and_or
#else
#define INTERLOCKED_OR8 InterlockedOr8
#define INTERLOCKED_AND8 InterlockedAnd8

View File

@@ -21,6 +21,8 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#include "common/crash.h"
#include "common/debug.h"
#if defined(ENABLE_BACKTRACE)
#include <execinfo.h>
#include <signal.h>
#include <stdio.h>
@@ -206,7 +208,7 @@ static void crit_err_hdlr(int sig_num, siginfo_t * info, void * ucontext)
bool installCrashHandler(const char * exe)
{
struct sigaction sigact;
struct sigaction sigact = { 0 };
crash.exe = realpath(exe, NULL);
sigact.sa_sigaction = crit_err_hdlr;
@@ -219,4 +221,13 @@ bool installCrashHandler(const char * exe)
}
return true;
}
}
#else //ENABLE_BACKTRACE
bool installCrashHandler(const char * exe)
{
return true;
}
#endif

View File

@@ -427,6 +427,9 @@ bool option_load(const char * filename)
DEBUG_WARN("Ignored unknown option %s:%s", module, name);
else
{
if (value)
value[valueLen] = '\0';
if (!option_set(o, value))
DEBUG_ERROR("Failed to set the option value");
}

308
host/.gitignore vendored
View File

@@ -1,308 +0,0 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# compiled shader headers
Shaders/*.h
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Visual Studio 2015 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
**/Properties/launchSettings.json
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Typescript v1 declaration files
typings/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
# CodeRush
.cr/
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/

View File

@@ -1,829 +0,0 @@
/*
Looking Glass - KVM FrameRelay (KVMFR) Client
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 "Capture/DXGI.h"
using namespace Capture;
#include "WinDebug.h"
#include "common/memcpySSE.h"
static const char * DXGI_FORMAT_STR[] = {
"DXGI_FORMAT_UNKNOWN",
"DXGI_FORMAT_R32G32B32A32_TYPELESS",
"DXGI_FORMAT_R32G32B32A32_FLOAT",
"DXGI_FORMAT_R32G32B32A32_UINT",
"DXGI_FORMAT_R32G32B32A32_SINT",
"DXGI_FORMAT_R32G32B32_TYPELESS",
"DXGI_FORMAT_R32G32B32_FLOAT",
"DXGI_FORMAT_R32G32B32_UINT",
"DXGI_FORMAT_R32G32B32_SINT",
"DXGI_FORMAT_R16G16B16A16_TYPELESS",
"DXGI_FORMAT_R16G16B16A16_FLOAT",
"DXGI_FORMAT_R16G16B16A16_UNORM",
"DXGI_FORMAT_R16G16B16A16_UINT",
"DXGI_FORMAT_R16G16B16A16_SNORM",
"DXGI_FORMAT_R16G16B16A16_SINT",
"DXGI_FORMAT_R32G32_TYPELESS",
"DXGI_FORMAT_R32G32_FLOAT",
"DXGI_FORMAT_R32G32_UINT",
"DXGI_FORMAT_R32G32_SINT",
"DXGI_FORMAT_R32G8X24_TYPELESS",
"DXGI_FORMAT_D32_FLOAT_S8X24_UINT",
"DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS",
"DXGI_FORMAT_X32_TYPELESS_G8X24_UINT",
"DXGI_FORMAT_R10G10B10A2_TYPELESS",
"DXGI_FORMAT_R10G10B10A2_UNORM",
"DXGI_FORMAT_R10G10B10A2_UINT",
"DXGI_FORMAT_R11G11B10_FLOAT",
"DXGI_FORMAT_R8G8B8A8_TYPELESS",
"DXGI_FORMAT_R8G8B8A8_UNORM",
"DXGI_FORMAT_R8G8B8A8_UNORM_SRGB",
"DXGI_FORMAT_R8G8B8A8_UINT",
"DXGI_FORMAT_R8G8B8A8_SNORM",
"DXGI_FORMAT_R8G8B8A8_SINT",
"DXGI_FORMAT_R16G16_TYPELESS",
"DXGI_FORMAT_R16G16_FLOAT",
"DXGI_FORMAT_R16G16_UNORM",
"DXGI_FORMAT_R16G16_UINT",
"DXGI_FORMAT_R16G16_SNORM",
"DXGI_FORMAT_R16G16_SINT",
"DXGI_FORMAT_R32_TYPELESS",
"DXGI_FORMAT_D32_FLOAT",
"DXGI_FORMAT_R32_FLOAT",
"DXGI_FORMAT_R32_UINT",
"DXGI_FORMAT_R32_SINT",
"DXGI_FORMAT_R24G8_TYPELESS",
"DXGI_FORMAT_D24_UNORM_S8_UINT",
"DXGI_FORMAT_R24_UNORM_X8_TYPELESS",
"DXGI_FORMAT_X24_TYPELESS_G8_UINT",
"DXGI_FORMAT_R8G8_TYPELESS",
"DXGI_FORMAT_R8G8_UNORM",
"DXGI_FORMAT_R8G8_UINT",
"DXGI_FORMAT_R8G8_SNORM",
"DXGI_FORMAT_R8G8_SINT",
"DXGI_FORMAT_R16_TYPELESS",
"DXGI_FORMAT_R16_FLOAT",
"DXGI_FORMAT_D16_UNORM",
"DXGI_FORMAT_R16_UNORM",
"DXGI_FORMAT_R16_UINT",
"DXGI_FORMAT_R16_SNORM",
"DXGI_FORMAT_R16_SINT",
"DXGI_FORMAT_R8_TYPELESS",
"DXGI_FORMAT_R8_UNORM",
"DXGI_FORMAT_R8_UINT",
"DXGI_FORMAT_R8_SNORM",
"DXGI_FORMAT_R8_SINT",
"DXGI_FORMAT_A8_UNORM",
"DXGI_FORMAT_R1_UNORM",
"DXGI_FORMAT_R9G9B9E5_SHAREDEXP",
"DXGI_FORMAT_R8G8_B8G8_UNORM",
"DXGI_FORMAT_G8R8_G8B8_UNORM",
"DXGI_FORMAT_BC1_TYPELESS",
"DXGI_FORMAT_BC1_UNORM",
"DXGI_FORMAT_BC1_UNORM_SRGB",
"DXGI_FORMAT_BC2_TYPELESS",
"DXGI_FORMAT_BC2_UNORM",
"DXGI_FORMAT_BC2_UNORM_SRGB",
"DXGI_FORMAT_BC3_TYPELESS",
"DXGI_FORMAT_BC3_UNORM",
"DXGI_FORMAT_BC3_UNORM_SRGB",
"DXGI_FORMAT_BC4_TYPELESS",
"DXGI_FORMAT_BC4_UNORM",
"DXGI_FORMAT_BC4_SNORM",
"DXGI_FORMAT_BC5_TYPELESS",
"DXGI_FORMAT_BC5_UNORM",
"DXGI_FORMAT_BC5_SNORM",
"DXGI_FORMAT_B5G6R5_UNORM",
"DXGI_FORMAT_B5G5R5A1_UNORM",
"DXGI_FORMAT_B8G8R8A8_UNORM",
"DXGI_FORMAT_B8G8R8X8_UNORM",
"DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM",
"DXGI_FORMAT_B8G8R8A8_TYPELESS",
"DXGI_FORMAT_B8G8R8A8_UNORM_SRGB",
"DXGI_FORMAT_B8G8R8X8_TYPELESS",
"DXGI_FORMAT_B8G8R8X8_UNORM_SRGB",
"DXGI_FORMAT_BC6H_TYPELESS",
"DXGI_FORMAT_BC6H_UF16",
"DXGI_FORMAT_BC6H_SF16",
"DXGI_FORMAT_BC7_TYPELESS",
"DXGI_FORMAT_BC7_UNORM",
"DXGI_FORMAT_BC7_UNORM_SRGB",
"DXGI_FORMAT_AYUV",
"DXGI_FORMAT_Y410",
"DXGI_FORMAT_Y416",
"DXGI_FORMAT_NV12",
"DXGI_FORMAT_P010",
"DXGI_FORMAT_P016",
"DXGI_FORMAT_420_OPAQUE",
"DXGI_FORMAT_YUY2",
"DXGI_FORMAT_Y210",
"DXGI_FORMAT_Y216",
"DXGI_FORMAT_NV11",
"DXGI_FORMAT_AI44",
"DXGI_FORMAT_IA44",
"DXGI_FORMAT_P8",
"DXGI_FORMAT_A8P8",
"DXGI_FORMAT_B4G4R4A4_UNORM",
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
"DXGI_FORMAT_P208",
"DXGI_FORMAT_V208",
"DXGI_FORMAT_V408"
};
const char * GetDXGIFormatStr(DXGI_FORMAT format)
{
if (format > _countof(DXGI_FORMAT_STR))
return DXGI_FORMAT_STR[0];
return DXGI_FORMAT_STR[format];
}
DXGI::DXGI() :
m_options(NULL),
m_initialized(false),
m_dxgiFactory(),
m_device(),
m_deviceContext(),
m_dup()
{
}
DXGI::~DXGI()
{
}
bool DXGI::CanInitialize()
{
HDESK desktop = OpenInputDesktop(0, TRUE, GENERIC_READ);
if (!desktop)
return false;
CloseDesktop(desktop);
return true;
}
bool DXGI::Initialize(CaptureOptions * options)
{
if (m_initialized)
DeInitialize();
m_options = options;
HRESULT status;
m_cursorRPos = 0;
m_cursorWPos = 0;
for (int i = 0; i < _countof(m_cursorRing); ++i)
{
CursorInfo & cursor = m_cursorRing[i];
cursor.visible = false;
cursor.hasPos = false;
cursor.hasShape = false;
}
status = CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void **)(&m_dxgiFactory));
if (FAILED(status))
{
DEBUG_ERROR("Failed to create DXGIFactory: %08x", (int)status);
return false;
}
bool done = false;
IDXGIAdapter1Ptr adapter;
for (int i = 0; m_dxgiFactory->EnumAdapters1(i, &adapter) != DXGI_ERROR_NOT_FOUND; i++)
{
for (int i = 0; adapter->EnumOutputs(i, &m_output) != DXGI_ERROR_NOT_FOUND; i++)
{
DXGI_OUTPUT_DESC outputDesc;
m_output->GetDesc(&outputDesc);
if (!outputDesc.AttachedToDesktop)
{
m_output = NULL;
continue;
}
DXGI_ADAPTER_DESC1 adapterDesc;
adapter->GetDesc1(&adapterDesc);
DEBUG_INFO("Device Descripion: %ls" , adapterDesc.Description);
DEBUG_INFO("Device Vendor ID : 0x%x" , adapterDesc.VendorId);
DEBUG_INFO("Device Device ID : 0x%x" , adapterDesc.DeviceId);
DEBUG_INFO("Device Video Mem : %lld MB", adapterDesc.DedicatedVideoMemory / 1048576);
DEBUG_INFO("Device Sys Mem : %lld MB", adapterDesc.DedicatedSystemMemory / 1048576);
DEBUG_INFO("Shared Sys Mem : %lld MB", adapterDesc.SharedSystemMemory / 1048576);
m_width = outputDesc.DesktopCoordinates.right - outputDesc.DesktopCoordinates.left;
m_height = outputDesc.DesktopCoordinates.bottom - outputDesc.DesktopCoordinates.top;
DEBUG_INFO("Capture Size : %u x %u", m_width, m_height);
done = true;
break;
}
if (done)
break;
adapter = NULL;
}
if (!done)
{
DEBUG_ERROR("Failed to locate a valid output device");
DeInitialize();
return false;
}
static const D3D_FEATURE_LEVEL featureLevels[] = {
D3D_FEATURE_LEVEL_12_1,
D3D_FEATURE_LEVEL_12_0,
D3D_FEATURE_LEVEL_11_1,
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
D3D_FEATURE_LEVEL_9_3,
D3D_FEATURE_LEVEL_9_2,
D3D_FEATURE_LEVEL_9_1
};
#ifdef _DEBUG
#define CREATE_FLAGS (D3D11_CREATE_DEVICE_DEBUG)
#else
#define CREATE_FLAGS (0)
#endif
status = D3D11CreateDevice(
adapter,
D3D_DRIVER_TYPE_UNKNOWN,
NULL,
CREATE_FLAGS | D3D11_CREATE_DEVICE_VIDEO_SUPPORT,
featureLevels, ARRAYSIZE(featureLevels),
D3D11_SDK_VERSION,
&m_device,
&m_featureLevel,
&m_deviceContext
);
#undef CREATE_FLAGS
if (FAILED(status))
{
DEBUG_WINERROR("Failed to create D3D11 device", status);
DeInitialize();
return false;
}
DEBUG_INFO("Feature Level : 0x%x", m_featureLevel);
IDXGIDevicePtr dxgi;
status = m_device->QueryInterface(__uuidof(IDXGIDevice), (void **)&dxgi);
if (FAILED(status))
{
DEBUG_WINERROR("Failed to obtain the IDXGIDevice interface from the D3D11 device", status);
DeInitialize();
return false;
}
dxgi->SetGPUThreadPriority(7);
// first try to use the newer API
IDXGIOutput5Ptr output5 = m_output;
if (output5)
{
// we try this twice in case we still get an error on re-initialization
for (int i = 0; i < 2; ++i)
{
const DXGI_FORMAT supportedFormats[] = {
DXGI_FORMAT_B8G8R8A8_UNORM,
DXGI_FORMAT_R8G8B8A8_UNORM,
DXGI_FORMAT_R10G10B10A2_UNORM
};
status = output5->DuplicateOutput1(m_device, 0, _countof(supportedFormats), supportedFormats, &m_dup);
if (SUCCEEDED(status))
break;
Sleep(200);
}
if (FAILED(status))
{
DEBUG_WINERROR("DuplicateOutput1 Failed", status);
DeInitialize();
return false;
}
}
else
{
DEBUG_WARN("IDXGIOutput5 is not available, please update windows for improved performance!");
DEBUG_WARN("Falling back to IDXIGOutput1");
IDXGIOutput1Ptr output1 = m_output;
if (!output1)
{
DEBUG_ERROR("Failed to get IDXGIOutput1");
DeInitialize();
return false;
}
// we try this twice in case we still get an error on re-initialization
for (int i = 0; i < 2; ++i)
{
status = output1->DuplicateOutput(m_device, &m_dup);
if (SUCCEEDED(status))
break;
Sleep(200);
}
if (FAILED(status))
{
DEBUG_WINERROR("DuplicateOutput Failed", status);
DeInitialize();
return false;
}
}
DXGI_OUTDUPL_DESC dupDesc;
m_dup->GetDesc(&dupDesc);
DEBUG_INFO("Source Format : %s", GetDXGIFormatStr(dupDesc.ModeDesc.Format));
m_started = false;
m_initialized = true;
return true;
}
bool DXGI::InitRawCapture()
{
D3D11_TEXTURE2D_DESC texDesc;
ZeroMemory(&texDesc, sizeof(texDesc));
texDesc.Width = m_width;
texDesc.Height = m_height;
texDesc.MipLevels = 1;
texDesc.ArraySize = 1;
texDesc.SampleDesc.Count = 1;
texDesc.SampleDesc.Quality = 0;
texDesc.Usage = D3D11_USAGE_STAGING;
texDesc.Format = m_pixelFormat;
texDesc.BindFlags = 0;
texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
texDesc.MiscFlags = 0;
HRESULT status = m_device->CreateTexture2D(&texDesc, NULL, &m_texture[0]);
if (FAILED(status))
{
DEBUG_WINERROR("Failed to create texture", status);
return false;
}
return true;
}
bool DXGI::InitYUV420Capture()
{
HRESULT status;
D3D11_TEXTURE2D_DESC texDesc;
ZeroMemory(&texDesc, sizeof(texDesc));
texDesc.Width = m_width;
texDesc.Height = m_height;
texDesc.MipLevels = 1;
texDesc.ArraySize = 1;
texDesc.SampleDesc.Count = 1;
texDesc.SampleDesc.Quality = 0;
texDesc.Usage = D3D11_USAGE_STAGING;
texDesc.Format = DXGI_FORMAT_R8_UNORM;
texDesc.BindFlags = 0;
texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
texDesc.MiscFlags = 0;
status = m_device->CreateTexture2D(&texDesc, NULL, &m_texture[0]);
if (FAILED(status))
{
DEBUG_WINERROR("Failed to create texture", status);
return false;
}
texDesc.Width /= 2;
texDesc.Height /= 2;
status = m_device->CreateTexture2D(&texDesc, NULL, &m_texture[1]);
if (FAILED(status))
{
DEBUG_WINERROR("Failed to create texture", status);
return false;
}
status = m_device->CreateTexture2D(&texDesc, NULL, &m_texture[2]);
if (FAILED(status))
{
DEBUG_WINERROR("Failed to create texture", status);
return false;
}
m_textureConverter = new TextureConverter();
if (!m_textureConverter->Initialize(m_deviceContext, m_device, m_width, m_height, FRAME_TYPE_YUV420))
return false;
return true;
}
void DXGI::DeInitialize()
{
if (m_h264)
{
delete m_h264;
m_h264 = NULL;
}
if (m_textureConverter)
{
delete m_textureConverter;
m_textureConverter = NULL;
}
ReleaseFrame();
for(int i = 0; i < _countof(m_cursorRing); ++i)
{
if (m_cursorRing[i].shape.buffer)
delete[] m_cursorRing[i].shape.buffer;
m_cursorRing[i].shape.buffer = NULL;
m_cursorRing[i].shape.bufferSize = 0;
}
for(int i = 0; i < _countof(m_texture); ++i)
m_texture[i] = NULL;
m_dup = NULL;
m_output = NULL;
m_deviceContext = NULL;
m_device = NULL;
m_dxgiFactory = NULL;
m_initialized = false;
}
FrameType DXGI::GetFrameType()
{
if (!m_initialized)
return FRAME_TYPE_INVALID;
return m_frameType;
}
size_t DXGI::GetMaxFrameSize()
{
if (!m_initialized)
return 0;
return (m_width * m_height * 4);
}
unsigned int Capture::DXGI::Capture()
{
if (!m_initialized)
return GRAB_STATUS_ERROR;
CursorInfo & cursor = m_cursorRing[m_cursorWPos];
DXGI_OUTDUPL_FRAME_INFO frameInfo;
IDXGIResourcePtr res;
unsigned int ret;
HRESULT status;
for (int retryCount = 0; retryCount < 2; ++retryCount)
{
ret = ReleaseFrame();
if (ret != GRAB_STATUS_OK)
return ret;
status = m_dup->AcquireNextFrame(1000, &frameInfo, &res);
switch (status)
{
case S_OK:
m_releaseFrame = true;
break;
case DXGI_ERROR_WAIT_TIMEOUT:
return GRAB_STATUS_TIMEOUT;
// desktop switch, mode change, switch DWM on or off or Secure Desktop
case DXGI_ERROR_ACCESS_LOST:
case WAIT_ABANDONED:
return GRAB_STATUS_REINIT;
default:
// unknown failure
DEBUG_WINERROR("AcquireNextFrame failed", status);
return GRAB_STATUS_ERROR;
}
// if the pointer shape has changed
if (frameInfo.PointerShapeBufferSize > 0)
{
// resize the buffer if required
if (cursor.shape.bufferSize < frameInfo.PointerShapeBufferSize)
{
delete[] cursor.shape.buffer;
cursor.shape.buffer = new char[frameInfo.PointerShapeBufferSize];
cursor.shape.bufferSize = frameInfo.PointerShapeBufferSize;
}
cursor.shape.pointerSize = 0;
ret |= GRAB_STATUS_CURSOR;
DXGI_OUTDUPL_POINTER_SHAPE_INFO shapeInfo;
status = m_dup->GetFramePointerShape(cursor.shape.bufferSize, cursor.shape.buffer, &cursor.shape.pointerSize, &shapeInfo);
if (FAILED(status))
{
DEBUG_WINERROR("Failed to get the new pointer shape", status);
return GRAB_STATUS_ERROR;
}
switch (shapeInfo.Type)
{
case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_COLOR : cursor.type = CURSOR_TYPE_COLOR; break;
case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR: cursor.type = CURSOR_TYPE_MASKED_COLOR; break;
case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME : cursor.type = CURSOR_TYPE_MONOCHROME; break;
default:
DEBUG_ERROR("Invalid cursor type");
return GRAB_STATUS_ERROR;
}
cursor.hasShape = true;
cursor.w = shapeInfo.Width;
cursor.h = shapeInfo.Height;
cursor.pitch = shapeInfo.Pitch;
}
// if we have a mouse update
if (frameInfo.LastMouseUpdateTime.QuadPart)
{
if (
m_lastCursorX != frameInfo.PointerPosition.Position.x ||
m_lastCursorY != frameInfo.PointerPosition.Position.y
) {
ret |= GRAB_STATUS_CURSOR;
cursor.hasPos = true;
cursor.x = m_lastCursorX = frameInfo.PointerPosition.Position.x;
cursor.y = m_lastCursorY = frameInfo.PointerPosition.Position.y;
}
}
if (m_lastMouseVis != frameInfo.PointerPosition.Visible)
m_lastMouseVis = frameInfo.PointerPosition.Visible;
cursor.visible = m_lastMouseVis == TRUE;
if (ret & GRAB_STATUS_CURSOR && m_cursorWPos == m_cursorRPos)
{
// atomic advance so we don't have to worry about locking
m_cursorWPos = (m_cursorWPos + 1 == DXGI_CURSOR_RING_SIZE) ? 0 : m_cursorWPos + 1;
}
// if we don't have frame data
if (frameInfo.LastPresentTime.QuadPart == 0)
{
// if there is nothing to update, just start again
if (!ret)
{
--retryCount;
continue;
}
res = NULL;
ret |= GRAB_STATUS_OK;
return ret;
}
// success, break out of the retry loop
break;
}
ret |= GRAB_STATUS_FRAME;
// ensure we have a frame
if (!m_releaseFrame)
{
DEBUG_WINERROR("Failed to acquire next frame", status);
return GRAB_STATUS_ERROR;
}
// get the texture
res.QueryInterface(IID_PPV_ARGS(&m_ftexture));
res = NULL;
if (!m_ftexture)
{
DEBUG_ERROR("Failed to get src ID3D11Texture2D");
return GRAB_STATUS_ERROR;
}
if (!m_started)
{
m_started = true;
// determine the native pixel format
D3D11_TEXTURE2D_DESC dupDesc;
ZeroMemory(&dupDesc, sizeof(dupDesc));
m_ftexture->GetDesc(&dupDesc);
m_pixelFormat = dupDesc.Format;
switch(m_pixelFormat)
{
case DXGI_FORMAT_R8G8B8A8_UNORM:
m_frameType = FRAME_TYPE_RGBA;
break;
case DXGI_FORMAT_B8G8R8A8_UNORM:
m_frameType = FRAME_TYPE_BGRA;
break;
case DXGI_FORMAT_R10G10B10A2_UNORM:
m_frameType = FRAME_TYPE_RGBA10;
break;
default:
DEBUG_WARN("Unsupported pixel format %s, enabling conversions", GetDXGIFormatStr(m_pixelFormat));
return GRAB_STATUS_ERROR;
}
DEBUG_INFO("Pixel Format : %s", GetDXGIFormatStr(m_pixelFormat));
for(CaptureOptions::const_iterator it = m_options->cbegin(); it != m_options->cend(); ++it)
{
if (_stricmp(*it, "yuv420") == 0) m_frameType = FRAME_TYPE_YUV420;
}
bool ok = false;
switch (m_frameType)
{
case FRAME_TYPE_BGRA :
case FRAME_TYPE_RGBA :
case FRAME_TYPE_RGBA10: ok = InitRawCapture (); break;
case FRAME_TYPE_YUV420: ok = InitYUV420Capture(); break;
}
if (!ok)
return GRAB_STATUS_ERROR;
}
// initiate the texture copy as early as possible
if (m_frameType == FRAME_TYPE_YUV420)
{
TextureList planes;
if (!m_textureConverter->Convert(m_ftexture, planes))
return GRAB_STATUS_ERROR;
for (int i = 0; i < 3; ++i)
{
ID3D11Texture2DPtr t = planes.at(i);
m_deviceContext->CopyResource(m_texture[i], t);
}
}
else
m_deviceContext->CopyResource(m_texture[0], m_ftexture);
ret |= GRAB_STATUS_OK;
return ret;
}
GrabStatus Capture::DXGI::ReleaseFrame()
{
if (!m_releaseFrame)
return GRAB_STATUS_OK;
m_releaseFrame = false;
m_ftexture = NULL;
switch (m_dup->ReleaseFrame())
{
case S_OK:
break;
case DXGI_ERROR_INVALID_CALL:
DEBUG_ERROR("Frame was already released");
return GRAB_STATUS_ERROR;
case WAIT_ABANDONED:
case DXGI_ERROR_ACCESS_LOST:
return GRAB_STATUS_REINIT;
}
return GRAB_STATUS_OK;
}
GrabStatus Capture::DXGI::DiscardFrame()
{
return ReleaseFrame();
}
GrabStatus Capture::DXGI::GrabFrameRaw(FrameInfo & frame)
{
D3D11_MAPPED_SUBRESOURCE mapping;
HRESULT status;
status = m_deviceContext->Map(m_texture[0], 0, D3D11_MAP_READ, 0, &mapping);
if (FAILED(status))
{
DEBUG_WINERROR("Failed to map the texture", status);
DeInitialize();
return GRAB_STATUS_ERROR;
}
frame.pitch = mapping.RowPitch;
frame.stride = mapping.RowPitch / 4;
memcpySSE(frame.buffer, mapping.pData, frame.pitch * m_height);
m_deviceContext->Unmap(m_texture[0], 0);
return GRAB_STATUS_OK;
}
GrabStatus Capture::DXGI::GrabFrameYUV420(struct FrameInfo & frame)
{
uint8_t * data = (uint8_t *)frame.buffer;
size_t remain = frame.bufferSize;
for(int i = 0; i < 3; ++i)
{
HRESULT status;
D3D11_MAPPED_SUBRESOURCE mapping;
D3D11_TEXTURE2D_DESC desc;
m_texture[i]->GetDesc(&desc);
status = m_deviceContext->Map(m_texture[i], 0, D3D11_MAP_READ, 0, &mapping);
if (FAILED(status))
{
DEBUG_WINERROR("Failed to map the texture", status);
DeInitialize();
return GRAB_STATUS_ERROR;
}
const unsigned int size = desc.Height * desc.Width;
if (size > remain)
{
m_deviceContext->Unmap(m_texture[i], 0);
DEBUG_ERROR("Too much data to fit in buffer");
return GRAB_STATUS_ERROR;
}
const uint8_t * src = (uint8_t *)mapping.pData;
for(unsigned int y = 0; y < desc.Height; ++y)
{
memcpySSE(data, src, desc.Width);
data += desc.Width;
src += mapping.RowPitch;
}
m_deviceContext->Unmap(m_texture[i], 0);
remain -= size;
}
frame.pitch = m_width;
frame.stride = m_width;
return GRAB_STATUS_OK;
}
GrabStatus DXGI::GetFrame(struct FrameInfo & frame)
{
if (!m_ftexture)
{
DEBUG_ERROR("A frame has not been captured");
return GRAB_STATUS_ERROR;
}
frame.width = m_width;
frame.height = m_height;
if (m_frameType == FRAME_TYPE_YUV420)
return GrabFrameYUV420(frame);
return GrabFrameRaw(frame);
}
bool DXGI::GetCursor(CursorInfo & cursor)
{
if (m_cursorRPos == m_cursorWPos)
return false;
cursor = m_cursorRing[m_cursorRPos];
return true;
}
void DXGI::FreeCursor()
{
assert(m_cursorRPos != m_cursorWPos);
CursorInfo & cursor = m_cursorRing[m_cursorRPos];
cursor.visible = false;
cursor.hasPos = false;
cursor.hasShape = false;
m_cursorRPos = (m_cursorRPos + 1 == DXGI_CURSOR_RING_SIZE) ? 0 : m_cursorRPos + 1;
}

View File

@@ -1,106 +0,0 @@
/*
Looking Glass - KVM FrameRelay (KVMFR) Client
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
*/
#pragma once
#include "ICapture.h"
#include "Com.h"
#include "TextureConverter.h"
#include "MFT/H264.h"
#include <list>
#define W32_LEAN_AND_MEAN
#include <windows.h>
#include <shlwapi.h>
#include <stdio.h>
#define DXGI_CURSOR_RING_SIZE 3
namespace Capture
{
class DXGI : public ICapture
{
public:
DXGI();
virtual ~DXGI();
const char * GetName() { return "DXGI"; }
bool CanInitialize();
bool Initialize(CaptureOptions * options);
void DeInitialize();
bool ReInitialize()
{
DeInitialize();
/*
DXGI needs some time when mode switches occur, failing to do so causes
failure to start and exceptions internal to DXGI
*/
Sleep(400);
return Initialize(m_options);
}
enum FrameType GetFrameType();
size_t GetMaxFrameSize();
unsigned int Capture();
GrabStatus GetFrame (struct FrameInfo & frame );
bool GetCursor(CursorInfo & cursor);
void FreeCursor();
GrabStatus DiscardFrame();
private:
bool InitRawCapture();
bool InitYUV420Capture();
CursorInfo m_cursorRing[DXGI_CURSOR_RING_SIZE];
unsigned int m_cursorRPos, m_cursorWPos;
ID3D11Texture2DPtr m_ftexture;
GrabStatus ReleaseFrame();
GrabStatus GrabFrameRaw (struct FrameInfo & frame);
GrabStatus GrabFrameYUV420 (struct FrameInfo & frame);
CaptureOptions * m_options;
bool m_initialized;
bool m_started;
unsigned int m_width;
unsigned int m_height;
DXGI_FORMAT m_pixelFormat;
enum FrameType m_frameType;
IDXGIFactory1Ptr m_dxgiFactory;
ID3D11DevicePtr m_device;
D3D_FEATURE_LEVEL m_featureLevel;
ID3D11DeviceContextPtr m_deviceContext;
IDXGIOutputPtr m_output;
IDXGIOutputDuplicationPtr m_dup;
bool m_releaseFrame;
ID3D11Texture2DPtr m_texture[3];
TextureConverter * m_textureConverter;
MFT::H264 * m_h264;
int m_lastCursorX, m_lastCursorY;
BOOL m_lastMouseVis;
};
};

View File

@@ -1,395 +0,0 @@
/*
Looking Glass - KVM FrameRelay (KVMFR) Client
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
*/
#if CONFIG_CAPTURE_NVFBC
#include "NvFBC.h"
using namespace Capture;
#include <string>
#include "common/debug.h"
#include "common/memcpySSE.h"
#include "Util.h"
#ifdef _WIN64
#define NVFBC_LIBRARY_NAME "NvFBC64.dll"
#else
#define NVFBC_LIBRARY_NAME "NvFBC.dll"
#endif
#define MOPT "privData"
NvFBC::NvFBC() :
m_options(NULL),
m_optNoCrop(false),
m_optNoWait(false),
m_initialized(false),
m_first(true),
m_hDLL(NULL),
m_nvFBC(NULL)
{
}
NvFBC::~NvFBC()
{
}
bool Capture::NvFBC::CanInitialize()
{
return true;
}
bool NvFBC::Initialize(CaptureOptions * options)
{
if (m_initialized)
DeInitialize();
m_first = true;
m_options = options;
m_optNoCrop = false;
uint8_t * privData = NULL;
NvU32 privDataSize = 0;
for (CaptureOptions::const_iterator it = options->cbegin(); it != options->cend(); ++it)
{
if (_strcmpi(*it, "nocrop") == 0) { m_optNoCrop = false; continue; }
if (_strcmpi(*it, "nowait") == 0) { m_optNoWait = true ; continue; }
if (_strnicmp(*it, MOPT " ", sizeof(MOPT)) == 0)
{
std::string value(*it);
value.erase(0, sizeof(MOPT));
if (value.empty() || value.length() & 1)
continue;
privDataSize = (NvU32)(value.length() / 2);
privData = new uint8_t[privDataSize];
uint8_t *p = privData;
for (int i = 0; i < value.length(); i += 2, ++p)
{
char hex[3];
#pragma warning(disable:4996)
value.copy(hex, 2, i);
#pragma warning(restore:4996)
hex[2] = 0;
*p = (uint8_t)strtoul(hex, NULL, 16);
}
}
}
std::string nvfbc = Util::GetSystemRoot() + "\\" + NVFBC_LIBRARY_NAME;
m_hDLL = LoadLibraryA(nvfbc.c_str());
if (!m_hDLL)
{
DEBUG_ERROR("Failed to load the NvFBC library: %d - %s", (int)GetLastError(), nvfbc.c_str());
return false;
}
m_fnCreateEx = (NvFBC_CreateFunctionExType )GetProcAddress(m_hDLL, "NvFBC_CreateEx" );
m_fnSetGlobalFlags = (NvFBC_SetGlobalFlagsType )GetProcAddress(m_hDLL, "NvFBC_SetGlobalFlags");
m_fnGetStatusEx = (NvFBC_GetStatusExFunctionType)GetProcAddress(m_hDLL, "NvFBC_GetStatusEx" );
m_fnEnable = (NvFBC_EnableFunctionType )GetProcAddress(m_hDLL, "NvFBC_Enable" );
if (!m_fnCreateEx || !m_fnSetGlobalFlags || !m_fnGetStatusEx || !m_fnEnable)
{
DEBUG_ERROR("Unable to locate required entry points in %s", nvfbc.c_str());
DeInitialize();
return false;
}
NvFBCStatusEx status;
ZeroMemory(&status, sizeof(NvFBCStatusEx));
status.dwVersion = NVFBC_STATUS_VER;
status.dwAdapterIdx = 0;
NVFBCRESULT ret = m_fnGetStatusEx(&status);
if (ret != NVFBC_SUCCESS)
{
DEBUG_ERROR("Failed to get NvFBC status");
DeInitialize();
return false;
}
if (!status.bIsCapturePossible)
{
DEBUG_INFO("Attempting to enable NvFBC");
switch(m_fnEnable(NVFBC_STATE_ENABLE))
{
case NVFBC_SUCCESS:
DEBUG_INFO("Success, attempting to get status again");
if (m_fnGetStatusEx(&status) != NVFBC_SUCCESS)
{
DEBUG_ERROR("Failed to get NvFBC status");
DeInitialize();
return false;
}
break;
case NVFBC_ERROR_INSUFFICIENT_PRIVILEGES:
DEBUG_ERROR("Please run once as administrator to enable the NvFBC API");
DeInitialize();
return false;
default:
DEBUG_ERROR("Unknown failure enabling NvFBC");
DeInitialize();
return false;
}
if (!status.bIsCapturePossible)
{
DEBUG_ERROR("Capture is not possible, unsupported device or driver");
DeInitialize();
return false;
}
}
if (!status.bCanCreateNow)
{
DEBUG_ERROR("Can not create an instance of NvFBC at this time");
DeInitialize();
return false;
}
NvFBCCreateParams params;
ZeroMemory(&params, sizeof(NvFBCCreateParams));
params.dwVersion = NVFBC_CREATE_PARAMS_VER;
params.dwInterfaceType = NVFBC_TO_SYS;
params.pDevice = NULL;
params.dwAdapterIdx = 0;
params.dwPrivateDataSize = privDataSize;
params.pPrivateData = privData;
if (m_fnCreateEx(&params) != NVFBC_SUCCESS)
{
if (privData)
delete [] privData;
DEBUG_ERROR("Failed to create an instance of NvFBC");
DeInitialize();
return false;
}
if (privData)
delete[] privData;
m_maxCaptureWidth = params.dwMaxDisplayWidth;
m_maxCaptureHeight = params.dwMaxDisplayHeight;
m_nvFBC = static_cast<NvFBCToSys *>(params.pNvFBC);
NVFBC_TOSYS_SETUP_PARAMS setupParams;
ZeroMemory(&setupParams, sizeof(NVFBC_TOSYS_SETUP_PARAMS));
setupParams.dwVersion = NVFBC_TOSYS_SETUP_PARAMS_VER;
setupParams.eMode = NVFBC_TOSYS_ARGB;
setupParams.bWithHWCursor = TRUE;
setupParams.bDiffMap = TRUE;
setupParams.eDiffMapBlockSize = NVFBC_TOSYS_DIFFMAP_BLOCKSIZE_128X128;
setupParams.ppBuffer = (void **)&m_frameBuffer;
setupParams.ppDiffMap = (void **)&m_diffMap;
if (m_nvFBC->NvFBCToSysSetUp(&setupParams) != NVFBC_SUCCESS)
{
DEBUG_ERROR("NvFBCToSysSetUp Failed");
DeInitialize();
return false;
}
// this is required according to NVidia sample code
Sleep(100);
HMONITOR monitor = MonitorFromWindow(GetDesktopWindow(), MONITOR_DEFAULTTOPRIMARY);
MONITORINFO monitorInfo;
monitorInfo.cbSize = sizeof(MONITORINFO);
unsigned int screenWidth, screenHeight;
GetMonitorInfo(monitor, &monitorInfo);
screenWidth = monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left;
screenHeight = monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top;
ZeroMemory(&m_grabFrameParams, sizeof(NVFBC_TOSYS_GRAB_FRAME_PARAMS));
ZeroMemory(&m_grabInfo, sizeof(NvFBCFrameGrabInfo));
m_grabFrameParams.dwVersion = NVFBC_TOSYS_GRAB_FRAME_PARAMS_VER;
m_grabFrameParams.dwFlags = m_optNoWait ? NVFBC_TOSYS_NOWAIT : NVFBC_TOSYS_WAIT_WITH_TIMEOUT;
m_grabFrameParams.dwWaitTime = 1000;
m_grabFrameParams.eGMode = NVFBC_TOSYS_SOURCEMODE_CROP;
m_grabFrameParams.dwStartX = 0;
m_grabFrameParams.dwStartY = 0;
m_grabFrameParams.dwTargetWidth = screenWidth;
m_grabFrameParams.dwTargetHeight = screenHeight;
m_grabFrameParams.pNvFBCFrameGrabInfo = &m_grabInfo;
m_initialized = true;
return true;
}
void NvFBC::DeInitialize()
{
m_frameBuffer = NULL;
if (m_nvFBC)
{
m_nvFBC->NvFBCToSysRelease();
m_nvFBC = NULL;
}
m_maxCaptureWidth = 0;
m_maxCaptureHeight = 0;
m_fnCreateEx = NULL;
m_fnSetGlobalFlags = NULL;
m_fnGetStatusEx = NULL;
m_fnEnable = NULL;
if (m_hDLL)
{
FreeLibrary(m_hDLL);
m_hDLL = NULL;
}
m_initialized = false;
}
FrameType NvFBC::GetFrameType()
{
if (!m_initialized)
return FRAME_TYPE_INVALID;
return FRAME_TYPE_BGRA;
}
size_t NvFBC::GetMaxFrameSize()
{
if (!m_initialized)
return false;
return m_maxCaptureWidth * m_maxCaptureHeight * 4;
}
unsigned int Capture::NvFBC::Capture()
{
if (!m_initialized)
return GRAB_STATUS_ERROR;
for (int i = 0; i < 2; ++i)
{
NVFBCRESULT status = m_nvFBC->NvFBCToSysGrabFrame(&m_grabFrameParams);
if (status == NVFBC_SUCCESS)
{
const int diffW = (m_grabInfo.dwWidth + 0x7F) >> 7;
const int diffH = (m_grabInfo.dwHeight + 0x7F) >> 7;
bool hasDiff = false;
for (int y = 0; y < diffH && !hasDiff; ++y)
for (int x = 0; x < diffW; ++x)
if (m_diffMap[y * diffW + x])
{
hasDiff = true;
break;
}
if (!hasDiff)
{
i = 0;
continue;
}
break;
}
else
{
if (status == NVFBC_ERROR_DYNAMIC_DISABLE)
{
DEBUG_ERROR("NvFBC was disabled by someone else");
return GRAB_STATUS_ERROR;
}
if (status == NVFBC_ERROR_INVALIDATED_SESSION)
{
DEBUG_WARN("Session was invalidated, attempting to restart");
return GRAB_STATUS_REINIT;
}
if (i == 1)
{
DEBUG_ERROR("NvFBCToSysGrabFrame failed");
return GRAB_STATUS_ERROR;
}
}
}
// if the capture size doesn't match the screen resolution then re-initialize to avoid
// copying black/blank areas of the screen
HMONITOR monitor = MonitorFromWindow(GetDesktopWindow(), MONITOR_DEFAULTTOPRIMARY);
MONITORINFO monitorInfo;
monitorInfo.cbSize = sizeof(MONITORINFO);
unsigned int screenWidth, screenHeight;
GetMonitorInfo(monitor, &monitorInfo);
screenWidth = monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left;
screenHeight = monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top;
if (m_grabInfo.dwWidth != screenWidth || m_grabInfo.dwHeight != screenHeight)
{
DEBUG_INFO("Resolution change detected");
return GRAB_STATUS_REINIT;
}
// turn off the cursor on the first frame as NvFBC is drawing it
if (m_first)
return GRAB_STATUS_OK | GRAB_STATUS_FRAME | GRAB_STATUS_CURSOR;
else
return GRAB_STATUS_OK | GRAB_STATUS_FRAME;
}
bool Capture::NvFBC::GetCursor(CursorInfo & cursor)
{
cursor.hasShape = false;
cursor.hasPos = false;
cursor.visible = false;
if (m_first)
{
m_first = false;
return true;
}
return false;
}
void Capture::NvFBC::FreeCursor()
{
}
GrabStatus Capture::NvFBC::DiscardFrame()
{
return GrabStatus();
}
enum GrabStatus NvFBC::GetFrame(struct FrameInfo & frame)
{
if (!m_initialized)
return GRAB_STATUS_ERROR;
frame.width = m_grabInfo.dwWidth;
frame.height = m_grabInfo.dwHeight;
frame.stride = m_grabInfo.dwBufferWidth;
frame.pitch = m_grabInfo.dwBufferWidth * 4;
memcpySSE((uint8_t*)frame.buffer, (uint8_t *)m_frameBuffer, frame.pitch * frame.height);
return GRAB_STATUS_OK;
}
#endif// CONFIG_CAPTURE_NVFBC

View File

@@ -1,79 +0,0 @@
/*
Looking Glass - KVM FrameRelay (KVMFR) Client
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
*/
#if CONFIG_CAPTURE_NVFBC
#pragma once
#include "ICapture.h"
#define W32_LEAN_AND_MEAN
#include <windows.h>
#include <NvFBC/nvFBC.h>
#include <NvFBC/nvFBCToSys.h>
namespace Capture
{
class NvFBC : public ICapture
{
public:
NvFBC();
~NvFBC();
const char * GetName() { return "NvFBC"; }
bool CanInitialize();
bool Initialize(CaptureOptions * options);
void DeInitialize();
bool ReInitialize()
{
DeInitialize();
return Initialize(m_options);
}
enum FrameType GetFrameType();
size_t GetMaxFrameSize();
unsigned int Capture();
enum GrabStatus GetFrame(struct FrameInfo & frame);
bool GetCursor(CursorInfo & cursor);
void FreeCursor() ;
enum GrabStatus DiscardFrame();
private:
CaptureOptions * m_options;
bool m_optNoCrop;
bool m_optNoWait;
bool m_initialized;
bool m_first;
HMODULE m_hDLL;
NvFBC_CreateFunctionExType m_fnCreateEx;
NvFBC_SetGlobalFlagsType m_fnSetGlobalFlags;
NvFBC_GetStatusExFunctionType m_fnGetStatusEx;
NvFBC_EnableFunctionType m_fnEnable;
DWORD m_maxCaptureWidth, m_maxCaptureHeight;
NvFBCToSys * m_nvFBC;
uint8_t * m_frameBuffer;
uint8_t * m_diffMap;
NvFBCFrameGrabInfo m_grabInfo;
NVFBC_TOSYS_GRAB_FRAME_PARAMS m_grabFrameParams;
};
};
#endif //CONFIG_CAPTURE_NVFBC

View File

@@ -1,95 +0,0 @@
/*
Looking Glass - KVM FrameRelay (KVMFR) Client
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
*/
#pragma once
#define W32_LEAN_AND_MEAN
#include <windows.h>
#include <vector>
#include "common/debug.h"
#include "ICapture.h"
#if CONFIG_CAPTURE_NVFBC
#include "Capture/NvFBC.h"
#endif
#include "Capture/DXGI.h"
class CaptureFactory
{
public:
typedef std::vector<ICapture *> DeviceList;
static DeviceList & GetDevices()
{
static DeviceList devices;
if (!devices.empty())
return devices;
#if CONFIG_CAPTURE_NVFBC
devices.push_back(new Capture::NvFBC());
#endif
devices.push_back(new Capture::DXGI ());
return devices;
}
static ICapture * GetDevice(const char * name, CaptureOptions * options)
{
DeviceList devices = GetDevices();
for (DeviceList::const_iterator it = devices.begin(); it != devices.end(); ++it)
{
ICapture * device = *it;
if (_strcmpi(name, device->GetName()) != 0)
continue;
if (device->Initialize(options))
{
DEBUG_INFO("Using %s", device->GetName());
return device;
}
device->DeInitialize();
DEBUG_ERROR("Failed to initialize %s", device->GetName());
return NULL;
}
DEBUG_ERROR("No such device: %s", name);
return NULL;
}
static ICapture * DetectDevice(CaptureOptions * options)
{
DeviceList devices = GetDevices();
for (DeviceList::const_iterator it = devices.cbegin(); it != devices.cend(); ++it)
{
ICapture * device = *it;
DEBUG_INFO("Trying %s", device->GetName());
if (device->Initialize(options))
{
DEBUG_INFO("Using %s", device->GetName());
return device;
}
device->DeInitialize();
}
DEBUG_ERROR("Failed to initialize a capture device");
return NULL;
}
};

View File

@@ -1,58 +0,0 @@
/*
Looking Glass - KVM FrameRelay (KVMFR) Client
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
*/
#pragma once
#include <comdef.h>
#include <dxgi1_2.h>
#include <dxgi1_5.h>
#include <d3d11.h>
#include <mftransform.h>
_COM_SMARTPTR_TYPEDEF(IDXGIFactory1 , __uuidof(IDXGIFactory1 ));
_COM_SMARTPTR_TYPEDEF(ID3D11Device , __uuidof(ID3D11Device ));
_COM_SMARTPTR_TYPEDEF(ID3D11DeviceContext , __uuidof(ID3D11DeviceContext ));
_COM_SMARTPTR_TYPEDEF(IDXGIDevice , __uuidof(IDXGIDevice ));
_COM_SMARTPTR_TYPEDEF(IDXGIOutput1 , __uuidof(IDXGIOutput1 ));
_COM_SMARTPTR_TYPEDEF(IDXGIOutput5 , __uuidof(IDXGIOutput5 ));
_COM_SMARTPTR_TYPEDEF(IDXGIOutput , __uuidof(IDXGIOutput ));
_COM_SMARTPTR_TYPEDEF(IDXGIAdapter1 , __uuidof(IDXGIAdapter1 ));
_COM_SMARTPTR_TYPEDEF(IDXGIOutputDuplication , __uuidof(IDXGIOutputDuplication ));
_COM_SMARTPTR_TYPEDEF(ID3D11Texture2D , __uuidof(ID3D11Texture2D ));
_COM_SMARTPTR_TYPEDEF(IDXGIResource , __uuidof(IDXGIResource ));
_COM_SMARTPTR_TYPEDEF(ID3D10Multithread , __uuidof(ID3D10Multithread ));
_COM_SMARTPTR_TYPEDEF(IMFActivate , __uuidof(IMFActivate ));
_COM_SMARTPTR_TYPEDEF(IMFAttributes , __uuidof(IMFAttributes ));
_COM_SMARTPTR_TYPEDEF(IMFDXGIDeviceManager , __uuidof(IMFDXGIDeviceManager ));
_COM_SMARTPTR_TYPEDEF(IMFTransform , __uuidof(IMFTransform ));
_COM_SMARTPTR_TYPEDEF(IMFMediaEvent , __uuidof(IMFMediaEvent ));
_COM_SMARTPTR_TYPEDEF(IMFMediaEventGenerator , __uuidof(IMFMediaEventGenerator ));
_COM_SMARTPTR_TYPEDEF(IMFMediaType , __uuidof(IMFMediaType ));
_COM_SMARTPTR_TYPEDEF(IMFSample , __uuidof(IMFSample ));
_COM_SMARTPTR_TYPEDEF(IMFMediaBuffer , __uuidof(IMFMediaBuffer ));
_COM_SMARTPTR_TYPEDEF(IMF2DBuffer , __uuidof(IMF2DBuffer ));
_COM_SMARTPTR_TYPEDEF(ID3D11RenderTargetView , __uuidof(ID3D11RenderTargetView ));
_COM_SMARTPTR_TYPEDEF(ID3D11ShaderResourceView, __uuidof(ID3D11ShaderResourceView));
_COM_SMARTPTR_TYPEDEF(ID3D11DepthStencilView , __uuidof(ID3D11DepthStencilView ));
_COM_SMARTPTR_TYPEDEF(ID3D11InputLayout , __uuidof(ID3D11InputLayout ));
_COM_SMARTPTR_TYPEDEF(ID3D11VertexShader , __uuidof(ID3D11VertexShader ));
_COM_SMARTPTR_TYPEDEF(ID3D11PixelShader , __uuidof(ID3D11PixelShader ));
_COM_SMARTPTR_TYPEDEF(ID3D11SamplerState , __uuidof(ID3D11SamplerState ));
_COM_SMARTPTR_TYPEDEF(ID3D11Buffer , __uuidof(ID3D11Buffer ));

View File

@@ -1,80 +0,0 @@
/*
Looking Glass - KVM FrameRelay (KVMFR) Client
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 "CrashHandler.h"
typedef BOOL (WINAPI * PMiniDumpWriteDump)(
_In_ HANDLE hProcess,
_In_ DWORD ProcessId,
_In_ HANDLE hFile,
_In_ MINIDUMP_TYPE DumpType,
_In_opt_ PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
_In_opt_ PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
_In_opt_ PMINIDUMP_CALLBACK_INFORMATION CallbackParam
);
void CrashHandler::Initialize()
{
SetUnhandledExceptionFilter(CrashHandler::ExceptionFilter);
}
LONG WINAPI CrashHandler::ExceptionFilter(struct _EXCEPTION_POINTERS * apExceptionInfo)
{
HMODULE lib;
PMiniDumpWriteDump fn_MiniDumpWriteDump;
lib = LoadLibraryA("dbghelp.dll");
if (!lib)
return EXCEPTION_CONTINUE_SEARCH;
fn_MiniDumpWriteDump = (PMiniDumpWriteDump)GetProcAddress(lib, "MiniDumpWriteDump");
if (!fn_MiniDumpWriteDump)
return EXCEPTION_CONTINUE_SEARCH;
HANDLE hFile = CreateFileA(
"looking-glass-host.dump",
GENERIC_WRITE,
FILE_SHARE_WRITE,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (hFile == INVALID_HANDLE_VALUE)
return EXCEPTION_CONTINUE_SEARCH;
_MINIDUMP_EXCEPTION_INFORMATION info;
info.ThreadId = GetCurrentThreadId();
info.ExceptionPointers = apExceptionInfo;
info.ClientPointers = FALSE;
fn_MiniDumpWriteDump(
GetCurrentProcess(),
GetCurrentProcessId(),
hFile,
MiniDumpNormal,
&info,
NULL,
NULL
);
CloseHandle(hFile);
return EXCEPTION_CONTINUE_SEARCH;
}

View File

@@ -1,30 +0,0 @@
/*
Looking Glass - KVM FrameRelay (KVMFR) Client
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
*/
#pragma once
#include <windows.h>
#include <dbghelp.h>
class CrashHandler
{
public:
static void Initialize();
private:
static LONG WINAPI ExceptionFilter(struct _EXCEPTION_POINTERS * apExceptionInfo);
};

View File

@@ -1,84 +0,0 @@
/*
Looking Glass - KVM FrameRelay (KVMFR) Client
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
*/
#pragma once
#include "common/KVMFR.h"
#include <vector>
#include <windows.h>
struct CursorBuffer
{
unsigned int bufferSize;
char * buffer;
unsigned int pointerSize;
};
struct CursorInfo
{
bool visible;
bool hasPos;
bool hasShape;
int x, y;
enum CursorType type;
unsigned int w, h;
unsigned int pitch;
CursorBuffer shape;
};
struct FrameInfo
{
unsigned int width;
unsigned int height;
unsigned int stride;
unsigned int pitch;
void * buffer;
size_t bufferSize;
};
enum GrabStatus
{
GRAB_STATUS_OK = 1,
GRAB_STATUS_TIMEOUT = 2,
GRAB_STATUS_REINIT = 4,
GRAB_STATUS_CURSOR = 8,
GRAB_STATUS_FRAME = 16,
GRAB_STATUS_ERROR = 32
};
typedef std::vector<const char *> CaptureOptions;
class ICapture
{
public:
virtual const char * GetName() = 0;
virtual bool CanInitialize() = 0;
virtual bool Initialize(CaptureOptions * options) = 0;
virtual void DeInitialize() = 0;
virtual bool ReInitialize() = 0;
virtual enum FrameType GetFrameType() = 0;
virtual size_t GetMaxFrameSize() = 0;
virtual unsigned int Capture() = 0;
virtual enum GrabStatus GetFrame(struct FrameInfo & frame) = 0;
virtual bool GetCursor(CursorInfo & cursor) = 0;
virtual void FreeCursor() = 0;
virtual enum GrabStatus DiscardFrame() = 0;
};

View File

@@ -1,380 +0,0 @@
/*
Looking Glass - KVM FrameRelay (KVMFR) Client
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 "IVSHMEM.h"
#include <windows.h>
#include <setupapi.h>
#include "kvm-guest-drivers-windows/ivshmem/Public.h"
#include "common/debug.h"
IVSHMEM * IVSHMEM::m_instance = NULL;
void IVSHMEM::listDevices() {
HDEVINFO deviceInfoSet;
PSP_DEVICE_INTERFACE_DETAIL_DATA infData = NULL;
SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
deviceInfoSet = SetupDiGetClassDevs(NULL, NULL, NULL, DIGCF_PRESENT | DIGCF_ALLCLASSES | DIGCF_DEVICEINTERFACE);
ZeroMemory(&deviceInterfaceData, sizeof(SP_DEVICE_INTERFACE_DATA));
deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
fprintf(stderr, "Found devices:\n");
DWORD i = 0;
while(SetupDiEnumDeviceInterfaces(deviceInfoSet, NULL, &GUID_DEVINTERFACE_IVSHMEM, i, &deviceInterfaceData) != FALSE)
{
DWORD reqSize = 0;
SP_DEVINFO_DATA d;
d.cbSize = sizeof(SP_DEVINFO_DATA);
SetupDiGetDeviceInterfaceDetail(deviceInfoSet, &deviceInterfaceData, NULL, 0, &reqSize, &d);
if (!reqSize)
{
fprintf(stderr, "SetupDiGetDeviceInterfaceDetail");
break;
}
infData = static_cast<PSP_DEVICE_INTERFACE_DETAIL_DATA>(malloc(reqSize));
ZeroMemory(infData, reqSize);
infData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
if (!SetupDiGetDeviceInterfaceDetail(deviceInfoSet, &deviceInterfaceData, infData, reqSize, NULL, NULL))
{
fprintf(stderr, "SetupDiGetDeviceInterfaceDetail");
break;
}
DWORD bus, addr, slot, func;
if (!SetupDiGetDeviceRegistryProperty(deviceInfoSet, &d,SPDRP_BUSNUMBER,NULL,(PBYTE)&bus,sizeof(bus),NULL))
{
DEBUG_ERROR("SetupDiGetDeviceRegistryProperty - SPDRP_BUSNUMBER: %lu\n", GetLastError());
free(infData);
break;
}
if (!SetupDiGetDeviceRegistryProperty(deviceInfoSet, &d,SPDRP_ADDRESS,NULL, (PBYTE)&addr,sizeof(addr),NULL))
{
DEBUG_ERROR("SetupDiGetDeviceRegistryProperty - SPDRP_ADDRESS: %lu\n", GetLastError());
free(infData);
break;
}
slot = (addr >> 16) & 0xFFFF;
func = addr & 0xFFFF;
fprintf(stderr, "[%lu] Found Device: %ls\n"
" Bus: 0x%lx\n"
" Slot: 0x%lx\n"
" Func: 0x%lx\n",
i, infData->DevicePath, bus, slot, func);
i++;
}
DWORD error = GetLastError();
if (error != ERROR_NO_MORE_ITEMS)
{
fprintf(stderr, "Unknown error on index %u: %lu\n", i, error);
}
fprintf(stderr, "%lu devices found\n\n", i);
}
IVSHMEM::IVSHMEM() :
m_initialized(false),
m_handle(INVALID_HANDLE_VALUE),
m_gotSize(false),
m_gotPeerID(false),
m_gotMemory(false)
{
}
IVSHMEM::~IVSHMEM()
{
DeInitialize();
}
bool IVSHMEM::Initialize(PCI_DEVICE dev)
{
if (m_initialized)
DeInitialize();
HDEVINFO deviceInfoSet;
PSP_DEVICE_INTERFACE_DETAIL_DATA infData = NULL;
SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
deviceInfoSet = SetupDiGetClassDevs(NULL, NULL, NULL, DIGCF_PRESENT | DIGCF_ALLCLASSES | DIGCF_DEVICEINTERFACE);
ZeroMemory(&deviceInterfaceData, sizeof(SP_DEVICE_INTERFACE_DATA));
deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
DWORD devid = 0;
while (SetupDiEnumDeviceInterfaces(deviceInfoSet, NULL, &GUID_DEVINTERFACE_IVSHMEM, devid, &deviceInterfaceData) != FALSE)
{
DWORD reqSize = 0;
SP_DEVINFO_DATA d;
d.cbSize = sizeof(SP_DEVINFO_DATA);
SetupDiGetDeviceInterfaceDetail(deviceInfoSet, &deviceInterfaceData, NULL, 0, &reqSize, &d);
if (!reqSize)
{
DEBUG_ERROR("SetupDiGetDeviceInterfaceDetail");
break;
}
infData = static_cast<PSP_DEVICE_INTERFACE_DETAIL_DATA>(malloc(reqSize));
ZeroMemory(infData, reqSize);
infData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
if (!SetupDiGetDeviceInterfaceDetail(deviceInfoSet, &deviceInterfaceData, infData, reqSize, NULL, NULL))
{
DEBUG_ERROR("SetupDiGetDeviceInterfaceDetail");
free(infData);
break;
}
DWORD bus, addr, slot, func;
if (!SetupDiGetDeviceRegistryProperty(deviceInfoSet, &d,SPDRP_BUSNUMBER,NULL,(PBYTE)&bus,sizeof(bus),NULL))
{
DEBUG_ERROR("SetupDiGetDeviceRegistryProperty - SPDRP_BUSNUMBER");
free(infData);
break;
}
if (!SetupDiGetDeviceRegistryProperty(deviceInfoSet, &d,SPDRP_ADDRESS,NULL, (PBYTE)&addr,sizeof(addr),NULL))
{
DEBUG_ERROR("SetupDiGetDeviceRegistryProperty - SPDRP_ADDRESS");
free(infData);
break;
}
slot = (addr >> 16) & 0xFFFF;
func = addr & 0xFFFF;
if (dev.bus != bus || dev.addr != slot || dev.func != func) //not the right device, keep searching
{
free(infData);
devid++;
continue;
}
fprintf(stderr, "Found Device at Index %lu: %ls\n"
" Bus: %lu\n"
" Addr: %lu\n"
" Func: %lu\n",
devid, infData->DevicePath, bus, slot, func);
m_handle = CreateFile(infData->DevicePath, 0, 0, NULL, OPEN_EXISTING, 0, 0);
if (m_handle == INVALID_HANDLE_VALUE)
{
DEBUG_ERROR("CreateFile returned INVALID_HANDLE_VALUE");
free(infData);
break;
}
m_initialized = true;
break;
}
DWORD error = GetLastError();
if (m_initialized == false)
{
if (error == ERROR_NO_MORE_ITEMS)
{
DEBUG_ERROR("Unable to enumerate the device, is it attached?");
}
else
{
DEBUG_ERROR("Unable to enumerate the device. Error: %lu\n", error);
}
}
SetupDiDestroyDeviceInfoList(deviceInfoSet);
return m_initialized;
}
void IVSHMEM::DeInitialize()
{
if (!m_initialized)
return;
if (m_gotMemory)
{
if (!DeviceIoControl(m_handle, IOCTL_IVSHMEM_RELEASE_MMAP, NULL, 0, NULL, 0, NULL, NULL))
DEBUG_ERROR("DeviceIoControl failed: %d", (int)GetLastError());
m_memory = NULL;
}
if (m_handle != INVALID_HANDLE_VALUE)
CloseHandle(m_handle);
m_initialized = false;
m_handle = INVALID_HANDLE_VALUE;
m_gotSize = false;
m_gotPeerID = false;
m_gotVectors = false;
m_gotMemory = false;
}
bool IVSHMEM::IsInitialized()
{
return m_initialized;
}
UINT64 IVSHMEM::GetSize()
{
if (!m_initialized)
return 0;
if (m_gotSize)
return m_size;
IVSHMEM_SIZE size;
if (!DeviceIoControl(m_handle, IOCTL_IVSHMEM_REQUEST_SIZE, NULL, 0, &size, sizeof(IVSHMEM_SIZE), NULL, NULL))
{
DEBUG_ERROR("DeviceIoControl Failed: %d", (int)GetLastError());
return 0;
}
m_gotSize = true;
m_size = static_cast<UINT64>(size);
return m_size;
}
UINT16 IVSHMEM::GetPeerID()
{
if (!m_initialized)
return 0;
if (m_gotPeerID)
return m_peerID;
IVSHMEM_PEERID peerID;
if (!DeviceIoControl(m_handle, IOCTL_IVSHMEM_REQUEST_SIZE, NULL, 0, &peerID, sizeof(IVSHMEM_PEERID), NULL, NULL))
{
DEBUG_ERROR("DeviceIoControl Failed: %d", (int)GetLastError());
return 0;
}
m_gotPeerID = true;
m_peerID = static_cast<UINT16>(peerID);
return m_peerID;
}
UINT16 IVSHMEM::GetVectors()
{
if (!m_initialized)
return 0;
if (!m_gotVectors)
return 0;
return m_vectors;
}
void * IVSHMEM::GetMemory()
{
if (!m_initialized)
return NULL;
if (m_gotMemory)
return m_memory;
// this if define can be removed later once everyone is un the latest version
// old versions of the IVSHMEM driver ignore the input argument, as such this
// is completely backwards compatible
#if defined(IVSHMEM_CACHE_WRITECOMBINED)
IVSHMEM_MMAP_CONFIG config;
config.cacheMode = IVSHMEM_CACHE_WRITECOMBINED;
#endif
IVSHMEM_MMAP map;
ZeroMemory(&map, sizeof(IVSHMEM_MMAP));
if (!DeviceIoControl(
m_handle,
IOCTL_IVSHMEM_REQUEST_MMAP,
#if defined(IVSHMEM_CACHE_WRITECOMBINED)
&config, sizeof(IVSHMEM_MMAP_CONFIG),
#else
NULL , 0,
#endif
&map , sizeof(IVSHMEM_MMAP ),
NULL, NULL))
{
DEBUG_ERROR("DeviceIoControl Failed: %d", (int)GetLastError());
return NULL;
}
m_gotSize = true;
m_gotPeerID = true;
m_gotMemory = true;
m_gotVectors = true;
m_size = static_cast<UINT64>(map.size );
m_peerID = static_cast<UINT16>(map.peerID );
m_vectors = static_cast<UINT16>(map.vectors);
m_memory = map.ptr;
return m_memory;
}
HANDLE IVSHMEM::CreateVectorEvent(UINT16 vector)
{
if (!m_initialized)
return INVALID_HANDLE_VALUE;
HANDLE event = CreateEvent(NULL, TRUE, FALSE, NULL);
if (event == INVALID_HANDLE_VALUE)
{
DEBUG_ERROR("CreateEvent Failed: %d", (int)GetLastError());
return INVALID_HANDLE_VALUE;
}
IVSHMEM_EVENT msg;
msg.event = event;
msg.singleShot = false;
msg.vector = vector;
if (!DeviceIoControl(m_handle, IOCTL_IVSHMEM_REGISTER_EVENT, &msg, sizeof(IVSHMEM_EVENT), NULL, 0, NULL, NULL))
{
DEBUG_ERROR("DeviceIoControl Failed: %d", (int)GetLastError());
CloseHandle(event);
return INVALID_HANDLE_VALUE;
}
return event;
}
bool IVSHMEM::RingDoorbell(UINT16 peerID, UINT16 door)
{
if (!m_initialized)
return false;
IVSHMEM_RING msg;
msg.peerID = peerID;
msg.vector = door;
if (!DeviceIoControl(m_handle, IOCTL_IVSHMEM_RING_DOORBELL, &msg, sizeof(IVSHMEM_RING), NULL, 0, NULL, NULL))
{
DEBUG_ERROR("DeviceIoControl Failed: %d", (int)GetLastError());
return false;
}
return true;
}

View File

@@ -1,69 +0,0 @@
/*
Looking Glass - KVM FrameRelay (KVMFR) Client
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
*/
#pragma once
#define W32_LEAN_AND_MEAN
#include <windows.h>
#include <stdbool.h>
struct PCI_DEVICE {
BYTE bus, addr, func;
};
class IVSHMEM
{
public:
static IVSHMEM * Get()
{
if (!m_instance)
m_instance = new IVSHMEM();
return m_instance;
}
static void listDevices();
bool Initialize(PCI_DEVICE dev);
void DeInitialize();
bool IsInitialized();
UINT64 GetSize();
UINT16 GetPeerID();
UINT16 GetVectors();
void * GetMemory();
HANDLE CreateVectorEvent(UINT16 vector);
bool RingDoorbell(UINT16 peerID, UINT16 door);
protected:
private:
static IVSHMEM * m_instance;
IVSHMEM();
~IVSHMEM();
bool m_initialized;
HANDLE m_handle;
UINT64 m_size ; bool m_gotSize ;
UINT16 m_peerID ; bool m_gotPeerID;
void * m_memory ; bool m_gotMemory;
UINT16 m_vectors; bool m_gotVectors;
};

View File

@@ -1,60 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "looking-glass-host", "looking-glass-host.vcxproj", "{D439DE3E-32FB-4599-8B5D-C92674D400D4}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sync-test", "sync-test\sync-test.vcxproj", "{6CC4DA30-6FBD-4ACA-9BA6-2DE731032800}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{BE5778A4-4447-410B-B8E8-D86087F62CFD}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug - NvFBC|x64 = Debug - NvFBC|x64
Debug - NvFBC|x86 = Debug - NvFBC|x86
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release - NvFBC|x64 = Release - NvFBC|x64
Release - NvFBC|x86 = Release - NvFBC|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{D439DE3E-32FB-4599-8B5D-C92674D400D4}.Debug - NvFBC|x64.ActiveCfg = Debug - NvFBC|x64
{D439DE3E-32FB-4599-8B5D-C92674D400D4}.Debug - NvFBC|x64.Build.0 = Debug - NvFBC|x64
{D439DE3E-32FB-4599-8B5D-C92674D400D4}.Debug - NvFBC|x86.ActiveCfg = Debug - NvFBC|Win32
{D439DE3E-32FB-4599-8B5D-C92674D400D4}.Debug - NvFBC|x86.Build.0 = Debug - NvFBC|Win32
{D439DE3E-32FB-4599-8B5D-C92674D400D4}.Debug|x64.ActiveCfg = Debug|x64
{D439DE3E-32FB-4599-8B5D-C92674D400D4}.Debug|x64.Build.0 = Debug|x64
{D439DE3E-32FB-4599-8B5D-C92674D400D4}.Debug|x86.ActiveCfg = Debug|Win32
{D439DE3E-32FB-4599-8B5D-C92674D400D4}.Debug|x86.Build.0 = Debug|Win32
{D439DE3E-32FB-4599-8B5D-C92674D400D4}.Release - NvFBC|x64.ActiveCfg = Release - NvFBC|x64
{D439DE3E-32FB-4599-8B5D-C92674D400D4}.Release - NvFBC|x64.Build.0 = Release - NvFBC|x64
{D439DE3E-32FB-4599-8B5D-C92674D400D4}.Release - NvFBC|x86.ActiveCfg = Release - NvFBC|Win32
{D439DE3E-32FB-4599-8B5D-C92674D400D4}.Release - NvFBC|x86.Build.0 = Release - NvFBC|Win32
{D439DE3E-32FB-4599-8B5D-C92674D400D4}.Release|x64.ActiveCfg = Release|x64
{D439DE3E-32FB-4599-8B5D-C92674D400D4}.Release|x64.Build.0 = Release|x64
{D439DE3E-32FB-4599-8B5D-C92674D400D4}.Release|x86.ActiveCfg = Release|Win32
{D439DE3E-32FB-4599-8B5D-C92674D400D4}.Release|x86.Build.0 = Release|Win32
{6CC4DA30-6FBD-4ACA-9BA6-2DE731032800}.Debug - NvFBC|x64.ActiveCfg = Debug - NvFBC|x64
{6CC4DA30-6FBD-4ACA-9BA6-2DE731032800}.Debug - NvFBC|x64.Build.0 = Debug - NvFBC|x64
{6CC4DA30-6FBD-4ACA-9BA6-2DE731032800}.Debug - NvFBC|x86.ActiveCfg = Debug - NvFBC|Win32
{6CC4DA30-6FBD-4ACA-9BA6-2DE731032800}.Debug - NvFBC|x86.Build.0 = Debug - NvFBC|Win32
{6CC4DA30-6FBD-4ACA-9BA6-2DE731032800}.Debug|x64.ActiveCfg = Debug|x64
{6CC4DA30-6FBD-4ACA-9BA6-2DE731032800}.Debug|x64.Build.0 = Debug|x64
{6CC4DA30-6FBD-4ACA-9BA6-2DE731032800}.Debug|x86.ActiveCfg = Debug|Win32
{6CC4DA30-6FBD-4ACA-9BA6-2DE731032800}.Debug|x86.Build.0 = Debug|Win32
{6CC4DA30-6FBD-4ACA-9BA6-2DE731032800}.Release - NvFBC|x64.ActiveCfg = Release - NvFBC|x64
{6CC4DA30-6FBD-4ACA-9BA6-2DE731032800}.Release - NvFBC|x64.Build.0 = Release - NvFBC|x64
{6CC4DA30-6FBD-4ACA-9BA6-2DE731032800}.Release - NvFBC|x86.ActiveCfg = Release - NvFBC|Win32
{6CC4DA30-6FBD-4ACA-9BA6-2DE731032800}.Release - NvFBC|x86.Build.0 = Release - NvFBC|Win32
{6CC4DA30-6FBD-4ACA-9BA6-2DE731032800}.Release|x64.ActiveCfg = Release|x64
{6CC4DA30-6FBD-4ACA-9BA6-2DE731032800}.Release|x64.Build.0 = Release|x64
{6CC4DA30-6FBD-4ACA-9BA6-2DE731032800}.Release|x86.ActiveCfg = Release|Win32
{6CC4DA30-6FBD-4ACA-9BA6-2DE731032800}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@@ -1,453 +0,0 @@
/*
Looking Glass - KVM FrameRelay (KVMFR) Client
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 "MFT/H264.h"
#include "WinDebug.h"
#include "common/memcpySSE.h"
#include <mfapi.h>
#include <mfidl.h>
#include <mfreadwrite.h>
#include <wmcodecdsp.h>
#include <codecapi.h>
#include <mferror.h>
#include <evr.h>
using namespace MFT;
#if __MINGW32__
EXTERN_GUID(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, 0xa634a91c, 0x822b, 0x41b9, 0xa4, 0x94, 0x4d, 0xe4, 0x64, 0x36, 0x12, 0xb0);
EXTERN_GUID(MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING, 0xf81da2c, 0xb537, 0x4672, 0xa8, 0xb2, 0xa6, 0x81, 0xb1, 0x73, 0x07, 0xa3);
EXTERN_GUID(MF_SA_D3D11_AWARE, 0x206b4fc8, 0xfcf9, 0x4c51, 0xaf, 0xe3, 0x97, 0x64, 0x36, 0x9e, 0x33, 0xa0);
#define METransformUnknown 600
#define METransformNeedInput 601
#define METransformHaveOutput 602
#define METransformDrainComplete 603
#define METransformMarker 604
#endif
MFT::H264::H264() :
m_cRef(1)
{
MFStartup(MF_VERSION);
}
MFT::H264::~H264()
{
DeInitialize();
}
bool MFT::H264::Initialize(ID3D11DevicePtr device, unsigned int width, unsigned int height)
{
DeInitialize();
HRESULT status;
MFT_REGISTER_TYPE_INFO typeInfo;
IMFActivate **activationPointers;
UINT32 activationPointerCount;
m_device = device;
m_width = width;
m_height = height;
m_encodeEvent = CreateEvent(NULL, TRUE , FALSE, NULL);
m_shutdownEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
InitializeCriticalSection(&m_encodeCS);
ID3D10MultithreadPtr mt(m_device);
mt->SetMultithreadProtected(TRUE);
mt = NULL;
typeInfo.guidMajorType = MFMediaType_Video;
typeInfo.guidSubtype = MFVideoFormat_H264;
status = MFTEnumEx(
MFT_CATEGORY_VIDEO_ENCODER,
MFT_ENUM_FLAG_HARDWARE,
NULL,
&typeInfo,
&activationPointers,
&activationPointerCount
);
if (FAILED(status))
{
DEBUG_WINERROR("Failed to enumerate encoder MFTs", status);
return false;
}
if (activationPointerCount == 0)
{
DEBUG_WINERROR("Hardware H264 MFT not available", status);
return false;
}
{
UINT32 nameLen = 0;
activationPointers[0]->GetStringLength(MFT_FRIENDLY_NAME_Attribute, &nameLen);
wchar_t * name = new wchar_t[nameLen + 1];
activationPointers[0]->GetString(MFT_FRIENDLY_NAME_Attribute, name, nameLen + 1, NULL);
DEBUG_INFO("Using Encoder: %S", name);
delete[] name;
}
m_mfActivation = activationPointers[0];
CoTaskMemFree(activationPointers);
status = m_mfActivation->ActivateObject(IID_PPV_ARGS(&m_mfTransform));
if (FAILED(status))
{
DEBUG_WINERROR("Failed to create H264 encoder MFT", status);
return false;
}
IMFAttributesPtr attribs;
m_mfTransform->GetAttributes(&attribs);
attribs->SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, TRUE);
attribs->SetUINT32(MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING, TRUE);
attribs->SetUINT32(MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING, TRUE);
attribs->SetUINT32(MF_LOW_LATENCY, TRUE);
UINT32 d3d11Aware = 0;
UINT32 async = 0;
attribs->GetUINT32(MF_TRANSFORM_ASYNC, &async);
attribs->GetUINT32(MF_SA_D3D11_AWARE, &d3d11Aware);
if (async)
attribs->SetUINT32(MF_TRANSFORM_ASYNC_UNLOCK, TRUE);
attribs = NULL;
status = m_mfTransform.QueryInterface(IID_PPV_ARGS(&m_mediaEventGen));
if (FAILED(status))
{
DEBUG_WINERROR("Failed to obtain the media event generator interface", status);
return false;
}
status = m_mediaEventGen->BeginGetEvent(this, NULL);
if (FAILED(status))
{
DEBUG_WINERROR("Failed to set the begin get event", status);
return false;
}
if (d3d11Aware)
{
MFCreateDXGIDeviceManager(&m_resetToken, &m_mfDeviceManager);
status = m_mfDeviceManager->ResetDevice(m_device, m_resetToken);
if (FAILED(status))
{
DEBUG_WINERROR("Failed to call reset device", status);
return false;
}
status = m_mfTransform->ProcessMessage(MFT_MESSAGE_SET_D3D_MANAGER, ULONG_PTR(m_mfDeviceManager.GetInterfacePtr()));
if (FAILED(status))
{
DEBUG_WINERROR("Failed to set the D3D manager", status);
return false;
}
}
IMFMediaTypePtr outType;
MFCreateMediaType(&outType);
outType->SetGUID (MF_MT_MAJOR_TYPE , MFMediaType_Video );
outType->SetGUID (MF_MT_SUBTYPE , MFVideoFormat_H264 );
outType->SetUINT32(MF_MT_AVG_BITRATE , 384 * 1000 );
outType->SetUINT32(MF_MT_INTERLACE_MODE , MFVideoInterlace_Progressive);
outType->SetUINT32(MF_MT_MPEG2_PROFILE , eAVEncH264VProfile_High );
outType->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE);
MFSetAttributeSize (outType, MF_MT_FRAME_SIZE , m_width, m_height);
MFSetAttributeRatio(outType, MF_MT_FRAME_RATE , 60 , 1 );
MFSetAttributeRatio(outType, MF_MT_PIXEL_ASPECT_RATIO, 1 , 1 );
status = m_mfTransform->SetOutputType(0, outType, 0);
outType = NULL;
if (FAILED(status))
{
DEBUG_WINERROR("Failed to set the output media type on the H264 encoder MFT", status);
return false;
}
IMFMediaTypePtr inType;
MFCreateMediaType(&inType);
inType->SetGUID (MF_MT_MAJOR_TYPE , MFMediaType_Video );
inType->SetGUID (MF_MT_SUBTYPE , MFVideoFormat_NV12 );
inType->SetUINT32(MF_MT_INTERLACE_MODE , MFVideoInterlace_Progressive);
inType->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE );
MFSetAttributeSize (inType, MF_MT_FRAME_SIZE , m_width, m_height);
MFSetAttributeRatio(inType, MF_MT_FRAME_RATE , 60 , 1 );
MFSetAttributeRatio(inType, MF_MT_PIXEL_ASPECT_RATIO, 1 , 1 );
status = m_mfTransform->SetInputType(0, inType, 0);
inType = NULL;
if (FAILED(status))
{
DEBUG_WINERROR("Failed to set the input media type on the H264 encoder MFT", status);
return false;
}
m_mfTransform->ProcessMessage(MFT_MESSAGE_COMMAND_FLUSH, 0);
m_mfTransform->ProcessMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0);
m_mfTransform->ProcessMessage(MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0);
return true;
}
void MFT::H264::DeInitialize()
{
if (m_mediaEventGen)
{
m_mfTransform->ProcessMessage(MFT_MESSAGE_NOTIFY_END_OF_STREAM, 0);
m_mfTransform->ProcessMessage(MFT_MESSAGE_COMMAND_DRAIN, 0);
while (WaitForSingleObject(m_shutdownEvent, INFINITE) != WAIT_OBJECT_0) {}
m_mfTransform->DeleteInputStream(0);
}
m_mediaEventGen = NULL;
m_mfTransform = NULL;
m_mfDeviceManager = NULL;
if (m_encodeEvent)
{
CloseHandle(m_encodeEvent );
CloseHandle(m_shutdownEvent);
m_encodeEvent = NULL;
m_shutdownEvent = NULL;
DeleteCriticalSection(&m_encodeCS);
}
if (m_mfActivation)
{
m_mfActivation->ShutdownObject();
m_mfActivation = NULL;
}
}
unsigned int MFT::H264::Process()
{
while(true)
{
// only reset the event if there isn't work pending
EnterCriticalSection(&m_encodeCS);
if (!m_encodeHasData && !m_encodeNeedsData)
ResetEvent(m_encodeEvent);
LeaveCriticalSection(&m_encodeCS);
switch (WaitForSingleObject(m_encodeEvent, 1000))
{
case WAIT_FAILED:
DEBUG_WINERROR("Wait for encode event failed", GetLastError());
return H264_EVENT_ERROR;
case WAIT_ABANDONED:
DEBUG_ERROR("Wait abandoned");
return H264_EVENT_ERROR;
case WAIT_TIMEOUT:
continue;
case WAIT_OBJECT_0:
break;
}
unsigned int events = 0;
EnterCriticalSection(&m_encodeCS);
if (m_encodeNeedsData) events |= H264_EVENT_NEEDS_DATA;
if (m_encodeHasData ) events |= H264_EVENT_HAS_DATA;
LeaveCriticalSection(&m_encodeCS);
return events;
}
return H264_EVENT_ERROR;
}
bool MFT::H264::ProvideFrame(ID3D11Texture2DPtr texture)
{
EnterCriticalSection(&m_encodeCS);
if (!m_encodeNeedsData)
{
LeaveCriticalSection(&m_encodeCS);
return false;
}
m_encodeNeedsData = false;
LeaveCriticalSection(&m_encodeCS);
HRESULT status;
IMFMediaBufferPtr buffer;
status = MFCreateDXGISurfaceBuffer(__uuidof(ID3D11Texture2D), texture, 0, FALSE, &buffer);
if (FAILED(status))
{
DEBUG_WINERROR("Failed to create DXGI surface buffer from texture", status);
return false;
}
IMF2DBufferPtr imfBuffer(buffer);
DWORD length;
imfBuffer->GetContiguousLength(&length);
buffer->SetCurrentLength(length);
IMFSamplePtr sample;
MFCreateSample(&sample);
sample->AddBuffer(buffer);
status = m_mfTransform->ProcessInput(0, sample, 0);
if (FAILED(status))
{
DEBUG_WINERROR("Failed to process the input", status);
return false;
}
return true;
}
bool MFT::H264::GetFrame(void * buffer, const size_t bufferSize, unsigned int & dataLen)
{
EnterCriticalSection(&m_encodeCS);
if (!m_encodeHasData)
{
LeaveCriticalSection(&m_encodeCS);
return false;
}
m_encodeHasData = false;
LeaveCriticalSection(&m_encodeCS);
HRESULT status;
MFT_OUTPUT_STREAM_INFO streamInfo;
status = m_mfTransform->GetOutputStreamInfo(0, &streamInfo);
if (FAILED(status))
{
DEBUG_WINERROR("GetOutputStreamInfo", status);
return false;
}
DWORD outStatus;
MFT_OUTPUT_DATA_BUFFER outDataBuffer = { 0 };
status = m_mfTransform->ProcessOutput(0, 1, &outDataBuffer, &outStatus);
if (FAILED(status))
{
DEBUG_WINERROR("ProcessOutput", status);
return false;
}
IMFMediaBufferPtr mb;
outDataBuffer.pSample->ConvertToContiguousBuffer(&mb);
BYTE *pixels;
DWORD curLen;
mb->Lock(&pixels, NULL, &curLen);
memcpy(buffer, pixels, curLen);
mb->Unlock();
if (outDataBuffer.pSample)
outDataBuffer.pSample->Release();
if (outDataBuffer.pEvents)
outDataBuffer.pEvents->Release();
dataLen = curLen;
return true;
}
STDMETHODIMP MFT::H264::Invoke(IMFAsyncResult * pAsyncResult)
{
HRESULT status, evtStatus;
MediaEventType meType = MEUnknown;
IMFMediaEventPtr pEvent = NULL;
status = m_mediaEventGen->EndGetEvent(pAsyncResult, &pEvent);
if (FAILED(status))
{
DEBUG_WINERROR("EndGetEvent", status);
return status;
}
status = pEvent->GetStatus(&evtStatus);
if (FAILED(status))
{
DEBUG_WINERROR("GetStatus", status);
return status;
}
if (FAILED(evtStatus))
{
DEBUG_WINERROR("evtStatus", evtStatus);
return evtStatus;
}
status = pEvent->GetType(&meType);
if (FAILED(status))
{
DEBUG_WINERROR("GetType", status);
return status;
}
switch (meType)
{
case METransformNeedInput:
EnterCriticalSection(&m_encodeCS);
m_encodeNeedsData = true;
SetEvent(m_encodeEvent);
LeaveCriticalSection(&m_encodeCS);
break;
case METransformHaveOutput:
EnterCriticalSection(&m_encodeCS);
m_encodeHasData = true;
SetEvent(m_encodeEvent);
LeaveCriticalSection(&m_encodeCS);
break;
case METransformDrainComplete:
{
status = m_mfTransform->ProcessMessage(MFT_MESSAGE_COMMAND_FLUSH, 0);
if (FAILED(status))
{
DEBUG_WINERROR("MFT_MESSAGE_COMMAND_FLUSH", status);
return status;
}
SetEvent(m_shutdownEvent);
return S_OK;
}
case MEError:
DEBUG_INFO("err");
break;
default:
DEBUG_INFO("unk");
break;
}
status = m_mediaEventGen->BeginGetEvent(this, NULL);
if (FAILED(status))
{
DEBUG_WINERROR("BeginGetEvent", status);
return status;
}
return status;
}

View File

@@ -1,101 +0,0 @@
/*
Looking Glass - KVM FrameRelay (KVMFR) Client
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
*/
#pragma once
#define W32_LEAN_AND_MEAN
#include <windows.h>
#include <shlwapi.h>
#include <stdio.h>
#include "Com.h"
namespace MFT
{
enum H264_Event
{
H264_EVENT_ENCODE = 0x01,
H264_EVENT_NEEDS_DATA = 0x04,
H264_EVENT_HAS_DATA = 0x08,
H264_EVENT_ERROR = 0x10
};
class H264: public IMFAsyncCallback
{
public:
H264();
~H264();
bool Initialize(ID3D11DevicePtr device, unsigned int width, unsigned int height);
void DeInitialize();
unsigned int Process();
bool ProvideFrame(ID3D11Texture2DPtr texture);
bool GetFrame(void * buffer, const size_t bufferSize, unsigned int & dataLen);
ID3D11DevicePtr m_device;
unsigned int m_width;
unsigned int m_height;
HANDLE m_encodeEvent;
HANDLE m_shutdownEvent;
bool m_encodeNeedsData;
bool m_encodeHasData;
CRITICAL_SECTION m_encodeCS;
UINT m_resetToken;
IMFDXGIDeviceManagerPtr m_mfDeviceManager;
IMFActivatePtr m_mfActivation;
IMFTransformPtr m_mfTransform;
IMFMediaEventGeneratorPtr m_mediaEventGen;
/*
Junk needed for the horrid IMFAsyncCallback interface
*/
STDMETHODIMP QueryInterface(REFIID riid, void ** ppv)
{
if (riid == __uuidof(IUnknown) || riid == __uuidof(IMFAsyncCallback)) {
*ppv = static_cast<IMFAsyncCallback*>(this);
AddRef();
return S_OK;
}
else {
*ppv = NULL;
return E_NOINTERFACE;
}
}
STDMETHODIMP_(ULONG) AddRef()
{
return InterlockedIncrement(&m_cRef);
}
STDMETHODIMP_(ULONG) Release()
{
long cRef = InterlockedDecrement(&m_cRef);
if (!cRef)
delete this;
return cRef;
}
STDMETHODIMP GetParameters(DWORD *pdwFlags, DWORD *pdwQueue) { return E_NOTIMPL; }
STDMETHODIMP Invoke(IMFAsyncResult *pAsyncResult);
private:
long m_cRef;
};
};

View File

@@ -1,59 +0,0 @@
BINARY = looking-glass-host.exe
CFLAGS = -g -O3 -march=native -Wall -Werror -I./ -I../common # -DDEBUG
LDFLAGS = -lshlwapi -ldxgi -ld3d11 -lsetupapi -luuid -lole32 -lmfplat -lmfuuid
CFLAGS += -ffast-math
CFLAGS += -fdata-sections -ffunction-sections
CFLAGS += -I../ -I.
LDFLAGS += -Wl,--gc-sections -mwindows
CFLAGS += -DWINVER=0x0602 -DUNICODE
PREFIX ?= x86_64-w64-mingw32-
STRIP = $(PREFIX)strip
CC = $(PREFIX)cc
CXX = $(PREFIX)c++
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
ifeq ($(ENABLE_TRACING),1)
CFLAGS += -DENABLE_TRACING
OBJS += TraceUtil.o
endif
ifeq ($(CONFIG_CAPTURE_NVFBC),1)
CFLAGS += -DCONFIG_CAPTURE_NVFBC=1 -I../vendor
OBJS += Capture/NvFBC.o
endif
BUILD_OBJS = $(foreach obj,$(OBJS),$(BUILD)/$(obj))
all: $(BIN)/$(BINARY)
$(BUILD)/%.o: %.c
@mkdir -p $(dir $@)
$(CC) -c $(CFLAGS) -o $@ $<
$(BUILD)/%.o: %.cpp
@mkdir -p $(dir $@)
$(CXX) -c $(CFLAGS) -o $@ $<
$(BIN)/$(BINARY): $(BUILD_OBJS)
@mkdir -p $(dir $@)
$(LD) -o $@ $^ $(LDFLAGS)
$(STRIP) -s $@
clean:
rm -rf $(BUILD) $(BIN)
.PHONY: clean

View File

@@ -1,391 +0,0 @@
/*
Looking Glass - KVM FrameRelay (KVMFR) Client
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 "Service.h"
#include "IVSHMEM.h"
#include "TraceUtil.h"
#include "common/debug.h"
#include "common/KVMFR.h"
#include "Util.h"
#include "CaptureFactory.h"
PCI_DEVICE Service::s_dev = {0x13, 0x01, 0x00};
Service::Service() :
m_initialized(false),
m_memory(NULL),
m_timer(NULL),
m_capture(NULL),
m_shmHeader(NULL),
m_frameIndex(0),
m_cursorDataSize(0),
m_cursorData(NULL)
{
m_consoleSessionID = WTSGetActiveConsoleSessionId();
m_ivshmem = IVSHMEM::Get();
if (!m_ivshmem->Initialize(s_dev))
throw "IVSHMEM failed to initalize";
if (m_ivshmem->GetSize() < sizeof(KVMFRHeader))
throw "Shared memory is not large enough for the KVMFRHeader";
m_memory = static_cast<uint8_t*>(m_ivshmem->GetMemory());
if (!m_memory)
throw "Failed to get IVSHMEM memory";
if (!InitPointers())
throw "Failed to initialize the shared memory pointers";
}
Service::~Service()
{
DeInitialize();
}
LRESULT Service::LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == HC_ACTION && wParam == WM_MOUSEMOVE)
{
MSLLHOOKSTRUCT *msg = (MSLLHOOKSTRUCT *)lParam;
volatile KVMFRCursor * cursor = &(m_shmHeader->cursor);
volatile char * flags = (volatile char *)&(cursor->flags);
cursor->x = (int16_t)msg->pt.x;
cursor->y = (int16_t)msg->pt.y;
INTERLOCKED_OR8(flags, KVMFR_CURSOR_FLAG_POS);
}
return CallNextHookEx(m_mouseHook, nCode, wParam, lParam);
}
bool Service::Initialize(ICapture * captureDevice)
{
if (m_initialized)
DeInitialize();
m_tryTarget = 0;
m_capture = captureDevice;
if (m_capture->GetMaxFrameSize() > m_frameSize)
{
DEBUG_ERROR("Maximum frame size of %zu bytes excceds maximum space available", m_capture->GetMaxFrameSize());
DeInitialize();
return false;
}
// Create the cursor thread
m_cursorThread = CreateThread(NULL, 0, _CursorThread, NULL, 0, NULL);
m_cursorEvent = CreateEvent (NULL, FALSE, FALSE, L"CursorEvent");
InitializeCriticalSection(&m_cursorCS);
// update everything except for the hostID
memcpy(m_shmHeader->magic, KVMFR_HEADER_MAGIC, sizeof(KVMFR_HEADER_MAGIC));
m_shmHeader->version = KVMFR_HEADER_VERSION;
// zero and tell the client we have restarted
ZeroMemory(&(m_shmHeader->frame ), sizeof(KVMFRFrame ));
ZeroMemory(&(m_shmHeader->cursor), sizeof(KVMFRCursor));
m_shmHeader->flags &= ~KVMFR_HEADER_FLAG_RESTART;
m_haveFrame = false;
m_initialized = true;
m_running = true;
return true;
}
#define ALIGN_DN(x) ((uintptr_t)(x) & ~0x7F)
#define ALIGN_UP(x) ALIGN_DN(x + 0x7F)
bool Service::InitPointers()
{
m_shmHeader = reinterpret_cast<KVMFRHeader *>(m_memory);
m_cursorData = (uint8_t *)ALIGN_UP(m_memory + sizeof(KVMFRHeader));
m_cursorDataSize = 1048576; // 1MB fixed for cursor size, should be more then enough
m_cursorOffset = m_cursorData - m_memory;
uint8_t * m_frames = (uint8_t *)ALIGN_UP(m_cursorData + m_cursorDataSize);
m_frameSize = ALIGN_DN((m_ivshmem->GetSize() - (m_frames - m_memory)) / MAX_FRAMES);
DEBUG_INFO("Total Available : %3u MB", (unsigned int)(m_ivshmem->GetSize() / 1024 / 1024));
DEBUG_INFO("Max Cursor Size : %3u MB", (unsigned int)(m_cursorDataSize / 1024 / 1024));
DEBUG_INFO("Max Frame Size : %3u MB", (unsigned int)(m_frameSize / 1024 / 1024));
DEBUG_INFO("Cursor : %p (0x%08x)", m_cursorData, (int)m_cursorOffset);
for (int i = 0; i < MAX_FRAMES; ++i)
{
m_frame[i] = m_frames + i * m_frameSize;
m_dataOffset[i] = m_frame[i] - m_memory;
DEBUG_INFO("Frame %d : %p (0x%08x)", i, m_frame[i], (int)m_dataOffset[i]);
}
return true;
}
void Service::DeInitialize()
{
m_running = false;
WaitForSingleObject(m_cursorThread, INFINITE);
CloseHandle(m_cursorThread);
CloseHandle(m_cursorEvent);
m_shmHeader = NULL;
m_cursorData = NULL;
m_cursorDataSize = 0;
m_cursorOffset = 0;
m_haveFrame = false;
for(int i = 0; i < MAX_FRAMES; ++i)
{
m_frame [i] = NULL;
m_dataOffset[i] = 0;
}
m_frameSize = 0;
m_ivshmem->DeInitialize();
if (m_capture)
{
m_capture->DeInitialize();
m_capture = NULL;
}
m_memory = NULL;
m_initialized = false;
}
bool Service::ReInit(volatile char * flags)
{
DEBUG_INFO("ReInitialize Requested");
INTERLOCKED_OR8(flags, KVMFR_HEADER_FLAG_PAUSED);
if (WTSGetActiveConsoleSessionId() != m_consoleSessionID)
{
DEBUG_INFO("User switch detected, waiting to regain control");
while (WTSGetActiveConsoleSessionId() != m_consoleSessionID)
Sleep(100);
}
while (!m_capture->CanInitialize())
Sleep(100);
if (!m_capture->ReInitialize())
{
DEBUG_ERROR("ReInitialize Failed");
return false;
}
if (m_capture->GetMaxFrameSize() > m_frameSize)
{
DEBUG_ERROR("Maximum frame size of %zd bytes excceds maximum space available", m_capture->GetMaxFrameSize());
return false;
}
INTERLOCKED_AND8(flags, ~KVMFR_HEADER_FLAG_PAUSED);
return true;
}
ProcessStatus Service::Process()
{
if (!m_initialized)
return PROCESS_STATUS_ERROR;
volatile char * flags = (volatile char *)&(m_shmHeader->flags);
// check if the client has flagged a restart
if (*flags & KVMFR_HEADER_FLAG_RESTART)
{
DEBUG_INFO("Restart Requested");
if (!m_capture->ReInitialize())
{
DEBUG_ERROR("ReInitialize Failed");
return PROCESS_STATUS_ERROR;
}
if (m_capture->GetMaxFrameSize() > m_frameSize)
{
DEBUG_ERROR("Maximum frame size of %zd bytes exceeds maximum space available", m_capture->GetMaxFrameSize());
return PROCESS_STATUS_ERROR;
}
INTERLOCKED_AND8(flags, ~(KVMFR_HEADER_FLAG_RESTART));
}
unsigned int status;
bool notify = false;
status = m_capture->Capture();
if (status & GRAB_STATUS_ERROR)
{
DEBUG_WARN("Capture error, retrying");
return PROCESS_STATUS_RETRY;
}
if (status & GRAB_STATUS_TIMEOUT)
{
// timeouts should not count towards a failure to capture
if (!m_haveFrame)
return PROCESS_STATUS_OK;
notify = true;
}
if (status & GRAB_STATUS_REINIT)
{
if (!ReInit(flags))
return PROCESS_STATUS_ERROR;
// re-init request should not count towards a failure to capture
return PROCESS_STATUS_OK;
}
if ((status & (GRAB_STATUS_OK | GRAB_STATUS_TIMEOUT)) == 0)
{
DEBUG_ERROR("Capture interface returned an unexpected result");
return PROCESS_STATUS_ERROR;
}
if (status & GRAB_STATUS_CURSOR)
SetEvent(m_cursorEvent);
volatile KVMFRFrame * fi = &(m_shmHeader->frame);
if (status & GRAB_STATUS_FRAME)
{
FrameInfo frame = { 0 };
frame.buffer = m_frame[m_frameIndex];
frame.bufferSize = m_frameSize;
GrabStatus result = m_capture->GetFrame(frame);
if (result != GRAB_STATUS_OK)
{
if (result == GRAB_STATUS_REINIT)
{
if (!ReInit(flags))
return PROCESS_STATUS_ERROR;
// re-init request should not count towards a failure to capture
return PROCESS_STATUS_OK;
}
DEBUG_INFO("GetFrame failed");
return PROCESS_STATUS_ERROR;
}
/* don't touch the frame information until the client is done with it */
while (fi->flags & KVMFR_FRAME_FLAG_UPDATE)
{
/* this generally never occurs */
Sleep(1);
if (*flags & KVMFR_HEADER_FLAG_RESTART)
break;
}
fi->type = m_capture->GetFrameType();
fi->width = frame.width;
fi->height = frame.height;
fi->stride = frame.stride;
fi->pitch = frame.pitch;
fi->dataPos = m_dataOffset[m_frameIndex];
if (++m_frameIndex == MAX_FRAMES)
m_frameIndex = 0;
// remember that we have a valid frame
m_haveFrame = true;
notify = true;
}
if (notify)
{
/* don't touch the frame inforamtion until the client is done with it */
while (fi->flags & KVMFR_FRAME_FLAG_UPDATE)
{
if (*flags & KVMFR_HEADER_FLAG_RESTART)
break;
}
// signal a frame update
fi->flags |= KVMFR_FRAME_FLAG_UPDATE;
}
// update the flags
INTERLOCKED_AND8(flags, KVMFR_HEADER_FLAG_RESTART);
return PROCESS_STATUS_OK;
}
DWORD Service::CursorThread()
{
while(m_running)
{
if (WaitForSingleObject(m_cursorEvent, 1000) != WAIT_OBJECT_0)
continue;
CursorInfo ci;
while (m_capture->GetCursor(ci))
{
volatile KVMFRCursor * cursor = &(m_shmHeader->cursor);
// wait until the client is ready
while ((cursor->flags & ~KVMFR_CURSOR_FLAG_POS) != 0)
{
Sleep(1);
if (!m_capture)
return 0;
}
uint8_t flags = cursor->flags;
if (ci.hasPos)
{
cursor->x = ci.x;
cursor->y = ci.y;
flags |= KVMFR_CURSOR_FLAG_POS;
}
if (ci.hasShape)
{
if (ci.shape.pointerSize > m_cursorDataSize)
DEBUG_ERROR("Cursor size exceeds allocated space");
else
{
// give the client the new cursor shape
flags |= KVMFR_CURSOR_FLAG_SHAPE;
++cursor->version;
cursor->type = ci.type;
cursor->width = ci.w;
cursor->height = ci.h;
cursor->pitch = ci.pitch;
cursor->dataPos = m_cursorOffset;
memcpy(m_cursorData, ci.shape.buffer, ci.shape.bufferSize);
}
}
if (ci.visible)
flags |= KVMFR_CURSOR_FLAG_VISIBLE;
flags |= KVMFR_CURSOR_FLAG_UPDATE;
cursor->flags = flags;
m_capture->FreeCursor();
}
}
return 0;
}

View File

@@ -1,114 +0,0 @@
/*
Looking Glass - KVM FrameRelay (KVMFR) Client
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
*/
#pragma once
#define W32_LEAN_AND_MEAN
#include <windows.h>
#include <stdbool.h>
#include "IVSHMEM.h"
#include "ICapture.h"
#include "common/debug.h"
#define MAX_FRAMES 2
enum ProcessStatus
{
PROCESS_STATUS_OK,
PROCESS_STATUS_RETRY,
PROCESS_STATUS_ERROR
};
class Service
{
public:
static Service & Instance()
{
static Service service;
return service;
}
static void InstallHook()
{
if (Instance().m_mouseHook)
RemoveHook();
Instance().m_mouseHook = SetWindowsHookEx(WH_MOUSE_LL, _LowLevelMouseProc, NULL, 0);
}
static void RemoveHook()
{
if (Instance().m_mouseHook)
{
UnhookWindowsHookEx(Instance().m_mouseHook);
Instance().m_mouseHook = NULL;
}
}
static void SetDevice(PCI_DEVICE dev)
{
s_dev = dev;
}
bool Initialize(ICapture * captureDevice);
void DeInitialize();
ProcessStatus Process();
private:
bool InitPointers();
int m_tryTarget;
int m_lastTryCount;
Service();
~Service();
HHOOK m_mouseHook;
LRESULT LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam);
static LRESULT WINAPI _LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam) { return Service::Instance().LowLevelMouseProc(nCode, wParam, lParam); }
bool ReInit(volatile char * flags);
bool m_initialized;
bool m_running;
DWORD m_consoleSessionID;
uint8_t * m_memory;
IVSHMEM * m_ivshmem;
HANDLE m_timer;
ICapture * m_capture;
KVMFRHeader * m_shmHeader;
bool m_haveFrame;
uint8_t * m_frame[MAX_FRAMES];
size_t m_frameSize;
uint64_t m_dataOffset[MAX_FRAMES];
int m_frameIndex;
static PCI_DEVICE s_dev;
static DWORD WINAPI _CursorThread(LPVOID lpParameter) { return Service::Instance().CursorThread(); }
DWORD CursorThread();
HANDLE m_cursorThread;
HANDLE m_cursorEvent;
CRITICAL_SECTION m_cursorCS;
size_t m_cursorDataSize;
uint8_t * m_cursorData;
uint64_t m_cursorOffset;
};

View File

@@ -1,13 +0,0 @@
Texture2D texTexture;
SamplerState texSampler;
struct VS
{
float4 pos : SV_Position;
float2 tex : TEXCOORD;
};
float4 main(VS input): SV_Target
{
return texTexture.Sample(texSampler, input.tex);
}

View File

@@ -1,31 +0,0 @@
Texture2D texTexture;
SamplerState texSampler;
struct VS
{
float4 pos : SV_Position;
float2 tex : TEXCOORD;
};
struct OUT
{
float4 y: SV_TARGET0;
float4 u: SV_TARGET1;
float4 v: SV_TARGET2;
};
OUT main(VS input)
{
OUT o;
const float4 rgba = texTexture.Sample(texSampler, input.tex);
o.y.gba = 1.0f;
o.u.gba = 1.0f;
o.v.gba = 1.0f;
o.y.r = rgba.r * 0.2126 + 0.7152 * rgba.g + 0.0722 * rgba.b;
o.u.r = ((rgba.b - o.y.r) / 1.8556) + 0.5;
o.v.r = ((rgba.r - o.y.r) / 1.5748) + 0.5;
return o;
}

View File

@@ -1,16 +0,0 @@
struct VS
{
float4 pos : POSITION;
float2 tex : TEXCOORD;
};
struct PS
{
float4 pos : SV_Position;
float2 tex : TEXCOORD;
};
PS main(VS input)
{
return input;
}

View File

@@ -1,418 +0,0 @@
/*
Looking Glass - KVM FrameRelay (KVMFR) Client
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 "TextureConverter.h"
#include "common\debug.h"
#include "Shaders\Vertex.h"
#include "Shaders\Pixel.h"
#include "Shaders\RGBtoYUV.h"
TextureConverter::TextureConverter()
{
}
TextureConverter::~TextureConverter()
{
DeInitialize();
}
bool TextureConverter::Initialize(
ID3D11DeviceContextPtr deviceContext,
ID3D11DevicePtr device,
const unsigned int width,
const unsigned int height,
FrameType format
)
{
HRESULT result;
D3D11_TEXTURE2D_DESC texDesc;
D3D11_RENDER_TARGET_VIEW_DESC targetDesc;
D3D11_SHADER_RESOURCE_VIEW_DESC shaderDesc;
D3D11_SAMPLER_DESC samplerDesc;
m_deviceContext = deviceContext;
m_device = device;
m_width = width;
m_height = height;
m_format = format;
result = device->CreatePixelShader(g_Pixel, sizeof(g_Pixel), NULL, &m_psCopy);
if (FAILED(result))
{
DeInitialize();
DEBUG_ERROR("Failed to create the copy pixel shader");
return false;
}
switch (format)
{
case FRAME_TYPE_YUV420:
result = device->CreatePixelShader(g_RGBtoYUV, sizeof(g_RGBtoYUV), NULL, &m_psConversion);
m_texFormats[0] = DXGI_FORMAT_R8_UNORM; m_scaleFormats[0] = 1;
m_texFormats[1] = DXGI_FORMAT_R8_UNORM; m_scaleFormats[1] = 2;
m_texFormats[2] = DXGI_FORMAT_R8_UNORM; m_scaleFormats[2] = 2;
break;
default:
DEBUG_ERROR("Unsupported format");
return false;
}
if (FAILED(result))
{
DeInitialize();
DEBUG_ERROR("Failed to create the pixel shader");
return false;
}
const D3D11_INPUT_ELEMENT_DESC inputDesc[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT , 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 }
};
result = device->CreateInputLayout(inputDesc, _countof(inputDesc), g_Vertex, sizeof(g_Vertex), &m_layout);
if (FAILED(result))
{
DeInitialize();
DEBUG_ERROR("Failed to create the input layout");
return false;
}
result = device->CreateVertexShader(g_Vertex, sizeof(g_Vertex), NULL, &m_vertexShader);
if (FAILED(result))
{
DeInitialize();
DEBUG_ERROR("Failed to create the vertex shader");
return false;
}
ZeroMemory(&texDesc , sizeof(texDesc ));
ZeroMemory(&targetDesc , sizeof(targetDesc ));
ZeroMemory(&shaderDesc , sizeof(shaderDesc ));
ZeroMemory(&samplerDesc, sizeof(samplerDesc));
texDesc.Width = width;
texDesc.Height = height;
texDesc.MipLevels = 1;
texDesc.ArraySize = 1;
texDesc.SampleDesc.Count = 1;
texDesc.Usage = D3D11_USAGE_DEFAULT;
texDesc.CPUAccessFlags = 0;
texDesc.MiscFlags = 0;
texDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
targetDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
shaderDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
shaderDesc.Texture2D.MipLevels = 1;
for(int i = 0; i < _countof(m_targetTexture); ++i)
{
if (m_texFormats[i] == DXGI_FORMAT_UNKNOWN)
continue;
texDesc .Format = m_texFormats[i];
targetDesc.Format = m_texFormats[i];
shaderDesc.Format = m_texFormats[i];
result = device->CreateTexture2D(&texDesc, NULL, &m_targetTexture[i]);
if (FAILED(result))
{
DeInitialize();
DEBUG_ERROR("Failed to create the render texture");
return false;
}
result = device->CreateRenderTargetView(m_targetTexture[i], &targetDesc, &m_renderView[i]);
if (FAILED(result))
{
DeInitialize();
DEBUG_ERROR("Failed to create the render view");
return false;
}
result = device->CreateShaderResourceView(m_targetTexture[i], &shaderDesc, &m_shaderView[i]);
if (FAILED(result))
{
DeInitialize();
DEBUG_ERROR("Failed to create the resource view");
return false;
}
}
samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
samplerDesc.MipLODBias = 0.0f;
samplerDesc.MaxAnisotropy = 1;
samplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
samplerDesc.BorderColor[0] = 1.0f;
samplerDesc.BorderColor[1] = 1.0f;
samplerDesc.BorderColor[2] = 1.0f;
samplerDesc.MinLOD = -FLT_MAX;
samplerDesc.MaxLOD = FLT_MAX;
result = device->CreateSamplerState(&samplerDesc, &m_samplerState);
if (FAILED(result))
{
DeInitialize();
DEBUG_ERROR("Failed to create sampler state");
return false;
}
return IntializeBuffers();
}
bool TextureConverter::IntializeBuffers()
{
struct VS_INPUT * verticies;
unsigned long * indicies;
HRESULT result;
D3D11_BUFFER_DESC vertexDesc, indexDesc;
D3D11_SUBRESOURCE_DATA vertexData, indexData;
m_vertexCount = 4;
m_indexCount = 4;
verticies = new struct VS_INPUT[m_vertexCount];
if (!verticies)
{
DeInitialize();
DEBUG_ERROR("new failure");
return false;
}
indicies = new unsigned long[m_indexCount];
if (!indicies)
{
DeInitialize();
DEBUG_ERROR("new failure");
return false;
}
verticies[0].pos = DirectX::XMFLOAT3(-1.0f, -1.0f, 0.5f); //BL
verticies[1].pos = DirectX::XMFLOAT3(-1.0f, 1.0f, 0.5f); //TL
verticies[2].pos = DirectX::XMFLOAT3( 1.0f, -1.0f, 0.5f); //BR
verticies[3].pos = DirectX::XMFLOAT3( 1.0f, 1.0f, 0.5f); //TR
verticies[0].tex = DirectX::XMFLOAT2(0.0f, 1.0f);
verticies[1].tex = DirectX::XMFLOAT2(0.0f, 0.0f);
verticies[2].tex = DirectX::XMFLOAT2(1.0f, 1.0f);
verticies[3].tex = DirectX::XMFLOAT2(1.0f, 0.0f);
indicies[0] = 0;
indicies[1] = 1;
indicies[2] = 2;
indicies[3] = 3;
vertexDesc.Usage = D3D11_USAGE_DEFAULT;
vertexDesc.ByteWidth = sizeof(struct VS_INPUT) * m_vertexCount;
vertexDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vertexDesc.CPUAccessFlags = 0;
vertexDesc.MiscFlags = 0;
vertexDesc.StructureByteStride = 0;
vertexData.pSysMem = verticies;
vertexData.SysMemPitch = 0;
vertexData.SysMemSlicePitch = 0;
result = m_device->CreateBuffer(&vertexDesc, &vertexData, &m_vertexBuffer);
if (FAILED(result))
{
delete[] indicies;
delete[] verticies;
DeInitialize();
DEBUG_ERROR("Failed to create vertex buffer");
return false;
}
indexDesc.Usage = D3D11_USAGE_DEFAULT;
indexDesc.ByteWidth = sizeof(unsigned long) * m_indexCount;
indexDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
indexDesc.CPUAccessFlags = 0;
indexDesc.MiscFlags = 0;
indexDesc.StructureByteStride = 0;
indexData.pSysMem = indicies;
indexData.SysMemPitch = 0;
indexData.SysMemSlicePitch = 0;
result = m_device->CreateBuffer(&indexDesc, &indexData, &m_indexBuffer);
if (FAILED(result))
{
delete[] indicies;
delete[] verticies;
DeInitialize();
DEBUG_ERROR("Failed to create index buffer");
return false;
}
delete[] indicies;
delete[] verticies;
return true;
}
void TextureConverter::DeInitialize()
{
m_samplerState = NULL;
m_indexBuffer = NULL;
m_indexBuffer = NULL;
for(int i = 0; i < _countof(m_targetTexture); ++i)
{
m_shaderView [i] = NULL;
m_renderView [i] = NULL;
m_targetTexture[i] = NULL;
}
m_vertexShader = NULL;
m_psConversion = NULL;
m_layout = NULL;
m_psCopy = NULL;
}
bool TextureConverter::Convert(ID3D11Texture2DPtr texture, TextureList & output)
{
unsigned int stride;
unsigned int offset;
float color[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
HRESULT result;
D3D11_TEXTURE2D_DESC texDesc;
D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc;
ID3D11ShaderResourceViewPtr textureView;
texture->GetDesc(&texDesc);
viewDesc.Format = texDesc.Format;
viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
viewDesc.Texture2D.MostDetailedMip = 0;
viewDesc.Texture2D.MipLevels = 1;
result = m_device->CreateShaderResourceView(texture, &viewDesc, &textureView);
if (FAILED(result))
{
DeInitialize();
DEBUG_ERROR("Failed to create shader resource view");
return false;
}
ID3D11Buffer *buffers [] = { m_vertexBuffer.GetInterfacePtr() };
ID3D11SamplerState *samplerStates[] = { m_samplerState.GetInterfacePtr() };
ID3D11ShaderResourceView *shaderViews [] = { textureView .GetInterfacePtr() };
D3D11_VIEWPORT viewPorts [] = { {
0.0f , 0.0f,
(float)m_width, (float)m_height,
0.0f , 1.0f
} };
int targetCount = 0;
ID3D11RenderTargetView **renderViews = new ID3D11RenderTargetView*[_countof(m_renderView)];
for(int i = 0; i < _countof(m_renderView); ++i)
{
if (m_texFormats[i] == DXGI_FORMAT_UNKNOWN)
continue;
m_deviceContext->ClearRenderTargetView(m_renderView[i], color);
renderViews[i] = m_renderView[i].GetInterfacePtr();
++targetCount;
}
m_deviceContext->PSSetShaderResources(0, _countof(shaderViews), shaderViews);
m_deviceContext->OMSetRenderTargets(targetCount, renderViews, NULL);
delete [] renderViews;
stride = sizeof(VS_INPUT);
offset = 0;
m_deviceContext->RSSetViewports (_countof(viewPorts), viewPorts);
m_deviceContext->IASetInputLayout (m_layout);
m_deviceContext->IASetVertexBuffers (0, _countof(buffers), buffers, &stride, &offset);
m_deviceContext->IASetIndexBuffer (m_indexBuffer, DXGI_FORMAT_R32_UINT, 0);
m_deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
m_deviceContext->VSSetShader (m_vertexShader, NULL, 0);
m_deviceContext->PSSetSamplers (0, _countof(samplerStates), samplerStates);
m_deviceContext->PSSetShader (m_psConversion, NULL, 0);
m_deviceContext->DrawIndexed(m_indexCount, 0, 0);
textureView = NULL;
D3D11_RENDER_TARGET_VIEW_DESC targetDesc;
ZeroMemory(&targetDesc, sizeof(targetDesc));
targetDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
m_deviceContext->PSSetShader(m_psCopy, NULL, 0);
renderViews = new ID3D11RenderTargetView*[1];
for (int i = 0; i < _countof(m_renderView); ++i)
{
if (m_texFormats[i] == DXGI_FORMAT_UNKNOWN)
continue;
ID3D11Texture2DPtr src = m_targetTexture[i];
ID3D11Texture2DPtr dest;
ID3D11RenderTargetViewPtr view;
D3D11_TEXTURE2D_DESC srcDesc;
// if there is no scaling
if (m_scaleFormats[i] == 1)
{
output.push_back(src);
continue;
}
src->GetDesc(&srcDesc);
viewPorts[0].Width = srcDesc.Width / m_scaleFormats[i];
viewPorts[0].Height = srcDesc.Height / m_scaleFormats[i];
srcDesc.Width = (UINT)viewPorts[0].Width;
srcDesc.Height = (UINT)viewPorts[0].Height;
result = m_device->CreateTexture2D(&srcDesc, NULL, &dest);
if (FAILED(result))
{
delete[] renderViews;
DeInitialize();
DEBUG_ERROR("Failed to create the target texture");
return false;
}
targetDesc.Format = srcDesc.Format;
result = m_device->CreateRenderTargetView(dest, &targetDesc, &view);
if (FAILED(result))
{
delete[] renderViews;
DeInitialize();
DEBUG_ERROR("Failed to create the target view");
return false;
}
renderViews[0] = view.GetInterfacePtr();
shaderViews[0] = m_shaderView[i].GetInterfacePtr();
m_deviceContext->OMSetRenderTargets(1, renderViews, NULL);
m_deviceContext->RSSetViewports(_countof(viewPorts), viewPorts);
m_deviceContext->PSSetShaderResources(0, 1, shaderViews);
m_deviceContext->DrawIndexed(m_indexCount, 0, 0);
output.push_back(dest);
view = NULL;
}
delete[] renderViews;
return true;
}

View File

@@ -1,80 +0,0 @@
/*
Looking Glass - KVM FrameRelay (KVMFR) Client
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
*/
#pragma once
#include "Com.h"
#include "common\KVMFR.h"
#include <DirectXMath.h>
#include <vector>
typedef std::vector<ID3D11Texture2DPtr> TextureList;
class TextureConverter
{
public:
TextureConverter();
~TextureConverter();
bool Initialize(
ID3D11DeviceContextPtr deviceContext,
ID3D11DevicePtr device,
const unsigned int width,
const unsigned int height,
FrameType format
);
void DeInitialize();
bool Convert(ID3D11Texture2DPtr texture, TextureList & output);
private:
struct VS_INPUT
{
DirectX::XMFLOAT3 pos;
DirectX::XMFLOAT2 tex;
};
bool IntializeBuffers();
ID3D11DeviceContextPtr m_deviceContext;
ID3D11DevicePtr m_device;
unsigned int m_width, m_height;
FrameType m_format;
DXGI_FORMAT m_texFormats [3];
unsigned int m_scaleFormats [3];
ID3D11Texture2DPtr m_targetTexture[3];
ID3D11RenderTargetViewPtr m_renderView [3];
ID3D11ShaderResourceViewPtr m_shaderView [3];
ID3D11InputLayoutPtr m_layout;
ID3D11VertexShaderPtr m_vertexShader;
ID3D11PixelShaderPtr m_psCopy;
ID3D11PixelShaderPtr m_psConversion;
ID3D11SamplerStatePtr m_samplerState;
ID3D11BufferPtr m_vertexBuffer;
unsigned int m_vertexCount;
ID3D11BufferPtr m_indexBuffer;
unsigned int m_indexCount;
};

View File

@@ -1,25 +0,0 @@
/*
Looking Glass - KVM FrameRelay (KVMFR) Client
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 "TraceUtil.h"
double TraceUtil::m_freq;
LARGE_INTEGER TraceUtil::m_last;
LARGE_INTEGER TraceUtil::m_start;
const char * TraceUtil::m_traceName;

View File

@@ -1,79 +0,0 @@
/*
Looking Glass - KVM FrameRelay (KVMFR) Client
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
*/
#pragma once
#include <windows.h>
#include <stdint.h>
#include "common/debug.h"
#ifdef ENABLE_TRACING
#define TRACE TraceUtil::Trace(__FUNCTION__, __LINE__)
#define TRACE_START(x) TraceUtil::TraceStart(x)
#define TRACE_END TraceUtil::TraceEnd()
#else
#define TRACE
#define TRACE_START(x)
#define TRACE_END
#endif
class TraceUtil
{
private:
static double m_freq;
static LARGE_INTEGER m_last;
static LARGE_INTEGER m_start;
static const char * m_traceName;
public:
static void Initialize()
{
#ifdef ENABLE_TRACING
LARGE_INTEGER now;
QueryPerformanceFrequency(&now);
m_freq = (double)now.QuadPart / 1000.0;
QueryPerformanceCounter(&m_last);
#endif
}
static inline void Trace(const char * function, const unsigned int line)
{
LARGE_INTEGER now;
QueryPerformanceCounter(&now);
const double diff = (now.QuadPart - m_last.QuadPart) / m_freq;
m_last = now;
DEBUG_INFO("Trace [%8.4f] %s:%u", diff, function, line);
}
static inline void TraceStart(const char * traceName)
{
QueryPerformanceCounter(&m_start);
m_traceName = traceName;
}
static inline void TraceEnd()
{
LARGE_INTEGER now;
QueryPerformanceCounter(&now);
const double diff = (now.QuadPart - m_start.QuadPart) / m_freq;
DEBUG_INFO("Trace [%8.4f] %s", diff, m_traceName);
}
};

View File

@@ -1,154 +0,0 @@
/*
Looking Glass - KVM FrameRelay (KVMFR) Client
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
*/
#pragma once
#include <string>
#include <assert.h>
#include <inttypes.h>
#include <tmmintrin.h>
#include "common/debug.h"
#if !defined(min)
#define LG_MIN(a, b) ((a) < (b) ? (a) : (b))
#else
#define LG_MIN min
#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:
static void DebugWinError(const char * file, const unsigned int line, const char * function, const char * desc, HRESULT status)
{
char *buffer;
FormatMessageA(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
NULL,
status,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(char*)&buffer,
1024,
NULL
);
for(size_t i = strlen(buffer) - 1; i > 0; --i)
if (buffer[i] == '\n' || buffer[i] == '\r')
buffer[i] = 0;
fprintf(stderr, "[E] %20s:%-4u | %-30s | %s: 0x%08x (%s)\n", file, line, function, desc, (int)status, buffer);
LocalFree(buffer);
}
static std::string GetSystemRoot()
{
std::string defaultPath;
#if __MINGW32__
const char * libPath = getenv("SystemRoot");
const size_t libPathLen = strlen(libPath);
#else
char * libPath;
size_t libPathLen;
_dupenv_s(&libPath, &libPathLen, "SystemRoot");
#endif
if (!libPath)
{
DEBUG_ERROR("Unable to get the SystemRoot environment variable");
return defaultPath;
}
if (!libPathLen)
{
DEBUG_ERROR("The SystemRoot environment variable is not set");
#ifndef __MINGW32__
free(libPath);
#endif
return defaultPath;
}
#ifdef _WIN64
defaultPath = std::string(libPath) + "\\System32";
#else
if (IsWow64())
{
defaultPath = std::string(libPath) + "\\Syswow64";
}
else
{
defaultPath = std::string(libPath) + "\\System32";
}
#endif
#ifndef __MINGW32__
free(libPath);
#endif
return defaultPath;
}
static inline void BGRAtoRGB(uint8_t * orig, size_t imagesize, uint8_t * dest)
{
assert((uintptr_t)orig % 16 == 0);
assert((uintptr_t)dest % 16 == 0);
assert(imagesize % 16 == 0);
__m128i mask_right = _mm_set_epi8
(
12, 13, 14, 8,
9, 10, 4, 5,
6, 0, 1, 2,
-128, -128, -128, -128
);
__m128i mask_left = _mm_set_epi8
(
-128, -128, -128, -128,
12, 13, 14, 8,
9, 10, 4, 5,
6, 0, 1, 2
);
uint8_t *end = orig + imagesize * 4;
for (; orig != end; orig += 64, dest += 48)
{
_mm_prefetch((char *)(orig + 128), _MM_HINT_NTA);
_mm_prefetch((char *)(orig + 192), _MM_HINT_NTA);
__m128i v0 = _mm_shuffle_epi8(_mm_load_si128((__m128i *)&orig[0 ]), mask_right);
__m128i v1 = _mm_shuffle_epi8(_mm_load_si128((__m128i *)&orig[16]), mask_left );
__m128i v2 = _mm_shuffle_epi8(_mm_load_si128((__m128i *)&orig[32]), mask_left );
__m128i v3 = _mm_shuffle_epi8(_mm_load_si128((__m128i *)&orig[48]), mask_left );
v0 = _mm_alignr_epi8(v1, v0, 4);
v1 = _mm_alignr_epi8(v2, _mm_slli_si128(v1, 4), 8);
v2 = _mm_alignr_epi8(v3, _mm_slli_si128(v2, 4), 12);
_mm_stream_si128((__m128i *)&dest[0 ], v0);
_mm_stream_si128((__m128i *)&dest[16], v1);
_mm_stream_si128((__m128i *)&dest[32], v2);
}
}
};

View File

@@ -1,24 +0,0 @@
/*
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
*/
#pragma once
#include "Util.h"
#define DEBUG_WINERROR(x, y) Util::DebugWinError(STRIPPATH(__FILE__), __LINE__, __FUNCTION__, x, y)

View File

@@ -1,418 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug - NvFBC|Win32">
<Configuration>Debug - NvFBC</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug - NvFBC|x64">
<Configuration>Debug - NvFBC</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release - NvFBC|Win32">
<Configuration>Release - NvFBC</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release - NvFBC|x64">
<Configuration>Release - NvFBC</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{D439DE3E-32FB-4599-8B5D-C92674D400D4}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>kvmivshmemhost</RootNamespace>
<WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
<ProjectName>looking-glass-host</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug - NvFBC|Win32'" Label="Configuration">
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release - NvFBC|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug - NvFBC|x64'" Label="Configuration">
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release - NvFBC|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.props" />
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug - NvFBC|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release - NvFBC|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug - NvFBC|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release - NvFBC|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);C:\Program Files %28x86%29\NVIDIA Corporation\NVIDIA Capture SDK\inc</IncludePath>
<ExecutablePath>C:\Program Files (x86)\Windows Kits\10\bin\$(TargetPlatformVersion)\$(PreferredToolArchitecture);$(ExecutablePath)</ExecutablePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug - NvFBC|Win32'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);C:\Program Files %28x86%29\NVIDIA Corporation\NVIDIA Capture SDK\inc</IncludePath>
<ExecutablePath>C:\Program Files (x86)\Windows Kits\10\bin\$(TargetPlatformVersion)\$(PreferredToolArchitecture);$(ExecutablePath)</ExecutablePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);C:\Program Files %28x86%29\NVIDIA Corporation\NVIDIA Capture SDK\inc</IncludePath>
<ExecutablePath>C:\Program Files (x86)\Windows Kits\10\bin\$(TargetPlatformVersion)\$(PreferredToolArchitecture);$(ExecutablePath)</ExecutablePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug - NvFBC|x64'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);C:\Program Files %28x86%29\NVIDIA Corporation\NVIDIA Capture SDK\inc</IncludePath>
<ExecutablePath>C:\Program Files (x86)\Windows Kits\10\bin\$(TargetPlatformVersion)\$(PreferredToolArchitecture);$(ExecutablePath)</ExecutablePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);C:\Program Files %28x86%29\NVIDIA Corporation\NVIDIA Capture SDK\inc</IncludePath>
<ExecutablePath>C:\Program Files (x86)\Windows Kits\10\bin\$(TargetPlatformVersion)\$(PreferredToolArchitecture);$(ExecutablePath)</ExecutablePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release - NvFBC|Win32'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);C:\Program Files %28x86%29\NVIDIA Corporation\NVIDIA Capture SDK\inc</IncludePath>
<ExecutablePath>C:\Program Files (x86)\Windows Kits\10\bin\$(TargetPlatformVersion)\$(PreferredToolArchitecture);$(ExecutablePath)</ExecutablePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);C:\Program Files %28x86%29\NVIDIA Corporation\NVIDIA Capture SDK\inc</IncludePath>
<ExecutablePath>C:\Program Files (x86)\Windows Kits\10\bin\$(TargetPlatformVersion)\$(PreferredToolArchitecture);$(ExecutablePath)</ExecutablePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release - NvFBC|x64'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);C:\Program Files %28x86%29\NVIDIA Corporation\NVIDIA Capture SDK\inc</IncludePath>
<ExecutablePath>C:\Program Files (x86)\Windows Kits\10\bin\$(TargetPlatformVersion)\$(PreferredToolArchitecture);$(ExecutablePath)</ExecutablePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>ENABLE_TRACING;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>..\vendor;..\common\include;.\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<AdditionalDependencies>kernel32.lib;shlwapi.lib;dxgi.lib;d3d11.lib;setupapi.lib;uuid.lib;wmcodecdspuuid.lib;mfplat.lib;mfuuid.lib;evr.lib;avrt.lib;ntdll.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
<Manifest>
<EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>
</Manifest>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug - NvFBC|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>ENABLE_TRACING;CONFIG_CAPTURE_NVFBC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>..\vendor;..\common\include;.\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<AdditionalDependencies>kernel32.lib;shlwapi.lib;dxgi.lib;d3d11.lib;setupapi.lib;uuid.lib;wmcodecdspuuid.lib;mfplat.lib;mfuuid.lib;evr.lib;avrt.lib;ntdll.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
<Manifest>
<EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>
</Manifest>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>ENABLE_TRACING;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>..\vendor;..\common\include;.\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<AdditionalDependencies>kernel32.lib;shlwapi.lib;dxgi.lib;d3d11.lib;setupapi.lib;uuid.lib;wmcodecdspuuid.lib;mfplat.lib;mfuuid.lib;evr.lib;avrt.lib;ntdll.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
<Manifest>
<EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>
</Manifest>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug - NvFBC|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>ENABLE_TRACING;CONFIG_CAPTURE_NVFBC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>..\vendor;..\common\include;.\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<AdditionalDependencies>kernel32.lib;shlwapi.lib;dxgi.lib;d3d11.lib;setupapi.lib;uuid.lib;wmcodecdspuuid.lib;mfplat.lib;mfuuid.lib;evr.lib;avrt.lib;ntdll.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
<Manifest>
<EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>
</Manifest>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>..\vendor;..\common\include;.\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>kernel32.lib;shlwapi.lib;dxgi.lib;d3d11.lib;setupapi.lib;uuid.lib;wmcodecdspuuid.lib;mfplat.lib;mfuuid.lib;evr.lib;avrt.lib;ntdll.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
</Link>
<Manifest>
<EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>
</Manifest>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release - NvFBC|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>CONFIG_CAPTURE_NVFBC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>..\vendor;..\common\include;.\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>kernel32.lib;shlwapi.lib;dxgi.lib;d3d11.lib;setupapi.lib;uuid.lib;wmcodecdspuuid.lib;mfplat.lib;mfuuid.lib;evr.lib;avrt.lib;ntdll.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
<Manifest>
<EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>
</Manifest>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>..\vendor;..\common\include;.\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>kernel32.lib;shlwapi.lib;dxgi.lib;d3d11.lib;setupapi.lib;uuid.lib;wmcodecdspuuid.lib;mfplat.lib;mfuuid.lib;evr.lib;avrt.lib;ntdll.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
</Link>
<Manifest>
<EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>
</Manifest>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release - NvFBC|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>CONFIG_CAPTURE_NVFBC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>..\vendor;..\common\include;.\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>kernel32.lib;shlwapi.lib;dxgi.lib;d3d11.lib;setupapi.lib;uuid.lib;wmcodecdspuuid.lib;mfplat.lib;mfuuid.lib;evr.lib;avrt.lib;ntdll.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
<Manifest>
<EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>
</Manifest>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\vendor\getopt\getopt.c" />
<ClCompile Include="Capture\DXGI.cpp" />
<ClCompile Include="Capture\NvFBC.cpp" />
<ClCompile Include="CrashHandler.cpp" />
<ClCompile Include="ivshmem.cpp" />
<ClCompile Include="main.cpp" />
<ClCompile Include="MFT\H264.cpp" />
<ClCompile Include="TextureConverter.cpp" />
<ClCompile Include="Service.cpp" />
<ClCompile Include="TraceUtil.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="CaptureFactory.h" />
<ClInclude Include="Capture\DXGI.h" />
<ClInclude Include="Capture\NvFBC.h" />
<ClInclude Include="Com.h" />
<ClInclude Include="CrashHandler.h" />
<ClInclude Include="ICapture.h" />
<ClInclude Include="ivshmem.h" />
<ClInclude Include="MFT\H264.h" />
<ClInclude Include="TextureConverter.h" />
<ClInclude Include="Service.h" />
<ClInclude Include="TraceUtil.h" />
<ClInclude Include="Util.h" />
</ItemGroup>
<ItemGroup>
<MASM Include="..\common\src\memcpySSE.asm" />
</ItemGroup>
<ItemGroup>
<FxCompile Include="Shaders\Pixel.hlsl">
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Pixel</ShaderType>
<VariableName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">g_Pixel</VariableName>
<HeaderFileOutput Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Shaders\Pixel.h</HeaderFileOutput>
<ShaderModel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">4.0_level_9_1</ShaderModel>
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug - NvFBC|x64'">Pixel</ShaderType>
<ShaderModel Condition="'$(Configuration)|$(Platform)'=='Debug - NvFBC|x64'">4.0_level_9_1</ShaderModel>
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Release - NvFBC|x64'">Pixel</ShaderType>
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Pixel</ShaderType>
<VariableName Condition="'$(Configuration)|$(Platform)'=='Debug - NvFBC|x64'">g_Pixel</VariableName>
<HeaderFileOutput Condition="'$(Configuration)|$(Platform)'=='Debug - NvFBC|x64'">Shaders\Pixel.h</HeaderFileOutput>
<VariableName Condition="'$(Configuration)|$(Platform)'=='Release - NvFBC|x64'">g_Pixel</VariableName>
<HeaderFileOutput Condition="'$(Configuration)|$(Platform)'=='Release - NvFBC|x64'">Shaders\Pixel.h</HeaderFileOutput>
<VariableName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">g_Pixel</VariableName>
<HeaderFileOutput Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Shaders\Pixel.h</HeaderFileOutput>
</FxCompile>
<FxCompile Include="Shaders\RGBtoYUV.hlsl">
<FileType>HLSL</FileType>
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Pixel</ShaderType>
<VariableName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">g_RGBtoYUV</VariableName>
<HeaderFileOutput Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Shaders\RGBtoYUV.h</HeaderFileOutput>
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug - NvFBC|x64'">Pixel</ShaderType>
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Release - NvFBC|x64'">Pixel</ShaderType>
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Pixel</ShaderType>
<ShaderModel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">4.0_level_9_1</ShaderModel>
<ShaderModel Condition="'$(Configuration)|$(Platform)'=='Debug - NvFBC|x64'">4.0_level_9_1</ShaderModel>
<VariableName Condition="'$(Configuration)|$(Platform)'=='Debug - NvFBC|x64'">g_RGBtoYUV</VariableName>
<VariableName Condition="'$(Configuration)|$(Platform)'=='Release - NvFBC|x64'">g_RGBtoYUV</VariableName>
<VariableName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">g_RGBtoYUV</VariableName>
<HeaderFileOutput Condition="'$(Configuration)|$(Platform)'=='Debug - NvFBC|x64'">Shaders\RGBtoYUV.h</HeaderFileOutput>
<HeaderFileOutput Condition="'$(Configuration)|$(Platform)'=='Release - NvFBC|x64'">Shaders\RGBtoYUV.h</HeaderFileOutput>
<HeaderFileOutput Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Shaders\RGBtoYUV.h</HeaderFileOutput>
</FxCompile>
<FxCompile Include="Shaders\Vertex.hlsl">
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Vertex</ShaderType>
<VariableName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">g_Vertex</VariableName>
<HeaderFileOutput Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Shaders\Vertex.h</HeaderFileOutput>
<VariableName Condition="'$(Configuration)|$(Platform)'=='Debug - NvFBC|x64'">g_Vertex</VariableName>
<VariableName Condition="'$(Configuration)|$(Platform)'=='Release - NvFBC|x64'">g_Vertex</VariableName>
<VariableName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">g_Vertex</VariableName>
<HeaderFileOutput Condition="'$(Configuration)|$(Platform)'=='Debug - NvFBC|x64'">Shaders\Vertex.h</HeaderFileOutput>
<HeaderFileOutput Condition="'$(Configuration)|$(Platform)'=='Release - NvFBC|x64'">Shaders\Vertex.h</HeaderFileOutput>
<HeaderFileOutput Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Shaders\Vertex.h</HeaderFileOutput>
<ShaderModel Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">4.0_level_9_1</ShaderModel>
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug - NvFBC|x64'">Vertex</ShaderType>
<ShaderModel Condition="'$(Configuration)|$(Platform)'=='Debug - NvFBC|x64'">4.0_level_9_1</ShaderModel>
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Release - NvFBC|x64'">Vertex</ShaderType>
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Vertex</ShaderType>
</FxCompile>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />
</ImportGroup>
</Project>

View File

@@ -1,118 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
<Filter Include="Header Files\Capture">
<UniqueIdentifier>{3a65593b-37a9-448d-acf0-6339dea46ed1}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\Capture">
<UniqueIdentifier>{0a865d22-907e-44ea-a230-ad7ede7edeb0}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\MFT">
<UniqueIdentifier>{bd9c6e76-f398-49eb-acfb-3f50cd99724c}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\MFT">
<UniqueIdentifier>{fead4000-1954-4480-8ee7-b817d7042761}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\Shaders">
<UniqueIdentifier>{afb06b60-4959-4447-92ec-75cc07995a8f}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="ivshmem.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Service.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Capture\NvFBC.cpp">
<Filter>Source Files\Capture</Filter>
</ClCompile>
<ClCompile Include="Capture\DXGI.cpp">
<Filter>Source Files\Capture</Filter>
</ClCompile>
<ClCompile Include="..\vendor\getopt\getopt.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="CrashHandler.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="TraceUtil.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="MFT\H264.cpp">
<Filter>Source Files\MFT</Filter>
</ClCompile>
<ClCompile Include="TextureConverter.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="ivshmem.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ICapture.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Service.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="CaptureFactory.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Capture\NvFBC.h">
<Filter>Header Files\Capture</Filter>
</ClInclude>
<ClInclude Include="Util.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Capture\DXGI.h">
<Filter>Header Files\Capture</Filter>
</ClInclude>
<ClInclude Include="CrashHandler.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="TraceUtil.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="MFT\H264.h">
<Filter>Header Files\MFT</Filter>
</ClInclude>
<ClInclude Include="Com.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="TextureConverter.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<FxCompile Include="Shaders\Vertex.hlsl">
<Filter>Source Files\Shaders</Filter>
</FxCompile>
<FxCompile Include="Shaders\RGBtoYUV.hlsl">
<Filter>Source Files\Shaders</Filter>
</FxCompile>
<FxCompile Include="Shaders\Pixel.hlsl">
<Filter>Source Files\Shaders</Filter>
</FxCompile>
</ItemGroup>
<ItemGroup>
<MASM Include="..\common\src\memcpySSE.asm">
<Filter>Source Files</Filter>
</MASM>
</ItemGroup>
</Project>

View File

@@ -1,373 +0,0 @@
/*
Looking Glass - KVM FrameRelay (KVMFR) Client
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 <windows.h>
#include <shlwapi.h>
#include <avrt.h>
#include "common/debug.h"
#include "getopt/getopt.h"
#include "CrashHandler.h"
#include "TraceUtil.h"
#include "CaptureFactory.h"
#include "Service.h"
#include <io.h>
#include <fcntl.h>
#include <iostream>
int parseArgs(struct StartupArgs & args);
static DWORD WINAPI CaptureThread(LPVOID lpParameter);
int run();
void doHelp();
void doLicense();
bool running = true;
bool consoleActive = false;
void setupConsole();
extern "C" NTSYSAPI NTSTATUS NTAPI NtSetTimerResolution(ULONG DesiredResolution, BOOLEAN SetResolution, PULONG CurrentResolution);
struct StartupArgs
{
bool foreground;
const char * captureDevice;
CaptureOptions captureOptions;
};
struct StartupArgs args;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdParam, int iCmdShow)
{
CrashHandler::Initialize();
TraceUtil::Initialize();
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
args.foreground = false;
args.captureDevice = NULL;
int ret = parseArgs(args);
if (ret != 0)
fprintf(stderr, "Failed to parse command line arguments\n");
else
{
if (args.foreground)
setupConsole();
Service::InstallHook();
HANDLE captureThread = CreateThread(NULL, 0, CaptureThread, NULL, 0, NULL);
while (running)
{
MSG msg;
BOOL bRet = GetMessage(&msg, NULL, 0, 0);
if (bRet == -1 || bRet == 0)
{
ret = msg.wParam;
break;
}
DispatchMessage(&msg);
}
Service::RemoveHook();
running = false;
ret = WaitForSingleObject(captureThread, INFINITE);
CloseHandle(captureThread);
}
if (ret != 0)
{
if (!args.foreground)
{
setupConsole();
fprintf(stderr, "An error occurred, re-run in forground mode (-f) for more information\n");
}
}
if (consoleActive)
{
fprintf(stderr, "\nPress enter to terminate...");
fflush(stderr);
getc(stdin);
}
return ret;
}
static DWORD WINAPI CaptureThread(LPVOID lpParameter)
{
int ret = 0;
while (running)
{
ret = run();
if (ret != 0)
break;
}
running = false;
return ret;
}
int run()
{
/* increase the system timer resolution */
ULONG currentRes;
NtSetTimerResolution(0, TRUE, &currentRes);
/* boost our thread priority class as high as possible */
SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
/* use MMCSS to boost our priority for capture */
DWORD taskIndex = 0;
HANDLE task = AvSetMmThreadCharacteristics(L"Capture", &taskIndex);
if (!task || (AvSetMmThreadPriority(task, AVRT_PRIORITY_CRITICAL) == FALSE))
DEBUG_WARN("Failed to boosted priority using MMCSS");
ICapture * captureDevice;
if (args.captureDevice == NULL)
captureDevice = CaptureFactory::DetectDevice(&args.captureOptions);
else
{
captureDevice = CaptureFactory::GetDevice(args.captureDevice, &args.captureOptions);
if (!captureDevice)
{
setupConsole();
fprintf(stderr, "Failed to configure requested capture device\n");
return -1;
}
}
if (!captureDevice)
{
setupConsole();
fprintf(stderr, "Unable to configure a capture device\n");
return -1;
}
Service &svc = Service::Instance();
if (!svc.Initialize(captureDevice))
return -1;
int retry = 0;
bool running = true;
while (running)
{
switch (svc.Process())
{
case PROCESS_STATUS_OK:
retry = 0;
break;
case PROCESS_STATUS_RETRY:
if (retry++ == 3)
{
fprintf(stderr, "Too many consecutive retries, aborting");
running = false;
}
break;
case PROCESS_STATUS_ERROR:
fprintf(stderr, "Capture process returned error");
running = false;
}
}
svc.DeInitialize();
if (task)
AvRevertMmThreadCharacteristics(task);
return 0;
}
int parseArgs(struct StartupArgs & args)
{
int c;
while((c = getopt(__argc, __argv, "hc:o:fld:")) != -1)
{
switch (c)
{
case '?':
case 'h':
doHelp();
return -1;
case 'c':
{
const CaptureFactory::DeviceList deviceList = CaptureFactory::GetDevices();
bool found = false;
if (strcmp(optarg, "?") != 0)
{
for (CaptureFactory::DeviceList::const_iterator it = deviceList.begin(); it != deviceList.end(); ++it)
{
if (_strcmpi(optarg, (*it)->GetName()) == 0)
{
args.captureDevice = (*it)->GetName();
found = true;
break;
}
}
if (!found)
{
setupConsole();
fprintf(stderr, "Invalid capture device: %s\n\n", optarg);
}
}
if (!found)
{
setupConsole();
fprintf(stderr, "Available Capture Devices:\n\n");
for (CaptureFactory::DeviceList::const_iterator it = deviceList.begin(); it != deviceList.end(); ++it)
fprintf(stderr, " %s\n", (*it)->GetName());
return -1;
}
break;
}
case 'o':
{
args.captureOptions.push_back(optarg);
break;
}
case 'f':
args.foreground = true;
break;
case 'l':
doLicense();
return -1;
case 'd':
if (optarg == NULL || strlen(optarg) == 0)
{
setupConsole();
fprintf(stderr, "Device ID missing\n");
return -1;
}
else if (*optarg == '?')
{
setupConsole();
IVSHMEM::listDevices();
return -1;
}
else
{
PCI_DEVICE dev;
int cnt = sscanf_s(optarg, "%hhu,%hhu,%hhu", &dev.bus, &dev.addr, &dev.func);
if (cnt == 3)
{
Service::SetDevice(dev);
}
else
{
setupConsole();
fprintf(stderr, "Invalid Parameter\n");
return -1;
}
}
break;
}
}
return 0;
}
void doHelp()
{
setupConsole();
const char *app = PathFindFileNameA(__argv[0]);
fprintf(stderr,
"Usage: %s [OPTION]...\n"
"Example: %s -c ?\n"
"\n"
" -h Print out this help\n"
" -c Specify the capture device to use or ? to list availble (device is probed if not specified)\n"
" -o Option to pass to the capture device, may be specified multiple times for extra options\n"
" -f Foreground mode\n"
" -l License information\n"
" -d Specify the IVSHMEM device with \"<bus>,<slot>,<function>\" or ? to list available\n",
app,
app
);
}
void doLicense()
{
setupConsole();
fprintf(stderr,
"Looking Glass - KVM FrameRelay (KVMFR) Client\n"
"Copyright(C) 2017-2019 Geoffrey McRae <geoff@hostfission.com>\n"
"\n"
"This program is free software; you can redistribute it and / or modify it under\n"
"the terms of the GNU General Public License as published by the Free Software\n"
"Foundation; either version 2 of the License, or (at your option) any later\n"
"version.\n"
"\n"
"This program is distributed in the hope that it will be useful, but WITHOUT ANY\n"
"WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A\n"
"PARTICULAR PURPOSE.See the GNU General Public License for more details.\n"
"\n"
"You should have received a copy of the GNU General Public License along with\n"
"this program; if not, write to the Free Software Foundation, Inc., 59 Temple\n"
"Place, Suite 330, Boston, MA 02111 - 1307 USA\n"
);
}
void setupConsole()
{
if (consoleActive)
return;
HANDLE _handle;
int _conout;
FILE * fp;
AllocConsole();
CONSOLE_SCREEN_BUFFER_INFO conInfo;
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &conInfo);
conInfo.dwSize.Y = 500;
SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), conInfo.dwSize);
_handle = GetStdHandle(STD_INPUT_HANDLE);
_conout = _open_osfhandle((intptr_t)_handle, _O_TEXT);
fp = _fdopen(_conout, "r");
freopen_s(&fp, "CONIN$", "r", stdin);
_handle = GetStdHandle(STD_OUTPUT_HANDLE);
_conout = _open_osfhandle((intptr_t)_handle, _O_TEXT);
fp = _fdopen(_conout, "w");
freopen_s(&fp, "CONOUT$", "w", stdout);
_handle = GetStdHandle(STD_ERROR_HANDLE);
_conout = _open_osfhandle((intptr_t)_handle, _O_TEXT);
fp = _fdopen(_conout, "w");
freopen_s(&fp, "CONOUT$", "w", stderr);
std::ios::sync_with_stdio();
std::wcout.clear();
std::cout.clear();
std::wcerr.clear();
std::cerr.clear();
std::wcin.clear();
std::cin.clear();
consoleActive = true;
}

View File

@@ -1,109 +0,0 @@
#include <stdbool.h>
#include <SDL.h>
#include <SDL_ttf.h>
#include <stdio.h>
int main(int argc, char * argv[])
{
SDL_Window * window;
SDL_Renderer * renderer;
TTF_Init();
SDL_Init(SDL_INIT_VIDEO);
window = SDL_CreateWindow("sync-test", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1000, 1040, SDL_WINDOW_RESIZABLE);
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
SDL_Event event;
bool running = true;
unsigned int frameCount = 0;
Uint32 fpsFrame = 0;
Uint32 fpsStart = SDL_GetTicks();
float fps = 0.0f;
TTF_Font * fpsFont = NULL;
SDL_Rect fpsTextRect = {5, 5};
SDL_Texture * fpsText = NULL;
int width = 1000;
int boxX = 100;
int boxY = 100;
fpsFont = TTF_OpenFont("C:\\Windows\\Fonts\\cour.ttf", 24);
while (running)
{
while (SDL_PollEvent(&event))
switch(event.type)
{
case SDL_QUIT:
running = false;
break;
case SDL_KEYUP:
switch(event.key.keysym.scancode)
{
case SDL_SCANCODE_ESCAPE:
running = false;
break;
case SDL_SCANCODE_F11:
SDL_SetWindowFullscreen(window, (SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN_DESKTOP) ? 0 : SDL_WINDOW_FULLSCREEN_DESKTOP);
break;
}
case SDL_WINDOWEVENT:
switch (event.window.event)
{
case SDL_WINDOWEVENT_RESIZED:
width = event.window.data1;
boxX = event.window.data1 / 10;
boxY = (event.window.data2 - 40) / 10;
break;
}
}
SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, SDL_ALPHA_OPAQUE);
SDL_RenderClear(renderer);
SDL_SetRenderDrawColor(renderer, 0xff, 0xff, 0xff, SDL_ALPHA_OPAQUE);
for (int y = 0; y < 10; ++y)
for (int x = 0; x < 10; ++x)
{
const SDL_Rect rect = { x * boxX, y * boxY + 40, boxX, boxY};
if (y * 10 + x == frameCount % 100)
SDL_RenderFillRect(renderer, &rect);
else
SDL_RenderDrawRect(renderer, &rect);
}
if (SDL_GetTicks() - fpsStart > 1000)
{
const float delta = (float)(SDL_GetTicks() - fpsStart) / 1000.0f;
const unsigned int frames = frameCount - fpsFrame;
fps = (float)frames / delta;
fpsStart = SDL_GetTicks();
fpsFrame = frameCount;
}
const SDL_Color c = {0x00, 0xff, 0x00, 0xff};
char text[128];
snprintf(text, sizeof(text), "FPS: %7.4f, Frame: %05u \"F11\" to toggle Full Screen", fps, frameCount);
SDL_Surface * fpsSurf = TTF_RenderText_Solid(fpsFont, text, c);
if (fpsText)
SDL_DestroyTexture(fpsText);
fpsText = SDL_CreateTextureFromSurface(renderer, fpsSurf);
fpsTextRect.x = width / 2 - fpsSurf->w / 2;
fpsTextRect.y = 20 - fpsSurf->h / 2;
fpsTextRect.w = fpsSurf->w;
fpsTextRect.h = fpsSurf->h;
SDL_FreeSurface(fpsSurf);
SDL_RenderCopy(renderer, fpsText, NULL, &fpsTextRect);
SDL_RenderPresent(renderer);
++frameCount;
}
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
return 0;
}

View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="freetype.redist" version="2.6.2.1" targetFramework="native" />
<package id="sdl2.v140" version="2.0.4" targetFramework="native" />
<package id="sdl2.v140.redist" version="2.0.4" targetFramework="native" />
<package id="sdl2_ttf.v140" version="2.0.14" targetFramework="native" />
<package id="sdl2_ttf.v140.redist" version="2.0.14" targetFramework="native" />
</packages>

View File

@@ -1,302 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug - NvFBC|Win32">
<Configuration>Debug - NvFBC</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug - NvFBC|x64">
<Configuration>Debug - NvFBC</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release - NvFBC|Win32">
<Configuration>Release - NvFBC</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release - NvFBC|x64">
<Configuration>Release - NvFBC</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{6CC4DA30-6FBD-4ACA-9BA6-2DE731032800}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>synctest</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug - NvFBC|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release - NvFBC|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug - NvFBC|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release - NvFBC|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug - NvFBC|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release - NvFBC|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug - NvFBC|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release - NvFBC|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug - NvFBC|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug - NvFBC|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release - NvFBC|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release - NvFBC|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug - NvFBC|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug - NvFBC|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release - NvFBC|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release - NvFBC|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="main.c" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\packages\freetype.redist.2.6.2.1\build\native\freetype.redist.targets" Condition="Exists('..\packages\freetype.redist.2.6.2.1\build\native\freetype.redist.targets')" />
<Import Project="..\packages\sdl2.v140.redist.2.0.4\build\native\sdl2.v140.redist.targets" Condition="Exists('..\packages\sdl2.v140.redist.2.0.4\build\native\sdl2.v140.redist.targets')" />
<Import Project="..\packages\sdl2_ttf.v140.redist.2.0.14\build\native\sdl2_ttf.v140.redist.targets" Condition="Exists('..\packages\sdl2_ttf.v140.redist.2.0.14\build\native\sdl2_ttf.v140.redist.targets')" />
<Import Project="..\packages\sdl2_ttf.v140.2.0.14\build\native\sdl2_ttf.v140.targets" Condition="Exists('..\packages\sdl2_ttf.v140.2.0.14\build\native\sdl2_ttf.v140.targets')" />
<Import Project="..\packages\sdl2.v140.2.0.4\build\native\sdl2.v140.targets" Condition="Exists('..\packages\sdl2.v140.2.0.4\build\native\sdl2.v140.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\freetype.redist.2.6.2.1\build\native\freetype.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\freetype.redist.2.6.2.1\build\native\freetype.redist.targets'))" />
<Error Condition="!Exists('..\packages\sdl2.v140.redist.2.0.4\build\native\sdl2.v140.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\sdl2.v140.redist.2.0.4\build\native\sdl2.v140.redist.targets'))" />
<Error Condition="!Exists('..\packages\sdl2_ttf.v140.redist.2.0.14\build\native\sdl2_ttf.v140.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\sdl2_ttf.v140.redist.2.0.14\build\native\sdl2_ttf.v140.redist.targets'))" />
<Error Condition="!Exists('..\packages\sdl2_ttf.v140.2.0.14\build\native\sdl2_ttf.v140.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\sdl2_ttf.v140.2.0.14\build\native\sdl2_ttf.v140.targets'))" />
<Error Condition="!Exists('..\packages\sdl2.v140.2.0.4\build\native\sdl2.v140.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\sdl2.v140.2.0.4\build\native\sdl2.v140.targets'))" />
</Target>
</Project>

View File

@@ -1,25 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="main.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
</Project>

View File

@@ -1,11 +1,13 @@
obj-m += kvmfr.o
USER := $(shell whoami)
KVER ?= $(shell uname -r)
KDIR ?= /lib/modules/$(KVER)/build
all:
make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) modules
make -C $(KDIR) M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) clean
make -C $(KDIR) M=$(PWD) clean
test: all
grep -q '^uio' /proc/modules || sudo modprobe uio

View File

@@ -1,8 +1,7 @@
PACKAGE_NAME=kvmfr
PACKAGE_VERSION=0.1
BUILT_MODULE_NAME[0]="$PACKAGE_NAME"
MAKE[0]="make -C ${kernel_source_dir} M=${dkms_tree}/${PACKAGE_NAME}/${PACKAGE_VERSION}/build"
CLEAN="make -C ${kernel_source_dir} M=${dkms_tree}/${PACKAGE_NAME}/${PACKAGE_VERSION}/build clean"
DEST_MODULE_LOCATION[0]=/extra
REMAKE_INITRD=yes
AUTOINSTALL=yes
PACKAGE_NAME="kvmfr"
PACKAGE_VERSION="0.0.1"
BUILT_MODULE_NAME[0]="${PACKAGE_NAME}"
MAKE[0]="make KDIR=${kernel_source_dir}"
CLEAN="make KDIR=${kernel_source_dir} clean"
DEST_MODULE_LOCATION[0]="/kernel/drivers/misc"
AUTOINSTALL="yes"

BIN
resources/icon-128x128.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
resources/icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

56
vendor/ivshmem/ivshmem.h vendored Normal file
View File

@@ -0,0 +1,56 @@
#include <initguid.h>
DEFINE_GUID (GUID_DEVINTERFACE_IVSHMEM,
0xdf576976,0x569d,0x4672,0x95,0xa0,0xf5,0x7e,0x4e,0xa0,0xb2,0x10);
// {df576976-569d-4672-95a0-f57e4ea0b210}
typedef UINT16 IVSHMEM_PEERID;
typedef UINT64 IVSHMEM_SIZE;
/*
This structure is for use with the IOCTL_IVSHMEM_REQUEST_MMAP IOCTL
*/
typedef struct IVSHMEM_MMAP
{
IVSHMEM_PEERID peerID; // our peer id
IVSHMEM_SIZE size; // the size of the memory region
PVOID ptr; // pointer to the memory region
UINT16 vectors; // the number of vectors available
}
IVSHMEM_MMAP, *PIVSHMEM_MMAP;
/*
This structure is for use with the IOCTL_IVSHMEM_RING_DOORBELL IOCTL
*/
typedef struct IVSHMEM_RING
{
IVSHMEM_PEERID peerID; // the id of the peer to ring
UINT16 vector; // the doorbell to ring
}
IVSHMEM_RING, *PIVSHMEM_RING;
/*
This structure is for use with the IOCTL_IVSHMEM_REGISTER_EVENT IOCTL
Please Note:
- The IVSHMEM driver has a hard limit of 32 events.
- Events that are singleShot are released after they have been set.
- At this time repeating events are only released when the driver device
handle is closed, closing the event handle doesn't release it from the
drivers list. While this won't cause a problem in the driver, it will
cause you to run out of event slots.
*/
typedef struct IVSHMEM_EVENT
{
UINT16 vector; // the vector that triggers the event
HANDLE event; // the event to trigger
BOOLEAN singleShot; // set to TRUE if you want the driver to only trigger this event once
}
IVSHMEM_EVENT, *PIVSHMEM_EVENT;
#define IOCTL_IVSHMEM_REQUEST_PEERID CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_IVSHMEM_REQUEST_SIZE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_IVSHMEM_REQUEST_MMAP CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_IVSHMEM_RELEASE_MMAP CTL_CODE(FILE_DEVICE_UNKNOWN, 0x803, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_IVSHMEM_RING_DOORBELL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x804, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_IVSHMEM_REGISTER_EVENT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x805, METHOD_BUFFERED, FILE_ANY_ACCESS)