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