int shadow_client_send_bitmap_update(rdpShadowClient* client, rdpShadowSurface* surface, int nXSrc, int nYSrc, int nWidth, int nHeight) { BYTE* data; BYTE* buffer; int yIdx, xIdx, k; int rows, cols; int nSrcStep; BYTE* pSrcData; UINT32 DstSize; UINT32 SrcFormat; BITMAP_DATA* bitmap; rdpUpdate* update; rdpContext* context; rdpSettings* settings; UINT32 maxUpdateSize; UINT32 totalBitmapSize; UINT32 updateSizeEstimate; BITMAP_DATA* bitmapData; BITMAP_UPDATE bitmapUpdate; rdpShadowServer* server; rdpShadowEncoder* encoder; context = (rdpContext*) client; update = context->update; settings = context->settings; server = client->server; encoder = client->encoder; maxUpdateSize = settings->MultifragMaxRequestSize; if (settings->ColorDepth < 32) shadow_encoder_prepare(encoder, FREERDP_CODEC_INTERLEAVED); else shadow_encoder_prepare(encoder, FREERDP_CODEC_PLANAR); pSrcData = surface->data; nSrcStep = surface->scanline; SrcFormat = PIXEL_FORMAT_RGB32; if (server->shareSubRect) { int subX, subY; int subWidth, subHeight; subX = server->subRect.left; subY = server->subRect.top; subWidth = server->subRect.right - server->subRect.left; subHeight = server->subRect.bottom - server->subRect.top; nXSrc -= subX; nYSrc -= subY; pSrcData = &pSrcData[(subY * nSrcStep) + (subX * 4)]; } if ((nXSrc % 4) != 0) { nWidth += (nXSrc % 4); nXSrc -= (nXSrc % 4); } if ((nYSrc % 4) != 0) { nHeight += (nYSrc % 4); nYSrc -= (nYSrc % 4); } rows = (nHeight / 64) + ((nHeight % 64) ? 1 : 0); cols = (nWidth / 64) + ((nWidth % 64) ? 1 : 0); k = 0; totalBitmapSize = 0; bitmapUpdate.count = bitmapUpdate.number = rows * cols; if (!(bitmapData = (BITMAP_DATA*) malloc(sizeof(BITMAP_DATA) * bitmapUpdate.number))) return -1; bitmapUpdate.rectangles = bitmapData; if ((nWidth % 4) != 0) { nWidth += (4 - (nWidth % 4)); } if ((nHeight % 4) != 0) { nHeight += (4 - (nHeight % 4)); } for (yIdx = 0; yIdx < rows; yIdx++) { for (xIdx = 0; xIdx < cols; xIdx++) { bitmap = &bitmapData[k]; bitmap->width = 64; bitmap->height = 64; bitmap->destLeft = nXSrc + (xIdx * 64); bitmap->destTop = nYSrc + (yIdx * 64); if ((bitmap->destLeft + bitmap->width) > (nXSrc + nWidth)) bitmap->width = (nXSrc + nWidth) - bitmap->destLeft; if ((bitmap->destTop + bitmap->height) > (nYSrc + nHeight)) bitmap->height = (nYSrc + nHeight) - bitmap->destTop; bitmap->destRight = bitmap->destLeft + bitmap->width - 1; bitmap->destBottom = bitmap->destTop + bitmap->height - 1; bitmap->compressed = TRUE; if ((bitmap->width < 4) || (bitmap->height < 4)) continue; if (settings->ColorDepth < 32) { int bitsPerPixel = settings->ColorDepth; int bytesPerPixel = (bitsPerPixel + 7) / 8; DstSize = 64 * 64 * 4; buffer = encoder->grid[k]; interleaved_compress(encoder->interleaved, buffer, &DstSize, bitmap->width, bitmap->height, pSrcData, SrcFormat, nSrcStep, bitmap->destLeft, bitmap->destTop, NULL, bitsPerPixel); bitmap->bitmapDataStream = buffer; bitmap->bitmapLength = DstSize; bitmap->bitsPerPixel = bitsPerPixel; bitmap->cbScanWidth = bitmap->width * bytesPerPixel; bitmap->cbUncompressedSize = bitmap->width * bitmap->height * bytesPerPixel; } else { int dstSize; buffer = encoder->grid[k]; data = &pSrcData[(bitmap->destTop * nSrcStep) + (bitmap->destLeft * 4)]; buffer = freerdp_bitmap_compress_planar(encoder->planar, data, SrcFormat, bitmap->width, bitmap->height, nSrcStep, buffer, &dstSize); bitmap->bitmapDataStream = buffer; bitmap->bitmapLength = dstSize; bitmap->bitsPerPixel = 32; bitmap->cbScanWidth = bitmap->width * 4; bitmap->cbUncompressedSize = bitmap->width * bitmap->height * 4; } bitmap->cbCompFirstRowSize = 0; bitmap->cbCompMainBodySize = bitmap->bitmapLength; totalBitmapSize += bitmap->bitmapLength; k++; } } bitmapUpdate.count = bitmapUpdate.number = k; updateSizeEstimate = totalBitmapSize + (k * bitmapUpdate.count) + 16; if (updateSizeEstimate > maxUpdateSize) { UINT32 i, j; UINT32 updateSize; UINT32 newUpdateSize; BITMAP_DATA* fragBitmapData = NULL; if (k > 0) fragBitmapData = (BITMAP_DATA*) malloc(sizeof(BITMAP_DATA) * k); if (!fragBitmapData) { free(bitmapData); return -1; } bitmapUpdate.rectangles = fragBitmapData; i = j = 0; updateSize = 1024; while (i < k) { newUpdateSize = updateSize + (bitmapData[i].bitmapLength + 16); if ((newUpdateSize < maxUpdateSize) && ((i + 1) < k)) { CopyMemory(&fragBitmapData[j++], &bitmapData[i++], sizeof(BITMAP_DATA)); updateSize = newUpdateSize; } else { if ((i + 1) >= k) { CopyMemory(&fragBitmapData[j++], &bitmapData[i++], sizeof(BITMAP_DATA)); updateSize = newUpdateSize; } bitmapUpdate.count = bitmapUpdate.number = j; IFCALL(update->BitmapUpdate, context, &bitmapUpdate); updateSize = 1024; j = 0; } } free(fragBitmapData); } else { IFCALL(update->BitmapUpdate, context, &bitmapUpdate); } free(bitmapData); return 1; }
int freerds_send_bitmap_update(rdsConnection* connection, int bpp, RDS_MSG_PAINT_RECT* msg) { BYTE* data; BYTE* tile; BYTE* buffer; int i, j, k; wStream* s; wStream* ts; int e, lines; int scanline; int rows, cols; int MaxRegionWidth; int MaxRegionHeight; INT32 nWidth, nHeight; pixman_image_t* image; pixman_image_t* fbImage; BITMAP_DATA* bitmapData; BITMAP_UPDATE bitmapUpdate; rdpUpdate* update = connection->client->update; //printf("%s\n", __FUNCTION__); MaxRegionWidth = 64 * 4; MaxRegionHeight = 64 * 1; if ((msg->nLeftRect % 4) != 0) { msg->nWidth += (msg->nLeftRect % 4); msg->nLeftRect -= (msg->nLeftRect % 4); } if ((msg->nTopRect % 4) != 0) { msg->nHeight += (msg->nTopRect % 4); msg->nTopRect -= (msg->nTopRect % 4); } if ((msg->nWidth * msg->nHeight) > (MaxRegionWidth * MaxRegionHeight)) { RDS_MSG_PAINT_RECT subMsg; rows = (msg->nWidth + (MaxRegionWidth - (msg->nWidth % MaxRegionWidth))) / MaxRegionWidth; cols = (msg->nHeight + (MaxRegionHeight - (msg->nHeight % MaxRegionHeight))) / MaxRegionHeight; //printf("Partitioning x: %d y: %d width: %d height: %d in %d partitions (%d rows, %d cols)\n", // msg->nLeftRect, msg->nTopRect, msg->nWidth, msg->nHeight, rows * cols, rows, cols); for (i = 0; i < rows; i++) { for (j = 0; j < cols; j++) { CopyMemory(&subMsg, msg, sizeof(RDS_MSG_PAINT_RECT)); subMsg.nLeftRect = msg->nLeftRect + (i * MaxRegionWidth); subMsg.nTopRect = msg->nTopRect + (j * MaxRegionHeight); subMsg.nWidth = (i < (rows - 1)) ? MaxRegionWidth : msg->nWidth - (i * MaxRegionWidth); subMsg.nHeight = (j < (cols - 1)) ? MaxRegionHeight : msg->nHeight - (j * MaxRegionHeight); //printf("\t[%d, %d]: x: %d y: %d width: %d height: %d\n", // i, j, subMsg.nLeftRect, subMsg.nTopRect, subMsg.nWidth, subMsg.nHeight); if ((subMsg.nWidth * subMsg.nHeight) > 0) freerds_send_bitmap_update(connection, bpp, &subMsg); } } return 0; } tile = (BYTE*) malloc(64 * 64 * 4); fbImage = (pixman_image_t*) msg->framebuffer->image; rows = (msg->nWidth + (64 - (msg->nWidth % 64))) / 64; cols = (msg->nHeight + (64 - (msg->nHeight % 64))) / 64; k = 0; bitmapUpdate.count = bitmapUpdate.number = rows * cols; bitmapData = (BITMAP_DATA*) malloc(sizeof(BITMAP_DATA) * bitmapUpdate.number); bitmapUpdate.rectangles = bitmapData; if ((msg->nWidth % 4) != 0) { msg->nLeftRect -= (msg->nWidth % 4); msg->nWidth += (msg->nWidth % 4); } if ((msg->nHeight % 4) != 0) { msg->nTopRect -= (msg->nHeight % 4); msg->nHeight += (msg->nHeight % 4); } for (i = 0; i < rows; i++) { for (j = 0; j < cols; j++) { nWidth = (i < (rows - 1)) ? 64 : msg->nWidth - (i * 64); nHeight = (j < (cols - 1)) ? 64 : msg->nHeight - (j * 64); bitmapData[k].bitsPerPixel = 16; bitmapData[k].width = nWidth; bitmapData[k].height = nHeight; bitmapData[k].destLeft = msg->nLeftRect + (i * 64); bitmapData[k].destTop = msg->nTopRect + (j * 64); bitmapData[k].destRight = bitmapData[k].destLeft + nWidth - 1; bitmapData[k].destBottom = bitmapData[k].destTop + nHeight - 1; bitmapData[k].compressed = TRUE; if (((nWidth * nHeight) > 0) && (nWidth >= 4) && (nHeight >= 4)) { e = nWidth % 4; if (e != 0) e = 4 - e; //printf("k: %d destLeft: %d destTop: %d destRight: %d destBottom: %d nWidth: %d nHeight: %d\n", // k, bitmapData[k].destLeft, bitmapData[k].destTop, // bitmapData[k].destRight, bitmapData[k].destBottom, nWidth, nHeight); s = connection->encoder->bs; ts = connection->encoder->bts; Stream_SetPosition(s, 0); Stream_SetPosition(ts, 0); data = msg->framebuffer->fbSharedMemory; data = &data[(bitmapData[k].destTop * msg->framebuffer->fbScanline) + (bitmapData[k].destLeft * msg->framebuffer->fbBytesPerPixel)]; scanline = msg->framebuffer->fbScanline; if (bpp > 16) { int dstSize; UINT32 format; format = FREERDP_PIXEL_FORMAT(msg->framebuffer->fbBitsPerPixel, FREERDP_PIXEL_FORMAT_TYPE_ARGB, FREERDP_PIXEL_FLIP_NONE); buffer = connection->encoder->grid[k]; buffer = freerdp_bitmap_compress_planar(connection->encoder->planar_context, data, format, nWidth, nHeight, scanline, buffer, &dstSize); bitmapData[k].bitmapDataStream = buffer; bitmapData[k].bitmapLength = dstSize; bitmapData[k].bitsPerPixel = 32; bitmapData[k].cbScanWidth = nWidth * 4; bitmapData[k].cbUncompressedSize = nWidth * nHeight * 4; } else { image = pixman_image_create_bits(PIXMAN_r5g6b5, nWidth, nHeight, (uint32_t*) tile, nWidth * 2); pixman_image_composite(PIXMAN_OP_OVER, fbImage, NULL, image, bitmapData[k].destLeft, bitmapData[k].destTop, 0, 0, 0, 0, nWidth, nHeight); lines = freerdp_bitmap_compress((char*) pixman_image_get_data(image), nWidth, nHeight, s, 16, 16384, nHeight - 1, ts, e); Stream_SealLength(s); bitmapData[k].bitmapDataStream = Stream_Buffer(s); bitmapData[k].bitmapLength = Stream_Length(s); buffer = connection->encoder->grid[k]; CopyMemory(buffer, bitmapData[k].bitmapDataStream, bitmapData[k].bitmapLength); bitmapData[k].bitmapDataStream = buffer; bitmapData[k].bitsPerPixel = 16; bitmapData[k].cbScanWidth = nWidth * 2; bitmapData[k].cbUncompressedSize = nWidth * nHeight * 2; pixman_image_unref(image); } bitmapData[k].cbCompFirstRowSize = 0; bitmapData[k].cbCompMainBodySize = bitmapData[k].bitmapLength; k++; } } } bitmapUpdate.count = bitmapUpdate.number = k; IFCALL(update->BitmapUpdate, (rdpContext*) connection, &bitmapUpdate); free(bitmapData); free(tile); return 0; }
int freerds_send_bitmap_update(rdsConnection* connection, int bpp, RDS_MSG_PAINT_RECT* msg) { int nXSrc; int nYSrc; int nWidth; int nHeight; BYTE* data; BYTE* buffer; int yIdx, xIdx, k; int rows, cols, extra; int nSrcStep; BYTE* pSrcData; UINT32 DstSize; UINT32 SrcFormat; BITMAP_DATA* bitmap; rdpUpdate* update; rdsEncoder* encoder; rdpContext* context; rdpSettings* settings; UINT32 maxUpdateSize; UINT32 totalBitmapSize; UINT32 updateSizeEstimate; BITMAP_DATA* bitmapData; BITMAP_UPDATE bitmapUpdate; WLog_VRB(TAG, "%s", __FUNCTION__); nXSrc = msg->nLeftRect; nYSrc = msg->nTopRect; nWidth = msg->nWidth; nHeight = msg->nHeight; context = (rdpContext*) connection; update = context->update; settings = connection->settings; encoder = connection->encoder; maxUpdateSize = settings->MultifragMaxRequestSize; if (settings->ColorDepth < 32) freerds_encoder_prepare(encoder, FREERDP_CODEC_INTERLEAVED); else freerds_encoder_prepare(encoder, FREERDP_CODEC_PLANAR); pSrcData = msg->framebuffer->fbSharedMemory; nSrcStep = msg->framebuffer->fbScanline; SrcFormat = PIXEL_FORMAT_RGB32; if ((nXSrc % 4) != 0) { nWidth += (nXSrc % 4); nXSrc -= (nXSrc % 4); } if ((nYSrc % 4) != 0) { nHeight += (nYSrc % 4); nYSrc -= (nYSrc % 4); } rows = (nHeight / 64) + ((nHeight % 64) ? 1 : 0); cols = (nWidth / 64) + ((nWidth % 64) ? 1 : 0); k = 0; totalBitmapSize = 0; bitmapUpdate.count = bitmapUpdate.number = rows * cols; bitmapData = (BITMAP_DATA*) malloc(sizeof(BITMAP_DATA) * bitmapUpdate.number); bitmapUpdate.rectangles = bitmapData; if (!bitmapData) return -1; if ((nWidth % 4) != 0) { nXSrc -= (nWidth % 4); nWidth += (nWidth % 4); } if ((nHeight % 4) != 0) { nYSrc -= (nHeight % 4); nHeight += (nHeight % 4); } /* Clip the rectangle to the confines of the frame buffer. */ if (nXSrc < 0) { nWidth += nXSrc; nXSrc = 0; } if (nYSrc < 0) { nHeight += nYSrc; nYSrc = 0; } extra = (nXSrc + nWidth) - msg->framebuffer->fbWidth; if (extra > 0) { nWidth -= extra; } extra = (nYSrc + nHeight) - msg->framebuffer->fbHeight; if (extra > 0) { nHeight -= extra; } if ((nWidth <= 0) || (nHeight <= 0)) { /* Nothing to do. */ return 1; } for (yIdx = 0; yIdx < rows; yIdx++) { for (xIdx = 0; xIdx < cols; xIdx++) { bitmap = &bitmapData[k]; bitmap->width = 64; bitmap->height = 64; bitmap->destLeft = nXSrc + (xIdx * 64); bitmap->destTop = nYSrc + (yIdx * 64); if ((bitmap->destLeft + bitmap->width) > (nXSrc + nWidth)) bitmap->width = (nXSrc + nWidth) - bitmap->destLeft; if ((bitmap->destTop + bitmap->height) > (nYSrc + nHeight)) bitmap->height = (nYSrc + nHeight) - bitmap->destTop; bitmap->destRight = bitmap->destLeft + bitmap->width - 1; bitmap->destBottom = bitmap->destTop + bitmap->height - 1; bitmap->compressed = TRUE; if ((bitmap->width < 4) || (bitmap->height < 4)) continue; if (settings->ColorDepth < 32) { int bitsPerPixel = settings->ColorDepth; int bytesPerPixel = (bitsPerPixel + 7) / 8; DstSize = 64 * 64 * 4; buffer = encoder->grid[k]; interleaved_compress(encoder->interleaved, buffer, &DstSize, bitmap->width, bitmap->height, pSrcData, SrcFormat, nSrcStep, bitmap->destLeft, bitmap->destTop, NULL, bitsPerPixel); bitmap->bitmapDataStream = buffer; bitmap->bitmapLength = DstSize; bitmap->bitsPerPixel = bitsPerPixel; bitmap->cbScanWidth = bitmap->width * bytesPerPixel; bitmap->cbUncompressedSize = bitmap->width * bitmap->height * bytesPerPixel; } else { int dstSize; buffer = encoder->grid[k]; data = &pSrcData[(bitmap->destTop * nSrcStep) + (bitmap->destLeft * 4)]; buffer = freerdp_bitmap_compress_planar(encoder->planar, data, SrcFormat, bitmap->width, bitmap->height, nSrcStep, buffer, &dstSize); bitmap->bitmapDataStream = buffer; bitmap->bitmapLength = dstSize; bitmap->bitsPerPixel = 32; bitmap->cbScanWidth = bitmap->width * 4; bitmap->cbUncompressedSize = bitmap->width * bitmap->height * 4; } bitmap->cbCompFirstRowSize = 0; bitmap->cbCompMainBodySize = bitmap->bitmapLength; totalBitmapSize += bitmap->bitmapLength; k++; } } bitmapUpdate.count = bitmapUpdate.number = k; updateSizeEstimate = totalBitmapSize + (k * bitmapUpdate.count) + 16; if (updateSizeEstimate > maxUpdateSize) { UINT32 i, j; UINT32 updateSize; UINT32 newUpdateSize; BITMAP_DATA* fragBitmapData; fragBitmapData = (BITMAP_DATA*) malloc(sizeof(BITMAP_DATA) * k); bitmapUpdate.rectangles = fragBitmapData; i = j = 0; updateSize = 1024; while (i < k) { newUpdateSize = updateSize + (bitmapData[i].bitmapLength + 16); if ((newUpdateSize < maxUpdateSize) && ((i + 1) < k)) { CopyMemory(&fragBitmapData[j++], &bitmapData[i++], sizeof(BITMAP_DATA)); updateSize = newUpdateSize; } else { if ((i + 1) >= k) { CopyMemory(&fragBitmapData[j++], &bitmapData[i++], sizeof(BITMAP_DATA)); updateSize = newUpdateSize; } bitmapUpdate.count = bitmapUpdate.number = j; IFCALL(update->BitmapUpdate, context, &bitmapUpdate); updateSize = 1024; j = 0; } } free(fragBitmapData); } else { IFCALL(update->BitmapUpdate, context, &bitmapUpdate); } free(bitmapData); return 1; }