/** * Function description * * @return TRUE on success (or nothing need to be updated) */ static BOOL shadow_client_send_surface_update(rdpShadowClient* client, SHADOW_GFX_STATUS* pStatus) { BOOL ret = TRUE; int nXSrc, nYSrc; int nWidth, nHeight; rdpContext* context; rdpSettings* settings; rdpShadowServer* server; rdpShadowSurface* surface; rdpShadowEncoder* encoder; REGION16 invalidRegion; RECTANGLE_16 surfaceRect; const RECTANGLE_16* extents; BYTE* pSrcData; int nSrcStep; int index; int numRects = 0; const RECTANGLE_16* rects; context = (rdpContext*) client; settings = context->settings; server = client->server; encoder = client->encoder; surface = client->inLobby ? server->lobby : server->surface; EnterCriticalSection(&(client->lock)); region16_init(&invalidRegion); region16_copy(&invalidRegion, &(client->invalidRegion)); region16_clear(&(client->invalidRegion)); LeaveCriticalSection(&(client->lock)); rects = region16_rects(&(surface->invalidRegion), &numRects); for (index = 0; index < numRects; index++) { region16_union_rect(&invalidRegion, &invalidRegion, &rects[index]); } surfaceRect.left = 0; surfaceRect.top = 0; surfaceRect.right = surface->width; surfaceRect.bottom = surface->height; region16_intersect_rect(&invalidRegion, &invalidRegion, &surfaceRect); if (server->shareSubRect) { region16_intersect_rect(&invalidRegion, &invalidRegion, &(server->subRect)); } if (region16_is_empty(&invalidRegion)) { /* No image region need to be updated. Success */ goto out; } extents = region16_extents(&invalidRegion); nXSrc = extents->left; nYSrc = extents->top; nWidth = extents->right - extents->left; nHeight = extents->bottom - extents->top; pSrcData = surface->data; nSrcStep = surface->scanline; /* Move to new pSrcData / nXSrc / nYSrc according to sub rect */ if (server->shareSubRect) { int subX, subY; subX = server->subRect.left; subY = server->subRect.top; nXSrc -= subX; nYSrc -= subY; pSrcData = &pSrcData[(subY * nSrcStep) + (subX * 4)]; } //WLog_INFO(TAG, "shadow_client_send_surface_update: x: %d y: %d width: %d height: %d right: %d bottom: %d", // nXSrc, nYSrc, nWidth, nHeight, nXSrc + nWidth, nYSrc + nHeight); if (settings->SupportGraphicsPipeline && settings->GfxH264 && pStatus->gfxOpened) { /* GFX/h264 always full screen encoded */ nWidth = settings->DesktopWidth; nHeight = settings->DesktopHeight; /* Create primary surface if have not */ if (!pStatus->gfxSurfaceCreated) { /* Only init surface when we have h264 supported */ if (!(ret = shadow_client_rdpgfx_reset_graphic(client))) goto out; if (!(ret = shadow_client_rdpgfx_new_surface(client))) goto out; pStatus->gfxSurfaceCreated = TRUE; } ret = shadow_client_send_surface_gfx(client, pSrcData, nSrcStep, 0, 0, nWidth, nHeight); } else if (settings->RemoteFxCodec || settings->NSCodec) { ret = shadow_client_send_surface_bits(client, pSrcData, nSrcStep, nXSrc, nYSrc, nWidth, nHeight); } else { ret = shadow_client_send_bitmap_update(client, pSrcData, nSrcStep, nXSrc, nYSrc, nWidth, nHeight); } out: region16_uninit(&invalidRegion); return ret; }
RFX_MESSAGE* rfx_encode_message(RFX_CONTEXT* context, const RFX_RECT* rects, int numRects, BYTE* data, int width, int height, int scanline) { int i, maxNbTiles, maxTilesX, maxTilesY; int xIdx, yIdx, regionNbRects; int gridRelX, gridRelY, ax, ay, bytesPerPixel; RFX_TILE* tile; RFX_RECT* rfxRect; RFX_MESSAGE* message = NULL; PTP_WORK* workObject = NULL; RFX_TILE_COMPOSE_WORK_PARAM *workParam = NULL; REGION16 rectsRegion, tilesRegion; RECTANGLE_16 currentTileRect; const RECTANGLE_16 *regionRect; const RECTANGLE_16 *extents; assert(data); assert(rects); assert(numRects > 0); assert(width > 0); assert(height > 0); assert(scanline > 0); message = (RFX_MESSAGE*)calloc(1, sizeof(RFX_MESSAGE)); if (!message) return NULL; if (context->state == RFX_STATE_SEND_HEADERS) rfx_update_context_properties(context); message->frameIdx = context->frameIdx++; if (!context->numQuant) { context->numQuant = 1; context->quants = (UINT32*) malloc(sizeof(rfx_default_quantization_values)); CopyMemory(context->quants, &rfx_default_quantization_values, sizeof(rfx_default_quantization_values)); context->quantIdxY = 0; context->quantIdxCb = 0; context->quantIdxCr = 0; } message->numQuant = context->numQuant; message->quantVals = context->quants; bytesPerPixel = (context->bits_per_pixel / 8); region16_init(&rectsRegion); if (!computeRegion(rects, numRects, &rectsRegion, width, height)) goto out_free_message; extents = region16_extents(&rectsRegion); assert(extents->right - extents->left > 0); assert(extents->bottom - extents->top > 0); maxTilesX = 1 + TILE_NO(extents->right - 1) - TILE_NO(extents->left); maxTilesY = 1 + TILE_NO(extents->bottom - 1) - TILE_NO(extents->top); maxNbTiles = maxTilesX * maxTilesY; message->tiles = calloc(maxNbTiles, sizeof(RFX_TILE*)); if (!message->tiles) goto out_free_message; if (!setupWorkers(context, maxNbTiles)) goto out_clean_tiles; if (context->priv->UseThreads) { workObject = context->priv->workObjects; workParam = context->priv->tileWorkParams; } regionRect = region16_rects(&rectsRegion, ®ionNbRects); message->rects = rfxRect = calloc(regionNbRects, sizeof(RFX_RECT)); if (!message->rects) goto out_clean_tiles; message->numRects = regionNbRects; region16_init(&tilesRegion); for (i = 0; i < regionNbRects; i++, regionRect++, rfxRect++) { int startTileX = regionRect->left / 64; int endTileX = (regionRect->right - 1) / 64; int startTileY = regionRect->top / 64; int endTileY = (regionRect->bottom - 1) / 64; rfxRect->x = regionRect->left; rfxRect->y = regionRect->top; rfxRect->width = (regionRect->right - regionRect->left); rfxRect->height = (regionRect->bottom - regionRect->top); for (yIdx = startTileY, gridRelY = startTileY * 64; yIdx <= endTileY; yIdx++, gridRelY += 64 ) { int tileHeight = 64; if ((yIdx == endTileY) && (gridRelY + 64 > height)) tileHeight = height - gridRelY; currentTileRect.top = gridRelY; currentTileRect.bottom = gridRelY + tileHeight; for (xIdx = startTileX, gridRelX = startTileX * 64; xIdx <= endTileX; xIdx++, gridRelX += 64) { int tileWidth = 64; if ((xIdx == endTileX) && (gridRelX + 64 > width)) tileWidth = width - gridRelX; currentTileRect.left = gridRelX; currentTileRect.right = gridRelX + tileWidth; /* checks if this tile is already treated */ if (region16_intersects_rect(&tilesRegion, ¤tTileRect)) continue; tile = (RFX_TILE*) ObjectPool_Take(context->priv->TilePool); if (!tile) goto out_clean_rects;; tile->xIdx = xIdx; tile->yIdx = yIdx; tile->x = gridRelX; tile->y = gridRelY; tile->scanline = scanline; tile->width = tileWidth; tile->height = tileHeight; ax = gridRelX; ay = gridRelY; if (tile->data && tile->allocated) { free(tile->data); tile->allocated = FALSE; } tile->data = &data[(ay * scanline) + (ax * bytesPerPixel)]; tile->quantIdxY = context->quantIdxY; tile->quantIdxCb = context->quantIdxCb; tile->quantIdxCr = context->quantIdxCr; tile->YLen = tile->CbLen = tile->CrLen = 0; tile->YCbCrData = (BYTE *)BufferPool_Take(context->priv->BufferPool, -1); if (!tile->YCbCrData) goto out_clean_rects; tile->YData = (BYTE*) &(tile->YCbCrData[((8192 + 32) * 0) + 16]); tile->CbData = (BYTE*) &(tile->YCbCrData[((8192 + 32) * 1) + 16]); tile->CrData = (BYTE*) &(tile->YCbCrData[((8192 + 32) * 2) + 16]); if (context->priv->UseThreads) { workParam->context = context; workParam->tile = tile; *workObject = CreateThreadpoolWork( (PTP_WORK_CALLBACK)rfx_compose_message_tile_work_callback, (void*) workParam, &context->priv->ThreadPoolEnv ); SubmitThreadpoolWork(*workObject); workObject++; workParam++; } else { rfx_encode_rgb(context, tile); } message->tiles[message->numTiles] = tile; message->numTiles++; if (!region16_union_rect(&tilesRegion, &tilesRegion, ¤tTileRect)) goto out_clean_rects; } /* xIdx */ } /* yIdx */ } /* rects */ if (message->numTiles != maxNbTiles) { message->tiles = realloc(message->tiles, sizeof(RFX_TILE*) * message->numTiles); if (!message->tiles) goto out_clean_rects; } region16_uninit(&tilesRegion); /* when using threads ensure all computations are done */ message->tilesDataSize = 0; workObject = context->priv->workObjects; for (i = 0; i < message->numTiles; i++) { tile = message->tiles[i]; if (context->priv->UseThreads) { WaitForThreadpoolWorkCallbacks(*workObject, FALSE); CloseThreadpoolWork(*workObject); workObject++; } message->tilesDataSize += rfx_tile_length(tile); } region16_uninit(&rectsRegion); return message; out_clean_rects: free(message->rects); out_clean_tiles: free(message->tiles); region16_uninit(&tilesRegion); out_free_message: fprintf(stderr, "remoteFx error\n"); region16_uninit(&rectsRegion); free(message); return 0; }