diff --git a/host/platform/Windows/capture/DXGI/src/dxgi.c b/host/platform/Windows/capture/DXGI/src/dxgi.c index d4f4975a..90940bf0 100644 --- a/host/platform/Windows/capture/DXGI/src/dxgi.c +++ b/host/platform/Windows/capture/DXGI/src/dxgi.c @@ -27,6 +27,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA #include #include +#include #include #include #include @@ -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;