mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-05-06 15:37:48 +00:00
Compare commits
34 Commits
B1-rc2
...
Release/B1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
163a2e5d0a | ||
|
|
b979752989 | ||
|
|
8ad2d5f949 | ||
|
|
745ba66119 | ||
|
|
4cf6dec592 | ||
|
|
d7fa0aeff9 | ||
|
|
2def6346e6 | ||
|
|
607539a2af | ||
|
|
6d24dd52d6 | ||
|
|
e3343cbd01 | ||
|
|
71ffa0a137 | ||
|
|
2b4f8091f9 | ||
|
|
113da121e9 | ||
|
|
dd7413f973 | ||
|
|
0851fd13e6 | ||
|
|
97024041f3 | ||
|
|
22238c3200 | ||
|
|
780bb248f7 | ||
|
|
026bdb00f2 | ||
|
|
373d4ac932 | ||
|
|
7d26027752 | ||
|
|
3d426ccef8 | ||
|
|
b31e8e1cee | ||
|
|
f0923c4ed7 | ||
|
|
aabf19e63b | ||
|
|
f4fc1eb5f6 | ||
|
|
5e201a32ca | ||
|
|
438e9e0969 | ||
|
|
9554e82c47 | ||
|
|
4cf2c7a350 | ||
|
|
664d7dccdb | ||
|
|
21b02efb4d | ||
|
|
d07aa4b29e | ||
|
|
9f33043d17 |
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -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
|
||||
|
||||
@@ -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}
|
||||
)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 |
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
116
c-host/src/app.c
116
c-host/src/app.c
@@ -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())
|
||||
{
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <GL/gl.h>
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
@@ -1 +0,0 @@
|
||||
.
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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), ¤t) == 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
308
host/.gitignore
vendored
@@ -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/
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
};
|
||||
@@ -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(¶ms, 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(¶ms) != 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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
58
host/Com.h
58
host/Com.h
@@ -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 ));
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
};
|
||||
@@ -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;
|
||||
};
|
||||
380
host/IVSHMEM.cpp
380
host/IVSHMEM.cpp
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
101
host/MFT/H264.h
101
host/MFT/H264.h
@@ -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;
|
||||
};
|
||||
};
|
||||
@@ -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
|
||||
391
host/Service.cpp
391
host/Service.cpp
@@ -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;
|
||||
}
|
||||
114
host/Service.h
114
host/Service.h
@@ -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;
|
||||
};
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
154
host/Util.h
154
host/Util.h
@@ -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);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -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)
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
373
host/main.cpp
373
host/main.cpp
@@ -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, ¤tRes);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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
|
||||
|
||||
@@ -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
BIN
resources/icon-128x128.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
BIN
resources/icon.ico
Normal file
BIN
resources/icon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 88 KiB |
56
vendor/ivshmem/ivshmem.h
vendored
Normal file
56
vendor/ivshmem/ivshmem.h
vendored
Normal 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)
|
||||
1
vendor/kvm-guest-drivers-windows
vendored
1
vendor/kvm-guest-drivers-windows
vendored
Submodule vendor/kvm-guest-drivers-windows deleted from 8c097560f8
Reference in New Issue
Block a user