FreeRDP
Loading...
Searching...
No Matches
shadow_capture.c
1
19#include <freerdp/config.h>
20
21#include <winpr/crt.h>
22#include <winpr/print.h>
23
24#include <freerdp/log.h>
25
26#include "shadow_surface.h"
27
28#include "shadow_capture.h"
29
30int shadow_capture_align_clip_rect(RECTANGLE_16* rect, const RECTANGLE_16* clip)
31{
32 int dx = 0;
33 int dy = 0;
34 dx = (rect->left % 16);
35
36 if (dx != 0)
37 {
38 rect->left -= dx;
39 rect->right += dx;
40 }
41
42 dx = (rect->right % 16);
43
44 if (dx != 0)
45 {
46 rect->right += (16 - dx);
47 }
48
49 dy = (rect->top % 16);
50
51 if (dy != 0)
52 {
53 rect->top -= dy;
54 rect->bottom += dy;
55 }
56
57 dy = (rect->bottom % 16);
58
59 if (dy != 0)
60 {
61 rect->bottom += (16 - dy);
62 }
63
64 if (rect->left < clip->left)
65 rect->left = clip->left;
66
67 if (rect->top < clip->top)
68 rect->top = clip->top;
69
70 if (rect->right > clip->right)
71 rect->right = clip->right;
72
73 if (rect->bottom > clip->bottom)
74 rect->bottom = clip->bottom;
75
76 return 1;
77}
78
79#if !defined(WITHOUT_FREERDP_3x_DEPRECATED)
80int shadow_capture_compare(const BYTE* WINPR_RESTRICT pData1, UINT32 nStep1, UINT32 nWidth,
81 UINT32 nHeight, const BYTE* WINPR_RESTRICT pData2, UINT32 nStep2,
82 RECTANGLE_16* WINPR_RESTRICT rect)
83{
84 return shadow_capture_compare_with_format(pData1, PIXEL_FORMAT_BGRX32, nStep1, nWidth, nHeight,
85 pData2, PIXEL_FORMAT_BGRX32, nStep2, rect);
86}
87#endif
88
89WINPR_ATTR_NODISCARD
90static BOOL color_equal(UINT32 colorA, UINT32 formatA, UINT32 colorB, UINT32 formatB)
91{
92 BYTE ar = 0;
93 BYTE ag = 0;
94 BYTE ab = 0;
95 BYTE aa = 0;
96 BYTE br = 0;
97 BYTE bg = 0;
98 BYTE bb = 0;
99 BYTE ba = 0;
100 FreeRDPSplitColor(colorA, formatA, &ar, &ag, &ab, &aa, nullptr);
101 FreeRDPSplitColor(colorB, formatB, &br, &bg, &bb, &ba, nullptr);
102
103 if (ar != br)
104 return FALSE;
105 if (ag != bg)
106 return FALSE;
107 if (ab != bb)
108 return FALSE;
109 if (aa != ba)
110 return FALSE;
111 return TRUE;
112}
113
114WINPR_ATTR_NODISCARD
115static BOOL pixel_equal(const BYTE* WINPR_RESTRICT a, UINT32 formatA, const BYTE* WINPR_RESTRICT b,
116 UINT32 formatB, size_t count)
117{
118 const size_t bppA = FreeRDPGetBytesPerPixel(formatA);
119 const size_t bppB = FreeRDPGetBytesPerPixel(formatB);
120
121 for (size_t x = 0; x < count; x++)
122 {
123 const UINT32 colorA = FreeRDPReadColor(&a[bppA * x], formatA);
124 const UINT32 colorB = FreeRDPReadColor(&b[bppB * x], formatB);
125 if (!color_equal(colorA, formatA, colorB, formatB))
126 return FALSE;
127 }
128
129 return TRUE;
130}
131
132WINPR_ATTR_NODISCARD
133static BOOL color_equal_no_alpha(UINT32 colorA, UINT32 formatA, UINT32 colorB, UINT32 formatB)
134{
135 BYTE ar = 0;
136 BYTE ag = 0;
137 BYTE ab = 0;
138 BYTE br = 0;
139 BYTE bg = 0;
140 BYTE bb = 0;
141 FreeRDPSplitColor(colorA, formatA, &ar, &ag, &ab, nullptr, nullptr);
142 FreeRDPSplitColor(colorB, formatB, &br, &bg, &bb, nullptr, nullptr);
143
144 if (ar != br)
145 return FALSE;
146 if (ag != bg)
147 return FALSE;
148 if (ab != bb)
149 return FALSE;
150 return TRUE;
151}
152
153WINPR_ATTR_NODISCARD
154static BOOL pixel_equal_no_alpha(const BYTE* WINPR_RESTRICT a, UINT32 formatA,
155 const BYTE* WINPR_RESTRICT b, UINT32 formatB, size_t count)
156{
157 const size_t bppA = FreeRDPGetBytesPerPixel(formatA);
158 const size_t bppB = FreeRDPGetBytesPerPixel(formatB);
159
160 for (size_t x = 0; x < count; x++)
161 {
162 const UINT32 colorA = FreeRDPReadColor(&a[bppA * x], formatA);
163 const UINT32 colorB = FreeRDPReadColor(&b[bppB * x], formatB);
164 if (!color_equal_no_alpha(colorA, formatA, colorB, formatB))
165 return FALSE;
166 }
167
168 return TRUE;
169}
170
171WINPR_ATTR_NODISCARD
172static BOOL pixel_equal_same_format(const BYTE* WINPR_RESTRICT a, UINT32 formatA,
173 const BYTE* WINPR_RESTRICT b, UINT32 formatB, size_t count)
174{
175 if (formatA != formatB)
176 return FALSE;
177 const size_t bppA = FreeRDPGetBytesPerPixel(formatA);
178 return memcmp(a, b, count * bppA) == 0;
179}
180
181typedef BOOL (*pixel_equal_fn_t)(const BYTE* WINPR_RESTRICT a, UINT32 formatA,
182 const BYTE* WINPR_RESTRICT b, UINT32 formatB, size_t count);
183
184WINPR_ATTR_NODISCARD
185static pixel_equal_fn_t get_comparison_fn(DWORD format1, DWORD format2)
186{
187
188 if (format1 == format2)
189 return pixel_equal_same_format;
190
191 const UINT32 bpp1 = FreeRDPGetBitsPerPixel(format1);
192
193 if (!FreeRDPColorHasAlpha(format1) || !FreeRDPColorHasAlpha(format2))
194 {
195 /* In case we have RGBA32 and RGBX32 or similar assume the alpha data is equal.
196 * This allows us to use the fast memcmp comparison. */
197 if ((bpp1 == 32) && FreeRDPAreColorFormatsEqualNoAlpha(format1, format2))
198 {
199 switch (format1)
200 {
201 case PIXEL_FORMAT_ARGB32:
202 case PIXEL_FORMAT_XRGB32:
203 case PIXEL_FORMAT_ABGR32:
204 case PIXEL_FORMAT_XBGR32:
205 return pixel_equal;
206 case PIXEL_FORMAT_RGBA32:
207 case PIXEL_FORMAT_RGBX32:
208 case PIXEL_FORMAT_BGRA32:
209 case PIXEL_FORMAT_BGRX32:
210 return pixel_equal;
211 default:
212 break;
213 }
214 }
215 return pixel_equal_no_alpha;
216 }
217 else
218 return pixel_equal_no_alpha;
219}
220
221int shadow_capture_compare_with_format(const BYTE* WINPR_RESTRICT pData1, UINT32 format1,
222 UINT32 nStep1, UINT32 nWidth, UINT32 nHeight,
223 const BYTE* WINPR_RESTRICT pData2, UINT32 format2,
224 UINT32 nStep2, RECTANGLE_16* WINPR_RESTRICT rect)
225{
226 pixel_equal_fn_t pixel_equal_fn = get_comparison_fn(format1, format2);
227 BOOL allEqual = TRUE;
228 UINT32 tw = 0;
229 const UINT32 nrow = (nHeight + 15) / 16;
230 const UINT32 ncol = (nWidth + 15) / 16;
231 UINT32 l = ncol + 1;
232 UINT32 t = nrow + 1;
233 UINT32 r = 0;
234 UINT32 b = 0;
235 const size_t bppA = FreeRDPGetBytesPerPixel(format1);
236 const size_t bppB = FreeRDPGetBytesPerPixel(format2);
237 const RECTANGLE_16 empty = WINPR_C_ARRAY_INIT;
238 WINPR_ASSERT(rect);
239
240 *rect = empty;
241
242 for (size_t ty = 0; ty < nrow; ty++)
243 {
244 BOOL rowEqual = TRUE;
245 size_t th = ((ty + 1) == nrow) ? (nHeight % 16) : 16;
246
247 if (!th)
248 th = 16;
249
250 for (size_t tx = 0; tx < ncol; tx++)
251 {
252 BOOL equal = TRUE;
253 tw = ((tx + 1) == ncol) ? (nWidth % 16) : 16;
254
255 if (!tw)
256 tw = 16;
257
258 const BYTE* p1 = &pData1[(ty * 16ULL * nStep1) + (tx * 16ull * bppA)];
259 const BYTE* p2 = &pData2[(ty * 16ULL * nStep2) + (tx * 16ull * bppB)];
260
261 for (size_t k = 0; k < th; k++)
262 {
263 if (!pixel_equal_fn(p1, format1, p2, format2, tw))
264 {
265 equal = FALSE;
266 break;
267 }
268
269 p1 += nStep1;
270 p2 += nStep2;
271 }
272
273 if (!equal)
274 {
275 rowEqual = FALSE;
276 if (l > tx)
277 l = (UINT32)tx;
278
279 if (r < tx)
280 r = (UINT32)tx;
281 }
282 }
283
284 if (!rowEqual)
285 {
286 allEqual = FALSE;
287
288 if (t > ty)
289 t = (UINT32)ty;
290
291 if (b < ty)
292 b = (UINT32)ty;
293 }
294 }
295
296 if (allEqual)
297 return 0;
298
299 WINPR_ASSERT(l * 16 <= UINT16_MAX);
300 WINPR_ASSERT(t * 16 <= UINT16_MAX);
301 WINPR_ASSERT((r + 1) * 16 <= UINT16_MAX);
302 WINPR_ASSERT((b + 1) * 16 <= UINT16_MAX);
303 rect->left = (UINT16)l * 16;
304 rect->top = (UINT16)t * 16;
305 rect->right = (UINT16)(r + 1) * 16;
306 rect->bottom = (UINT16)(b + 1) * 16;
307
308 WINPR_ASSERT(nWidth <= UINT16_MAX);
309 if (rect->right > nWidth)
310 rect->right = (UINT16)nWidth;
311
312 WINPR_ASSERT(nHeight <= UINT16_MAX);
313 if (rect->bottom > nHeight)
314 rect->bottom = (UINT16)nHeight;
315
316 return 1;
317}
318
319rdpShadowCapture* shadow_capture_new(rdpShadowServer* server)
320{
321 WINPR_ASSERT(server);
322
323 rdpShadowCapture* capture = (rdpShadowCapture*)calloc(1, sizeof(rdpShadowCapture));
324
325 if (!capture)
326 return nullptr;
327
328 capture->server = server;
329
330 if (!InitializeCriticalSectionAndSpinCount(&(capture->lock), 4000))
331 {
332 WINPR_PRAGMA_DIAG_PUSH
333 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
334 shadow_capture_free(capture);
335 WINPR_PRAGMA_DIAG_POP
336 return nullptr;
337 }
338
339 return capture;
340}
341
342void shadow_capture_free(rdpShadowCapture* capture)
343{
344 if (!capture)
345 return;
346
347 DeleteCriticalSection(&(capture->lock));
348 free(capture);
349}