[c-host] renamed finall to just plain host

This commit is contained in:
Geoffrey McRae
2020-05-25 13:42:43 +10:00
parent d579705b10
commit bc7871f630
34 changed files with 2 additions and 2 deletions

View File

@@ -0,0 +1,19 @@
cmake_minimum_required(VERSION 3.0)
project(capture_NVFBC LANGUAGES C CXX)
add_library(capture_NVFBC STATIC
src/nvfbc.c
src/wrapper.cpp
)
file(TO_CMAKE_PATH "${NVFBC_SDK}" nvfbc_sdk)
include_directories(file, "${nvfbc_sdk}/inc")
target_include_directories(capture_NVFBC
PRIVATE
src
)
target_link_libraries(capture_NVFBC
platform_Windows
)

View File

@@ -0,0 +1,387 @@
/*
Looking Glass - KVM FrameRelay (KVMFR) Client
Copyright (C) 2017-2020 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 "interface/capture.h"
#include "interface/platform.h"
#include "common/windebug.h"
#include "windows/mousehook.h"
#include "common/option.h"
#include "common/framebuffer.h"
#include "common/event.h"
#include "common/thread.h"
#include <assert.h>
#include <stdlib.h>
#include <windows.h>
#include <NvFBC/nvFBC.h>
#include "wrapper.h"
struct iface
{
bool stop;
NvFBCHandle nvfbc;
bool seperateCursor;
CaptureGetPointerBuffer getPointerBufferFn;
CapturePostPointerBuffer postPointerBufferFn;
LGThread * pointerThread;
unsigned int maxWidth, maxHeight;
unsigned int width , height;
uint8_t * frameBuffer;
uint8_t * diffMap;
NvFBCFrameGrabInfo grabInfo;
LGEvent * frameEvent;
LGEvent * cursorEvents[2];
int mouseX, mouseY, mouseHotX, mouseHotY;
bool mouseVisible;
};
static struct iface * this = NULL;
static void nvfbc_free();
static int pointerThread(void * unused);
static void getDesktopSize(unsigned int * width, unsigned int * height)
{
HMONITOR monitor = MonitorFromWindow(GetDesktopWindow(), MONITOR_DEFAULTTOPRIMARY);
MONITORINFO monitorInfo = {
.cbSize = sizeof(MONITORINFO)
};
GetMonitorInfo(monitor, &monitorInfo);
CloseHandle(monitor);
*width = monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left;
*height = monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top;
}
static void on_mouseMove(int x, int y)
{
this->mouseX = x;
this->mouseY = y;
lgSignalEvent(this->cursorEvents[0]);
}
static const char * nvfbc_getName()
{
return "NVFBC (NVidia Frame Buffer Capture)";
};
static void nvfbc_initOptions()
{
struct Option options[] =
{
{
.module = "nvfbc",
.name = "decoupleCursor",
.description = "Capture the cursor seperately",
.type = OPTION_TYPE_BOOL,
.value.x_bool = true
},
{0}
};
option_register(options);
}
static bool nvfbc_create(
CaptureGetPointerBuffer getPointerBufferFn,
CapturePostPointerBuffer postPointerBufferFn)
{
if (!NvFBCInit())
return false;
int bufferLen = GetEnvironmentVariable("NVFBC_PRIV_DATA", NULL, 0);
uint8_t * privData = NULL;
int privDataLen = 0;
if(bufferLen)
{
char * buffer = malloc(bufferLen);
GetEnvironmentVariable("NVFBC_PRIV_DATA", buffer, bufferLen);
privDataLen = (bufferLen - 1) / 2;
privData = (uint8_t *)malloc(privDataLen);
char hex[3] = {0};
for(int i = 0; i < privDataLen; ++i)
{
memcpy(hex, &buffer[i*2], 2);
privData[i] = (uint8_t)strtoul(hex, NULL, 16);
}
free(buffer);
}
this = (struct iface *)calloc(sizeof(struct iface), 1);
if (!NvFBCToSysCreate(privData, privDataLen, &this->nvfbc, &this->maxWidth, &this->maxHeight))
{
free(privData);
nvfbc_free();
return false;
}
free(privData);
this->frameEvent = lgCreateEvent(true, 17);
if (!this->frameEvent)
{
DEBUG_ERROR("failed to create the frame event");
nvfbc_free();
return false;
}
this->seperateCursor = option_get_bool("nvfbc", "decoupleCursor");
this->getPointerBufferFn = getPointerBufferFn;
this->postPointerBufferFn = postPointerBufferFn;
return true;
}
static bool nvfbc_init()
{
this->stop = false;
getDesktopSize(&this->width, &this->height);
lgResetEvent(this->frameEvent);
HANDLE event;
if (!NvFBCToSysSetup(
this->nvfbc,
BUFFER_FMT_ARGB,
!this->seperateCursor,
this->seperateCursor,
true,
DIFFMAP_BLOCKSIZE_128X128,
(void **)&this->frameBuffer,
(void **)&this->diffMap,
&event
))
{
return false;
}
this->cursorEvents[0] = lgCreateEvent(true, 10);
mouseHook_install(on_mouseMove);
if (this->seperateCursor)
this->cursorEvents[1] = lgWrapEvent(event);
DEBUG_INFO("Cursor mode : %s", this->seperateCursor ? "decoupled" : "integrated");
Sleep(100);
if (!lgCreateThread("NvFBCPointer", pointerThread, NULL, &this->pointerThread))
{
DEBUG_ERROR("Failed to create the NvFBCPointer thread");
return false;
}
return true;
}
static void nvfbc_stop()
{
this->stop = true;
lgSignalEvent(this->cursorEvents[0]);
lgSignalEvent(this->frameEvent);
if (this->pointerThread)
{
lgJoinThread(this->pointerThread, NULL);
this->pointerThread = NULL;
}
}
static bool nvfbc_deinit()
{
mouseHook_remove();
if (this->cursorEvents[0])
{
lgFreeEvent(this->cursorEvents[0]);
this->cursorEvents[0] = NULL;
}
return true;
}
static void nvfbc_free()
{
NvFBCToSysRelease(&this->nvfbc);
if (this->frameEvent)
lgFreeEvent(this->frameEvent);
free(this);
this = NULL;
NvFBCFree();
}
static unsigned int nvfbc_getMaxFrameSize()
{
return this->maxWidth * this->maxHeight * 4;
}
static CaptureResult nvfbc_capture()
{
getDesktopSize(&this->width, &this->height);
NvFBCFrameGrabInfo grabInfo;
CaptureResult result = NvFBCToSysCapture(
this->nvfbc,
1000,
0, 0,
this->width,
this->height,
&grabInfo
);
if (result != CAPTURE_RESULT_OK)
return result;
bool changed = false;
const unsigned int h = (this->height + 127) / 128;
const unsigned int w = (this->width + 127) / 128;
for(unsigned int y = 0; y < h; ++y)
for(unsigned int x = 0; x < w; ++x)
if (this->diffMap[(y*w)+x])
{
changed = true;
break;
}
if (!changed)
return CAPTURE_RESULT_TIMEOUT;
memcpy(&this->grabInfo, &grabInfo, sizeof(grabInfo));
lgSignalEvent(this->frameEvent);
return CAPTURE_RESULT_OK;
}
static CaptureResult nvfbc_waitFrame(CaptureFrame * frame)
{
if (!lgWaitEvent(this->frameEvent, 1000))
return CAPTURE_RESULT_TIMEOUT;
if (this->stop)
return CAPTURE_RESULT_REINIT;
frame->width = this->grabInfo.dwWidth;
frame->height = this->grabInfo.dwHeight;
frame->pitch = this->grabInfo.dwBufferWidth * 4;
frame->stride = this->grabInfo.dwBufferWidth;
#if 0
//NvFBC never sets bIsHDR so instead we check for any data in the alpha channel
//If there is data, it's HDR. This is clearly suboptimal
if (!this->grabInfo.bIsHDR)
for(int y = 0; y < frame->height; ++y)
for(int x = 0; x < frame->width; ++x)
{
int offset = (y * frame->pitch) + (x * 4);
if (this->frameBuffer[offset + 3])
{
this->grabInfo.bIsHDR = 1;
break;
}
}
#endif
frame->format = this->grabInfo.bIsHDR ? CAPTURE_FMT_RGBA10 : CAPTURE_FMT_BGRA;
return CAPTURE_RESULT_OK;
}
static CaptureResult nvfbc_getFrame(FrameBuffer * frame)
{
framebuffer_write(
frame,
this->frameBuffer,
this->grabInfo.dwHeight * this->grabInfo.dwBufferWidth * 4
);
return CAPTURE_RESULT_OK;
}
static int pointerThread(void * unused)
{
while(!this->stop)
{
LGEvent * events[2];
memcpy(&events, &this->cursorEvents, sizeof(LGEvent *) * 2);
if (!lgWaitEvents(events, this->seperateCursor ? 2 : 1, false, 1000))
continue;
if (this->stop)
break;
CaptureResult result;
CapturePointer pointer = { 0 };
if (this->seperateCursor && events[1])
{
void * data;
uint32_t size;
if (!this->getPointerBufferFn(&data, &size))
{
DEBUG_WARN("failed to get a pointer buffer");
continue;
}
result = NvFBCToSysGetCursor(this->nvfbc, &pointer, data, size);
if (result != CAPTURE_RESULT_OK)
{
DEBUG_WARN("NvFBCToSysGetCursor failed");
continue;
}
this->mouseVisible = pointer.visible;
this->mouseHotX = pointer.x;
this->mouseHotY = pointer.y;
}
if (events[0])
{
pointer.positionUpdate = true;
pointer.visible = this->mouseVisible;
pointer.x = this->mouseX - this->mouseHotX;
pointer.y = this->mouseY - this->mouseHotY;
}
this->postPointerBufferFn(pointer);
}
return 0;
}
struct CaptureInterface Capture_NVFBC =
{
.getName = nvfbc_getName,
.initOptions = nvfbc_initOptions,
.create = nvfbc_create,
.init = nvfbc_init,
.stop = nvfbc_stop,
.deinit = nvfbc_deinit,
.free = nvfbc_free,
.getMaxFrameSize = nvfbc_getMaxFrameSize,
.capture = nvfbc_capture,
.waitFrame = nvfbc_waitFrame,
.getFrame = nvfbc_getFrame
};

View File

@@ -0,0 +1,330 @@
/*
Looking Glass - KVM FrameRelay (KVMFR) Client
Copyright (C) 2017-2020 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 "wrapper.h"
#include "common/windebug.h"
#include <windows.h>
#include <NvFBC/nvFBCToSys.h>
#ifdef _WIN64
#define NVFBC_DLL "NvFBC64.dll"
#else
#define NVFBC_DLL "NvFBC.dll"
#endif
struct NVAPI
{
bool initialized;
HMODULE dll;
NvFBC_CreateFunctionExType createEx;
NvFBC_SetGlobalFlagsType setGlobalFlags;
NvFBC_GetStatusExFunctionType getStatusEx;
NvFBC_EnableFunctionType enable;
NvFBC_GetSDKVersionFunctionType getVersion;
};
struct stNvFBCHandle
{
NvFBCToSys * nvfbc;
HANDLE cursorEvent;
int retry;
};
static NVAPI nvapi;
bool NvFBCInit()
{
if (nvapi.initialized)
return true;
nvapi.dll = LoadLibraryA(NVFBC_DLL);
if (!nvapi.dll)
{
DEBUG_WINERROR("Failed to load " NVFBC_DLL, GetLastError());
return false;
}
nvapi.createEx = (NvFBC_CreateFunctionExType )GetProcAddress(nvapi.dll, "NvFBC_CreateEx" );
nvapi.setGlobalFlags = (NvFBC_SetGlobalFlagsType )GetProcAddress(nvapi.dll, "NvFBC_SetGlobalFlags");
nvapi.getStatusEx = (NvFBC_GetStatusExFunctionType )GetProcAddress(nvapi.dll, "NvFBC_GetStatusEx" );
nvapi.enable = (NvFBC_EnableFunctionType )GetProcAddress(nvapi.dll, "NvFBC_Enable" );
nvapi.getVersion = (NvFBC_GetSDKVersionFunctionType)GetProcAddress(nvapi.dll, "NvFBC_GetSDKVersion" );
if (
!nvapi.createEx ||
!nvapi.setGlobalFlags ||
!nvapi.getStatusEx ||
!nvapi.enable ||
!nvapi.getVersion)
{
DEBUG_ERROR("Failed to get the required proc addresses");
return false;
}
NvU32 version;
if (nvapi.getVersion(&version) != NVFBC_SUCCESS)
{
DEBUG_ERROR("Failed to get the NvFBC SDK version");
return false;
}
DEBUG_INFO("NvFBC SDK Version: %lu", version);
if (nvapi.enable(NVFBC_STATE_ENABLE) != NVFBC_SUCCESS)
{
DEBUG_ERROR("Failed to enable the NvFBC interface");
return false;
}
nvapi.initialized = true;
return true;
}
void NvFBCFree()
{
if (!nvapi.initialized)
return;
FreeLibrary(nvapi.dll);
nvapi.initialized = false;
}
bool NvFBCToSysCreate(
void * privData,
unsigned int privDataSize,
NvFBCHandle * handle,
unsigned int * maxWidth,
unsigned int * maxHeight
)
{
NvFBCCreateParams params = {0};
params.dwVersion = NVFBC_CREATE_PARAMS_VER;
params.dwInterfaceType = NVFBC_TO_SYS;
params.pDevice = NULL;
params.dwAdapterIdx = 0;
params.dwPrivateDataSize = privDataSize;
params.pPrivateData = privData;
if (nvapi.createEx(&params) != NVFBC_SUCCESS)
{
*handle = NULL;
return false;
}
*handle = (NvFBCHandle)calloc(sizeof(struct stNvFBCHandle), 1);
(*handle)->nvfbc = static_cast<NvFBCToSys *>(params.pNvFBC);
if (maxWidth)
*maxWidth = params.dwMaxDisplayWidth;
if (maxHeight)
*maxHeight = params.dwMaxDisplayHeight;
return true;
}
void NvFBCToSysRelease(NvFBCHandle * handle)
{
if (!*handle)
return;
(*handle)->nvfbc->NvFBCToSysRelease();
free(*handle);
*handle = NULL;
}
bool NvFBCToSysSetup(
NvFBCHandle handle,
enum BufferFormat format,
bool hwCursor,
bool seperateCursorCapture,
bool useDiffMap,
enum DiffMapBlockSize diffMapBlockSize,
void ** frameBuffer,
void ** diffMap,
HANDLE * cursorEvent
)
{
NVFBC_TOSYS_SETUP_PARAMS params = {0};
params.dwVersion = NVFBC_TOSYS_SETUP_PARAMS_VER;
switch(format)
{
case BUFFER_FMT_ARGB : params.eMode = NVFBC_TOSYS_ARGB ; break;
case BUFFER_FMT_RGB : params.eMode = NVFBC_TOSYS_RGB ; break;
case BUFFER_FMT_YYYYUV420p: params.eMode = NVFBC_TOSYS_YYYYUV420p; break;
case BUFFER_FMT_RGB_PLANAR: params.eMode = NVFBC_TOSYS_RGB_PLANAR; break;
case BUFFER_FMT_XOR : params.eMode = NVFBC_TOSYS_XOR ; break;
case BUFFER_FMT_YUV444p : params.eMode = NVFBC_TOSYS_YUV444p ; break;
case BUFFER_FMT_ARGB10 :
params.eMode = NVFBC_TOSYS_ARGB10;
params.bHDRRequest = TRUE;
break;
default:
DEBUG_INFO("Invalid format");
return false;
}
params.bWithHWCursor = hwCursor ? TRUE : FALSE;
params.bEnableSeparateCursorCapture = seperateCursorCapture ? TRUE : FALSE;
params.bDiffMap = useDiffMap ? TRUE : FALSE;
switch(diffMapBlockSize)
{
case DIFFMAP_BLOCKSIZE_128X128: params.eDiffMapBlockSize = NVFBC_TOSYS_DIFFMAP_BLOCKSIZE_128X128; break;
case DIFFMAP_BLOCKSIZE_16X16 : params.eDiffMapBlockSize = NVFBC_TOSYS_DIFFMAP_BLOCKSIZE_16X16 ; break;
case DIFFMAP_BLOCKSIZE_32X32 : params.eDiffMapBlockSize = NVFBC_TOSYS_DIFFMAP_BLOCKSIZE_32X32 ; break;
case DIFFMAP_BLOCKSIZE_64X64 : params.eDiffMapBlockSize = NVFBC_TOSYS_DIFFMAP_BLOCKSIZE_64X64 ; break;
default:
DEBUG_ERROR("Invalid diffMapBlockSize");
return false;
}
params.ppBuffer = frameBuffer;
params.ppDiffMap = diffMap;
NVFBCRESULT status = handle->nvfbc->NvFBCToSysSetUp(&params);
if (status != NVFBC_SUCCESS)
{
DEBUG_ERROR("Failed to setup NVFBCToSys");
return false;
}
if (cursorEvent)
*cursorEvent = params.hCursorCaptureEvent;
return true;
}
CaptureResult NvFBCToSysCapture(
NvFBCHandle handle,
const unsigned int waitTime,
const unsigned int x,
const unsigned int y,
const unsigned int width,
const unsigned int height,
NvFBCFrameGrabInfo * grabInfo
)
{
NVFBC_TOSYS_GRAB_FRAME_PARAMS params = {0};
params.dwVersion = NVFBC_TOSYS_GRAB_FRAME_PARAMS_VER;
params.dwFlags = NVFBC_TOSYS_WAIT_WITH_TIMEOUT;
params.dwWaitTime = waitTime;
params.eGMode = NVFBC_TOSYS_SOURCEMODE_CROP;
params.dwStartX = x;
params.dwStartY = y;
params.dwTargetWidth = width;
params.dwTargetHeight = height;
params.pNvFBCFrameGrabInfo = grabInfo;
grabInfo->bMustRecreate = FALSE;
NVFBCRESULT status = handle->nvfbc->NvFBCToSysGrabFrame(&params);
if (grabInfo->bMustRecreate)
{
DEBUG_INFO("NvFBC reported recreation is required");
return CAPTURE_RESULT_REINIT;
}
switch(status)
{
case NVFBC_SUCCESS:
handle->retry = 0;
break;
case NVFBC_ERROR_INVALID_PARAM:
if (handle->retry < 2)
{
Sleep(100);
++handle->retry;
return CAPTURE_RESULT_TIMEOUT;
}
return CAPTURE_RESULT_ERROR;
case NVFBC_ERROR_DYNAMIC_DISABLE:
DEBUG_ERROR("NvFBC was disabled by someone else");
return CAPTURE_RESULT_ERROR;
case NVFBC_ERROR_INVALIDATED_SESSION:
DEBUG_WARN("Session was invalidated, attempting to restart");
return CAPTURE_RESULT_REINIT;
default:
DEBUG_ERROR("Unknown NVFBCRESULT failure 0x%x", status);
return CAPTURE_RESULT_ERROR;
}
return CAPTURE_RESULT_OK;
}
CaptureResult NvFBCToSysGetCursor(NvFBCHandle handle, CapturePointer * pointer, void * buffer, unsigned int size)
{
NVFBC_CURSOR_CAPTURE_PARAMS params;
params.dwVersion = NVFBC_CURSOR_CAPTURE_PARAMS_VER;
if (handle->nvfbc->NvFBCToSysCursorCapture(&params) != NVFBC_SUCCESS)
{
DEBUG_ERROR("Failed to get the cursor");
return CAPTURE_RESULT_ERROR;
}
pointer->x = params.dwXHotSpot;
pointer->y = params.dwYHotSpot;
pointer->width = params.dwWidth;
pointer->height = params.dwHeight;
pointer->pitch = params.dwPitch;
pointer->visible = params.bIsHwCursor;
pointer->shapeUpdate = params.bIsHwCursor;
if (!params.bIsHwCursor)
return CAPTURE_RESULT_OK;
switch(params.dwPointerFlags & 0x7)
{
case 0x1:
pointer->format = CAPTURE_FMT_MONO;
pointer->height *= 2;
break;
case 0x2:
pointer->format = CAPTURE_FMT_COLOR;
break;
case 0x4:
pointer->format = CAPTURE_FMT_MASKED;
break;
default:
DEBUG_ERROR("Invalid/unknown pointer data format");
return CAPTURE_RESULT_ERROR;
}
if (params.dwBufferSize > size)
{
DEBUG_WARN("Cursor data larger then provided buffer");
params.dwBufferSize = size;
}
memcpy(buffer, params.pBits, params.dwBufferSize);
return CAPTURE_RESULT_OK;
}

View File

@@ -0,0 +1,88 @@
/*
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 <stdbool.h>
#include <NvFBC/nvFBC.h>
#ifdef __cplusplus
extern "C" {
#endif
#include "interface/capture.h"
typedef struct stNvFBCHandle * NvFBCHandle;
enum BufferFormat
{
BUFFER_FMT_ARGB,
BUFFER_FMT_RGB,
BUFFER_FMT_YYYYUV420p,
BUFFER_FMT_RGB_PLANAR,
BUFFER_FMT_XOR,
BUFFER_FMT_YUV444p,
BUFFER_FMT_ARGB10
};
enum DiffMapBlockSize
{
DIFFMAP_BLOCKSIZE_128X128 = 0,
DIFFMAP_BLOCKSIZE_16X16,
DIFFMAP_BLOCKSIZE_32X32,
DIFFMAP_BLOCKSIZE_64X64
};
bool NvFBCInit();
void NvFBCFree();
bool NvFBCToSysCreate(
void * privData,
unsigned int privDataSize,
NvFBCHandle * handle,
unsigned int * maxWidth,
unsigned int * maxHeight
);
void NvFBCToSysRelease(NvFBCHandle * handle);
bool NvFBCToSysSetup(
NvFBCHandle handle,
enum BufferFormat format,
bool hwCursor,
bool seperateCursorCapture,
bool useDiffMap,
enum DiffMapBlockSize diffMapBlockSize,
void ** frameBuffer,
void ** diffMap,
HANDLE * cursorEvent
);
CaptureResult NvFBCToSysCapture(
NvFBCHandle handle,
const unsigned int waitTime,
const unsigned int x,
const unsigned int y,
const unsigned int width,
const unsigned int height,
NvFBCFrameGrabInfo * grabInfo
);
CaptureResult NvFBCToSysGetCursor(NvFBCHandle handle, CapturePointer * pointer, void * buffer, unsigned int size);
#ifdef __cplusplus
}
#endif