mirror of
https://github.com/gnif/LookingGlass.git
synced 2024-11-25 23:07:18 +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 <assert.h>
|
||||||
#include <stdatomic.h>
|
#include <stdatomic.h>
|
||||||
|
#include <unistd.h>
|
||||||
#include <dxgi.h>
|
#include <dxgi.h>
|
||||||
#include <d3d11.h>
|
#include <d3d11.h>
|
||||||
#include <d3dcommon.h>
|
#include <d3dcommon.h>
|
||||||
@ -56,7 +57,7 @@ enum TextureState
|
|||||||
|
|
||||||
typedef struct Texture
|
typedef struct Texture
|
||||||
{
|
{
|
||||||
enum TextureState state;
|
volatile enum TextureState state;
|
||||||
ID3D11Texture2D * tex;
|
ID3D11Texture2D * tex;
|
||||||
D3D11_MAPPED_SUBRESOURCE map;
|
D3D11_MAPPED_SUBRESOURCE map;
|
||||||
}
|
}
|
||||||
@ -706,6 +707,15 @@ static CaptureResult dxgi_capture()
|
|||||||
DXGI_OUTDUPL_FRAME_INFO frameInfo;
|
DXGI_OUTDUPL_FRAME_INFO frameInfo;
|
||||||
IDXGIResource * res;
|
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
|
// release the prior frame
|
||||||
result = dxgi_releaseFrame();
|
result = dxgi_releaseFrame();
|
||||||
if (result != CAPTURE_RESULT_OK)
|
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
|
// check if the texture is free, if not skip the frame to keep up
|
||||||
if (tex->state == TEXTURE_STATE_UNUSED)
|
if (tex->state == TEXTURE_STATE_UNUSED)
|
||||||
{
|
{
|
||||||
ID3D11Texture2D * src;
|
copyFrame = true;
|
||||||
status = IDXGIResource_QueryInterface(res, &IID_ID3D11Texture2D, (void **)&src);
|
status = IDXGIResource_QueryInterface(res, &IID_ID3D11Texture2D, (void **)&src);
|
||||||
if (FAILED(status))
|
if (FAILED(status))
|
||||||
{
|
{
|
||||||
@ -745,13 +755,43 @@ static CaptureResult dxgi_capture()
|
|||||||
IDXGIResource_Release(res);
|
IDXGIResource_Release(res);
|
||||||
return CAPTURE_RESULT_ERROR;
|
return CAPTURE_RESULT_ERROR;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LOCKED({
|
// if the pointer shape has changed
|
||||||
// issue the copy from GPU to CPU RAM and release the src
|
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,
|
ID3D11DeviceContext_CopyResource(this->deviceContext,
|
||||||
(ID3D11Resource *)tex->tex, (ID3D11Resource *)src);
|
(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);
|
ID3D11Texture2D_Release(src);
|
||||||
|
|
||||||
// set the state, and signal
|
// set the state, and signal
|
||||||
@ -766,51 +806,9 @@ static CaptureResult dxgi_capture()
|
|||||||
// update the last frame time
|
// update the last frame time
|
||||||
this->frameTime.QuadPart = frameInfo.LastPresentTime.QuadPart;
|
this->frameTime.QuadPart = frameInfo.LastPresentTime.QuadPart;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
IDXGIResource_Release(res);
|
if (copyPointer)
|
||||||
|
|
||||||
// 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))
|
|
||||||
{
|
{
|
||||||
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);
|
result = dxgi_hResultToCaptureResult(status);
|
||||||
if (result != CAPTURE_RESULT_OK)
|
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
|
// post back the pointer information
|
||||||
if (postPointer)
|
if (postPointer)
|
||||||
{
|
{
|
||||||
@ -866,15 +890,26 @@ static CaptureResult dxgi_waitFrame(CaptureFrame * frame)
|
|||||||
Texture * tex = &this->texture[this->texRIndex];
|
Texture * tex = &this->texture[this->texRIndex];
|
||||||
|
|
||||||
// try to map the resource, but don't wait for it
|
// try to map the resource, but don't wait for it
|
||||||
HRESULT status;
|
for (int i = 0; ; ++i)
|
||||||
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))
|
|
||||||
{
|
{
|
||||||
DEBUG_WINERROR("Failed to map the texture", status);
|
HRESULT status;
|
||||||
return CAPTURE_RESULT_ERROR;
|
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;
|
tex->state = TEXTURE_STATE_MAPPED;
|
||||||
|
Loading…
Reference in New Issue
Block a user