mirror of
https://github.com/gnif/LookingGlass.git
synced 2024-11-25 14:57:20 +00:00
[c-host] add spinlock support to events and alter dxgi to use them
This commit is contained in:
parent
db2f5b85a9
commit
9c5f9906fa
@ -46,7 +46,7 @@ bool os_joinThread (osThreadHandle * handle, int * resultCode);
|
|||||||
|
|
||||||
typedef struct osEventHandle osEventHandle;
|
typedef struct osEventHandle osEventHandle;
|
||||||
|
|
||||||
osEventHandle * os_createEvent(bool autoReset);
|
osEventHandle * os_createEvent(bool autoReset, unsigned int msSpinTime);
|
||||||
void os_freeEvent (osEventHandle * handle);
|
void os_freeEvent (osEventHandle * handle);
|
||||||
bool os_waitEvent (osEventHandle * handle, unsigned int timeout);
|
bool os_waitEvent (osEventHandle * handle, unsigned int timeout);
|
||||||
bool os_waitEvents (osEventHandle * handles[], int count, bool waitAll, unsigned int timeout);
|
bool os_waitEvents (osEventHandle * handles[], int count, bool waitAll, unsigned int timeout);
|
||||||
|
@ -46,7 +46,7 @@ typedef struct Texture
|
|||||||
enum TextureState state;
|
enum TextureState state;
|
||||||
ID3D11Texture2D * tex;
|
ID3D11Texture2D * tex;
|
||||||
D3D11_MAPPED_SUBRESOURCE map;
|
D3D11_MAPPED_SUBRESOURCE map;
|
||||||
volatile int free;
|
osEventHandle * readyEvent;
|
||||||
}
|
}
|
||||||
Texture;
|
Texture;
|
||||||
|
|
||||||
@ -80,7 +80,6 @@ struct iface
|
|||||||
IDXGIOutputDuplication * dup;
|
IDXGIOutputDuplication * dup;
|
||||||
int maxTextures;
|
int maxTextures;
|
||||||
Texture * texture;
|
Texture * texture;
|
||||||
volatile int texPending;
|
|
||||||
volatile int texRIndex;
|
volatile int texRIndex;
|
||||||
int texWIndex;
|
int texWIndex;
|
||||||
bool needsRelease;
|
bool needsRelease;
|
||||||
@ -165,7 +164,7 @@ static bool dxgi_create()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->pointerEvent = os_createEvent(true);
|
this->pointerEvent = os_createEvent(true, 10);
|
||||||
if (!this->pointerEvent)
|
if (!this->pointerEvent)
|
||||||
{
|
{
|
||||||
DEBUG_ERROR("failed to create the pointer event");
|
DEBUG_ERROR("failed to create the pointer event");
|
||||||
@ -178,6 +177,20 @@ static bool dxgi_create()
|
|||||||
this->maxTextures = 1;
|
this->maxTextures = 1;
|
||||||
|
|
||||||
this->texture = calloc(sizeof(struct Texture), this->maxTextures);
|
this->texture = calloc(sizeof(struct Texture), this->maxTextures);
|
||||||
|
for(int i = 0; i < this->maxTextures; ++i)
|
||||||
|
{
|
||||||
|
this->texture[i].readyEvent = os_createEvent(false, 30);
|
||||||
|
if (!this->texture[i].readyEvent)
|
||||||
|
{
|
||||||
|
DEBUG_ERROR("failed to create the texture event");
|
||||||
|
|
||||||
|
for(int x = 0; x < i; ++x)
|
||||||
|
os_freeEvent(this->texture[x].readyEvent);
|
||||||
|
|
||||||
|
free(this->texture);
|
||||||
|
free(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this->useAcquireLock = option_get_bool("dxgi", "useAcquireLock");
|
this->useAcquireLock = option_get_bool("dxgi", "useAcquireLock");
|
||||||
return true;
|
return true;
|
||||||
@ -211,7 +224,6 @@ static bool dxgi_init(void * pointerShape, const unsigned int pointerSize)
|
|||||||
this->pointerUsed = 0;
|
this->pointerUsed = 0;
|
||||||
|
|
||||||
this->stop = false;
|
this->stop = false;
|
||||||
this->texPending = 0;
|
|
||||||
this->texRIndex = 0;
|
this->texRIndex = 0;
|
||||||
this->texWIndex = 0;
|
this->texWIndex = 0;
|
||||||
|
|
||||||
@ -483,8 +495,6 @@ static bool dxgi_init(void * pointerShape, const unsigned int pointerSize)
|
|||||||
DEBUG_WINERROR("Failed to create texture", status);
|
DEBUG_WINERROR("Failed to create texture", status);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->texture[i].free = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// map the texture simply to get the pitch and stride
|
// map the texture simply to get the pitch and stride
|
||||||
@ -653,7 +663,7 @@ static CaptureResult dxgi_capture()
|
|||||||
tex = &this->texture[this->texWIndex];
|
tex = &this->texture[this->texWIndex];
|
||||||
|
|
||||||
// check if the texture is free, if not skip the frame to keep up
|
// check if the texture is free, if not skip the frame to keep up
|
||||||
if (INTERLOCKED_GET(&tex->free))
|
if (tex->state == TEXTURE_STATE_UNUSED)
|
||||||
{
|
{
|
||||||
ID3D11Texture2D * src;
|
ID3D11Texture2D * src;
|
||||||
status = IDXGIResource_QueryInterface(res, &IID_ID3D11Texture2D, (void **)&src);
|
status = IDXGIResource_QueryInterface(res, &IID_ID3D11Texture2D, (void **)&src);
|
||||||
@ -672,10 +682,9 @@ static CaptureResult dxgi_capture()
|
|||||||
|
|
||||||
ID3D11Texture2D_Release(src);
|
ID3D11Texture2D_Release(src);
|
||||||
|
|
||||||
// set the state
|
// set the state and signal
|
||||||
tex->state = TEXTURE_STATE_PENDING_MAP;
|
tex->state = TEXTURE_STATE_PENDING_MAP;
|
||||||
INTERLOCKED_DEC(&tex->free);
|
os_signalEvent(tex->readyEvent);
|
||||||
INTERLOCKED_INC(&this->texPending);
|
|
||||||
|
|
||||||
// advance our write pointer
|
// advance our write pointer
|
||||||
if (++this->texWIndex == this->maxTextures)
|
if (++this->texWIndex == this->maxTextures)
|
||||||
@ -752,11 +761,8 @@ static CaptureResult dxgi_waitFrame(CaptureFrame * frame)
|
|||||||
assert(this->initialized);
|
assert(this->initialized);
|
||||||
|
|
||||||
Texture * tex = &this->texture[INTERLOCKED_GET(&this->texRIndex)];
|
Texture * tex = &this->texture[INTERLOCKED_GET(&this->texRIndex)];
|
||||||
if (INTERLOCKED_GET(&tex->free))
|
if (!os_waitEvent(tex->readyEvent, 1000))
|
||||||
{
|
|
||||||
Sleep(1);
|
|
||||||
return CAPTURE_RESULT_TIMEOUT;
|
return CAPTURE_RESULT_TIMEOUT;
|
||||||
}
|
|
||||||
|
|
||||||
// try to map the resource, but don't wait for it
|
// try to map the resource, but don't wait for it
|
||||||
HRESULT status;
|
HRESULT status;
|
||||||
@ -771,7 +777,6 @@ static CaptureResult dxgi_waitFrame(CaptureFrame * frame)
|
|||||||
}
|
}
|
||||||
|
|
||||||
tex->state = TEXTURE_STATE_MAPPED;
|
tex->state = TEXTURE_STATE_MAPPED;
|
||||||
INTERLOCKED_DEC(&this->texPending);
|
|
||||||
|
|
||||||
frame->width = this->width;
|
frame->width = this->width;
|
||||||
frame->height = this->height;
|
frame->height = this->height;
|
||||||
@ -779,6 +784,7 @@ static CaptureResult dxgi_waitFrame(CaptureFrame * frame)
|
|||||||
frame->stride = this->stride;
|
frame->stride = this->stride;
|
||||||
frame->format = this->format;
|
frame->format = this->format;
|
||||||
|
|
||||||
|
os_resetEvent(tex->readyEvent);
|
||||||
return CAPTURE_RESULT_OK;
|
return CAPTURE_RESULT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -791,8 +797,8 @@ static CaptureResult dxgi_getFrame(FrameBuffer frame)
|
|||||||
|
|
||||||
framebuffer_write(frame, tex->map.pData, this->pitch * this->height);
|
framebuffer_write(frame, tex->map.pData, this->pitch * this->height);
|
||||||
LOCKED({ID3D11DeviceContext_Unmap(this->deviceContext, (ID3D11Resource*)tex->tex, 0);});
|
LOCKED({ID3D11DeviceContext_Unmap(this->deviceContext, (ID3D11Resource*)tex->tex, 0);});
|
||||||
|
tex->state = TEXTURE_STATE_UNUSED;
|
||||||
|
|
||||||
INTERLOCKED_INC(&tex->free);
|
|
||||||
INTERLOCKED_INC(&this->texRIndex);
|
INTERLOCKED_INC(&this->texRIndex);
|
||||||
INTERLOCKED_CE (&this->texRIndex, this->maxTextures, 0);
|
INTERLOCKED_CE (&this->texRIndex, this->maxTextures, 0);
|
||||||
|
|
||||||
|
@ -38,6 +38,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
|
|
||||||
struct AppState
|
struct AppState
|
||||||
{
|
{
|
||||||
|
LARGE_INTEGER perfFreq;
|
||||||
HINSTANCE hInst;
|
HINSTANCE hInst;
|
||||||
|
|
||||||
int argc;
|
int argc;
|
||||||
@ -69,6 +70,15 @@ struct osThreadHandle
|
|||||||
int resultCode;
|
int resultCode;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct osEventHandle
|
||||||
|
{
|
||||||
|
bool reset;
|
||||||
|
HANDLE handle;
|
||||||
|
bool wrapped;
|
||||||
|
unsigned int msSpinTime;
|
||||||
|
volatile bool signaled;
|
||||||
|
};
|
||||||
|
|
||||||
// undocumented API to adjust the system timer resolution (yes, its a nasty hack)
|
// undocumented API to adjust the system timer resolution (yes, its a nasty hack)
|
||||||
typedef NTSTATUS (__stdcall *ZwSetTimerResolution_t)(ULONG RequestedResolution, BOOLEAN Set, PULONG ActualResolution);
|
typedef NTSTATUS (__stdcall *ZwSetTimerResolution_t)(ULONG RequestedResolution, BOOLEAN Set, PULONG ActualResolution);
|
||||||
static ZwSetTimerResolution_t ZwSetTimerResolution = NULL;
|
static ZwSetTimerResolution_t ZwSetTimerResolution = NULL;
|
||||||
@ -320,6 +330,9 @@ bool app_init()
|
|||||||
DEBUG_INFO("System timer resolution: %.2f ns", (float)actualResolution / 100.0f);
|
DEBUG_INFO("System timer resolution: %.2f ns", (float)actualResolution / 100.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get the performance frequency for spinlocks
|
||||||
|
QueryPerformanceFrequency(&app.perfFreq);
|
||||||
|
|
||||||
HDEVINFO deviceInfoSet;
|
HDEVINFO deviceInfoSet;
|
||||||
PSP_DEVICE_INTERFACE_DETAIL_DATA infData = NULL;
|
PSP_DEVICE_INTERFACE_DETAIL_DATA infData = NULL;
|
||||||
SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
|
SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
|
||||||
@ -488,36 +501,98 @@ bool os_joinThread(osThreadHandle * handle, int * resultCode)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
osEventHandle * os_createEvent(bool autoReset)
|
osEventHandle * os_createEvent(bool autoReset, unsigned int msSpinTime)
|
||||||
{
|
{
|
||||||
HANDLE event = CreateEvent(NULL, autoReset ? FALSE : TRUE, FALSE, NULL);
|
osEventHandle * event = (osEventHandle *)malloc(sizeof(osEventHandle));
|
||||||
if (!event)
|
if (!event)
|
||||||
{
|
{
|
||||||
DEBUG_WINERROR("Failed to create the event", GetLastError());
|
DEBUG_ERROR("out of ram");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (osEventHandle*)event;
|
event->reset = autoReset;
|
||||||
|
event->wrapped = false;
|
||||||
|
event->msSpinTime = msSpinTime;
|
||||||
|
event->handle = CreateEvent(NULL, autoReset ? FALSE : TRUE, FALSE, NULL);
|
||||||
|
if (!event->handle)
|
||||||
|
{
|
||||||
|
DEBUG_WINERROR("Failed to create the event", GetLastError());
|
||||||
|
free(event);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
osEventHandle * os_wrapEvent(HANDLE event)
|
osEventHandle * os_wrapEvent(HANDLE handle)
|
||||||
{
|
{
|
||||||
return (osEventHandle*)event;
|
osEventHandle * event = (osEventHandle *)malloc(sizeof(osEventHandle));
|
||||||
|
if (!event)
|
||||||
|
{
|
||||||
|
DEBUG_ERROR("out of ram");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
event->reset = false;
|
||||||
|
event->handle = event;
|
||||||
|
event->wrapped = true;
|
||||||
|
event->msSpinTime = 0;
|
||||||
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
void os_freeEvent(osEventHandle * handle)
|
void os_freeEvent(osEventHandle * event)
|
||||||
{
|
{
|
||||||
CloseHandle((HANDLE)handle);
|
CloseHandle(event->handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool os_waitEvent(osEventHandle * handle, unsigned int timeout)
|
bool os_waitEvent(osEventHandle * event, unsigned int timeout)
|
||||||
{
|
{
|
||||||
|
// wrapped events can't be enahnced
|
||||||
|
if (!event->wrapped)
|
||||||
|
{
|
||||||
|
if (event->signaled)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (timeout == 0)
|
||||||
|
return event->signaled;
|
||||||
|
|
||||||
|
if (event->msSpinTime)
|
||||||
|
{
|
||||||
|
unsigned int spinTime = event->msSpinTime;
|
||||||
|
if (timeout != TIMEOUT_INFINITE)
|
||||||
|
{
|
||||||
|
if (timeout > event->msSpinTime)
|
||||||
|
timeout -= event->msSpinTime;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
spinTime -= timeout;
|
||||||
|
timeout = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LARGE_INTEGER end, now;
|
||||||
|
QueryPerformanceCounter(&end);
|
||||||
|
end.QuadPart += (app.perfFreq.QuadPart / 1000) * spinTime;
|
||||||
|
while(!event->signaled)
|
||||||
|
{
|
||||||
|
QueryPerformanceCounter(&now);
|
||||||
|
if (now.QuadPart >= end.QuadPart)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event->signaled)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const DWORD to = (timeout == TIMEOUT_INFINITE) ? INFINITE : (DWORD)timeout;
|
const DWORD to = (timeout == TIMEOUT_INFINITE) ? INFINITE : (DWORD)timeout;
|
||||||
while(true)
|
while(true)
|
||||||
{
|
{
|
||||||
switch(WaitForSingleObject((HANDLE)handle, to))
|
switch(WaitForSingleObject(event->handle, to))
|
||||||
{
|
{
|
||||||
case WAIT_OBJECT_0:
|
case WAIT_OBJECT_0:
|
||||||
|
if (!event->reset)
|
||||||
|
event->signaled = true;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case WAIT_ABANDONED:
|
case WAIT_ABANDONED:
|
||||||
@ -539,18 +614,24 @@ bool os_waitEvent(osEventHandle * handle, unsigned int timeout)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool os_waitEvents(osEventHandle * handles[], int count, bool waitAll, unsigned int timeout)
|
bool os_waitEvents(osEventHandle * events[], int count, bool waitAll, unsigned int timeout)
|
||||||
{
|
{
|
||||||
const DWORD to = (timeout == TIMEOUT_INFINITE) ? INFINITE : (DWORD)timeout;
|
const DWORD to = (timeout == TIMEOUT_INFINITE) ? INFINITE : (DWORD)timeout;
|
||||||
|
|
||||||
|
HANDLE * handles = (HANDLE *)malloc(sizeof(HANDLE) * count);
|
||||||
|
for(int i = 0; i < count; ++i)
|
||||||
|
handles[i] = events[i]->handle;
|
||||||
|
|
||||||
while(true)
|
while(true)
|
||||||
{
|
{
|
||||||
DWORD result = WaitForMultipleObjects(count, (HANDLE*)handles, waitAll, to);
|
DWORD result = WaitForMultipleObjects(count, handles, waitAll, to);
|
||||||
if (result >= WAIT_OBJECT_0 && result < count)
|
if (result >= WAIT_OBJECT_0 && result < count)
|
||||||
{
|
{
|
||||||
// null non signalled events from the handle list
|
// null non signaled events from the handle list
|
||||||
for(int i = 0; i < count; ++i)
|
for(int i = 0; i < count; ++i)
|
||||||
if (i != result && !os_waitEvent(handles[i], 0))
|
if (i != result && !os_waitEvent(events[i], 0))
|
||||||
handles[i] = NULL;
|
handles[i] = NULL;
|
||||||
|
free(handles);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -563,24 +644,29 @@ bool os_waitEvents(osEventHandle * handles[], int count, bool waitAll, unsigned
|
|||||||
if (timeout == TIMEOUT_INFINITE)
|
if (timeout == TIMEOUT_INFINITE)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
free(handles);
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
case WAIT_FAILED:
|
case WAIT_FAILED:
|
||||||
DEBUG_WINERROR("Wait for event failed", GetLastError());
|
DEBUG_WINERROR("Wait for event failed", GetLastError());
|
||||||
|
free(handles);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_ERROR("Unknown wait event return code");
|
DEBUG_ERROR("Unknown wait event return code");
|
||||||
|
free(handles);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool os_signalEvent(osEventHandle * handle)
|
bool os_signalEvent(osEventHandle * event)
|
||||||
{
|
{
|
||||||
return SetEvent((HANDLE)handle);
|
event->signaled = true;
|
||||||
|
return SetEvent(event->handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool os_resetEvent(osEventHandle * handle)
|
bool os_resetEvent(osEventHandle * event)
|
||||||
{
|
{
|
||||||
return ResetEvent((HANDLE)handle);
|
event->signaled = false;
|
||||||
|
return ResetEvent(event->handle);
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user