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