Пример #1
0
/**
 * 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;
}
Пример #2
0
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, &regionNbRects);
	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, &currentTileRect))
					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, &currentTileRect))
					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;
}