mirror of
https://github.com/gnif/LookingGlass.git
synced 2024-11-10 08:38:20 +00:00
[host] dxgi: rework locking and retry logic for lower latency
This commit is contained in:
parent
cdc3384883
commit
1c7961daeb
@ -27,6 +27,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdatomic.h>
|
||||
#include <unistd.h>
|
||||
#include <dxgi.h>
|
||||
#include <d3d11.h>
|
||||
#include <d3dcommon.h>
|
||||
@ -56,7 +57,7 @@ enum TextureState
|
||||
|
||||
typedef struct Texture
|
||||
{
|
||||
enum TextureState state;
|
||||
volatile enum TextureState state;
|
||||
ID3D11Texture2D * tex;
|
||||
D3D11_MAPPED_SUBRESOURCE map;
|
||||
}
|
||||
@ -706,6 +707,15 @@ static CaptureResult dxgi_capture()
|
||||
DXGI_OUTDUPL_FRAME_INFO frameInfo;
|
||||
IDXGIResource * res;
|
||||
|
||||
bool copyFrame = false;
|
||||
bool copyPointer = false;
|
||||
ID3D11Texture2D * src;
|
||||
|
||||
bool postPointer = false;
|
||||
CapturePointer pointer = { 0 };
|
||||
void * pointerShape = NULL;
|
||||
UINT pointerShapeSize = 0;
|
||||
|
||||
// release the prior frame
|
||||
result = dxgi_releaseFrame();
|
||||
if (result != CAPTURE_RESULT_OK)
|
||||
@ -737,7 +747,7 @@ static CaptureResult dxgi_capture()
|
||||
// check if the texture is free, if not skip the frame to keep up
|
||||
if (tex->state == TEXTURE_STATE_UNUSED)
|
||||
{
|
||||
ID3D11Texture2D * src;
|
||||
copyFrame = true;
|
||||
status = IDXGIResource_QueryInterface(res, &IID_ID3D11Texture2D, (void **)&src);
|
||||
if (FAILED(status))
|
||||
{
|
||||
@ -745,13 +755,43 @@ static CaptureResult dxgi_capture()
|
||||
IDXGIResource_Release(res);
|
||||
return CAPTURE_RESULT_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LOCKED({
|
||||
// issue the copy from GPU to CPU RAM and release the src
|
||||
// if the pointer shape has changed
|
||||
uint32_t bufferSize;
|
||||
if (frameInfo.PointerShapeBufferSize > 0)
|
||||
{
|
||||
if(!this->getPointerBufferFn(&pointerShape, &bufferSize))
|
||||
DEBUG_WARN("Failed to obtain a buffer for the pointer shape");
|
||||
else
|
||||
copyPointer = true;
|
||||
}
|
||||
|
||||
if (copyFrame || copyPointer)
|
||||
{
|
||||
DXGI_OUTDUPL_POINTER_SHAPE_INFO shapeInfo;
|
||||
LOCKED(
|
||||
{
|
||||
if (copyFrame)
|
||||
{
|
||||
// issue the copy from GPU to CPU RAM
|
||||
ID3D11DeviceContext_CopyResource(this->deviceContext,
|
||||
(ID3D11Resource *)tex->tex, (ID3D11Resource *)src);
|
||||
});
|
||||
}
|
||||
|
||||
if (copyPointer)
|
||||
{
|
||||
// grab the pointer shape
|
||||
status = IDXGIOutputDuplication_GetFramePointerShape(
|
||||
this->dup, bufferSize, pointerShape, &pointerShapeSize, &shapeInfo);
|
||||
}
|
||||
|
||||
ID3D11DeviceContext_Flush(this->deviceContext);
|
||||
});
|
||||
|
||||
if (copyFrame)
|
||||
{
|
||||
ID3D11Texture2D_Release(src);
|
||||
|
||||
// set the state, and signal
|
||||
@ -766,51 +806,9 @@ static CaptureResult dxgi_capture()
|
||||
// update the last frame time
|
||||
this->frameTime.QuadPart = frameInfo.LastPresentTime.QuadPart;
|
||||
}
|
||||
}
|
||||
|
||||
IDXGIResource_Release(res);
|
||||
|
||||
// if the pointer has moved or changed state
|
||||
bool postPointer = false;
|
||||
CapturePointer pointer = { 0 };
|
||||
void * pointerShape = NULL;
|
||||
UINT pointerShapeSize = 0;
|
||||
|
||||
if (frameInfo.LastMouseUpdateTime.QuadPart)
|
||||
{
|
||||
/* the pointer position is only valid if the pointer is visible */
|
||||
if (frameInfo.PointerPosition.Visible &&
|
||||
(frameInfo.PointerPosition.Position.x != this->lastPointerX ||
|
||||
frameInfo.PointerPosition.Position.y != this->lastPointerY))
|
||||
if (copyPointer)
|
||||
{
|
||||
pointer.positionUpdate = true;
|
||||
pointer.x =
|
||||
this->lastPointerX =
|
||||
frameInfo.PointerPosition.Position.x;
|
||||
pointer.y =
|
||||
this->lastPointerY =
|
||||
frameInfo.PointerPosition.Position.y;
|
||||
postPointer = true;
|
||||
}
|
||||
|
||||
if (this->lastPointerVisible != frameInfo.PointerPosition.Visible)
|
||||
{
|
||||
this->lastPointerVisible = frameInfo.PointerPosition.Visible;
|
||||
postPointer = true;
|
||||
}
|
||||
}
|
||||
|
||||
// if the pointer shape has changed
|
||||
if (frameInfo.PointerShapeBufferSize > 0)
|
||||
{
|
||||
uint32_t bufferSize;
|
||||
if(!this->getPointerBufferFn(&pointerShape, &bufferSize))
|
||||
DEBUG_WARN("Failed to obtain a buffer for the pointer shape");
|
||||
else
|
||||
{
|
||||
DXGI_OUTDUPL_POINTER_SHAPE_INFO shapeInfo;
|
||||
|
||||
LOCKED({status = IDXGIOutputDuplication_GetFramePointerShape(this->dup, bufferSize, pointerShape, &pointerShapeSize, &shapeInfo);});
|
||||
result = dxgi_hResultToCaptureResult(status);
|
||||
if (result != CAPTURE_RESULT_OK)
|
||||
{
|
||||
@ -837,6 +835,32 @@ static CaptureResult dxgi_capture()
|
||||
}
|
||||
}
|
||||
|
||||
IDXGIResource_Release(res);
|
||||
|
||||
if (frameInfo.LastMouseUpdateTime.QuadPart)
|
||||
{
|
||||
/* the pointer position is only valid if the pointer is visible */
|
||||
if (frameInfo.PointerPosition.Visible &&
|
||||
(frameInfo.PointerPosition.Position.x != this->lastPointerX ||
|
||||
frameInfo.PointerPosition.Position.y != this->lastPointerY))
|
||||
{
|
||||
pointer.positionUpdate = true;
|
||||
pointer.x =
|
||||
this->lastPointerX =
|
||||
frameInfo.PointerPosition.Position.x;
|
||||
pointer.y =
|
||||
this->lastPointerY =
|
||||
frameInfo.PointerPosition.Position.y;
|
||||
postPointer = true;
|
||||
}
|
||||
|
||||
if (this->lastPointerVisible != frameInfo.PointerPosition.Visible)
|
||||
{
|
||||
this->lastPointerVisible = frameInfo.PointerPosition.Visible;
|
||||
postPointer = true;
|
||||
}
|
||||
}
|
||||
|
||||
// post back the pointer information
|
||||
if (postPointer)
|
||||
{
|
||||
@ -866,15 +890,26 @@ static CaptureResult dxgi_waitFrame(CaptureFrame * frame)
|
||||
Texture * tex = &this->texture[this->texRIndex];
|
||||
|
||||
// try to map the resource, but don't wait for it
|
||||
HRESULT status;
|
||||
LOCKED({status = ID3D11DeviceContext_Map(this->deviceContext, (ID3D11Resource*)tex->tex, 0, D3D11_MAP_READ, 0x100000L, &tex->map);});
|
||||
if (status == DXGI_ERROR_WAS_STILL_DRAWING)
|
||||
return CAPTURE_RESULT_TIMEOUT;
|
||||
|
||||
if (FAILED(status))
|
||||
for (int i = 0; ; ++i)
|
||||
{
|
||||
DEBUG_WINERROR("Failed to map the texture", status);
|
||||
return CAPTURE_RESULT_ERROR;
|
||||
HRESULT status;
|
||||
LOCKED({status = ID3D11DeviceContext_Map(this->deviceContext, (ID3D11Resource*)tex->tex, 0, D3D11_MAP_READ, 0x100000L, &tex->map);});
|
||||
if (status == DXGI_ERROR_WAS_STILL_DRAWING)
|
||||
{
|
||||
if (i == 100)
|
||||
return CAPTURE_RESULT_TIMEOUT;
|
||||
|
||||
usleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (FAILED(status))
|
||||
{
|
||||
DEBUG_WINERROR("Failed to map the texture", status);
|
||||
return CAPTURE_RESULT_ERROR;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
tex->state = TEXTURE_STATE_MAPPED;
|
||||
|
Loading…
Reference in New Issue
Block a user