22 #include <freerdp/config.h>
25 #include <winpr/assert.h>
26 #include <freerdp/log.h>
30 #include <X11/Xutil.h>
32 #define TAG CLIENT_TAG("x11")
34 static UINT xf_OutputUpdate(xfContext* xfc, xfGfxSurface* surface)
36 UINT rc = ERROR_INTERNAL_ERROR;
44 WINPR_ASSERT(surface);
46 rdpGdi* gdi = xfc->common.context.gdi;
49 rdpSettings* settings = xfc->common.context.settings;
50 WINPR_ASSERT(settings);
52 surfaceX = surface->gdi.outputOriginX;
53 surfaceY = surface->gdi.outputOriginY;
56 surfaceRect.right = surface->gdi.mappedWidth;
57 surfaceRect.bottom = surface->gdi.mappedHeight;
58 XSetClipMask(xfc->display, xfc->gc, None);
59 XSetFunction(xfc->display, xfc->gc, GXcopy);
60 XSetFillStyle(xfc->display, xfc->gc, FillSolid);
61 region16_intersect_rect(&(surface->gdi.invalidRegion), &(surface->gdi.invalidRegion),
63 const double sx = 1.0 * surface->gdi.outputTargetWidth / (double)surface->gdi.mappedWidth;
64 const double sy = 1.0 * surface->gdi.outputTargetHeight / (
double)surface->gdi.mappedHeight;
66 if (!(rects = region16_rects(&surface->gdi.invalidRegion, &nbRects)))
69 for (UINT32 x = 0; x < nbRects; x++)
72 const UINT32 nXSrc = rect->left;
73 const UINT32 nYSrc = rect->top;
74 const UINT32 swidth = rect->right - nXSrc;
75 const UINT32 sheight = rect->bottom - nYSrc;
76 const UINT32 nXDst = (UINT32)lround(1.0 * surfaceX + nXSrc * sx);
77 const UINT32 nYDst = (UINT32)lround(1.0 * surfaceY + nYSrc * sy);
78 const UINT32 dwidth = (UINT32)lround(1.0 * swidth * sx);
79 const UINT32 dheight = (UINT32)lround(1.0 * sheight * sy);
83 if (!freerdp_image_scale(surface->stage, gdi->dstFormat, surface->stageScanline, nXSrc,
84 nYSrc, dwidth, dheight, surface->gdi.data, surface->gdi.format,
85 surface->gdi.scanline, nXSrc, nYSrc, swidth, sheight))
91 XPutImage(xfc->display, xfc->primary, xfc->gc, surface->image, nXSrc, nYSrc, nXDst,
92 nYDst, dwidth, dheight);
94 xf_rail_paint_surface(xfc, surface->gdi.windowId, rect);
102 XPutImage(xfc->display, xfc->primary, xfc->gc, surface->image, nXSrc, nYSrc, nXDst,
103 nYDst, dwidth, dheight);
104 xf_draw_screen(xfc, nXDst, nYDst, dwidth, dheight);
109 XPutImage(xfc->display, xfc->drawable, xfc->gc, surface->image, nXSrc, nYSrc, nXDst,
110 nYDst, dwidth, dheight);
116 region16_clear(&surface->gdi.invalidRegion);
117 XSetClipMask(xfc->display, xfc->gc, None);
118 XSync(xfc->display, False);
122 static UINT xf_WindowUpdate(RdpgfxClientContext* context, xfGfxSurface* surface)
124 WINPR_ASSERT(context);
125 WINPR_ASSERT(surface);
126 return IFCALLRESULT(CHANNEL_RC_OK, context->UpdateWindowFromSurface, context, &surface->gdi);
129 static UINT xf_UpdateSurfaces(RdpgfxClientContext* context)
132 UINT status = CHANNEL_RC_OK;
133 UINT16* pSurfaceIds = NULL;
134 rdpGdi* gdi = (rdpGdi*)context->custom;
135 xfContext* xfc = NULL;
140 if (gdi->suppressOutput)
141 return CHANNEL_RC_OK;
143 xfc = (xfContext*)gdi->context;
144 EnterCriticalSection(&context->mux);
145 context->GetSurfaceIds(context, &pSurfaceIds, &count);
147 for (UINT32 index = 0; index < count; index++)
149 xfGfxSurface* surface = (xfGfxSurface*)context->GetSurfaceData(context, pSurfaceIds[index]);
155 if (context->UpdateSurfaceArea)
157 if (surface->gdi.handleInUpdateSurfaceArea)
161 if (surface->gdi.outputMapped)
162 status = xf_OutputUpdate(xfc, surface);
163 else if (surface->gdi.windowMapped)
164 status = xf_WindowUpdate(context, surface);
166 if (status != CHANNEL_RC_OK)
171 LeaveCriticalSection(&context->mux);
175 UINT xf_OutputExpose(xfContext* xfc, UINT32 x, UINT32 y, UINT32 width, UINT32 height)
178 UINT status = ERROR_INTERNAL_ERROR;
181 UINT16* pSurfaceIds = NULL;
182 RdpgfxClientContext* context = NULL;
185 WINPR_ASSERT(xfc->common.context.gdi);
187 context = xfc->common.context.gdi->gfx;
188 WINPR_ASSERT(context);
190 invalidRect.left = x;
192 invalidRect.right = x + width;
193 invalidRect.bottom = y + height;
194 status = context->GetSurfaceIds(context, &pSurfaceIds, &count);
196 if (status != CHANNEL_RC_OK)
199 if (!TryEnterCriticalSection(&context->mux))
202 return CHANNEL_RC_OK;
204 for (UINT32 index = 0; index < count; index++)
207 xfGfxSurface* surface = (xfGfxSurface*)context->GetSurfaceData(context, pSurfaceIds[index]);
209 if (!surface || (!surface->gdi.outputMapped && !surface->gdi.windowMapped))
212 surfaceRect.left = surface->gdi.outputOriginX;
213 surfaceRect.top = surface->gdi.outputOriginY;
214 surfaceRect.right = surface->gdi.outputOriginX + surface->gdi.outputTargetWidth;
215 surfaceRect.bottom = surface->gdi.outputOriginY + surface->gdi.outputTargetHeight;
217 if (rectangles_intersection(&invalidRect, &surfaceRect, &intersection))
220 intersection.left -= surfaceRect.left;
221 intersection.top -= surfaceRect.top;
222 intersection.right -= surfaceRect.left;
223 intersection.bottom -= surfaceRect.top;
224 region16_union_rect(&surface->gdi.invalidRegion, &surface->gdi.invalidRegion,
230 LeaveCriticalSection(&context->mux);
231 IFCALLRET(context->UpdateSurfaces, status, context);
233 if (status != CHANNEL_RC_OK)
240 static UINT32 x11_pad_scanline(UINT32 scanline, UINT32 inPad)
245 const UINT32 align = inPad / 8;
246 const UINT32 pad = align - scanline % align;
254 scanline += 16 - scanline % 16;
264 static UINT xf_CreateSurface(RdpgfxClientContext* context,
267 UINT ret = CHANNEL_RC_NO_MEMORY;
269 xfGfxSurface* surface = NULL;
270 rdpGdi* gdi = (rdpGdi*)context->custom;
271 xfContext* xfc = (xfContext*)gdi->context;
272 surface = (xfGfxSurface*)calloc(1,
sizeof(xfGfxSurface));
275 return CHANNEL_RC_NO_MEMORY;
277 surface->gdi.codecs = context->codecs;
279 if (!surface->gdi.codecs)
281 WLog_ERR(TAG,
"global GDI codecs aren't set");
285 surface->gdi.surfaceId = createSurface->surfaceId;
286 surface->gdi.width = x11_pad_scanline(createSurface->width, 0);
287 surface->gdi.height = x11_pad_scanline(createSurface->height, 0);
288 surface->gdi.mappedWidth = createSurface->width;
289 surface->gdi.mappedHeight = createSurface->height;
290 surface->gdi.outputTargetWidth = createSurface->width;
291 surface->gdi.outputTargetHeight = createSurface->height;
293 switch (createSurface->pixelFormat)
295 case GFX_PIXEL_FORMAT_ARGB_8888:
296 surface->gdi.format = PIXEL_FORMAT_BGRA32;
299 case GFX_PIXEL_FORMAT_XRGB_8888:
300 surface->gdi.format = PIXEL_FORMAT_BGRX32;
304 WLog_ERR(TAG,
"unknown pixelFormat 0x%" PRIx32
"", createSurface->pixelFormat);
305 ret = ERROR_INTERNAL_ERROR;
309 surface->gdi.scanline = surface->gdi.width * FreeRDPGetBytesPerPixel(surface->gdi.format);
310 surface->gdi.scanline = x11_pad_scanline(surface->gdi.scanline, xfc->scanline_pad);
311 size = 1ull * surface->gdi.scanline * surface->gdi.height;
312 surface->gdi.data = (BYTE*)winpr_aligned_malloc(size, 16);
314 if (!surface->gdi.data)
316 WLog_ERR(TAG,
"unable to allocate GDI data");
320 ZeroMemory(surface->gdi.data, size);
322 if (FreeRDPAreColorFormatsEqualNoAlpha(gdi->dstFormat, surface->gdi.format))
324 WINPR_ASSERT(xfc->depth != 0);
326 XCreateImage(xfc->display, xfc->visual, xfc->depth, ZPixmap, 0,
327 (
char*)surface->gdi.data, surface->gdi.mappedWidth,
328 surface->gdi.mappedHeight, xfc->scanline_pad, surface->gdi.scanline);
332 UINT32 width = surface->gdi.width;
333 UINT32 bytes = FreeRDPGetBytesPerPixel(gdi->dstFormat);
334 surface->stageScanline = width * bytes;
335 surface->stageScanline = x11_pad_scanline(surface->stageScanline, xfc->scanline_pad);
336 size = 1ull * surface->stageScanline * surface->gdi.height;
337 surface->stage = (BYTE*)winpr_aligned_malloc(size, 16);
341 WLog_ERR(TAG,
"unable to allocate stage buffer");
342 goto out_free_gdidata;
345 ZeroMemory(surface->stage, size);
346 WINPR_ASSERT(xfc->depth != 0);
348 XCreateImage(xfc->display, xfc->visual, xfc->depth, ZPixmap, 0, (
char*)surface->stage,
349 surface->gdi.mappedWidth, surface->gdi.mappedHeight, xfc->scanline_pad,
350 surface->stageScanline);
355 WLog_ERR(TAG,
"an error occurred when creating the XImage");
356 goto error_surface_image;
359 surface->image->byte_order = LSBFirst;
360 surface->image->bitmap_bit_order = LSBFirst;
362 region16_init(&surface->gdi.invalidRegion);
364 if (context->SetSurfaceData(context, surface->gdi.surfaceId, (
void*)surface) != CHANNEL_RC_OK)
366 WLog_ERR(TAG,
"an error occurred during SetSurfaceData");
367 goto error_set_surface_data;
370 return CHANNEL_RC_OK;
371 error_set_surface_data:
372 surface->image->data = NULL;
373 XDestroyImage(surface->image);
375 winpr_aligned_free(surface->stage);
377 winpr_aligned_free(surface->gdi.data);
388 static UINT xf_DeleteSurface(RdpgfxClientContext* context,
391 rdpCodecs* codecs = NULL;
392 xfGfxSurface* surface = NULL;
394 EnterCriticalSection(&context->mux);
395 surface = (xfGfxSurface*)context->GetSurfaceData(context, deleteSurface->surfaceId);
399 if (surface->gdi.windowMapped)
400 IFCALL(context->UnmapWindowForSurface, context, surface->gdi.windowId);
403 h264_context_free(surface->gdi.h264);
405 surface->image->data = NULL;
406 XDestroyImage(surface->image);
407 winpr_aligned_free(surface->gdi.data);
408 winpr_aligned_free(surface->stage);
409 region16_uninit(&surface->gdi.invalidRegion);
410 codecs = surface->gdi.codecs;
414 status = context->SetSurfaceData(context, deleteSurface->surfaceId, NULL);
416 if (codecs && codecs->progressive)
417 progressive_delete_surface_context(codecs->progressive, deleteSurface->surfaceId);
419 LeaveCriticalSection(&context->mux);
423 static UINT xf_UpdateWindowFromSurface(RdpgfxClientContext* context, gdiGfxSurface* surface)
425 WINPR_ASSERT(context);
426 WINPR_ASSERT(surface);
428 rdpGdi* gdi = (rdpGdi*)context->custom;
431 xfContext* xfc = (xfContext*)gdi->context;
432 WINPR_ASSERT(gdi->context);
435 return xf_AppUpdateWindowFromSurface(xfc, surface);
437 WLog_WARN(TAG,
"function not implemented");
438 return CHANNEL_RC_OK;
441 void xf_graphics_pipeline_init(xfContext* xfc, RdpgfxClientContext* gfx)
444 const rdpSettings* settings = NULL;
448 settings = xfc->common.context.settings;
449 WINPR_ASSERT(settings);
451 gdi = xfc->common.context.gdi;
453 gdi_graphics_pipeline_init(gdi, gfx);
457 gfx->UpdateSurfaces = xf_UpdateSurfaces;
458 gfx->CreateSurface = xf_CreateSurface;
459 gfx->DeleteSurface = xf_DeleteSurface;
461 gfx->UpdateWindowFromSurface = xf_UpdateWindowFromSurface;
464 void xf_graphics_pipeline_uninit(xfContext* xfc, RdpgfxClientContext* gfx)
470 gdi = xfc->common.context.gdi;
471 gdi_graphics_pipeline_uninit(gdi, gfx);
FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.