From c45ddc783e18603b7a6b99df72d146e01615ab1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Fri, 18 Jul 2014 17:26:21 -0400 Subject: [PATCH] shadow: improve DXGI 1.2 error checking --- include/freerdp/server/shadow.h | 11 +- server/shadow/Win/win_shadow.c | 301 +++++++++++++++++++++++--------- server/shadow/Win/win_shadow.h | 2 + server/shadow/shadow_client.c | 140 +++++++-------- server/shadow/shadow_client.h | 1 + server/shadow/shadow_encomsp.c | 2 +- server/shadow/shadow_server.c | 123 +++++++++++-- 7 files changed, 410 insertions(+), 170 deletions(-) diff --git a/include/freerdp/server/shadow.h b/include/freerdp/server/shadow.h index c5b7e2036..17820b996 100644 --- a/include/freerdp/server/shadow.h +++ b/include/freerdp/server/shadow.h @@ -55,6 +55,7 @@ typedef int (*pfnShadowSubsystemStop)(rdpShadowSubsystem* subsystem); typedef void (*pfnShadowSubsystemFree)(rdpShadowSubsystem* subsystem); typedef int (*pfnShadowSurfaceCopy)(rdpShadowSubsystem* subsystem); +typedef int (*pfnShadowSurfaceUpdate)(rdpShadowSubsystem* subsystem, REGION16* region); typedef int (*pfnShadowSynchronizeEvent)(rdpShadowSubsystem* subsystem, UINT32 flags); typedef int (*pfnShadowKeyboardEvent)(rdpShadowSubsystem* subsystem, UINT16 flags, UINT16 code); @@ -72,8 +73,11 @@ struct rdp_shadow_client BOOL mayView; BOOL mayInteract; HANDLE StopEvent; + CRITICAL_SECTION lock; + REGION16 invalidRegion; rdpShadowServer* server; rdpShadowSurface* lobby; + rdpShadowEncoder* encoder; HANDLE vcm; EncomspServerContext* encomsp; @@ -85,15 +89,18 @@ struct rdp_shadow_server void* ext; HANDLE thread; HANDLE StopEvent; + wArrayList* clients; rdpShadowScreen* screen; rdpShadowSurface* surface; - rdpShadowEncoder* encoder; rdpShadowSubsystem* subsystem; DWORD port; BOOL mayView; BOOL mayInteract; char* ConfigPath; + char* CertificateFile; + char* PrivateKeyFile; + CRITICAL_SECTION lock; freerdp_listener* listener; pfnShadowCreateSubsystem CreateSubsystem; }; @@ -103,6 +110,7 @@ struct rdp_shadow_server int monitorCount; \ MONITOR_DEF monitors[16]; \ MONITOR_DEF virtualScreen; \ + REGION16 invalidRegion; \ \ pfnShadowSubsystemInit Init; \ pfnShadowSubsystemUninit Uninit; \ @@ -111,6 +119,7 @@ struct rdp_shadow_server pfnShadowSubsystemFree Free; \ \ pfnShadowSurfaceCopy SurfaceCopy; \ + pfnShadowSurfaceUpdate SurfaceUpdate; \ \ pfnShadowSynchronizeEvent SynchronizeEvent; \ pfnShadowKeyboardEvent KeyboardEvent; \ diff --git a/server/shadow/Win/win_shadow.c b/server/shadow/Win/win_shadow.c index e49243cc6..e9e746675 100644 --- a/server/shadow/Win/win_shadow.c +++ b/server/shadow/Win/win_shadow.c @@ -136,6 +136,87 @@ DEFINE_GUID(IID_IDXGIFactory2, 0x50c83a1c, 0xe072, 0x4c48, 0x87, 0xb0, 0x36, 0x3 DEFINE_GUID(IID_IDXGIAdapter2, 0x0AA1AE0A, 0xFA0E, 0x4B84, 0x86, 0x44, 0xE0, 0x5F, 0xF8, 0xE5, 0xAC, 0xB5); DEFINE_GUID(IID_IDXGIOutput1, 0x00cddea8, 0x939b, 0x4b83, 0xa3, 0x40, 0xa6, 0x85, 0x22, 0x66, 0x66, 0xcc); +const char* GetDxgiErrorString(HRESULT hr) +{ + switch (hr) + { + case DXGI_STATUS_OCCLUDED: + return "DXGI_STATUS_OCCLUDED"; + case DXGI_STATUS_CLIPPED: + return "DXGI_STATUS_CLIPPED"; + case DXGI_STATUS_NO_REDIRECTION: + return "DXGI_STATUS_NO_REDIRECTION"; + case DXGI_STATUS_NO_DESKTOP_ACCESS: + return "DXGI_STATUS_NO_DESKTOP_ACCESS"; + case DXGI_STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE: + return "DXGI_STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE"; + case DXGI_STATUS_MODE_CHANGED: + return "DXGI_STATUS_MODE_CHANGED"; + case DXGI_STATUS_MODE_CHANGE_IN_PROGRESS: + return "DXGI_STATUS_MODE_CHANGE_IN_PROGRESS"; + case DXGI_ERROR_INVALID_CALL: + return "DXGI_ERROR_INVALID_CALL"; + case DXGI_ERROR_NOT_FOUND: + return "DXGI_ERROR_NOT_FOUND"; + case DXGI_ERROR_MORE_DATA: + return "DXGI_ERROR_MORE_DATA"; + case DXGI_ERROR_UNSUPPORTED: + return "DXGI_ERROR_UNSUPPORTED"; + case DXGI_ERROR_DEVICE_REMOVED: + return "DXGI_ERROR_DEVICE_REMOVED"; + case DXGI_ERROR_DEVICE_HUNG: + return "DXGI_ERROR_DEVICE_HUNG"; + case DXGI_ERROR_DEVICE_RESET: + return "DXGI_ERROR_DEVICE_RESET"; + case DXGI_ERROR_WAS_STILL_DRAWING: + return "DXGI_ERROR_WAS_STILL_DRAWING"; + case DXGI_ERROR_FRAME_STATISTICS_DISJOINT: + return "DXGI_ERROR_FRAME_STATISTICS_DISJOINT"; + case DXGI_ERROR_GRAPHICS_VIDPN_SOURCE_IN_USE: + return "DXGI_ERROR_GRAPHICS_VIDPN_SOURCE_IN_USE"; + case DXGI_ERROR_DRIVER_INTERNAL_ERROR: + return "DXGI_ERROR_DRIVER_INTERNAL_ERROR"; + case DXGI_ERROR_NONEXCLUSIVE: + return "DXGI_ERROR_NONEXCLUSIVE"; + case DXGI_ERROR_NOT_CURRENTLY_AVAILABLE: + return "DXGI_ERROR_NOT_CURRENTLY_AVAILABLE"; + case DXGI_ERROR_REMOTE_CLIENT_DISCONNECTED: + return "DXGI_ERROR_REMOTE_CLIENT_DISCONNECTED"; + case DXGI_ERROR_REMOTE_OUTOFMEMORY: + return "DXGI_ERROR_REMOTE_OUTOFMEMORY"; + case DXGI_ERROR_ACCESS_LOST: + return "DXGI_ERROR_ACCESS_LOST"; + case DXGI_ERROR_WAIT_TIMEOUT: + return "DXGI_ERROR_WAIT_TIMEOUT"; + case DXGI_ERROR_SESSION_DISCONNECTED: + return "DXGI_ERROR_SESSION_DISCONNECTED"; + case DXGI_ERROR_RESTRICT_TO_OUTPUT_STALE: + return "DXGI_ERROR_RESTRICT_TO_OUTPUT_STALE"; + case DXGI_ERROR_CANNOT_PROTECT_CONTENT: + return "DXGI_ERROR_CANNOT_PROTECT_CONTENT"; + case DXGI_ERROR_ACCESS_DENIED: + return "DXGI_ERROR_ACCESS_DENIED"; + case DXGI_ERROR_NAME_ALREADY_EXISTS: + return "DXGI_ERROR_NAME_ALREADY_EXISTS"; + case DXGI_ERROR_SDK_COMPONENT_MISSING: + return "DXGI_ERROR_SDK_COMPONENT_MISSING"; + case DXGI_STATUS_UNOCCLUDED: + return "DXGI_STATUS_UNOCCLUDED"; + case DXGI_STATUS_DDA_WAS_STILL_DRAWING: + return "DXGI_STATUS_DDA_WAS_STILL_DRAWING"; + case DXGI_ERROR_MODE_CHANGE_IN_PROGRESS: + return "DXGI_ERROR_MODE_CHANGE_IN_PROGRESS"; + case DXGI_DDI_ERR_WASSTILLDRAWING: + return "DXGI_DDI_ERR_WASSTILLDRAWING"; + case DXGI_DDI_ERR_UNSUPPORTED: + return "DXGI_DDI_ERR_UNSUPPORTED"; + case DXGI_DDI_ERR_NONEXCLUSIVE: + return "DXGI_DDI_ERR_NONEXCLUSIVE"; + } + + return "DXGI_ERROR_UNKNOWN"; +} + static void win_shadow_d3d11_module_init() { if (d3d11_module) @@ -155,39 +236,55 @@ int win_shadow_dxgi_init_duplication(winShadowSubsystem* subsystem) UINT dTop, i = 0; IDXGIOutput* pOutput; DXGI_OUTPUT_DESC outputDesc; + DXGI_OUTPUT_DESC* pOutputDesc; D3D11_TEXTURE2D_DESC textureDesc; - IDXGIDevice* DxgiDevice = NULL; - IDXGIAdapter* DxgiAdapter = NULL; - IDXGIOutput* DxgiOutput = NULL; - IDXGIOutput1* DxgiOutput1 = NULL; + IDXGIDevice* dxgiDevice = NULL; + IDXGIAdapter* dxgiAdapter = NULL; + IDXGIOutput* dxgiOutput = NULL; + IDXGIOutput1* dxgiOutput1 = NULL; hr = subsystem->dxgiDevice->lpVtbl->QueryInterface(subsystem->dxgiDevice, - &IID_IDXGIDevice, (void**) &DxgiDevice); + &IID_IDXGIDevice, (void**) &dxgiDevice); if (FAILED(hr)) + { + fprintf(stderr, "ID3D11Device::QueryInterface(IDXGIDevice) failure: %s (0x%04X)\n", + GetDxgiErrorString(hr), hr); return -1; + } - hr = DxgiDevice->lpVtbl->GetParent(DxgiDevice, &IID_IDXGIAdapter, (void**) &DxgiAdapter); + hr = dxgiDevice->lpVtbl->GetParent(dxgiDevice, &IID_IDXGIAdapter, (void**) &dxgiAdapter); - DxgiDevice->lpVtbl->Release(DxgiDevice); - DxgiDevice = NULL; + if (dxgiDevice) + { + dxgiDevice->lpVtbl->Release(dxgiDevice); + dxgiDevice = NULL; + } if (FAILED(hr)) + { + fprintf(stderr, "IDXGIDevice::GetParent(IDXGIAdapter) failure: %s (0x%04X)\n", + GetDxgiErrorString(hr), hr); return -1; + } pOutput = NULL; ZeroMemory(&outputDesc, sizeof(outputDesc)); - while (DxgiAdapter->lpVtbl->EnumOutputs(DxgiAdapter, i, &pOutput) != DXGI_ERROR_NOT_FOUND) + while (dxgiAdapter->lpVtbl->EnumOutputs(dxgiAdapter, i, &pOutput) != DXGI_ERROR_NOT_FOUND) { - DXGI_OUTPUT_DESC* pDesc = &outputDesc; + pOutputDesc = &outputDesc; - hr = pOutput->lpVtbl->GetDesc(pOutput, pDesc); + hr = pOutput->lpVtbl->GetDesc(pOutput, pOutputDesc); if (FAILED(hr)) + { + fprintf(stderr, "IDXGIOutput::GetDesc failure: %s (0x%04X)\n", + GetDxgiErrorString(hr), hr); return -1; + } - if (pDesc->AttachedToDesktop) + if (pOutputDesc->AttachedToDesktop) dTop = i; pOutput->lpVtbl->Release(pOutput); @@ -196,30 +293,51 @@ int win_shadow_dxgi_init_duplication(winShadowSubsystem* subsystem) dTop = 0; /* screen id */ - hr = DxgiAdapter->lpVtbl->EnumOutputs(DxgiAdapter, dTop, &DxgiOutput); + hr = dxgiAdapter->lpVtbl->EnumOutputs(dxgiAdapter, dTop, &dxgiOutput); - DxgiAdapter->lpVtbl->Release(DxgiAdapter); - DxgiAdapter = NULL; + if (dxgiAdapter) + { + dxgiAdapter->lpVtbl->Release(dxgiAdapter); + dxgiAdapter = NULL; + } if (FAILED(hr)) + { + fprintf(stderr, "IDXGIAdapter::EnumOutputs failure: %s (0x%04X)\n", + GetDxgiErrorString(hr), hr); return -1; + } - hr = DxgiOutput->lpVtbl->QueryInterface(DxgiOutput, &IID_IDXGIOutput1, (void**) &DxgiOutput1); + hr = dxgiOutput->lpVtbl->QueryInterface(dxgiOutput, &IID_IDXGIOutput1, (void**) &dxgiOutput1); - DxgiOutput->lpVtbl->Release(DxgiOutput); - DxgiOutput = NULL; + if (dxgiOutput) + { + dxgiOutput->lpVtbl->Release(dxgiOutput); + dxgiOutput = NULL; + } if (FAILED(hr)) + { + fprintf(stderr, "IDXGIOutput::QueryInterface(IDXGIOutput1) failure: %s (0x%04X)\n", + GetDxgiErrorString(hr), hr); return -1; + } - hr = DxgiOutput1->lpVtbl->DuplicateOutput(DxgiOutput1, (IUnknown*) subsystem->dxgiDevice, + hr = dxgiOutput1->lpVtbl->DuplicateOutput(dxgiOutput1, (IUnknown*) subsystem->dxgiDevice, &(subsystem->dxgiOutputDuplication)); - DxgiOutput1->lpVtbl->Release(DxgiOutput1); - DxgiOutput1 = NULL; + if (dxgiOutput1) + { + dxgiOutput1->lpVtbl->Release(dxgiOutput1); + dxgiOutput1 = NULL; + } if (FAILED(hr)) + { + fprintf(stderr, "IDXGIOutput1::DuplicateOutput failure: %s (0x%04X)\n", + GetDxgiErrorString(hr), hr); return -1; + } textureDesc.Width = subsystem->width; textureDesc.Height = subsystem->height; @@ -237,7 +355,11 @@ int win_shadow_dxgi_init_duplication(winShadowSubsystem* subsystem) &textureDesc, NULL, &(subsystem->dxgiStage)); if (FAILED(hr)) + { + fprintf(stderr, "ID3D11Device::CreateTexture2D failure: %s (0x%04X)\n", + GetDxgiErrorString(hr), hr); return -1; + } return 1; } @@ -268,7 +390,10 @@ int win_shadow_dxgi_init(winShadowSubsystem* subsystem) } if (FAILED(hr)) + { + fprintf(stderr, "D3D11CreateDevice failure: 0x%04X\n", hr); return -1; + } win_shadow_dxgi_init_duplication(subsystem); @@ -317,6 +442,9 @@ int win_shadow_dxgi_fetch_frame_data(winShadowSubsystem* subsystem, D3D11_BOX Box; DXGI_MAPPED_RECT mappedRect; + if ((width * height) < 1) + return 1; + Box.top = x; Box.left = y; Box.right = x + width; @@ -331,12 +459,22 @@ int win_shadow_dxgi_fetch_frame_data(winShadowSubsystem* subsystem, &IID_IDXGISurface, (void**) &(subsystem->dxgiSurface)); if (FAILED(hr)) + { + fprintf(stderr, "ID3D11Texture2D::QueryInterface(IDXGISurface) failure: %s 0x%04X\n", + GetDxgiErrorString(hr), hr); return -1; + } hr = subsystem->dxgiSurface->lpVtbl->Map(subsystem->dxgiSurface, &mappedRect, DXGI_MAP_READ); if (FAILED(hr)) + { + fprintf(stderr, "IDXGISurface::Map failure: %s 0x%04X\n", + GetDxgiErrorString(hr), hr); return -1; + } + + subsystem->dxgiSurfaceMapped = TRUE; *ppDstData = mappedRect.pBits; *pnDstStep = mappedRect.Pitch; @@ -346,22 +484,26 @@ int win_shadow_dxgi_fetch_frame_data(winShadowSubsystem* subsystem, int win_shadow_dxgi_release_frame_data(winShadowSubsystem* subsystem) { - HRESULT hr; - if (subsystem->dxgiSurface) { - subsystem->dxgiSurface->lpVtbl->Unmap(subsystem->dxgiSurface); + if (subsystem->dxgiSurfaceMapped) + { + subsystem->dxgiSurface->lpVtbl->Unmap(subsystem->dxgiSurface); + subsystem->dxgiSurfaceMapped = FALSE; + } + subsystem->dxgiSurface->lpVtbl->Release(subsystem->dxgiSurface); subsystem->dxgiSurface = NULL; } - hr = subsystem->dxgiOutputDuplication->lpVtbl->ReleaseFrame(subsystem->dxgiOutputDuplication); + if (subsystem->dxgiFrameAcquired) + { + subsystem->dxgiOutputDuplication->lpVtbl->ReleaseFrame(subsystem->dxgiOutputDuplication); + subsystem->dxgiFrameAcquired = FALSE; + } subsystem->pendingFrames = 0; - if (FAILED(hr)) - return -1; - return 1; } @@ -373,7 +515,7 @@ int win_shadow_dxgi_get_next_frame(winShadowSubsystem* subsystem) UINT DataBufferSize = 0; BYTE* DataBuffer = NULL; - if (subsystem->pendingFrames > 0) + if (subsystem->dxgiFrameAcquired) { win_shadow_dxgi_release_frame_data(subsystem); } @@ -387,11 +529,20 @@ int win_shadow_dxgi_get_next_frame(winShadowSubsystem* subsystem) hr = subsystem->dxgiOutputDuplication->lpVtbl->AcquireNextFrame(subsystem->dxgiOutputDuplication, 0, &(subsystem->dxgiFrameInfo), &(subsystem->dxgiResource)); + if (SUCCEEDED(hr)) + { + subsystem->dxgiFrameAcquired = TRUE; + subsystem->pendingFrames = subsystem->dxgiFrameInfo.AccumulatedFrames; + } + if (hr == DXGI_ERROR_WAIT_TIMEOUT) return 0; if (FAILED(hr)) { + fprintf(stderr, "IDXGIOutputDuplication::AcquireNextFrame failure: %s (0x%04X)\n", + GetDxgiErrorString(hr), hr); + if (hr == DXGI_ERROR_ACCESS_LOST) { if (subsystem->dxgiDesktopImage) @@ -413,34 +564,24 @@ int win_shadow_dxgi_get_next_frame(winShadowSubsystem* subsystem) return 0; } - else - { - hr = subsystem->dxgiOutputDuplication->lpVtbl->ReleaseFrame(subsystem->dxgiOutputDuplication); - if (FAILED(hr)) - return -1; - - return -1; - } + return -1; } hr = subsystem->dxgiResource->lpVtbl->QueryInterface(subsystem->dxgiResource, &IID_ID3D11Texture2D, (void**) &(subsystem->dxgiDesktopImage)); - subsystem->dxgiResource->lpVtbl->Release(subsystem->dxgiResource); - subsystem->dxgiResource = NULL; + if (subsystem->dxgiResource) + { + subsystem->dxgiResource->lpVtbl->Release(subsystem->dxgiResource); + subsystem->dxgiResource = NULL; + } if (FAILED(hr)) - return -1; - - subsystem->pendingFrames = subsystem->dxgiFrameInfo.AccumulatedFrames; - - if (subsystem->pendingFrames == 0) { - hr = subsystem->dxgiOutputDuplication->lpVtbl->ReleaseFrame(subsystem->dxgiOutputDuplication); - - if (FAILED(hr)) - return -1; + fprintf(stderr, "IDXGIResource::QueryInterface(ID3D11Texture2D) failure: %s (0x%04X)\n", + GetDxgiErrorString(hr), hr); + return -1; } return 1; @@ -456,21 +597,13 @@ int win_shadow_dxgi_get_invalid_region(winShadowSubsystem* subsystem) UINT numMoveRects; UINT numDirtyRects; UINT UsedBufferSize; - rdpShadowServer* server; - rdpShadowScreen* screen; RECTANGLE_16 invalidRect; UINT MetadataBufferSize; UINT MoveRectsBufferSize; UINT DirtyRectsBufferSize; - UINT PointerShapeBufferSize; RECT* pDirtyRectsBuffer; - void* pPointerShapeBuffer; DXGI_OUTDUPL_MOVE_RECT* pMoveRect; DXGI_OUTDUPL_MOVE_RECT* pMoveRectBuffer; - DXGI_OUTDUPL_POINTER_SHAPE_INFO PointerShapeInfo; - - server = subsystem->server; - screen = server->screen; if (subsystem->dxgiFrameInfo.AccumulatedFrames == 0) return 0; @@ -501,7 +634,11 @@ int win_shadow_dxgi_get_invalid_region(winShadowSubsystem* subsystem) MoveRectsBufferSize, pMoveRectBuffer, &MoveRectsBufferSize); if (FAILED(hr)) + { + fprintf(stderr, "IDXGIOutputDuplication::GetFrameMoveRects failure: %s (0x%04X) Size: %d Total %d Used: %d\n", + GetDxgiErrorString(hr), hr, MoveRectsBufferSize, MetadataBufferSize, UsedBufferSize); return -1; + } /* GetFrameDirtyRects */ @@ -514,22 +651,11 @@ int win_shadow_dxgi_get_invalid_region(winShadowSubsystem* subsystem) DirtyRectsBufferSize, pDirtyRectsBuffer, &DirtyRectsBufferSize); if (FAILED(hr)) + { + fprintf(stderr, "IDXGIOutputDuplication::GetFrameDirtyRects failure: %s (0x%04X) Size: %d Total %d Used: %d\n", + GetDxgiErrorString(hr), hr, DirtyRectsBufferSize, MetadataBufferSize, UsedBufferSize); return -1; - - /* GetFramePointerShape */ - - UsedBufferSize += MoveRectsBufferSize; - - PointerShapeBufferSize = MetadataBufferSize - UsedBufferSize; - pPointerShapeBuffer = (void*) &(subsystem->MetadataBuffer[UsedBufferSize]); - - hr = subsystem->dxgiOutputDuplication->lpVtbl->GetFramePointerShape(subsystem->dxgiOutputDuplication, - PointerShapeBufferSize, pPointerShapeBuffer, &PointerShapeBufferSize, &PointerShapeInfo); - - if (FAILED(hr)) - return -1; - - EnterCriticalSection(&(screen->lock)); + } numMoveRects = MoveRectsBufferSize / sizeof(DXGI_OUTDUPL_MOVE_RECT); @@ -544,7 +670,7 @@ int win_shadow_dxgi_get_invalid_region(winShadowSubsystem* subsystem) invalidRect.right = (UINT16) pDstRect->right; invalidRect.bottom = (UINT16) pDstRect->bottom; - region16_union_rect(&(screen->invalidRegion), &(screen->invalidRegion), &invalidRect); + region16_union_rect(&(subsystem->invalidRegion), &(subsystem->invalidRegion), &invalidRect); } numDirtyRects = DirtyRectsBufferSize / sizeof(RECT); @@ -558,11 +684,9 @@ int win_shadow_dxgi_get_invalid_region(winShadowSubsystem* subsystem) invalidRect.right = (UINT16) pDirtyRect->right; invalidRect.bottom = (UINT16) pDirtyRect->bottom; - region16_union_rect(&(screen->invalidRegion), &(screen->invalidRegion), &invalidRect); + region16_union_rect(&(subsystem->invalidRegion), &(subsystem->invalidRegion), &invalidRect); } - LeaveCriticalSection(&(screen->lock)); - return 1; } @@ -747,7 +871,6 @@ int win_shadow_surface_copy(winShadowSubsystem* subsystem) int status; int nDstStep = 0; BYTE* pDstData = NULL; - rdpShadowScreen* screen; rdpShadowServer* server; rdpShadowSurface* surface; RECTANGLE_16 surfaceRect; @@ -755,7 +878,6 @@ int win_shadow_surface_copy(winShadowSubsystem* subsystem) server = subsystem->server; surface = server->surface; - screen = server->screen; surfaceRect.left = surface->x; surfaceRect.top = surface->y; @@ -763,7 +885,8 @@ int win_shadow_surface_copy(winShadowSubsystem* subsystem) surfaceRect.bottom = surface->y + surface->height; region16_clear(&(surface->invalidRegion)); - region16_intersect_rect(&(surface->invalidRegion), &(screen->invalidRegion), &surfaceRect); + region16_copy(&(surface->invalidRegion), &(subsystem->invalidRegion)); + region16_intersect_rect(&(surface->invalidRegion), &(surface->invalidRegion), &surfaceRect); if (region16_is_empty(&(surface->invalidRegion))) return 1; @@ -775,7 +898,7 @@ int win_shadow_surface_copy(winShadowSubsystem* subsystem) width = extents->right - extents->left; height = extents->bottom - extents->top; - printf("x: %d y: %d width: %d height: %d right: %d bottom: %d\n", + printf("SurfaceCopy x: %d y: %d width: %d height: %d right: %d bottom: %d\n", x, y, width, height, x + width, y + height); status = win_shadow_dxgi_fetch_frame_data(subsystem, &pDstData, &nDstStep, x, y, width, height); @@ -783,10 +906,14 @@ int win_shadow_surface_copy(winShadowSubsystem* subsystem) if (status < 0) return -1; + EnterCriticalSection(&(surface->lock)); + freerdp_image_copy(surface->data, PIXEL_FORMAT_XRGB32, surface->scanline, x - surface->x, y - surface->y, width, height, pDstData, PIXEL_FORMAT_XRGB32, nDstStep, x, y); + LeaveCriticalSection(&(surface->lock)); + return 1; } @@ -832,14 +959,16 @@ void* win_shadow_subsystem_thread(winShadowSubsystem* subsystem) #ifdef WITH_DXGI_1_2 int dxgi_status; + //win_shadow_invalidate_region(subsystem, 0, 0, subsystem->width, subsystem->height); + dxgi_status = win_shadow_dxgi_get_next_frame(subsystem); + dxgi_status = win_shadow_dxgi_get_invalid_region(subsystem); + win_shadow_surface_copy(subsystem); - if (subsystem->pendingFrames > 0) - { - dxgi_status = win_shadow_dxgi_get_invalid_region(subsystem); + if (subsystem->SurfaceUpdate) + subsystem->SurfaceUpdate((rdpShadowSubsystem*) subsystem, &(subsystem->invalidRegion)); - win_shadow_invalidate_region(subsystem, 0, 0, subsystem->width, subsystem->height); - } + region16_clear(&(subsystem->invalidRegion)); #endif dwInterval = 1000 / fps; @@ -941,6 +1070,8 @@ void win_shadow_subsystem_free(winShadowSubsystem* subsystem) win_shadow_subsystem_uninit(subsystem); + region16_uninit(&(subsystem->invalidRegion)); + free(subsystem); } @@ -955,6 +1086,8 @@ winShadowSubsystem* win_shadow_subsystem_new(rdpShadowServer* server) subsystem->server = server; + region16_init(&(subsystem->invalidRegion)); + subsystem->Init = (pfnShadowSubsystemInit) win_shadow_subsystem_init; subsystem->Uninit = (pfnShadowSubsystemInit) win_shadow_subsystem_uninit; subsystem->Start = (pfnShadowSubsystemStart) win_shadow_subsystem_start; diff --git a/server/shadow/Win/win_shadow.h b/server/shadow/Win/win_shadow.h index 97f3ceccb..65196c642 100644 --- a/server/shadow/Win/win_shadow.h +++ b/server/shadow/Win/win_shadow.h @@ -56,6 +56,8 @@ struct win_shadow_subsystem UINT pendingFrames; BYTE* MetadataBuffer; UINT MetadataBufferSize; + BOOL dxgiSurfaceMapped; + BOOL dxgiFrameAcquired; ID3D11Device* dxgiDevice; IDXGISurface* dxgiSurface; ID3D11Texture2D* dxgiStage; diff --git a/server/shadow/shadow_client.c b/server/shadow/shadow_client.c index 372a5cac7..3d80ec08f 100644 --- a/server/shadow/shadow_client.c +++ b/server/shadow/shadow_client.c @@ -27,69 +27,8 @@ #include #include -#include - #include "shadow.h" -static const char* makecert_argv[6] = -{ - "makecert", - "-rdp", - "-live", - "-silent", - "-y", "5" -}; - -static int makecert_argc = (sizeof(makecert_argv) / sizeof(char*)); - -int shadow_generate_certificate(rdpShadowClient* client) -{ - char* filepath; - rdpContext* context; - rdpSettings* settings; - MAKECERT_CONTEXT* makecert; - rdpShadowServer* server = client->server; - - context = (rdpContext*) client; - settings = context->settings; - - if (!PathFileExistsA(server->ConfigPath)) - CreateDirectoryA(server->ConfigPath, 0); - - filepath = GetCombinedPath(server->ConfigPath, "shadow"); - - if (!filepath) - return -1; - - if (!PathFileExistsA(filepath)) - CreateDirectoryA(filepath, 0); - - settings->CertificateFile = GetCombinedPath(filepath, "shadow.crt"); - settings->PrivateKeyFile = GetCombinedPath(filepath, "shadow.key"); - - if ((!PathFileExistsA(settings->CertificateFile)) || - (!PathFileExistsA(settings->PrivateKeyFile))) - { - makecert = makecert_context_new(); - - makecert_context_process(makecert, makecert_argc, (char**) makecert_argv); - - makecert_context_set_output_file_name(makecert, "shadow"); - - if (!PathFileExistsA(settings->CertificateFile)) - makecert_context_output_certificate_file(makecert, filepath); - - if (!PathFileExistsA(settings->PrivateKeyFile)) - makecert_context_output_private_key_file(makecert, filepath); - - makecert_context_free(makecert); - } - - free(filepath); - - return 1; -} - void shadow_client_context_new(freerdp_peer* peer, rdpShadowClient* client) { rdpSettings* settings; @@ -110,19 +49,36 @@ void shadow_client_context_new(freerdp_peer* peer, rdpShadowClient* client) settings->TlsSecurity = TRUE; settings->NlaSecurity = FALSE; - shadow_generate_certificate(client); + settings->CertificateFile = _strdup(server->CertificateFile); + settings->PrivateKeyFile = _strdup(server->PrivateKeyFile); client->inLobby = TRUE; client->mayView = server->mayView; client->mayInteract = server->mayInteract; + InitializeCriticalSectionAndSpinCount(&(client->lock), 4000); + + region16_init(&(client->invalidRegion)); + client->vcm = WTSOpenServerA((LPSTR) peer->context); client->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + + client->encoder = shadow_encoder_new(server); + + ArrayList_Add(server->clients, (void*) client); } void shadow_client_context_free(freerdp_peer* peer, rdpShadowClient* client) { + rdpShadowServer* server = client->server; + + ArrayList_Remove(server->clients, (void*) client); + + DeleteCriticalSection(&(client->lock)); + + region16_uninit(&(client->invalidRegion)); + WTSCloseServer((HANDLE) client->vcm); CloseHandle(client->StopEvent); @@ -132,6 +88,12 @@ void shadow_client_context_free(freerdp_peer* peer, rdpShadowClient* client) shadow_surface_free(client->lobby); client->lobby = NULL; } + + if (client->encoder) + { + shadow_encoder_free(client->encoder); + client->encoder = NULL; + } } BOOL shadow_client_capabilities(freerdp_peer* peer) @@ -189,7 +151,7 @@ BOOL shadow_client_activate(freerdp_peer* peer) client->activated = TRUE; client->inLobby = client->mayView ? FALSE : TRUE; - shadow_encoder_reset(client->server->encoder); + shadow_encoder_reset(client->encoder); return TRUE; } @@ -199,7 +161,7 @@ void shadow_client_surface_frame_acknowledge(rdpShadowClient* client, UINT32 fra SURFACE_FRAME* frame; wListDictionary* frameList; - frameList = client->server->encoder->frameList; + frameList = client->encoder->frameList; frame = (SURFACE_FRAME*) ListDictionary_GetItemValue(frameList, (void*) (size_t) frameId); if (frame) @@ -248,7 +210,7 @@ int shadow_client_send_surface_bits(rdpShadowClient* client, rdpShadowSurface* s settings = context->settings; server = client->server; - encoder = server->encoder; + encoder = client->encoder; pSrcData = surface->data; nSrcStep = surface->scanline; @@ -336,8 +298,6 @@ int shadow_client_send_surface_bits(rdpShadowClient* client, rdpShadowSurface* s free(messages); } - region16_clear(&(surface->invalidRegion)); - if (encoder->frameAck) { shadow_client_send_surface_frame_marker(client, SURFACECMD_FRAMEACTION_END, frameId); @@ -372,7 +332,7 @@ int shadow_client_send_bitmap_update(rdpShadowClient* client, rdpShadowSurface* settings = context->settings; server = client->server; - encoder = server->encoder; + encoder = client->encoder; pSrcData = surface->data; nSrcStep = surface->scanline; @@ -562,27 +522,39 @@ int shadow_client_send_surface_update(rdpShadowClient* client) rdpShadowServer* server; rdpShadowSurface* surface; rdpShadowEncoder* encoder; + REGION16 invalidRegion; RECTANGLE_16 surfaceRect; const RECTANGLE_16* extents; context = (rdpContext*) client; settings = context->settings; server = client->server; - encoder = server->encoder; + encoder = client->encoder; surface = client->inLobby ? client->lobby : server->surface; + EnterCriticalSection(&(client->lock)); + + region16_init(&invalidRegion); + region16_copy(&invalidRegion, &(client->invalidRegion)); + region16_clear(&(client->invalidRegion)); + + LeaveCriticalSection(&(client->lock)); + surfaceRect.left = surface->x; surfaceRect.top = surface->y; surfaceRect.right = surface->x + surface->width; surfaceRect.bottom = surface->y + surface->height; - region16_intersect_rect(&(surface->invalidRegion), &(surface->invalidRegion), &surfaceRect); + region16_intersect_rect(&invalidRegion, &invalidRegion, &surfaceRect); - if (region16_is_empty(&(surface->invalidRegion))) + if (region16_is_empty(&invalidRegion)) + { + region16_uninit(&invalidRegion); return 1; + } - extents = region16_extents(&(surface->invalidRegion)); + extents = region16_extents(&invalidRegion); nXSrc = extents->left - surface->x; nYSrc = extents->top - surface->y; @@ -608,9 +580,31 @@ int shadow_client_send_surface_update(rdpShadowClient* client) status = shadow_client_send_bitmap_update(client, surface, nXSrc, nYSrc, nWidth, nHeight); } + region16_uninit(&invalidRegion); + return status; } +int shadow_client_surface_update(rdpShadowClient* client, REGION16* region) +{ + int index; + int numRects = 0; + const RECTANGLE_16* rects; + + EnterCriticalSection(&(client->lock)); + + rects = region16_rects(region, &numRects); + + for (index = 0; index < numRects; index++) + { + region16_union_rect(&(client->invalidRegion), &(client->invalidRegion), &rects[index]); + } + + LeaveCriticalSection(&(client->lock)); + + return 1; +} + void* shadow_client_thread(rdpShadowClient* client) { int fps; @@ -633,7 +627,7 @@ void* shadow_client_thread(rdpShadowClient* client) server = client->server; screen = server->screen; - encoder = server->encoder; + encoder = client->encoder; subsystem = server->subsystem; peer = ((rdpContext*) client)->peer; diff --git a/server/shadow/shadow_client.h b/server/shadow/shadow_client.h index f80f047f6..d067554f0 100644 --- a/server/shadow/shadow_client.h +++ b/server/shadow/shadow_client.h @@ -25,6 +25,7 @@ extern "C" { #endif +int shadow_client_surface_update(rdpShadowClient* client, REGION16* region); void shadow_client_accepted(freerdp_listener* instance, freerdp_peer* client); #ifdef __cplusplus diff --git a/server/shadow/shadow_encomsp.c b/server/shadow/shadow_encomsp.c index 3bca7e7d6..f0b1d48e3 100644 --- a/server/shadow/shadow_encomsp.c +++ b/server/shadow/shadow_encomsp.c @@ -83,7 +83,7 @@ static int encomsp_change_participant_control_level(EncomspServerContext* contex if (inLobby != client->inLobby) { - shadow_encoder_reset(client->server->encoder); + shadow_encoder_reset(client->encoder); client->inLobby = inLobby; } diff --git a/server/shadow/shadow_server.c b/server/shadow/shadow_server.c index 945189c34..d4faaa6b6 100644 --- a/server/shadow/shadow_server.c +++ b/server/shadow/shadow_server.c @@ -27,6 +27,8 @@ #include +#include + #ifndef _WIN32 #include #include @@ -226,6 +228,32 @@ int shadow_server_parse_command_line(rdpShadowServer* server, int argc, char** a return status; } +int shadow_server_surface_update(rdpShadowSubsystem* subsystem, REGION16* region) +{ + int index; + int count; + wArrayList* clients; + rdpShadowServer* server; + rdpShadowClient* client; + + server = subsystem->server; + clients = server->clients; + + ArrayList_Lock(clients); + + count = ArrayList_Count(clients); + + for (index = 0; index < count; index++) + { + client = ArrayList_GetItem(clients, index); + shadow_client_surface_update(client, region); + } + + ArrayList_Unlock(clients); + + return 1; +} + void* shadow_server_thread(rdpShadowServer* server) { DWORD status; @@ -317,6 +345,59 @@ int shadow_server_stop(rdpShadowServer* server) return 0; } +int shadow_server_init_certificate(rdpShadowServer* server) +{ + char* filepath; + MAKECERT_CONTEXT* makecert; + + const char* makecert_argv[6] = + { + "makecert", + "-rdp", + "-live", + "-silent", + "-y", "5" + }; + + int makecert_argc = (sizeof(makecert_argv) / sizeof(char*)); + + if (!PathFileExistsA(server->ConfigPath)) + CreateDirectoryA(server->ConfigPath, 0); + + filepath = GetCombinedPath(server->ConfigPath, "shadow"); + + if (!filepath) + return -1; + + if (!PathFileExistsA(filepath)) + CreateDirectoryA(filepath, 0); + + server->CertificateFile = GetCombinedPath(filepath, "shadow.crt"); + server->PrivateKeyFile = GetCombinedPath(filepath, "shadow.key"); + + if ((!PathFileExistsA(server->CertificateFile)) || + (!PathFileExistsA(server->PrivateKeyFile))) + { + makecert = makecert_context_new(); + + makecert_context_process(makecert, makecert_argc, (char**) makecert_argv); + + makecert_context_set_output_file_name(makecert, "shadow"); + + if (!PathFileExistsA(server->CertificateFile)) + makecert_context_output_certificate_file(makecert, filepath); + + if (!PathFileExistsA(server->PrivateKeyFile)) + makecert_context_output_private_key_file(makecert, filepath); + + makecert_context_free(makecert); + } + + free(filepath); + + return 1; +} + int shadow_server_init(rdpShadowServer* server) { int status; @@ -325,6 +406,11 @@ int shadow_server_init(rdpShadowServer* server) server->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + status = shadow_server_init_certificate(server); + + if (status < 0) + return -1; + server->listener = freerdp_listener_new(); if (!server->listener) @@ -351,6 +437,8 @@ int shadow_server_init(rdpShadowServer* server) if (!server->subsystem) return -1; + server->subsystem->SurfaceUpdate = shadow_server_surface_update; + if (server->subsystem->Init) { status = server->subsystem->Init(server->subsystem); @@ -364,11 +452,6 @@ int shadow_server_init(rdpShadowServer* server) if (!server->screen) return -1; - server->encoder = shadow_encoder_new(server); - - if (!server->encoder) - return -1; - return 1; } @@ -382,18 +465,24 @@ int shadow_server_uninit(rdpShadowServer* server) server->listener = NULL; } - if (server->encoder) - { - shadow_encoder_free(server->encoder); - server->encoder = NULL; - } - if (server->subsystem) { server->subsystem->Free(server->subsystem); server->subsystem = NULL; } + if (server->CertificateFile) + { + free(server->CertificateFile); + server->CertificateFile = NULL; + } + + if (server->PrivateKeyFile) + { + free(server->PrivateKeyFile); + server->PrivateKeyFile = NULL; + } + return 1; } @@ -417,6 +506,10 @@ rdpShadowServer* shadow_server_new() if (!server->ConfigPath) server->ConfigPath = GetKnownSubPath(KNOWN_PATH_XDG_CONFIG_HOME, "freerdp"); + InitializeCriticalSectionAndSpinCount(&(server->lock), 4000); + + server->clients = ArrayList_New(TRUE); + return server; } @@ -425,6 +518,14 @@ void shadow_server_free(rdpShadowServer* server) if (!server) return; + DeleteCriticalSection(&(server->lock)); + + if (server->clients) + { + ArrayList_Free(server->clients); + server->clients = NULL; + } + shadow_server_uninit(server); free(server);