shadow: improve Mac subsystem

This commit is contained in:
Marc-André Moreau 2014-09-19 19:58:49 -04:00
parent c4588fb14f
commit d6250b1aec
4 changed files with 156 additions and 140 deletions

View File

@ -25,8 +25,10 @@
#include <freerdp/codec/region.h>
#include "../shadow_screen.h"
#include "../shadow_client.h"
#include "../shadow_surface.h"
#include "../shadow_capture.h"
#include "../shadow_encoder.h"
#include "../shadow_subsystem.h"
#include "mac_shadow.h"
@ -56,27 +58,29 @@ void mac_shadow_input_keyboard_event(macShadowSubsystem* subsystem, UINT16 flags
if (extended)
vkcode |= KBDEXT;
keycode = GetKeycodeFromVirtualKeyCode(vkcode, KEYCODE_TYPE_APPLE) - 8;
keycode = GetKeycodeFromVirtualKeyCode(vkcode, KEYCODE_TYPE_APPLE);
if (keycode)
if (keycode < 8)
return;
keycode -= 8;
source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
if (flags & KBD_FLAGS_DOWN)
{
source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
if (flags & KBD_FLAGS_DOWN)
{
kbdEvent = CGEventCreateKeyboardEvent(source, (CGKeyCode) keycode, TRUE);
CGEventPost(kCGHIDEventTap, kbdEvent);
CFRelease(kbdEvent);
}
else if (flags & KBD_FLAGS_RELEASE)
{
kbdEvent = CGEventCreateKeyboardEvent(source, (CGKeyCode) keycode, FALSE);
CGEventPost(kCGHIDEventTap, kbdEvent);
CFRelease(kbdEvent);
}
CFRelease(source);
kbdEvent = CGEventCreateKeyboardEvent(source, (CGKeyCode) keycode, TRUE);
CGEventPost(kCGHIDEventTap, kbdEvent);
CFRelease(kbdEvent);
}
else if (flags & KBD_FLAGS_RELEASE)
{
kbdEvent = CGEventCreateKeyboardEvent(source, (CGKeyCode) keycode, FALSE);
CGEventPost(kCGHIDEventTap, kbdEvent);
CFRelease(kbdEvent);
}
CFRelease(source);
}
void mac_shadow_input_unicode_keyboard_event(macShadowSubsystem* subsystem, UINT16 flags, UINT16 code)
@ -261,7 +265,7 @@ int mac_shadow_capture_stop(macShadowSubsystem* subsystem)
return 1;
}
int mac_shadow_capture_peek_dirty_region(macShadowSubsystem* subsystem)
int mac_shadow_capture_get_dirty_region(macShadowSubsystem* subsystem)
{
size_t index;
size_t numRects;
@ -295,46 +299,6 @@ int mac_shadow_capture_peek_dirty_region(macShadowSubsystem* subsystem)
return 0;
}
int mac_shadow_capture_get_dirty_region(macShadowSubsystem* subsystem)
{
dispatch_semaphore_wait(subsystem->regionSemaphore, DISPATCH_TIME_FOREVER);
if (subsystem->lastUpdate)
{
mac_shadow_capture_peek_dirty_region(subsystem);
}
dispatch_semaphore_signal(subsystem->regionSemaphore);
return 1;
}
int mac_shadow_capture_clear_dirty_region(macShadowSubsystem* subsystem)
{
dispatch_semaphore_wait(subsystem->regionSemaphore, DISPATCH_TIME_FOREVER);
CFRelease(subsystem->lastUpdate);
subsystem->lastUpdate = NULL;
dispatch_semaphore_signal(subsystem->regionSemaphore);
return 1;
}
int mac_shadow_capture_surface_copy(macShadowSubsystem* subsystem)
{
dispatch_semaphore_wait(subsystem->regionSemaphore, DISPATCH_TIME_FOREVER);
subsystem->updateReady = TRUE;
dispatch_semaphore_wait(subsystem->dataSemaphore, DISPATCH_TIME_FOREVER);
dispatch_semaphore_signal(subsystem->regionSemaphore);
dispatch_semaphore_wait(subsystem->dataSemaphore, DISPATCH_TIME_FOREVER);
dispatch_semaphore_signal(subsystem->dataSemaphore);
return 1;
}
void (^mac_capture_stream_handler)(CGDisplayStreamFrameStatus, uint64_t, IOSurfaceRef, CGDisplayStreamUpdateRef) =
^(CGDisplayStreamFrameStatus status, uint64_t displayTime, IOSurfaceRef frameSurface, CGDisplayStreamUpdateRef updateRef)
{
@ -350,78 +314,80 @@ void (^mac_capture_stream_handler)(CGDisplayStreamFrameStatus, uint64_t, IOSurfa
rdpShadowServer* server = subsystem->server;
rdpShadowSurface* surface = server->surface;
if (ArrayList_Count(server->clients) < 1)
{
region16_clear(&(subsystem->invalidRegion));
count = ArrayList_Count(server->clients);
if (count < 1)
return;
}
dispatch_semaphore_wait(subsystem->regionSemaphore, DISPATCH_TIME_FOREVER);
if (!subsystem->updateReady)
{
dispatch_semaphore_signal(subsystem->regionSemaphore);
if ((count == 1) && subsystem->suppressOutput)
return;
}
mac_shadow_capture_peek_dirty_region(subsystem);
mac_shadow_capture_get_dirty_region(subsystem);
surfaceRect.left = surface->x;
surfaceRect.top = surface->y;
surfaceRect.right = surface->x + surface->width;
surfaceRect.bottom = surface->y + surface->height;
surfaceRect.left = 0;
surfaceRect.top = 0;
surfaceRect.right = surface->width;
surfaceRect.bottom = surface->height;
region16_intersect_rect(&(subsystem->invalidRegion), &(subsystem->invalidRegion), &surfaceRect);
if (region16_is_empty(&(subsystem->invalidRegion)))
if (!region16_is_empty(&(subsystem->invalidRegion)))
{
extents = region16_extents(&(subsystem->invalidRegion));
}
x = extents->left;
y = extents->top;
width = extents->right - extents->left;
height = extents->bottom - extents->top;
extents = region16_extents(&(subsystem->invalidRegion));
IOSurfaceLock(frameSurface, kIOSurfaceLockReadOnly, NULL);
pSrcData = (BYTE*) IOSurfaceGetBaseAddress(frameSurface);
nSrcStep = (int) IOSurfaceGetBytesPerRow(frameSurface);
x = extents->left;
y = extents->top;
width = extents->right - extents->left;
height = extents->bottom - extents->top;
if (subsystem->retina)
{
freerdp_image_copy_from_retina(surface->data, PIXEL_FORMAT_XRGB32, surface->scanline,
x, y, width, height, pSrcData, nSrcStep, x, y);
}
else
{
freerdp_image_copy(surface->data, PIXEL_FORMAT_XRGB32, surface->scanline,
x, y, width, height, pSrcData, PIXEL_FORMAT_XRGB32, nSrcStep, x, y, NULL);
}
IOSurfaceLock(frameSurface, kIOSurfaceLockReadOnly, NULL);
pSrcData = (BYTE*) IOSurfaceGetBaseAddress(frameSurface);
nSrcStep = (int) IOSurfaceGetBytesPerRow(frameSurface);
if (subsystem->retina)
{
freerdp_image_copy_from_retina(surface->data, PIXEL_FORMAT_XRGB32, surface->scanline,
x, y, width, height, pSrcData, nSrcStep, x, y);
IOSurfaceUnlock(frameSurface, kIOSurfaceLockReadOnly, NULL);
ArrayList_Lock(server->clients);
count = ArrayList_Count(server->clients);
InitializeSynchronizationBarrier(&(subsystem->barrier), count + 1, -1);
SetEvent(subsystem->updateEvent);
EnterSynchronizationBarrier(&(subsystem->barrier), 0);
DeleteSynchronizationBarrier(&(subsystem->barrier));
if (count == 1)
{
rdpShadowClient* client;
client = (rdpShadowClient*) ArrayList_GetItem(server->clients, 0);
if (client)
{
subsystem->captureFrameRate = client->encoder->fps;
}
}
ResetEvent(subsystem->updateEvent);
ArrayList_Unlock(server->clients);
region16_clear(&(subsystem->invalidRegion));
}
else
{
freerdp_image_copy(surface->data, PIXEL_FORMAT_XRGB32, surface->scanline,
x, y, width, height, pSrcData, PIXEL_FORMAT_XRGB32, nSrcStep, x, y, NULL);
}
IOSurfaceUnlock(frameSurface, kIOSurfaceLockReadOnly, NULL);
subsystem->updateReady = FALSE;
dispatch_semaphore_signal(subsystem->dataSemaphore);
ArrayList_Lock(server->clients);
count = ArrayList_Count(server->clients);
InitializeSynchronizationBarrier(&(subsystem->barrier), count + 1, -1);
SetEvent(subsystem->updateEvent);
EnterSynchronizationBarrier(&(subsystem->barrier), 0);
ResetEvent(subsystem->updateEvent);
DeleteSynchronizationBarrier(&(subsystem->barrier));
ArrayList_Unlock(server->clients);
region16_clear(&(subsystem->invalidRegion));
if (status != kCGDisplayStreamFrameStatusFrameComplete)
{
@ -451,8 +417,6 @@ void (^mac_capture_stream_handler)(CGDisplayStreamFrameStatus, uint64_t, IOSurfa
subsystem->lastUpdate = CGDisplayStreamUpdateCreateMergedUpdate(tmpRef, updateRef);
CFRelease(tmpRef);
}
dispatch_semaphore_signal(subsystem->regionSemaphore);
};
int mac_shadow_capture_init(macShadowSubsystem* subsystem)
@ -464,11 +428,11 @@ int mac_shadow_capture_init(macShadowSubsystem* subsystem)
displayId = CGMainDisplayID();
subsystem->regionSemaphore = dispatch_semaphore_create(1);
subsystem->dataSemaphore = dispatch_semaphore_create(1);
subsystem->updateBuffer = (BYTE*) malloc(subsystem->pixelWidth * subsystem->pixelHeight * 4);
if (!subsystem->updateBuffer)
return -1;
subsystem->captureQueue = dispatch_queue_create("mac.shadow.capture", NULL);
keys[0] = (void*) kCGDisplayStreamShowCursor;
@ -486,15 +450,58 @@ int mac_shadow_capture_init(macShadowSubsystem* subsystem)
int mac_shadow_screen_grab(macShadowSubsystem* subsystem)
{
mac_shadow_capture_get_dirty_region(subsystem);
mac_shadow_capture_surface_copy(subsystem);
return 1;
}
int mac_shadow_subsystem_process_message(macShadowSubsystem* subsystem, wMessage* message)
{
if (message->id == SHADOW_MSG_IN_REFRESH_OUTPUT_ID)
{
UINT32 index;
SHADOW_MSG_IN_REFRESH_OUTPUT* msg = (SHADOW_MSG_IN_REFRESH_OUTPUT*) message->wParam;
if (msg->numRects)
{
for (index = 0; index < msg->numRects; index++)
{
region16_union_rect(&(subsystem->invalidRegion),
&(subsystem->invalidRegion), &msg->rects[index]);
}
}
else
{
RECTANGLE_16 refreshRect;
refreshRect.left = 0;
refreshRect.top = 0;
refreshRect.right = subsystem->width;
refreshRect.bottom = subsystem->height;
region16_union_rect(&(subsystem->invalidRegion),
&(subsystem->invalidRegion), &refreshRect);
}
}
else if (message->id == SHADOW_MSG_IN_SUPPRESS_OUTPUT_ID)
{
SHADOW_MSG_IN_SUPPRESS_OUTPUT* msg = (SHADOW_MSG_IN_SUPPRESS_OUTPUT*) message->wParam;
subsystem->suppressOutput = (msg->allow) ? FALSE : TRUE;
if (msg->allow)
{
region16_union_rect(&(subsystem->invalidRegion),
&(subsystem->invalidRegion), &(msg->rect));
}
}
if (message->Free)
message->Free(message);
return 1;
}
void* mac_shadow_subsystem_thread(macShadowSubsystem* subsystem)
{
int fps;
DWORD status;
DWORD nCount;
UINT64 cTime;
@ -502,15 +509,16 @@ void* mac_shadow_subsystem_thread(macShadowSubsystem* subsystem)
DWORD dwInterval;
UINT64 frameTime;
HANDLE events[32];
HANDLE StopEvent;
wMessage message;
wMessagePipe* MsgPipe;
StopEvent = subsystem->server->StopEvent;
MsgPipe = subsystem->MsgPipe;
nCount = 0;
events[nCount++] = StopEvent;
events[nCount++] = MessageQueue_Event(MsgPipe->In);
fps = 16;
dwInterval = 1000 / fps;
subsystem->captureFrameRate = 16;
dwInterval = 1000 / subsystem->captureFrameRate;
frameTime = GetTickCount64() + dwInterval;
while (1)
@ -520,16 +528,22 @@ void* mac_shadow_subsystem_thread(macShadowSubsystem* subsystem)
status = WaitForMultipleObjects(nCount, events, FALSE, dwTimeout);
if (WaitForSingleObject(StopEvent, 0) == WAIT_OBJECT_0)
if (WaitForSingleObject(MessageQueue_Event(MsgPipe->In), 0) == WAIT_OBJECT_0)
{
break;
if (MessageQueue_Peek(MsgPipe->In, &message, TRUE))
{
if (message.id == WMQ_QUIT)
break;
mac_shadow_subsystem_process_message(subsystem, &message);
}
}
if ((status == WAIT_TIMEOUT) || (GetTickCount64() > frameTime))
{
mac_shadow_screen_grab(subsystem);
dwInterval = 1000 / fps;
dwInterval = 1000 / subsystem->captureFrameRate;
frameTime += dwInterval;
}
}
@ -583,6 +597,12 @@ int mac_shadow_subsystem_uninit(macShadowSubsystem* subsystem)
{
if (!subsystem)
return -1;
if (subsystem->lastUpdate)
{
CFRelease(subsystem->lastUpdate);
subsystem->lastUpdate = NULL;
}
return 1;
}

View File

@ -47,12 +47,9 @@ struct mac_shadow_subsystem
BOOL mouseDownLeft;
BOOL mouseDownRight;
BOOL mouseDownOther;
BOOL updateReady;
BYTE* updateBuffer;
CGDisplayStreamRef stream;
dispatch_queue_t captureQueue;
dispatch_semaphore_t dataSemaphore;
dispatch_semaphore_t regionSemaphore;
CGDisplayStreamUpdateRef lastUpdate;
};

View File

@ -43,7 +43,7 @@ void shadow_input_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code)
if (!client->mayInteract)
return;
if (subsystem->KeyboardEvent)
{
subsystem->KeyboardEvent(subsystem, flags, code);

View File

@ -145,8 +145,7 @@ int shadow_subsystem_init(rdpShadowSubsystem* subsystem, rdpShadowServer* server
if (!subsystem->ep.Init)
return -1;
if (subsystem->ep.Init)
status = subsystem->ep.Init(subsystem);
status = subsystem->ep.Init(subsystem);
return status;
}