diff options
Diffstat (limited to 'xorg')
-rw-r--r-- | xorg/server/module/rdpCapture.c | 440 | ||||
-rw-r--r-- | xorg/server/module/rdpCapture.h | 3 | ||||
-rw-r--r-- | xorg/server/module/rdpClientCon.c | 17 |
3 files changed, 362 insertions, 98 deletions
diff --git a/xorg/server/module/rdpCapture.c b/xorg/server/module/rdpCapture.c index e9fef483..d5ee04fb 100644 --- a/xorg/server/module/rdpCapture.c +++ b/xorg/server/module/rdpCapture.c @@ -39,9 +39,216 @@ #define LLOGLN(_level, _args) \ do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0) +#define RDP_MAX_TILES 1024 + +/******************************************************************************/ +static int +rdpLimitRects(RegionPtr reg, int max_rects, BoxPtr *rects) +{ + int nrects; + + nrects = REGION_NUM_RECTS(reg); + if (nrects > max_rects) + { + nrects = 1; + *rects = rdpRegionExtents(reg); + } + else + { + *rects = REGION_RECTS(reg); + } + return nrects; +} + +/******************************************************************************/ +/* copy rects with no error checking */ +static int +rdpCopyBox_a8r8g8b8_to_a8r8g8b8(void *src, int src_stride, int srcx, int srcy, + void *dst, int dst_stride, int dstx, int dsty, + BoxPtr rects, int num_rects) +{ + char *s8; + char *d8; + int index; + int jndex; + int bytes; + int height; + BoxPtr box; + + for (index = 0; index < num_rects; index++) + { + box = rects + index; + s8 = ((char *) src) + (box->y1 - srcy) * src_stride; + s8 += (box->x1 - srcx) * 4; + d8 = ((char *) dst) + (box->y1 - dsty) * dst_stride; + d8 += (box->x1 - dstx) * 4; + bytes = box->x2 - box->x1; + bytes *= 4; + height = box->y2 - box->y1; + for (jndex = 0; jndex < height; jndex++) + { + memcpy(d8, s8, bytes); + d8 += dst_stride; + s8 += src_stride; + } + } + return 0; +} + +/******************************************************************************/ +static int +rdpFillBox_yuvalp(int ax, int ay, + void *dst, int dst_stride) +{ + dst = ((char *) dst) + (ay << 8) * (dst_stride >> 8) + (ax << 8); + memset(dst, 0, 64 * 64 * 4); + return 0; +} + +/******************************************************************************/ +/* copy rects with no error checking + * convert ARGB32 to 64x64 linear planar YUVA */ +/* http://msdn.microsoft.com/en-us/library/ff635643.aspx + * 0.299 -0.168935 0.499813 + * 0.587 -0.331665 -0.418531 + * 0.114 0.50059 -0.081282 + y = r * 0.299000 + g * 0.587000 + b * 0.114000; + u = r * -0.168935 + g * -0.331665 + b * 0.500590; + v = r * 0.499813 + g * -0.418531 + b * -0.081282; */ +/* 19595 38470 7471 + -11071 -21736 32807 + 32756 -27429 -5327 */ +static int +rdpCopyBox_a8r8g8b8_to_yuvalp(int ax, int ay, + void *src, int src_stride, + void *dst, int dst_stride, + BoxPtr rects, int num_rects) +{ + char *s8; + char *d8; + char *yptr; + char *uptr; + char *vptr; + char *aptr; + int *s32; + int index; + int jndex; + int kndex; + int width; + int height; + int pixel; + int a; + int r; + int g; + int b; + int y; + int u; + int v; + BoxPtr box; + + dst = ((char *) dst) + (ay << 8) * (dst_stride >> 8) + (ax << 8); + for (index = 0; index < num_rects; index++) + { + box = rects + index; + s8 = ((char *) src) + box->y1 * src_stride; + s8 += box->x1 * 4; + d8 = ((char *) dst) + (box->y1 - ay) * 64; + d8 += box->x1 - ax; + width = box->x2 - box->x1; + height = box->y2 - box->y1; + for (jndex = 0; jndex < height; jndex++) + { + s32 = (int *) s8; + yptr = d8; + uptr = yptr + 64 * 64; + vptr = uptr + 64 * 64; + aptr = vptr + 64 * 64; + kndex = 0; + while (kndex < width) + { + pixel = *(s32++); + a = (pixel >> 24) & 0xff; + r = (pixel >> 16) & 0xff; + g = (pixel >> 8) & 0xff; + b = (pixel >> 0) & 0xff; + y = (r * 19595 + g * 38470 + b * 7471) >> 16; + u = (r * -11071 + g * -21736 + b * 32807) >> 16; + v = (r * 32756 + g * -27429 + b * -5327) >> 16; + y = y - 128; + y = max(y, -128); + u = max(u, -128); + v = max(v, -128); + y = min(y, 127); + u = min(u, 127); + v = min(v, 127); + *(yptr++) = y; + *(uptr++) = u; + *(vptr++) = v; + *(aptr++) = a; + kndex++; + } + d8 += 64; + s8 += src_stride; + } + } + return 0; +} + +/******************************************************************************/ +/* copy rects with no error checking */ +static int +rdpCopyBox_a8r8g8b8_to_a8b8g8r8(void *src, int src_stride, + void *dst, int dst_stride, + BoxPtr rects, int num_rects) +{ + char *s8; + char *d8; + int index; + int jndex; + int kndex; + int bytes; + int width; + int height; + int red; + int green; + int blue; + BoxPtr box; + unsigned int *s32; + unsigned int *d32; + + for (index = 0; index < num_rects; index++) + { + box = rects + index; + s8 = ((char *) src) + box->y1 * src_stride; + s8 += box->x1 * 4; + d8 = ((char *) dst) + box->y1 * dst_stride; + d8 += box->x1 * 4; + bytes = box->x2 - box->x1; + bytes *= 4; + width = box->x2 - box->x1; + height = box->y2 - box->y1; + for (jndex = 0; jndex < height; jndex++) + { + s32 = (unsigned int *) s8; + d32 = (unsigned int *) d8; + for (kndex = 0; kndex < width; kndex++) + { + SPLITCOLOR32(red, green, blue, *s32); + *d32 = COLOR24(red, green, blue); + s32++; + d32++; + } + d8 += dst_stride; + s8 += src_stride; + } + } + return 0; +} + /******************************************************************************/ static Bool -rdpCapture0(RegionPtr in_reg, BoxPtr *out_rects, int *num_out_rects, +rdpCapture0(rdpClientCon *clientCon, + RegionPtr in_reg, BoxPtr *out_rects, int *num_out_rects, void *src, int src_width, int src_height, int src_stride, int src_format, void *dst, int dst_width, int dst_height, @@ -52,15 +259,13 @@ rdpCapture0(RegionPtr in_reg, BoxPtr *out_rects, int *num_out_rects, RegionRec reg; char *src_rect; char *dst_rect; - int num_regions; - int bytespp; + int num_rects; int src_bytespp; int dst_bytespp; int width; int height; int src_offset; int dst_offset; - int bytes; int i; int j; int k; @@ -69,7 +274,6 @@ rdpCapture0(RegionPtr in_reg, BoxPtr *out_rects, int *num_out_rects, int blue; Bool rv; unsigned int *s32; - unsigned int *d32; unsigned short *d16; unsigned char *d8; @@ -84,27 +288,18 @@ rdpCapture0(RegionPtr in_reg, BoxPtr *out_rects, int *num_out_rects, rdpRegionInit(®, &rect, 0); rdpRegionIntersect(®, in_reg, ®); - num_regions = REGION_NUM_RECTS(®); - - if (num_regions > max_rects) - { - num_regions = 1; - psrc_rects = rdpRegionExtents(®); - } - else - { - psrc_rects = REGION_RECTS(®); - } - - if (num_regions < 1) + psrc_rects = 0; + num_rects = rdpLimitRects(®, max_rects, &psrc_rects); + if (num_rects < 1) { + rdpRegionUninit(®); return FALSE; } - *num_out_rects = num_regions; + *num_out_rects = num_rects; - *out_rects = (BoxPtr) g_malloc(sizeof(BoxRec) * num_regions, 0); - for (i = 0; i < num_regions; i++) + *out_rects = (BoxPtr) g_malloc(sizeof(BoxRec) * num_rects, 0); + for (i = 0; i < num_rects; i++) { rect = psrc_rects[i]; (*out_rects)[i] = rect; @@ -112,78 +307,22 @@ rdpCapture0(RegionPtr in_reg, BoxPtr *out_rects, int *num_out_rects, if ((src_format == XRDP_a8r8g8b8) && (dst_format == XRDP_a8r8g8b8)) { - bytespp = 4; - - for (i = 0; i < num_regions; i++) - { - /* get rect to copy */ - rect = (*out_rects)[i]; - - /* get rect dimensions */ - width = rect.x2 - rect.x1; - height = rect.y2 - rect.y1; - - /* point to start of each rect in respective memory */ - src_offset = rect.y1 * src_stride + rect.x1 * bytespp; - dst_offset = rect.y1 * dst_stride + rect.x1 * bytespp; - src_rect = src + src_offset; - dst_rect = dst + dst_offset; - - /* bytes per line */ - bytes = width * bytespp; - - /* copy one line at a time */ - for (j = 0; j < height; j++) - { - memcpy(dst_rect, src_rect, bytes); - src_rect += src_stride; - dst_rect += dst_stride; - } - } + rdpCopyBox_a8r8g8b8_to_a8r8g8b8(src, src_stride, 0, 0, + dst, dst_stride, 0, 0, + psrc_rects, num_rects); } else if ((src_format == XRDP_a8r8g8b8) && (dst_format == XRDP_a8b8g8r8)) { - src_bytespp = 4; - dst_bytespp = 4; - - for (i = 0; i < num_regions; i++) - { - /* get rect to copy */ - rect = (*out_rects)[i]; - - /* get rect dimensions */ - width = rect.x2 - rect.x1; - height = rect.y2 - rect.y1; - - /* point to start of each rect in respective memory */ - src_offset = rect.y1 * src_stride + rect.x1 * src_bytespp; - dst_offset = rect.y1 * dst_stride + rect.x1 * dst_bytespp; - src_rect = src + src_offset; - dst_rect = dst + dst_offset; - - /* copy one line at a time */ - for (j = 0; j < height; j++) - { - s32 = (unsigned int *) src_rect; - d32 = (unsigned int *) dst_rect; - for (k = 0; k < width; k++) - { - SPLITCOLOR32(red, green, blue, *s32); - *d32 = COLOR24(red, green, blue); - s32++; - d32++; - } - src_rect += src_stride; - dst_rect += dst_stride; - } - } + rdpCopyBox_a8r8g8b8_to_a8b8g8r8(src, src_stride, + dst, dst_stride, + psrc_rects, num_rects); } else if ((src_format == XRDP_a8r8g8b8) && (dst_format == XRDP_r5g6b5)) { src_bytespp = 4; dst_bytespp = 2; - for (i = 0; i < num_regions; i++) + for (i = 0; i < num_rects; i++) { /* get rect to copy */ rect = (*out_rects)[i]; @@ -220,7 +359,7 @@ rdpCapture0(RegionPtr in_reg, BoxPtr *out_rects, int *num_out_rects, src_bytespp = 4; dst_bytespp = 2; - for (i = 0; i < num_regions; i++) + for (i = 0; i < num_rects; i++) { /* get rect to copy */ rect = (*out_rects)[i]; @@ -257,7 +396,7 @@ rdpCapture0(RegionPtr in_reg, BoxPtr *out_rects, int *num_out_rects, src_bytespp = 4; dst_bytespp = 1; - for (i = 0; i < num_regions; i++) + for (i = 0; i < num_rects; i++) { /* get rect to copy */ rect = (*out_rects)[i]; @@ -300,7 +439,8 @@ rdpCapture0(RegionPtr in_reg, BoxPtr *out_rects, int *num_out_rects, /******************************************************************************/ /* make out_rects always multiple of 16 width and height */ static Bool -rdpCapture1(RegionPtr in_reg, BoxPtr *out_rects, int *num_out_rects, +rdpCapture1(rdpClientCon *clientCon, + RegionPtr in_reg, BoxPtr *out_rects, int *num_out_rects, void *src, int src_width, int src_height, int src_stride, int src_format, void *dst, int dst_width, int dst_height, @@ -475,11 +615,125 @@ rdpCapture1(RegionPtr in_reg, BoxPtr *out_rects, int *num_out_rects, return rv; } +/******************************************************************************/ +static Bool +rdpCapture2(rdpClientCon *clientCon, + RegionPtr in_reg, BoxPtr *out_rects, int *num_out_rects, + void *src, int src_width, int src_height, + int src_stride, int src_format, + void *dst, int dst_width, int dst_height, + int dst_stride, int dst_format, int max_rects) +{ + int x; + int y; + int out_rect_index; + int num_rects; + int rcode; + BoxRec rect; + BoxRec extents_rect; + BoxPtr rects; + RegionRec tile_reg; + RegionRec lin_reg; + RegionRec temp_reg; + RegionPtr pin_reg; + + LLOGLN(10, ("rdpCapture2:")); + + *out_rects = (BoxPtr) g_malloc(sizeof(BoxRec) * RDP_MAX_TILES, 0); + if (*out_rects == NULL) + { + return FALSE; + } + out_rect_index = 0; + + /* clip for smaller of 2 */ + rect.x1 = 0; + rect.y1 = 0; + rect.x2 = min(dst_width, src_width); + rect.y2 = min(dst_height, src_height); + rdpRegionInit(&temp_reg, &rect, 0); + rdpRegionIntersect(&temp_reg, in_reg, &temp_reg); + + /* limit the numer of rects */ + num_rects = REGION_NUM_RECTS(&temp_reg); + if (num_rects > max_rects) + { + LLOGLN(10, ("rdpCapture2: too many rects")); + rdpRegionInit(&lin_reg, rdpRegionExtents(&temp_reg), 0); + pin_reg = &lin_reg; + } + else + { + LLOGLN(10, ("rdpCapture2: not too many rects")); + rdpRegionInit(&lin_reg, NullBox, 0); + pin_reg = &temp_reg; + } + + extents_rect = *rdpRegionExtents(pin_reg); + y = extents_rect.y1 & ~63; + while (y < extents_rect.y2) + { + x = extents_rect.x1 & ~63; + while (x < extents_rect.x2) + { + rect.x1 = x; + rect.y1 = y; + rect.x2 = rect.x1 + 64; + rect.y2 = rect.y1 + 64; + rcode = rdpRegionContainsRect(pin_reg, &rect); + LLOGLN(10, ("rdpCapture2: rcode %d", rcode)); + + if (rcode != rgnOUT) + { + if (rcode == rgnPART) + { + LLOGLN(10, ("rdpCapture2: rgnPART")); + rdpFillBox_yuvalp(x, y, dst, dst_stride); + rdpRegionInit(&tile_reg, &rect, 0); + rdpRegionIntersect(&tile_reg, pin_reg, &tile_reg); + rects = REGION_RECTS(&tile_reg); + num_rects = REGION_NUM_RECTS(&tile_reg); + rdpCopyBox_a8r8g8b8_to_yuvalp(x, y, + src, src_stride, + dst, dst_stride, + rects, num_rects); + rdpRegionUninit(&tile_reg); + } + else /* rgnIN */ + { + LLOGLN(10, ("rdpCapture2: rgnIN")); + rdpCopyBox_a8r8g8b8_to_yuvalp(x, y, + src, src_stride, + dst, dst_stride, + &rect, 1); + } + (*out_rects)[out_rect_index] = rect; + out_rect_index++; + if (out_rect_index >= RDP_MAX_TILES) + { + g_free(*out_rects); + *out_rects = NULL; + rdpRegionUninit(&temp_reg); + rdpRegionUninit(&lin_reg); + return FALSE; + } + } + x += 64; + } + y += 64; + } + *num_out_rects = out_rect_index; + rdpRegionUninit(&temp_reg); + rdpRegionUninit(&lin_reg); + return TRUE; +} + /** * Copy an array of rectangles from one memory area to another *****************************************************************************/ Bool -rdpCapture(RegionPtr in_reg, BoxPtr *out_rects, int *num_out_rects, +rdpCapture(rdpClientCon *clientCon, + RegionPtr in_reg, BoxPtr *out_rects, int *num_out_rects, void *src, int src_width, int src_height, int src_stride, int src_format, void *dst, int dst_width, int dst_height, @@ -489,13 +743,19 @@ rdpCapture(RegionPtr in_reg, BoxPtr *out_rects, int *num_out_rects, switch (mode) { case 0: - return rdpCapture0(in_reg, out_rects, num_out_rects, + return rdpCapture0(clientCon, in_reg, out_rects, num_out_rects, src, src_width, src_height, src_stride, src_format, dst, dst_width, dst_height, dst_stride, dst_format, 15); case 1: - return rdpCapture1(in_reg, out_rects, num_out_rects, + return rdpCapture1(clientCon, in_reg, out_rects, num_out_rects, + src, src_width, src_height, + src_stride, src_format, + dst, dst_width, dst_height, + dst_stride, dst_format, 15); + case 2: + return rdpCapture2(clientCon, in_reg, out_rects, num_out_rects, src, src_width, src_height, src_stride, src_format, dst, dst_width, dst_height, diff --git a/xorg/server/module/rdpCapture.h b/xorg/server/module/rdpCapture.h index 5810e3b6..4dff1eea 100644 --- a/xorg/server/module/rdpCapture.h +++ b/xorg/server/module/rdpCapture.h @@ -19,7 +19,8 @@ */ Bool -rdpCapture(RegionPtr in_reg, BoxPtr *out_rects, int *num_out_rects, +rdpCapture(rdpClientCon *clientCon, + RegionPtr in_reg, BoxPtr *out_rects, int *num_out_rects, void *src, int src_width, int src_height, int src_stride, int src_format, void *dst, int dst_width, int dst_height, diff --git a/xorg/server/module/rdpClientCon.c b/xorg/server/module/rdpClientCon.c index 24870557..00ea4645 100644 --- a/xorg/server/module/rdpClientCon.c +++ b/xorg/server/module/rdpClientCon.c @@ -691,11 +691,9 @@ rdpClientConProcessMsgClientInfo(rdpPtr dev, rdpClientCon *clientCon) i1 = clientCon->client_info.offscreen_cache_entries; LLOGLN(0, (" offscreen entries %d", i1)); - if ((clientCon->client_info.mcs_connection_type == 6) && /* LAN */ - (clientCon->client_info.jpeg_codec_id == 2)) + if (clientCon->client_info.capture_format != 0) { - /* jpeg capture needs swap */ - clientCon->rdp_format = XRDP_a8b8g8r8; + clientCon->rdp_format = clientCon->client_info.capture_format; } if (clientCon->client_info.offscreen_support_level > 0) @@ -1964,7 +1962,9 @@ rdpDeferredUpdateCallback(OsTimerPtr timer, CARD32 now, pointer arg) LLOGLN(10, ("rdpDeferredUpdateCallback:")); clientCon = (rdpClientCon *) arg; - if (clientCon->rect_id > clientCon->rect_id_ack) + if ((clientCon->rect_id > clientCon->rect_id_ack) || + /* do not allow captures until we have the client_info */ + clientCon->client_info.size == 0) { LLOGLN(0, ("rdpDeferredUpdateCallback: reschedual rect_id %d " "rect_id_ack %d", @@ -1986,13 +1986,16 @@ rdpDeferredUpdateCallback(OsTimerPtr timer, CARD32 now, pointer arg) clientCon->updateSchedualed = FALSE; rects = 0; num_rects = 0; - if (rdpCapture(clientCon->dirtyRegion, &rects, &num_rects, + LLOGLN(10, ("rdpDeferredUpdateCallback: capture_code %d", + clientCon->client_info.capture_code)); + if (rdpCapture(clientCon, clientCon->dirtyRegion, &rects, &num_rects, id.pixels, id.width, id.height, id.lineBytes, XRDP_a8r8g8b8, id.shmem_pixels, clientCon->rdp_width, clientCon->rdp_height, clientCon->rdp_width * clientCon->rdp_Bpp, - clientCon->rdp_format, 0)) + clientCon->rdp_format, clientCon->client_info.capture_code)) { + LLOGLN(10, ("rdpDeferredUpdateCallback: num_rects %d", num_rects)); rdpClientConSendPaintRectShmEx(clientCon->dev, clientCon, &id, clientCon->dirtyRegion, rects, num_rects); |