From d9d9bf36094ba41e0d52defa18b8b424ef3d0e83 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Marc-Andr=C3=A9=20Moreau?= Date: Wed, 6 Aug 2014 17:51:38 -0400 Subject: [PATCH] shadow: start detecting invalid regions manually --- include/freerdp/server/shadow.h | 2 + server/shadow/CMakeLists.txt | 2 + server/shadow/X11/x11_shadow.c | 108 ++++++++++++++++++++++++- server/shadow/shadow.h | 1 + server/shadow/shadow_capture.c | 172 ++++++++++++++++++++++++++++++++++++++++ server/shadow/shadow_capture.h | 50 ++++++++++++ server/shadow/shadow_server.c | 5 ++ 7 files changed, 338 insertions(+), 2 deletions(-) create mode 100644 server/shadow/shadow_capture.c create mode 100644 server/shadow/shadow_capture.h diff --git a/include/freerdp/server/shadow.h b/include/freerdp/server/shadow.h index 3124bda..baaac3e 100644 --- a/include/freerdp/server/shadow.h +++ b/include/freerdp/server/shadow.h @@ -44,6 +44,7 @@ typedef struct rdp_shadow_server rdpShadowServer; typedef struct rdp_shadow_screen rdpShadowScreen; typedef struct rdp_shadow_surface rdpShadowSurface; typedef struct rdp_shadow_encoder rdpShadowEncoder; +typedef struct rdp_shadow_capture rdpShadowCapture; typedef struct rdp_shadow_subsystem rdpShadowSubsystem; typedef rdpShadowSubsystem* (*pfnShadowCreateSubsystem)(rdpShadowServer* server); @@ -92,6 +93,7 @@ struct rdp_shadow_server wArrayList* clients; rdpShadowScreen* screen; rdpShadowSurface* surface; + rdpShadowCapture* capture; rdpShadowSubsystem* subsystem; DWORD port; diff --git a/server/shadow/CMakeLists.txt b/server/shadow/CMakeLists.txt index d370672..620e1b9 100644 --- a/server/shadow/CMakeLists.txt +++ b/server/shadow/CMakeLists.txt @@ -126,6 +126,8 @@ set(${MODULE_PREFIX}_SRCS shadow_surface.h shadow_encoder.c shadow_encoder.h + shadow_capture.c + shadow_capture.h shadow_channels.c shadow_channels.h shadow_encomsp.c diff --git a/server/shadow/X11/x11_shadow.c b/server/shadow/X11/x11_shadow.c index 62103bd..430c5b4 100644 --- a/server/shadow/X11/x11_shadow.c +++ b/server/shadow/X11/x11_shadow.c @@ -38,6 +38,7 @@ #include #include "../shadow_screen.h" +#include "../shadow_capture.h" #include "../shadow_surface.h" #include "x11_shadow.h" @@ -263,6 +264,101 @@ int x11_shadow_surface_copy(x11ShadowSubsystem* subsystem) return 1; } +int x11_shadow_screen_grab(x11ShadowSubsystem* subsystem) +{ + int status; + int x, y; + int width, height; + XImage* image; + rdpShadowScreen* screen; + rdpShadowServer* server; + rdpShadowSurface* surface; + RECTANGLE_16 invalidRect; + + server = subsystem->server; + surface = server->surface; + screen = server->screen; + + XLockDisplay(subsystem->display); + + if (subsystem->use_xshm) + { + XCopyArea(subsystem->display, subsystem->root_window, subsystem->fb_pixmap, + subsystem->xshm_gc, 0, 0, subsystem->width, subsystem->height, 0, 0); + + XSync(subsystem->display, False); + + image = subsystem->fb_image; + + EnterCriticalSection(&(surface->lock)); + + status = shadow_capture_compare(surface->data, surface->scanline, surface->width, surface->height, + (BYTE*) image->data, image->bytes_per_line, &invalidRect); + + if (status > 0) + { + x = invalidRect.left; + y = invalidRect.top; + width = invalidRect.right - invalidRect.left; + height = invalidRect.bottom - invalidRect.top; + + if (width > subsystem->width) + width = subsystem->width; + + if (height > subsystem->height) + height = subsystem->height; + + freerdp_image_copy(surface->data, PIXEL_FORMAT_XRGB32, + surface->scanline, x - surface->x, y - surface->y, width, height, + (BYTE*) image->data, PIXEL_FORMAT_XRGB32, + image->bytes_per_line, x, y); + + x11_shadow_invalidate_region(subsystem, x, y, width, height); + } + + LeaveCriticalSection(&(surface->lock)); + } + else + { + image = XGetImage(subsystem->display, subsystem->root_window, + 0, 0, subsystem->width, subsystem->height, AllPlanes, ZPixmap); + + EnterCriticalSection(&(surface->lock)); + + status = shadow_capture_compare(surface->data, surface->scanline, surface->width, surface->height, + (BYTE*) image->data, image->bytes_per_line, &invalidRect); + + if (status > 0) + { + x = invalidRect.left; + y = invalidRect.top; + width = invalidRect.right - invalidRect.left; + height = invalidRect.bottom - invalidRect.top; + + if (width > subsystem->width) + width = subsystem->width; + + if (height > subsystem->height) + height = subsystem->height; + + freerdp_image_copy(surface->data, PIXEL_FORMAT_XRGB32, + surface->scanline, x, y, width, height, + (BYTE*) image->data, PIXEL_FORMAT_XRGB32, + image->bytes_per_line, x, y); + + x11_shadow_invalidate_region(subsystem, x, y, width, height); + } + + LeaveCriticalSection(&(surface->lock)); + + XDestroyImage(image); + } + + XUnlockDisplay(subsystem->display); + + return 1; +} + void* x11_shadow_subsystem_thread(x11ShadowSubsystem* subsystem) { int fps; @@ -288,6 +384,9 @@ void* x11_shadow_subsystem_thread(x11ShadowSubsystem* subsystem) dwInterval = 1000 / fps; frameTime = GetTickCount64() + dwInterval; + //x11_shadow_invalidate_region(subsystem, 0, 0, subsystem->width, subsystem->height); + //x11_shadow_surface_copy(subsystem); + while (1) { dwTimeout = INFINITE; @@ -327,8 +426,13 @@ void* x11_shadow_subsystem_thread(x11ShadowSubsystem* subsystem) { if ((status == WAIT_TIMEOUT) || (GetTickCount64() > frameTime)) { - x11_shadow_invalidate_region(subsystem, 0, 0, subsystem->width, subsystem->height); - x11_shadow_surface_copy(subsystem); + x11_shadow_screen_grab(subsystem); + + if (0) + { + x11_shadow_invalidate_region(subsystem, 0, 0, subsystem->width, subsystem->height); + x11_shadow_surface_copy(subsystem); + } if (subsystem->SurfaceUpdate) subsystem->SurfaceUpdate((rdpShadowSubsystem*) subsystem, &(subsystem->invalidRegion)); diff --git a/server/shadow/shadow.h b/server/shadow/shadow.h index b474c68..c6f3109 100644 --- a/server/shadow/shadow.h +++ b/server/shadow/shadow.h @@ -26,6 +26,7 @@ #include "shadow_screen.h" #include "shadow_surface.h" #include "shadow_encoder.h" +#include "shadow_capture.h" #include "shadow_channels.h" #ifdef __cplusplus diff --git a/server/shadow/shadow_capture.c b/server/shadow/shadow_capture.c new file mode 100644 index 0000000..5b8d0ea --- /dev/null +++ b/server/shadow/shadow_capture.c @@ -0,0 +1,172 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * Copyright 2014 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include "shadow_surface.h" + +#include "shadow_capture.h" + +int shadow_capture_compare(BYTE* pData1, int nStep1, int nWidth, int nHeight, BYTE* pData2, int nStep2, RECTANGLE_16* rect) +{ + BOOL equal; + BOOL allEqual; + int tw, th; + int tx, ty, k; + int nrow, ncol; + int l, t, r, b; + BYTE *p1, *p2; + BOOL rows[1024]; + BOOL cols[1024]; + BOOL grid[1024][1024]; + + allEqual = TRUE; + FillMemory(rows, sizeof(rows), 0xFF); + FillMemory(cols, sizeof(cols), 0xFF); + FillMemory(grid, sizeof(grid), 0xFF); + ZeroMemory(rect, sizeof(RECTANGLE_16)); + + nrow = (nHeight + 15) / 16; + ncol = (nWidth + 15) / 16; + + l = ncol + 1; + r = -1; + + t = nrow + 1; + b = -1; + + for (ty = 0; ty < nrow; ty++) + { + th = ((ty + 1) == nrow) ? nHeight % 16 : 16; + + for (tx = 0; tx < ncol; tx++) + { + equal = TRUE; + tw = ((tx + 1) == ncol) ? nWidth % 16 : 16; + + p1 = &pData1[(ty * 16 * nStep1) + (tx * 16 * 4)]; + p2 = &pData2[(ty * 16 * nStep2) + (tx * 16 * 4)]; + + for (k = 0; k < th; k++) + { + if (memcmp(p1, p2, tw) != 0) + { + equal = FALSE; + break; + } + + p1 += nStep1; + p2 += nStep2; + } + + if (!equal) + { + grid[ty][tx] = FALSE; + rows[ty] = FALSE; + cols[tx] = FALSE; + + if (l > tx) + l = tx; + + if (r < tx) + r = tx; + } + } + + if (!rows[ty]) + { + allEqual = FALSE; + + if (t > ty) + t = ty; + + if (b < ty) + b = ty; + } + } + + if (allEqual) + return 0; + + rect->left = l * 16; + rect->top = t * 16; + rect->right = (r + 1) * 16; + rect->bottom = (b + 1) * 16; + + if (0) + { + printf("\n"); + + for (tx = 0; tx < ncol; tx++) + printf("-"); + printf("\n"); + + for (tx = 0; tx < ncol; tx++) + printf("%s", cols[tx] ? "O" : "X"); + printf("\n"); + + for (tx = 0; tx < ncol; tx++) + printf("-"); + printf("\n"); + + for (ty = 0; ty < nrow; ty++) + { + for (tx = 0; tx < ncol; tx++) + { + printf("%s", grid[ty][tx] ? "O" : "X"); + } + + printf("|%s|\n", rows[ty] ? "O" : "X"); + } + } + + return 1; +} + +rdpShadowCapture* shadow_capture_new(rdpShadowServer* server) +{ + rdpShadowCapture* capture; + + capture = (rdpShadowCapture*) calloc(1, sizeof(rdpShadowCapture)); + + if (!capture) + return NULL; + + capture->server = server; + + if (!InitializeCriticalSectionAndSpinCount(&(capture->lock), 4000)) + return NULL; + + return capture; +} + +void shadow_capture_free(rdpShadowCapture* capture) +{ + if (!capture) + return; + + DeleteCriticalSection(&(capture->lock)); + + free(capture); +} + diff --git a/server/shadow/shadow_capture.h b/server/shadow/shadow_capture.h new file mode 100644 index 0000000..efac76c --- /dev/null +++ b/server/shadow/shadow_capture.h @@ -0,0 +1,50 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * Copyright 2014 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FREERDP_SHADOW_SERVER_CAPTURE_H +#define FREERDP_SHADOW_SERVER_CAPTURE_H + +#include + +#include +#include + +struct rdp_shadow_capture +{ + rdpShadowServer* server; + + int width; + int height; + + CRITICAL_SECTION lock; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +int shadow_capture_compare(BYTE* pData1, int nStep1, int nWidth, int nHeight, BYTE* pData2, int nStep2, RECTANGLE_16* rect); + +rdpShadowCapture* shadow_capture_new(rdpShadowServer* server); +void shadow_capture_free(rdpShadowCapture* capture); + +#ifdef __cplusplus +} +#endif + +#endif /* FREERDP_SHADOW_SERVER_CAPTURE_H */ diff --git a/server/shadow/shadow_server.c b/server/shadow/shadow_server.c index cdb2907..ab97729 100644 --- a/server/shadow/shadow_server.c +++ b/server/shadow/shadow_server.c @@ -463,6 +463,11 @@ int shadow_server_init(rdpShadowServer* server) if (!server->screen) return -1; + server->capture = shadow_capture_new(server); + + if (!server->capture) + return -1; + return 1; } -- 2.7.4