19#include <freerdp/config.h>
21#include <winpr/cmdline.h>
23#include <freerdp/log.h>
27#include "shadow_subsystem.h"
29#define TAG SERVER_TAG("shadow")
32#define SHADOW_SUBSYSTEM_MAX 8
33#define SHADOW_SUBSYSTEM_MONITORS 16
38 pfnShadowSubsystemEntry entry;
39} SHADOW_SUBSYSTEM_CANDIDATE;
41static SHADOW_SUBSYSTEM_CANDIDATE g_Candidates[SHADOW_SUBSYSTEM_MAX] = WINPR_C_ARRAY_INIT;
42static size_t g_CandidateCount = 0;
45static size_t g_Order[SHADOW_SUBSYSTEM_MAX] = WINPR_C_ARRAY_INIT;
46static size_t g_OrderCount = 0;
49static pfnShadowSubsystemEntry pSubsystemEntry =
nullptr;
51void shadow_subsystem_set_entry(pfnShadowSubsystemEntry pEntry)
53 pSubsystemEntry = pEntry;
56BOOL shadow_subsystem_add_entry(
const char* name, pfnShadowSubsystemEntry pEntry)
58 if (!name || !pEntry || (g_CandidateCount >= SHADOW_SUBSYSTEM_MAX))
61 SHADOW_SUBSYSTEM_CANDIDATE* candidate = &g_Candidates[g_CandidateCount];
62 const int rc = _snprintf(candidate->name,
sizeof(candidate->name),
"%s", name);
63 if ((rc < 0) || ((
size_t)rc >=
sizeof(candidate->name)))
66 candidate->entry = pEntry;
72static size_t shadow_subsystem_order_count(
void)
74 return (g_OrderCount > 0) ? g_OrderCount : g_CandidateCount;
78static const SHADOW_SUBSYSTEM_CANDIDATE* shadow_subsystem_order_at(
size_t index)
80 WINPR_ASSERT(index < shadow_subsystem_order_count());
81 const size_t candidate = (g_OrderCount > 0) ? g_Order[index] : index;
82 WINPR_ASSERT(candidate < g_CandidateCount);
83 return &g_Candidates[candidate];
88static UINT32 shadow_subsystem_probe(
const SHADOW_SUBSYSTEM_CANDIDATE* candidate)
90 WINPR_ASSERT(candidate);
91 WINPR_ASSERT(candidate->entry);
93 RDP_SHADOW_ENTRY_POINTS ep = WINPR_C_ARRAY_INIT;
94 if ((candidate->entry(&ep) < 0) || !ep.EnumMonitors)
97 MONITOR_DEF monitors[SHADOW_SUBSYSTEM_MONITORS] = WINPR_C_ARRAY_INIT;
98 return ep.EnumMonitors(monitors, ARRAYSIZE(monitors));
104static BOOL shadow_subsystem_select(
void)
109 const size_t count = shadow_subsystem_order_count();
113 const SHADOW_SUBSYSTEM_CANDIDATE* first = shadow_subsystem_order_at(0);
116 if (g_CandidateCount > 1)
117 WLog_INFO(TAG,
"subsystem: %s", first->name);
118 pSubsystemEntry = first->entry;
122 for (
size_t index = 0; index < count; index++)
124 const SHADOW_SUBSYSTEM_CANDIDATE* candidate = shadow_subsystem_order_at(index);
125 if (shadow_subsystem_probe(candidate) > 0)
127 WLog_INFO(TAG,
"subsystem: %s", candidate->name);
128 pSubsystemEntry = candidate->entry;
132 WLog_INFO(TAG,
"subsystem %s found no monitor%s", candidate->name,
133 (index + 1 < count) ?
", trying the next one" :
"");
136 WLog_WARN(TAG,
"no subsystem found a monitor, using %s", first->name);
137 pSubsystemEntry = first->entry;
141BOOL shadow_subsystem_set_order(
const char* names)
146 if (g_CandidateCount == 0)
148 WLog_ERR(TAG,
"this build has a single fixed subsystem");
153 char** list = CommandLineParseCommaSeparatedValues(names, &count);
154 if (!list || (count == 0))
161 size_t orderCount = 0;
162 size_t order[SHADOW_SUBSYSTEM_MAX] = WINPR_C_ARRAY_INIT;
163 for (
size_t x = 0; rc && (x < count); x++)
165 size_t found = g_CandidateCount;
166 for (
size_t y = 0; y < g_CandidateCount; y++)
168 if (_stricmp(list[x], g_Candidates[y].name) == 0)
172 if (found == g_CandidateCount)
174 WLog_ERR(TAG,
"unknown subsystem '%s' (/subsystem lists them)", list[x]);
179 BOOL duplicate = FALSE;
180 for (
size_t y = 0; y < orderCount; y++)
182 if (order[y] == found)
187 order[orderCount++] = found;
194 memcpy(g_Order, order,
sizeof(g_Order));
195 g_OrderCount = orderCount;
196 pSubsystemEntry =
nullptr;
200void shadow_subsystem_list(
void)
202 const size_t count = shadow_subsystem_order_count();
205 for (
size_t index = 0; index < count; index++)
207 const SHADOW_SUBSYSTEM_CANDIDATE* candidate = shadow_subsystem_order_at(index);
208 const UINT32 monitors = shadow_subsystem_probe(candidate);
209 const BOOL pick = !picked && (monitors > 0);
211 WLog_INFO(TAG,
" %s %s: %" PRIu32
" monitor(s)", pick ?
"*" :
" ", candidate->name,
216 WLog_INFO(TAG,
"this build has a single fixed subsystem");
220static int shadow_subsystem_load_entry_points(RDP_SHADOW_ENTRY_POINTS* pEntryPoints)
222 WINPR_ASSERT(pEntryPoints);
223 ZeroMemory(pEntryPoints,
sizeof(RDP_SHADOW_ENTRY_POINTS));
225 if (!shadow_subsystem_select())
228 if (pSubsystemEntry(pEntryPoints) < 0)
234rdpShadowSubsystem* shadow_subsystem_new(
void)
236 RDP_SHADOW_ENTRY_POINTS ep = WINPR_C_ARRAY_INIT;
238 if (shadow_subsystem_load_entry_points(&ep) < 0)
244 rdpShadowSubsystem* subsystem = ep.New();
254void shadow_subsystem_free(rdpShadowSubsystem* subsystem)
256 if (subsystem && subsystem->ep.Free)
257 subsystem->ep.Free(subsystem);
260int shadow_subsystem_init(rdpShadowSubsystem* subsystem, rdpShadowServer* server)
264 if (!subsystem || !subsystem->ep.Init)
267 subsystem->server = server;
268 subsystem->selectedMonitor = server->selectedMonitor;
270 if (!(subsystem->MsgPipe = MessagePipe_New()))
273 if (!(subsystem->updateEvent = shadow_multiclient_new()))
276 status = subsystem->ep.Init(subsystem);
281 if (subsystem->MsgPipe)
283 MessagePipe_Free(subsystem->MsgPipe);
284 subsystem->MsgPipe =
nullptr;
287 if (subsystem->updateEvent)
289 shadow_multiclient_free(subsystem->updateEvent);
290 subsystem->updateEvent =
nullptr;
296static void shadow_subsystem_free_queued_message(
void* obj)
298 wMessage* message = (wMessage*)obj;
301 message->Free(message);
302 message->Free =
nullptr;
306void shadow_subsystem_uninit(rdpShadowSubsystem* subsystem)
311 if (subsystem->ep.Uninit)
312 subsystem->ep.Uninit(subsystem);
314 if (subsystem->MsgPipe)
319 obj1 = MessageQueue_Object(subsystem->MsgPipe->In);
321 obj1->
fnObjectFree = shadow_subsystem_free_queued_message;
322 MessageQueue_Clear(subsystem->MsgPipe->In);
324 obj2 = MessageQueue_Object(subsystem->MsgPipe->Out);
325 obj2->
fnObjectFree = shadow_subsystem_free_queued_message;
326 MessageQueue_Clear(subsystem->MsgPipe->Out);
327 MessagePipe_Free(subsystem->MsgPipe);
328 subsystem->MsgPipe =
nullptr;
331 if (subsystem->updateEvent)
333 shadow_multiclient_free(subsystem->updateEvent);
334 subsystem->updateEvent =
nullptr;
338int shadow_subsystem_start(rdpShadowSubsystem* subsystem)
342 if (!subsystem || !subsystem->ep.Start)
345 status = subsystem->ep.Start(subsystem);
350int shadow_subsystem_stop(rdpShadowSubsystem* subsystem)
354 if (!subsystem || !subsystem->ep.Stop)
357 status = subsystem->ep.Stop(subsystem);
362UINT32 shadow_enum_monitors(
MONITOR_DEF* monitors, UINT32 maxMonitors)
364 UINT32 numMonitors = 0;
365 RDP_SHADOW_ENTRY_POINTS ep;
367 if (shadow_subsystem_load_entry_points(&ep) < 0)
370 numMonitors = ep.EnumMonitors(monitors, maxMonitors);
381#if !defined(WITHOUT_FREERDP_3x_DEPRECATED)
382int shadow_subsystem_pointer_convert_alpha_pointer_data(
383 const BYTE* WINPR_RESTRICT pixels, BOOL premultiplied, UINT32 width, UINT32 height,
386 return shadow_subsystem_pointer_convert_alpha_pointer_data_to_format(
387 pixels, PIXEL_FORMAT_BGRX32, premultiplied, width, height, pointerColor);
391int shadow_subsystem_pointer_convert_alpha_pointer_data_to_format(
392 const BYTE* WINPR_RESTRICT pixels, UINT32 format, BOOL premultiplied, UINT32 width,
398 BYTE* andBits =
nullptr;
400 const size_t bpp = FreeRDPGetBytesPerPixel(format);
402 xorStep = (width * 3);
403 xorStep += (xorStep % 2);
405 andStep = ((width + 7) / 8);
406 andStep += (andStep % 2);
408 WINPR_ASSERT(pointerColor);
410 pointerColor->lengthXorMask = height * xorStep;
411 pointerColor->xorMaskData = (BYTE*)calloc(1, pointerColor->lengthXorMask);
413 if (!pointerColor->xorMaskData)
416 pointerColor->lengthAndMask = height * andStep;
417 pointerColor->andMaskData = (BYTE*)calloc(1, pointerColor->lengthAndMask);
419 if (!pointerColor->andMaskData)
421 free(pointerColor->xorMaskData);
422 pointerColor->xorMaskData =
nullptr;
426 for (
size_t y = 0; y < height; y++)
428 WINPR_ASSERT(pixels);
429 const BYTE* pSrc8 = &pixels[(width * bpp) * (height - 1 - y)];
430 BYTE* pDst8 = &(pointerColor->xorMaskData[y * xorStep]);
433 andBits = &(pointerColor->andMaskData[andStep * y]);
435 for (
size_t x = 0; x < width; x++)
442 const UINT32 color = FreeRDPReadColor(&pSrc8[x * bpp], format);
443 FreeRDPSplitColor(color, format, &R, &G, &B, &A,
nullptr);
483void shadow_subsystem_frame_update(rdpShadowSubsystem* subsystem)
485 shadow_multiclient_publish_and_wait(subsystem->updateEvent);
This struct contains function pointer to initialize/free objects.
OBJECT_FREE_FN fnObjectFree