From 2a07ebec23c52311af3c23fe749dbc863c0d5843 Mon Sep 17 00:00:00 2001 From: Corey C Date: Sun, 16 Sep 2012 17:38:33 -0400 Subject: [PATCH] wfreerdp-server: win8 dxgi initial support --- server/Windows/CMakeLists.txt | 10 +- server/Windows/wf_info.c | 22 ++++ server/Windows/wf_info.h | 17 +++ server/Windows/wf_mirage.c | 31 ++---- server/Windows/wf_peer.c | 195 +++++++++++++++++++++++++++++++++- server/Windows/wf_peer.h | 3 + 6 files changed, 252 insertions(+), 26 deletions(-) diff --git a/server/Windows/CMakeLists.txt b/server/Windows/CMakeLists.txt index b68df72ab..304066cab 100644 --- a/server/Windows/CMakeLists.txt +++ b/server/Windows/CMakeLists.txt @@ -26,6 +26,8 @@ add_executable(wfreerdp-server wf_peer.h wf_info.c wf_info.h + wf_dxgi.c + wf_dxgi.h wfreerdp.c wfreerdp.h) @@ -42,6 +44,12 @@ else() freerdp-codec - freerdp-channels) + freerdp-channels + + d3d11.lib + + dxgi.lib + + dxguid.lib) endif() diff --git a/server/Windows/wf_info.c b/server/Windows/wf_info.c index b910bbf0d..733de8e89 100644 --- a/server/Windows/wf_info.c +++ b/server/Windows/wf_info.c @@ -124,6 +124,28 @@ wfInfo* wf_info_get_instance() return wfInfoInstance; } +void wf_info_get_screen_info(wfInfo* wfi) +{ + HDC dc; + int currentScreenBPP; + int currentScreenPixHeight; + int currentScreenPixWidth; + /* + * Will have to come back to this for supporting non primary displays and multimonitor setups + */ + dc = GetDC(NULL); + currentScreenPixHeight = GetDeviceCaps(dc, VERTRES); + currentScreenPixWidth = GetDeviceCaps(dc, HORZRES); + currentScreenBPP = GetDeviceCaps(dc, BITSPIXEL); + ReleaseDC(NULL, dc); + + wfi->height = currentScreenPixHeight; + wfi->width = currentScreenPixWidth; + wfi->bitsPerPix = currentScreenBPP; + + _tprintf(_T("Detected current screen settings: %dx%dx%d\n"), wfi->height, wfi->width, wfi->bitsPerPix); +} + void wf_info_mirror_init(wfInfo* wfi, wfPeerContext* context) { if (wf_info_lock(wfi) > 0) diff --git a/server/Windows/wf_info.h b/server/Windows/wf_info.h index 0236c69dc..5532c0170 100644 --- a/server/Windows/wf_info.h +++ b/server/Windows/wf_info.h @@ -20,11 +20,24 @@ #ifndef WF_INFO_H #define WF_INFO_H +#define CINTERFACE +#include +#include + #include struct wf_peer_context; typedef struct wf_peer_context wfPeerContext; +struct wf_dxgi_info +{ + ID3D11Device* Device; + ID3D11DeviceContext* DeviceContext; + IDXGIOutputDuplication* DeskDupl; + ID3D11Texture2D* AcquiredDesktopImage; +}; +typedef struct wf_dxgi_info wfDxgiInfo; + struct wf_info { STREAM* s; @@ -46,6 +59,8 @@ struct wf_info RFX_CONTEXT* rfx_context; unsigned long lastUpdate; unsigned long nextUpdate; + + wfDxgiInfo dxgi; }; typedef struct wf_info wfInfo; @@ -53,6 +68,8 @@ int wf_info_lock(wfInfo* wfi); int wf_info_try_lock(wfInfo* wfi, DWORD dwMilliseconds); int wf_info_unlock(wfInfo* wfi); +void wf_info_get_screen_info(wfInfo* wfi); + wfInfo* wf_info_get_instance(); void wf_info_mirror_init(wfInfo* wfi, wfPeerContext* context); void wf_info_subscriber_release(wfInfo* wfi, wfPeerContext* context); diff --git a/server/Windows/wf_mirage.c b/server/Windows/wf_mirage.c index f5d09f684..0299a1955 100644 --- a/server/Windows/wf_mirage.c +++ b/server/Windows/wf_mirage.c @@ -172,39 +172,22 @@ void wf_disp_change_print_status(LONG status) BOOL wf_update_mirror_drv(wfInfo* context, int unload) { - HDC dc; BOOL status; DWORD* extHdr; WORD drvExtraSaved; DEVMODE* deviceMode; - int currentScreenBPP; - int currentScreenPixHeight; - int currentScreenPixWidth; LONG disp_change_status; DWORD dmf_devmodewext_magic_sig = 0xDF20C0DE; if (!unload) { - /* - * Will have to come back to this for supporting non primary displays and multimonitor setups - */ - dc = GetDC(NULL); - currentScreenPixHeight = GetDeviceCaps(dc, VERTRES); - currentScreenPixWidth = GetDeviceCaps(dc, HORZRES); - currentScreenBPP = GetDeviceCaps(dc, BITSPIXEL); - ReleaseDC(NULL, dc); - - context->height = currentScreenPixHeight; - context->width = currentScreenPixWidth; - context->bitsPerPix = currentScreenBPP; - - _tprintf(_T("Detected current screen settings: %dx%dx%d\n"), currentScreenPixHeight, currentScreenPixWidth, currentScreenBPP); + wf_info_get_screen_info(context); } else { - currentScreenPixHeight = 0; - currentScreenPixWidth = 0; - currentScreenBPP = 0; + context->height = 0; + context->width = 0; + context->bitsPerPix = 0; } deviceMode = (DEVMODE*) malloc(sizeof(DEVMODE) + EXT_DEVMODE_SIZE_MAX); @@ -219,9 +202,9 @@ BOOL wf_update_mirror_drv(wfInfo* context, int unload) deviceMode->dmSize = sizeof(DEVMODE); deviceMode->dmDriverExtra = drvExtraSaved; - deviceMode->dmPelsWidth = currentScreenPixWidth; - deviceMode->dmPelsHeight = currentScreenPixHeight; - deviceMode->dmBitsPerPel = currentScreenBPP; + deviceMode->dmPelsWidth = context->height; + deviceMode->dmPelsHeight = context->width; + deviceMode->dmBitsPerPel = context->bitsPerPix; deviceMode->dmPosition.x = 0; deviceMode->dmPosition.y = 0; diff --git a/server/Windows/wf_peer.c b/server/Windows/wf_peer.c index ac202f949..2be4d6c04 100644 --- a/server/Windows/wf_peer.c +++ b/server/Windows/wf_peer.c @@ -31,17 +31,22 @@ #include "wf_input.h" #include "wf_mirage.h" +#include "wf_dxgi.h" #include "wf_peer.h" BOOL win8; + + void wf_peer_context_new(freerdp_peer* client, wfPeerContext* context) { context->info = wf_info_get_instance(); if(win8) { + wf_info_get_screen_info(context->info); + wf_dxgi_init(context->info); } else { @@ -53,6 +58,7 @@ void wf_peer_context_free(freerdp_peer* client, wfPeerContext* context) { if(win8) { + wf_dxgi_cleanup(context->info); } else { @@ -60,6 +66,7 @@ void wf_peer_context_free(freerdp_peer* client, wfPeerContext* context) } } + static DWORD WINAPI wf_peer_mirror_monitor(LPVOID lpParam) { DWORD fps; @@ -69,7 +76,7 @@ static DWORD WINAPI wf_peer_mirror_monitor(LPVOID lpParam) freerdp_peer* client; wfPeerContext* context; - fps = 24; + fps = 1; rate = 1000 / fps; client = (freerdp_peer*) lpParam; context = (wfPeerContext*) client->context; @@ -87,6 +94,9 @@ static DWORD WINAPI wf_peer_mirror_monitor(LPVOID lpParam) if (wf_info_have_updates(wfi)) { + //todo: changeme + if(win8) + wf_dxgi_encode(client); wf_rfx_encode(client); SetEvent(wfi->updateEvent); } @@ -111,6 +121,189 @@ static DWORD WINAPI wf_peer_mirror_monitor(LPVOID lpParam) return 0; } +void wf_dxgi_encode(freerdp_peer* client) +{ + STREAM* s; + wfInfo* wfi; + long offset; + RFX_RECT rect; + long height, width; + rdpUpdate* update; + wfPeerContext* wfp; + GETCHANGESBUF* buf; + SURFACE_BITS_COMMAND* cmd; + + /// + + BYTE* MetaDataBuffer = NULL; + UINT MeinMetaDataSize = 0; + UINT BufSize; + UINT i; + HRESULT hr; + IDXGIResource* DesktopResource = NULL; + DXGI_OUTDUPL_FRAME_INFO FrameInfo; + + BYTE* DirtyRects; + + UINT dirty; + RECT* pRect; + /// + + wfp = (wfPeerContext*) client->context; + wfi = wfp->info; + + if (client->activated == FALSE) + return; + + if (wfp->activated == FALSE) + return; + + //wf_info_find_invalid_region(wfi); + + _tprintf(_T("\nTrying to acquire a frame...\n")); + hr = wfi->dxgi.DeskDupl->lpVtbl->AcquireNextFrame(wfi->dxgi.DeskDupl, 800, &FrameInfo, &DesktopResource); + _tprintf(_T("hr = %#0X\n"), hr); + if (hr == DXGI_ERROR_WAIT_TIMEOUT) + { + _tprintf(_T("Timeout\n")); + return; + } + + if (FAILED(hr)) + { + _tprintf(_T("Failed to acquire next frame\n")); + return; + } + _tprintf(_T("Gut!\n")); + + /////////////////////////////////////////////// + + + _tprintf(_T("Trying to QI for ID3D11Texture2D...\n")); + hr = DesktopResource->lpVtbl->QueryInterface(DesktopResource, &IID_ID3D11Texture2D, (void**) &wfi->dxgi.AcquiredDesktopImage); + DesktopResource->lpVtbl->Release(DesktopResource); + DesktopResource = NULL; + if (FAILED(hr)) + { + _tprintf(_T("Failed to QI for ID3D11Texture2D from acquired IDXGIResource\n")); + return; + } + _tprintf(_T("Gut!\n")); + + _tprintf(_T("FrameInfo\n")); + _tprintf(_T("\tAccumulated Frames: %d\n"), FrameInfo.AccumulatedFrames); + _tprintf(_T("\tCoalesced Rectangles: %d\n"), FrameInfo.RectsCoalesced); + _tprintf(_T("\tMetadata buffer size: %d\n"), FrameInfo.TotalMetadataBufferSize); + + + if(FrameInfo.TotalMetadataBufferSize) + { + + if (FrameInfo.TotalMetadataBufferSize > MeinMetaDataSize) + { + if (MetaDataBuffer) + { + free(MetaDataBuffer); + MetaDataBuffer = NULL; + } + MetaDataBuffer = (BYTE*) malloc(FrameInfo.TotalMetadataBufferSize); + if (!MetaDataBuffer) + { + MeinMetaDataSize = 0; + _tprintf(_T("Failed to allocate memory for metadata\n")); + return; + } + MeinMetaDataSize = FrameInfo.TotalMetadataBufferSize; + } + + BufSize = FrameInfo.TotalMetadataBufferSize; + + // Get move rectangles + hr = wfi->dxgi.DeskDupl->lpVtbl->GetFrameMoveRects(wfi->dxgi.DeskDupl, BufSize, (DXGI_OUTDUPL_MOVE_RECT*) MetaDataBuffer, &BufSize); + if (FAILED(hr)) + { + _tprintf(_T("Failed to get frame move rects\n")); + return; + } + _tprintf(_T("Move rects: %d\n"), BufSize / sizeof(DXGI_OUTDUPL_MOVE_RECT)); + + DirtyRects = MetaDataBuffer + BufSize; + BufSize = FrameInfo.TotalMetadataBufferSize - BufSize; + + // Get dirty rectangles + hr = wfi->dxgi.DeskDupl->lpVtbl->GetFrameDirtyRects(wfi->dxgi.DeskDupl, BufSize, (RECT*) DirtyRects, &BufSize); + if (FAILED(hr)) + { + _tprintf(_T("Failed to get frame dirty rects\n")); + return; + } + dirty = BufSize / sizeof(RECT); + _tprintf(_T("Dirty rects: %d\n"), dirty); + + pRect = (RECT*) DirtyRects; + for(i = 0; ileft, + pRect->top, + pRect->right, + pRect->bottom); + + ++pRect; + } + + + } + + + hr = wfi->dxgi.DeskDupl->lpVtbl->ReleaseFrame(wfi->dxgi.DeskDupl); + if (FAILED(hr)) + { + _tprintf(_T("Failed to release frame\n")); + return; + } + + + //////////////////////// + //////////////////////// + + update = client->update; + cmd = &update->surface_bits_command; + buf = (GETCHANGESBUF*) wfi->changeBuffer; + + width = (wfi->invalid.right - wfi->invalid.left) + 1; + height = (wfi->invalid.bottom - wfi->invalid.top) + 1; + + stream_clear(wfi->s); + stream_set_pos(wfi->s, 0); + s = wfi->s; + + rect.x = 0; + rect.y = 0; + rect.width = (uint16) width; + rect.height = (uint16) height; + + offset = (4 * wfi->invalid.left) + (wfi->invalid.top * wfi->width * 4); + + rfx_compose_message(wfi->rfx_context, s, &rect, 1, + ((uint8*) (buf->Userbuffer)) + offset, width, height, wfi->width * 4); + + cmd->destLeft = wfi->invalid.left; + cmd->destTop = wfi->invalid.top; + cmd->destRight = wfi->invalid.left + width; + cmd->destBottom = wfi->invalid.top + height; + + cmd->bpp = 32; + cmd->codecID = client->settings->rfx_codec_id; + cmd->width = width; + cmd->height = height; + cmd->bitmapDataLength = stream_get_length(s); + cmd->bitmapData = stream_get_head(s); + + wfi->updatePending = TRUE; +} + + void wf_rfx_encode(freerdp_peer* client) { STREAM* s; diff --git a/server/Windows/wf_peer.h b/server/Windows/wf_peer.h index 17f00cf20..e32af3939 100644 --- a/server/Windows/wf_peer.h +++ b/server/Windows/wf_peer.h @@ -23,11 +23,14 @@ #include "wfreerdp.h" #include "wf_info.h" + + void wf_peer_context_new(freerdp_peer* client, wfPeerContext* context); void wf_peer_context_free(freerdp_peer* client, wfPeerContext* context); void wf_peer_init(freerdp_peer* client); +void wf_dxgi_encode(freerdp_peer* client); void wf_rfx_encode(freerdp_peer* client); boolean wf_peer_post_connect(freerdp_peer* client);