22#include <freerdp/config.h>
26#include <winpr/assert.h>
27#include <winpr/cast.h>
29#include <freerdp/log.h>
37#define TAG CLIENT_TAG("x11")
39static UINT xf_OutputUpdate(xfContext* xfc, xfGfxSurface* surface)
41 UINT rc = ERROR_INTERNAL_ERROR;
49 WINPR_ASSERT(surface);
51 rdpGdi* gdi = xfc->common.context.gdi;
54 rdpSettings* settings = xfc->common.context.settings;
55 WINPR_ASSERT(settings);
57 surfaceX = surface->gdi.outputOriginX;
58 surfaceY = surface->gdi.outputOriginY;
61 surfaceRect.right = WINPR_ASSERTING_INT_CAST(UINT16, surface->gdi.mappedWidth);
62 surfaceRect.bottom = WINPR_ASSERTING_INT_CAST(UINT16, surface->gdi.mappedHeight);
63 LogDynAndXSetClipMask(xfc->log, xfc->display, xfc->gc, None);
64 LogDynAndXSetFunction(xfc->log, xfc->display, xfc->gc, GXcopy);
65 LogDynAndXSetFillStyle(xfc->log, xfc->display, xfc->gc, FillSolid);
66 if (!region16_intersect_rect(&(surface->gdi.invalidRegion), &(surface->gdi.invalidRegion),
68 return ERROR_INTERNAL_ERROR;
70 WINPR_ASSERT(surface->gdi.mappedWidth);
71 WINPR_ASSERT(surface->gdi.mappedHeight);
72 const double sx = 1.0 * surface->gdi.outputTargetWidth / (double)surface->gdi.mappedWidth;
73 const double sy = 1.0 * surface->gdi.outputTargetHeight / (double)surface->gdi.mappedHeight;
75 if (!(rects = region16_rects(&surface->gdi.invalidRegion, &nbRects)))
79 for (UINT32 x = 0; x < nbRects; x++)
82 const UINT32 nXSrc = rect->left;
83 const UINT32 nYSrc = rect->top;
84 const UINT32 swidth = rect->right - nXSrc;
85 const UINT32 sheight = rect->bottom - nYSrc;
86 const UINT32 nXDst = (UINT32)lround(1.0 * surfaceX + nXSrc * sx);
87 const UINT32 nYDst = (UINT32)lround(1.0 * surfaceY + nYSrc * sy);
88 const UINT32 dwidth = (UINT32)lround(1.0 * swidth * sx);
89 const UINT32 dheight = (UINT32)lround(1.0 * sheight * sy);
93 if (!freerdp_image_scale(surface->stage, gdi->dstFormat, surface->stageScanline, nXSrc,
94 nYSrc, dwidth, dheight, surface->gdi.data, surface->gdi.format,
95 surface->gdi.scanline, nXSrc, nYSrc, swidth, sheight))
101 LogDynAndXPutImage(xfc->log, xfc->display, xfc->primary, xfc->gc, surface->image,
102 WINPR_ASSERTING_INT_CAST(
int, nXSrc),
103 WINPR_ASSERTING_INT_CAST(
int, nYSrc),
104 WINPR_ASSERTING_INT_CAST(
int, nXDst),
105 WINPR_ASSERTING_INT_CAST(
int, nYDst), dwidth, dheight);
106 (void)xf_rail_paint_surface(xfc, surface->gdi.windowId, rect);
113 LogDynAndXPutImage(xfc->log, xfc->display, xfc->primary, xfc->gc, surface->image,
114 WINPR_ASSERTING_INT_CAST(
int, nXSrc),
115 WINPR_ASSERTING_INT_CAST(
int, nYSrc),
116 WINPR_ASSERTING_INT_CAST(
int, nXDst),
117 WINPR_ASSERTING_INT_CAST(
int, nYDst), dwidth, dheight);
118 xf_draw_screen(xfc, WINPR_ASSERTING_INT_CAST(int32_t, nXDst),
119 WINPR_ASSERTING_INT_CAST(int32_t, nYDst),
120 WINPR_ASSERTING_INT_CAST(int32_t, dwidth),
121 WINPR_ASSERTING_INT_CAST(int32_t, dheight));
126 LogDynAndXPutImage(xfc->log, xfc->display, xfc->drawable, xfc->gc, surface->image,
127 WINPR_ASSERTING_INT_CAST(
int, nXSrc),
128 WINPR_ASSERTING_INT_CAST(
int, nYSrc),
129 WINPR_ASSERTING_INT_CAST(
int, nXDst),
130 WINPR_ASSERTING_INT_CAST(
int, nYDst), dwidth, dheight);
136 region16_clear(&surface->gdi.invalidRegion);
137 LogDynAndXSetClipMask(xfc->log, xfc->display, xfc->gc, None);
138 LogDynAndXSync(xfc->log, xfc->display, False);
143static UINT xf_WindowUpdate(RdpgfxClientContext* context, xfGfxSurface* surface)
145 WINPR_ASSERT(context);
146 WINPR_ASSERT(surface);
147 return IFCALLRESULT(CHANNEL_RC_OK, context->UpdateWindowFromSurface, context, &surface->gdi);
150static UINT xf_UpdateSurfaces(RdpgfxClientContext* context)
153 UINT status = CHANNEL_RC_OK;
154 UINT16* pSurfaceIds =
nullptr;
155 rdpGdi* gdi = (rdpGdi*)context->custom;
156 xfContext* xfc =
nullptr;
161 if (gdi->suppressOutput)
162 return CHANNEL_RC_OK;
164 xfc = (xfContext*)gdi->context;
165 EnterCriticalSection(&context->mux);
166 status = context->GetSurfaceIds(context, &pSurfaceIds, &count);
167 if (status != CHANNEL_RC_OK)
170 for (UINT32 index = 0; index < count; index++)
172 xfGfxSurface* surface = (xfGfxSurface*)context->GetSurfaceData(context, pSurfaceIds[index]);
178 if (context->UpdateSurfaceArea)
180 if (surface->gdi.handleInUpdateSurfaceArea)
184 if (surface->gdi.outputMapped)
185 status = xf_OutputUpdate(xfc, surface);
186 else if (surface->gdi.windowMapped)
187 status = xf_WindowUpdate(context, surface);
189 if (status != CHANNEL_RC_OK)
195 LeaveCriticalSection(&context->mux);
199UINT xf_OutputExpose(xfContext* xfc, UINT32 x, UINT32 y, UINT32 width, UINT32 height)
202 UINT status = ERROR_INTERNAL_ERROR;
205 UINT16* pSurfaceIds =
nullptr;
206 RdpgfxClientContext* context =
nullptr;
209 WINPR_ASSERT(xfc->common.context.gdi);
211 context = xfc->common.context.gdi->gfx;
212 WINPR_ASSERT(context);
214 invalidRect.left = WINPR_ASSERTING_INT_CAST(UINT16, x);
215 invalidRect.top = WINPR_ASSERTING_INT_CAST(UINT16, y);
216 invalidRect.right = WINPR_ASSERTING_INT_CAST(UINT16, x + width);
217 invalidRect.bottom = WINPR_ASSERTING_INT_CAST(UINT16, y + height);
218 status = context->GetSurfaceIds(context, &pSurfaceIds, &count);
220 if (status != CHANNEL_RC_OK)
223 if (!TryEnterCriticalSection(&context->mux))
226 return CHANNEL_RC_OK;
228 for (UINT32 index = 0; index < count; index++)
231 xfGfxSurface* surface = (xfGfxSurface*)context->GetSurfaceData(context, pSurfaceIds[index]);
233 if (!surface || (!surface->gdi.outputMapped && !surface->gdi.windowMapped))
236 surfaceRect.left = WINPR_ASSERTING_INT_CAST(UINT16, surface->gdi.outputOriginX);
237 surfaceRect.top = WINPR_ASSERTING_INT_CAST(UINT16, surface->gdi.outputOriginY);
238 surfaceRect.right = WINPR_ASSERTING_INT_CAST(UINT16, surface->gdi.outputOriginX +
239 surface->gdi.outputTargetWidth);
240 surfaceRect.bottom = WINPR_ASSERTING_INT_CAST(UINT16, surface->gdi.outputOriginY +
241 surface->gdi.outputTargetHeight);
243 if (rectangles_intersection(&invalidRect, &surfaceRect, &intersection))
246 intersection.left -= surfaceRect.left;
247 intersection.top -= surfaceRect.top;
248 intersection.right -= surfaceRect.left;
249 intersection.bottom -= surfaceRect.top;
250 if (!region16_union_rect(&surface->gdi.invalidRegion, &surface->gdi.invalidRegion,
254 LeaveCriticalSection(&context->mux);
262 LeaveCriticalSection(&context->mux);
263 IFCALLRET(context->UpdateSurfaces, status, context);
265 if (status != CHANNEL_RC_OK)
272static UINT32 x11_pad_scanline(UINT32 scanline, UINT32 inPad)
277 const UINT32 align = inPad / 8;
278 const UINT32 pad = align - scanline % align;
286 scanline += 16 - scanline % 16;
291static void DestroySurface(xfGfxSurface* surface)
297 h264_context_free(surface->gdi.h264);
299#if defined(WITH_GFX_AV1)
300 freerdp_av1_context_free(surface->gdi.av1);
302#if defined(WITH_GFX_AV2)
303 freerdp_av2_context_free(surface->gdi.av2);
307 surface->image->data =
nullptr;
308 XDestroyImage(surface->image);
311 winpr_aligned_free(surface->gdi.data);
312 winpr_aligned_free(surface->stage);
313 region16_uninit(&surface->gdi.invalidRegion);
322static UINT xf_CreateSurface(RdpgfxClientContext* context,
325 UINT ret = CHANNEL_RC_NO_MEMORY;
326 WINPR_ASSERT(context);
327 WINPR_ASSERT(createSurface);
329 rdpGdi* gdi = (rdpGdi*)context->custom;
330 xfContext* xfc = (xfContext*)gdi->context;
332 xfGfxSurface* surface = (xfGfxSurface*)calloc(1,
sizeof(xfGfxSurface));
335 return CHANNEL_RC_NO_MEMORY;
337 surface->gdi.codecs = context->codecs;
339 if (!surface->gdi.codecs)
341 WLog_ERR(TAG,
"global GDI codecs aren't set");
345 surface->gdi.surfaceId = createSurface->surfaceId;
346 surface->gdi.width = x11_pad_scanline(createSurface->width, 16);
347 surface->gdi.height = x11_pad_scanline(createSurface->height, 16);
348 surface->gdi.mappedWidth = createSurface->width;
349 surface->gdi.mappedHeight = createSurface->height;
350 surface->gdi.outputTargetWidth = createSurface->width;
351 surface->gdi.outputTargetHeight = createSurface->height;
355 switch (createSurface->pixelFormat)
357 case GFX_PIXEL_FORMAT_ARGB_8888:
358 surface->gdi.format = PIXEL_FORMAT_BGRA32;
361 case GFX_PIXEL_FORMAT_XRGB_8888:
362 surface->gdi.format = rails ? PIXEL_FORMAT_BGRA32 : PIXEL_FORMAT_BGRX32;
366 WLog_ERR(TAG,
"unknown pixelFormat 0x%" PRIx32
"", createSurface->pixelFormat);
367 ret = ERROR_INTERNAL_ERROR;
371 const UINT32 pad = WINPR_ASSERTING_INT_CAST(uint32_t, xfc->scanline_pad);
372 if (surface->gdi.width > UINT32_MAX / FreeRDPGetBytesPerPixel(surface->gdi.format) - 16 - pad)
377 surface->gdi.scanline = surface->gdi.width * FreeRDPGetBytesPerPixel(surface->gdi.format);
378 surface->gdi.scanline = x11_pad_scanline(surface->gdi.scanline, pad) + 16ul;
380 surface->gdi.data = (BYTE*)winpr_aligned_calloc(surface->gdi.scanline, surface->gdi.height, 16);
382 if (!surface->gdi.data)
384 WLog_ERR(TAG,
"unable to allocate GDI data");
388 for (UINT64 y = 0; y < surface->gdi.height; y++)
389 memset(&surface->gdi.data[surface->gdi.scanline * y], 0xff, surface->gdi.scanline);
391 if (FreeRDPAreColorFormatsEqualNoAlpha(gdi->dstFormat, surface->gdi.format))
393 WINPR_ASSERT(xfc->depth != 0);
394 surface->image = LogDynAndXCreateImage(
395 xfc->log, xfc->display, xfc->visual, WINPR_ASSERTING_INT_CAST(uint32_t, xfc->depth),
396 ZPixmap, 0, (
char*)surface->gdi.data, surface->gdi.mappedWidth,
397 surface->gdi.mappedHeight, xfc->scanline_pad,
398 WINPR_ASSERTING_INT_CAST(
int, surface->gdi.scanline));
402 UINT32 width = surface->gdi.width;
403 UINT32 bytes = FreeRDPGetBytesPerPixel(gdi->dstFormat);
404 if (width > UINT32_MAX / bytes - 16 - pad)
409 surface->stageScanline = width * bytes;
410 surface->stageScanline = x11_pad_scanline(surface->stageScanline, pad) + 16ul;
413 (BYTE*)winpr_aligned_calloc(surface->stageScanline, surface->gdi.height, 16);
417 WLog_ERR(TAG,
"unable to allocate stage buffer");
421 for (UINT64 y = 0; y < surface->gdi.height; y++)
422 memset(&surface->stage[surface->stageScanline * y], 0xff, surface->stageScanline);
424 WINPR_ASSERT(xfc->depth != 0);
425 surface->image = LogDynAndXCreateImage(
426 xfc->log, xfc->display, xfc->visual, WINPR_ASSERTING_INT_CAST(uint32_t, xfc->depth),
427 ZPixmap, 0, (
char*)surface->stage, surface->gdi.mappedWidth, surface->gdi.mappedHeight,
428 xfc->scanline_pad, WINPR_ASSERTING_INT_CAST(
int, surface->stageScanline));
433 WLog_ERR(TAG,
"an error occurred when creating the XImage");
437 surface->image->byte_order = LSBFirst;
438 surface->image->bitmap_bit_order = LSBFirst;
440 region16_init(&surface->gdi.invalidRegion);
442 if (context->SetSurfaceData(context, surface->gdi.surfaceId, (
void*)surface) != CHANNEL_RC_OK)
444 WLog_ERR(TAG,
"an error occurred during SetSurfaceData");
448 return CHANNEL_RC_OK;
450 DestroySurface(surface);
462static void xf_DetachWindowFromSurface(RdpgfxClientContext* context,
const gdiGfxSurface* surface)
464 WINPR_ASSERT(context);
465 WINPR_ASSERT(surface);
467 if (!surface->windowMapped)
470 rdpGdi* gdi = (rdpGdi*)context->custom;
473 xfContext* xfc = (xfContext*)gdi->context;
476 xfAppWindow* appWindow = xf_rail_get_window(xfc, surface->windowId, FALSE);
477 if (appWindow && (appWindow->surfaceId == surface->surfaceId))
480 xf_AppWindowDestroyImage(appWindow);
481 appWindow->surfaceId = UINT32_MAX;
482 appWindow->surfaceStale = FALSE;
484 xf_rail_return_window(appWindow, FALSE);
492static UINT xf_DeleteSurface(RdpgfxClientContext* context,
495 rdpCodecs* codecs =
nullptr;
498 EnterCriticalSection(&context->mux);
499 xfGfxSurface* surface =
500 (xfGfxSurface*)context->GetSurfaceData(context, deleteSurface->surfaceId);
504 xf_DetachWindowFromSurface(context, &surface->gdi);
506 if (surface->gdi.windowMapped)
508 status = IFCALLRESULT(CHANNEL_RC_OK, context->UnmapWindowForSurface, context,
509 surface->gdi.windowId);
510 if (status != CHANNEL_RC_OK)
514 codecs = surface->gdi.codecs;
515 DestroySurface(surface);
518 status = context->SetSurfaceData(context, deleteSurface->surfaceId,
nullptr);
520 if (codecs && codecs->progressive)
521 progressive_delete_surface_context(codecs->progressive, deleteSurface->surfaceId);
524 LeaveCriticalSection(&context->mux);
533static UINT xf_DeleteSurfaceSoftwareGdi(RdpgfxClientContext* context,
536 WINPR_ASSERT(context);
537 WINPR_ASSERT(deleteSurface);
539 rdpGdi* gdi = (rdpGdi*)context->custom;
542 xfContext* xfc = (xfContext*)gdi->context;
544 WINPR_ASSERT(xfc->gdiDeleteSurface);
547 EnterCriticalSection(&context->mux);
548 const gdiGfxSurface* surface =
549 (
const gdiGfxSurface*)context->GetSurfaceData(context, deleteSurface->surfaceId);
551 xf_DetachWindowFromSurface(context, surface);
553 const UINT status = xfc->gdiDeleteSurface(context, deleteSurface);
554 LeaveCriticalSection(&context->mux);
558static UINT xf_UpdateWindowFromSurface(RdpgfxClientContext* context, gdiGfxSurface* surface)
560 WINPR_ASSERT(context);
561 WINPR_ASSERT(surface);
563 rdpGdi* gdi = (rdpGdi*)context->custom;
566 xfContext* xfc = (xfContext*)gdi->context;
567 WINPR_ASSERT(gdi->context);
570 return xf_AppUpdateWindowFromSurface(xfc, surface);
572 WLog_WARN(TAG,
"function not implemented");
573 return CHANNEL_RC_OK;
576void xf_graphics_pipeline_init(xfContext* xfc, RdpgfxClientContext* gfx)
578 rdpGdi* gdi =
nullptr;
579 const rdpSettings* settings =
nullptr;
583 settings = xfc->common.context.settings;
584 WINPR_ASSERT(settings);
586 gdi = xfc->common.context.gdi;
588 gdi_graphics_pipeline_init(gdi, gfx);
592 gfx->UpdateSurfaces = xf_UpdateSurfaces;
593 gfx->CreateSurface = xf_CreateSurface;
594 gfx->DeleteSurface = xf_DeleteSurface;
598 xfc->gdiDeleteSurface = gfx->DeleteSurface;
599 gfx->DeleteSurface = xf_DeleteSurfaceSoftwareGdi;
602 gfx->UpdateWindowFromSurface = xf_UpdateWindowFromSurface;
605void xf_graphics_pipeline_uninit(xfContext* xfc, RdpgfxClientContext* gfx)
609 rdpGdi* gdi = xfc->common.context.gdi;
610 gdi_graphics_pipeline_uninit(gdi, gfx);
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.