1 /*
2 Copyright 2014 Laxmikant Rashinkar
3 Copyright 2014-2017 Jay Sorg
4
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
9 documentation.
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21 capture
22
23 */
24
25 #if defined(HAVE_CONFIG_H)
26 #include "config_ac.h"
27 #endif
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32
33 /* this should be before all X11 .h files */
34 #include <xorg-server.h>
35 #include <xorgVersion.h>
36
37 /* all driver need this */
38 #include <xf86.h>
39 #include <xf86_OSproc.h>
40
41 #include "rdp.h"
42 #include "rdpDraw.h"
43 #include "rdpClientCon.h"
44 #include "rdpReg.h"
45 #include "rdpMisc.h"
46 #include "rdpCapture.h"
47
48 #if defined(XORGXRDP_GLAMOR)
49 #include "rdpEgl.h"
50 #include <glamor.h>
51 #endif
52
53 #define LOG_LEVEL 1
54 #define LLOGLN(_level, _args) \
55 do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0)
56
57 /******************************************************************************/
58 /* copy rects with no error checking */
59 static int
rdpCopyBox_a8r8g8b8_to_a8r8g8b8(rdpClientCon * clientCon,const uint8_t * src,int src_stride,int srcx,int srcy,uint8_t * dst,int dst_stride,int dstx,int dsty,BoxPtr rects,int num_rects)60 rdpCopyBox_a8r8g8b8_to_a8r8g8b8(rdpClientCon *clientCon,
61 const uint8_t *src, int src_stride, int srcx, int srcy,
62 uint8_t *dst, int dst_stride, int dstx, int dsty,
63 BoxPtr rects, int num_rects)
64 {
65 const uint8_t *s8;
66 uint8_t *d8;
67 int index;
68 int jndex;
69 int bytes;
70 int height;
71 BoxPtr box;
72
73 for (index = 0; index < num_rects; index++)
74 {
75 box = rects + index;
76 s8 = src + (box->y1 - srcy) * src_stride;
77 s8 += (box->x1 - srcx) * 4;
78 d8 = dst + (box->y1 - dsty) * dst_stride;
79 d8 += (box->x1 - dstx) * 4;
80 bytes = box->x2 - box->x1;
81 bytes *= 4;
82 height = box->y2 - box->y1;
83 for (jndex = 0; jndex < height; jndex++)
84 {
85 g_memcpy(d8, s8, bytes);
86 d8 += dst_stride;
87 s8 += src_stride;
88 }
89 }
90 return 0;
91 }
92
93 /******************************************************************************/
94 static int
rdpFillBox_yuvalp(int ax,int ay,uint8_t * dst,int dst_stride)95 rdpFillBox_yuvalp(int ax, int ay,
96 uint8_t *dst, int dst_stride)
97 {
98 dst = dst + (ay << 8) * (dst_stride >> 8) + (ax << 8);
99 g_memset(dst, 0, 64 * 64 * 4);
100 return 0;
101 }
102
103 /******************************************************************************/
104 /* copy rects with no error checking
105 * convert ARGB32 to 64x64 linear planar YUVA */
106 /* http://msdn.microsoft.com/en-us/library/ff635643.aspx
107 * 0.299 -0.168935 0.499813
108 * 0.587 -0.331665 -0.418531
109 * 0.114 0.50059 -0.081282
110 y = r * 0.299000 + g * 0.587000 + b * 0.114000;
111 u = r * -0.168935 + g * -0.331665 + b * 0.500590;
112 v = r * 0.499813 + g * -0.418531 + b * -0.081282; */
113 /* 19595 38470 7471
114 -11071 -21736 32807
115 32756 -27429 -5327 */
116 static int
rdpCopyBox_a8r8g8b8_to_yuvalp(int ax,int ay,const uint8_t * src,int src_stride,uint8_t * dst,int dst_stride,BoxPtr rects,int num_rects)117 rdpCopyBox_a8r8g8b8_to_yuvalp(int ax, int ay,
118 const uint8_t *src, int src_stride,
119 uint8_t *dst, int dst_stride,
120 BoxPtr rects, int num_rects)
121 {
122 const uint8_t *s8;
123 uint8_t *d8;
124 uint8_t *yptr;
125 uint8_t *uptr;
126 uint8_t *vptr;
127 uint8_t *aptr;
128 const uint32_t *s32;
129 int index;
130 int jndex;
131 int kndex;
132 int width;
133 int height;
134 uint32_t pixel;
135 uint8_t a;
136 int r;
137 int g;
138 int b;
139 int y;
140 int u;
141 int v;
142 BoxPtr box;
143
144 dst = dst + (ay << 8) * (dst_stride >> 8) + (ax << 8);
145 for (index = 0; index < num_rects; index++)
146 {
147 box = rects + index;
148 s8 = src + box->y1 * src_stride;
149 s8 += box->x1 * 4;
150 d8 = dst + (box->y1 - ay) * 64;
151 d8 += box->x1 - ax;
152 width = box->x2 - box->x1;
153 height = box->y2 - box->y1;
154 for (jndex = 0; jndex < height; jndex++)
155 {
156 s32 = (const uint32_t *) s8;
157 yptr = d8;
158 uptr = yptr + 64 * 64;
159 vptr = uptr + 64 * 64;
160 aptr = vptr + 64 * 64;
161 kndex = 0;
162 while (kndex < width)
163 {
164 pixel = *(s32++);
165 a = (pixel >> 24) & 0xff;
166 r = (pixel >> 16) & 0xff;
167 g = (pixel >> 8) & 0xff;
168 b = (pixel >> 0) & 0xff;
169 y = (r * 19595 + g * 38470 + b * 7471) >> 16;
170 u = (r * -11071 + g * -21736 + b * 32807) >> 16;
171 v = (r * 32756 + g * -27429 + b * -5327) >> 16;
172 u = u + 128;
173 v = v + 128;
174 y = RDPCLAMP(y, 0, 255);
175 u = RDPCLAMP(u, 0, 255);
176 v = RDPCLAMP(v, 0, 255);
177 *(yptr++) = y;
178 *(uptr++) = u;
179 *(vptr++) = v;
180 *(aptr++) = a;
181 kndex++;
182 }
183 d8 += 64;
184 s8 += src_stride;
185 }
186 }
187 return 0;
188 }
189
190 /******************************************************************************/
191 int
a8r8g8b8_to_a8b8g8r8_box(const uint8_t * s8,int src_stride,uint8_t * d8,int dst_stride,int width,int height)192 a8r8g8b8_to_a8b8g8r8_box(const uint8_t *s8, int src_stride,
193 uint8_t *d8, int dst_stride,
194 int width, int height)
195 {
196 int index;
197 int jndex;
198 int red;
199 int green;
200 int blue;
201 const uint32_t *s32;
202 uint32_t *d32;
203
204 for (index = 0; index < height; index++)
205 {
206 s32 = (const uint32_t *) s8;
207 d32 = (uint32_t *) d8;
208 for (jndex = 0; jndex < width; jndex++)
209 {
210 SPLITCOLOR32(red, green, blue, *s32);
211 *d32 = COLOR24(red, green, blue);
212 s32++;
213 d32++;
214 }
215 d8 += dst_stride;
216 s8 += src_stride;
217 }
218 return 0;
219 }
220
221 /******************************************************************************/
222 /* copy rects with no error checking */
223 static int
rdpCopyBox_a8r8g8b8_to_a8b8g8r8(rdpClientCon * clientCon,const uint8_t * src,int src_stride,int srcx,int srcy,uint8_t * dst,int dst_stride,int dstx,int dsty,BoxPtr rects,int num_rects)224 rdpCopyBox_a8r8g8b8_to_a8b8g8r8(rdpClientCon *clientCon,
225 const uint8_t *src, int src_stride, int srcx, int srcy,
226 uint8_t *dst, int dst_stride, int dstx, int dsty,
227 BoxPtr rects, int num_rects)
228 {
229 const uint8_t *s8;
230 uint8_t *d8;
231 int index;
232 int width;
233 int height;
234 BoxPtr box;
235 copy_box_proc copy_box;
236
237 copy_box = clientCon->dev->a8r8g8b8_to_a8b8g8r8_box;
238 for (index = 0; index < num_rects; index++)
239 {
240 box = rects + index;
241 s8 = src + (box->y1 - srcy) * src_stride;
242 s8 += (box->x1 - srcx) * 4;
243 d8 = dst + (box->y1 - dsty) * dst_stride;
244 d8 += (box->x1 - dstx) * 4;
245 width = box->x2 - box->x1;
246 height = box->y2 - box->y1;
247 copy_box(s8, src_stride, d8, dst_stride, width, height);
248 }
249 return 0;
250 }
251
252 /******************************************************************************/
253 int
a8r8g8b8_to_r5g6b5_box(const uint8_t * s8,int src_stride,uint8_t * d8,int dst_stride,int width,int height)254 a8r8g8b8_to_r5g6b5_box(const uint8_t *s8, int src_stride,
255 uint8_t *d8, int dst_stride,
256 int width, int height)
257 {
258 int index;
259 int jndex;
260 int red;
261 int green;
262 int blue;
263 const uint32_t *s32;
264 uint16_t *d16;
265
266 for (index = 0; index < height; index++)
267 {
268 s32 = (const uint32_t *) s8;
269 d16 = (uint16_t *) d8;
270 for (jndex = 0; jndex < width; jndex++)
271 {
272 SPLITCOLOR32(red, green, blue, *s32);
273 *d16 = COLOR16(red, green, blue);
274 s32++;
275 d16++;
276 }
277 d8 += dst_stride;
278 s8 += src_stride;
279 }
280 return 0;
281 }
282
283 /******************************************************************************/
284 /* copy rects with no error checking */
285 static int
rdpCopyBox_a8r8g8b8_to_r5g6b5(rdpClientCon * clientCon,const uint8_t * src,int src_stride,int srcx,int srcy,uint8_t * dst,int dst_stride,int dstx,int dsty,BoxPtr rects,int num_rects)286 rdpCopyBox_a8r8g8b8_to_r5g6b5(rdpClientCon *clientCon,
287 const uint8_t *src, int src_stride, int srcx, int srcy,
288 uint8_t *dst, int dst_stride, int dstx, int dsty,
289 BoxPtr rects, int num_rects)
290 {
291 const uint8_t *s8;
292 uint8_t *d8;
293 int index;
294 int width;
295 int height;
296 BoxPtr box;
297 copy_box_proc copy_box;
298
299 copy_box = a8r8g8b8_to_r5g6b5_box; /* TODO, simd */
300 for (index = 0; index < num_rects; index++)
301 {
302 box = rects + index;
303 s8 = src + (box->y1 - srcy) * src_stride;
304 s8 += (box->x1 - srcx) * 4;
305 d8 = dst + (box->y1 - dsty) * dst_stride;
306 d8 += (box->x1 - dstx) * 2;
307 width = box->x2 - box->x1;
308 height = box->y2 - box->y1;
309 copy_box(s8, src_stride, d8, dst_stride, width, height);
310 }
311 return 0;
312 }
313
314 /******************************************************************************/
315 int
a8r8g8b8_to_a1r5g5b5_box(const uint8_t * s8,int src_stride,uint8_t * d8,int dst_stride,int width,int height)316 a8r8g8b8_to_a1r5g5b5_box(const uint8_t *s8, int src_stride,
317 uint8_t *d8, int dst_stride,
318 int width, int height)
319 {
320 int index;
321 int jndex;
322 int red;
323 int green;
324 int blue;
325 const uint32_t *s32;
326 uint16_t *d16;
327
328 for (index = 0; index < height; index++)
329 {
330 s32 = (const uint32_t *) s8;
331 d16 = (uint16_t *) d8;
332 for (jndex = 0; jndex < width; jndex++)
333 {
334 SPLITCOLOR32(red, green, blue, *s32);
335 *d16 = COLOR15(red, green, blue);
336 s32++;
337 d16++;
338 }
339 d8 += dst_stride;
340 s8 += src_stride;
341 }
342 return 0;
343 }
344
345 /******************************************************************************/
346 /* copy rects with no error checking */
347 static int
rdpCopyBox_a8r8g8b8_to_a1r5g5b5(rdpClientCon * clientCon,const uint8_t * src,int src_stride,int srcx,int srcy,uint8_t * dst,int dst_stride,int dstx,int dsty,BoxPtr rects,int num_rects)348 rdpCopyBox_a8r8g8b8_to_a1r5g5b5(rdpClientCon *clientCon,
349 const uint8_t *src, int src_stride, int srcx, int srcy,
350 uint8_t *dst, int dst_stride, int dstx, int dsty,
351 BoxPtr rects, int num_rects)
352 {
353 const uint8_t *s8;
354 uint8_t *d8;
355 int index;
356 int width;
357 int height;
358 BoxPtr box;
359 copy_box_proc copy_box;
360
361 copy_box = a8r8g8b8_to_a1r5g5b5_box; /* TODO, simd */
362 for (index = 0; index < num_rects; index++)
363 {
364 box = rects + index;
365 s8 = src + (box->y1 - srcy) * src_stride;
366 s8 += (box->x1 - srcx) * 4;
367 d8 = dst + (box->y1 - dsty) * dst_stride;
368 d8 += (box->x1 - dstx) * 2;
369 width = box->x2 - box->x1;
370 height = box->y2 - box->y1;
371 copy_box(s8, src_stride, d8, dst_stride, width, height);
372 }
373 return 0;
374 }
375
376 /******************************************************************************/
377 int
a8r8g8b8_to_r3g3b2_box(const uint8_t * s8,int src_stride,uint8_t * d8,int dst_stride,int width,int height)378 a8r8g8b8_to_r3g3b2_box(const uint8_t *s8, int src_stride,
379 uint8_t *d8, int dst_stride,
380 int width, int height)
381 {
382 int index;
383 int jndex;
384 int red;
385 int green;
386 int blue;
387 const uint32_t *s32;
388 uint8_t *ld8;
389
390 for (index = 0; index < height; index++)
391 {
392 s32 = (const uint32_t *) s8;
393 ld8 = (uint8_t *) d8;
394 for (jndex = 0; jndex < width; jndex++)
395 {
396 SPLITCOLOR32(red, green, blue, *s32);
397 *ld8 = COLOR8(red, green, blue);
398 s32++;
399 ld8++;
400 }
401 d8 += dst_stride;
402 s8 += src_stride;
403 }
404 return 0;
405 }
406
407 /******************************************************************************/
408 /* copy rects with no error checking */
409 static int
rdpCopyBox_a8r8g8b8_to_r3g3b2(rdpClientCon * clientCon,const uint8_t * src,int src_stride,int srcx,int srcy,uint8_t * dst,int dst_stride,int dstx,int dsty,BoxPtr rects,int num_rects)410 rdpCopyBox_a8r8g8b8_to_r3g3b2(rdpClientCon *clientCon,
411 const uint8_t *src, int src_stride, int srcx, int srcy,
412 uint8_t *dst, int dst_stride, int dstx, int dsty,
413 BoxPtr rects, int num_rects)
414 {
415 const uint8_t *s8;
416 uint8_t *d8;
417 int index;
418 int width;
419 int height;
420 BoxPtr box;
421 copy_box_proc copy_box;
422
423 copy_box = a8r8g8b8_to_r3g3b2_box; /* TODO, simd */
424 for (index = 0; index < num_rects; index++)
425 {
426 box = rects + index;
427 s8 = src + (box->y1 - srcy) * src_stride;
428 s8 += (box->x1 - srcx) * 4;
429 d8 = dst + (box->y1 - dsty) * dst_stride;
430 d8 += (box->x1 - dstx) * 1;
431 width = box->x2 - box->x1;
432 height = box->y2 - box->y1;
433 copy_box(s8, src_stride, d8, dst_stride, width, height);
434 }
435 return 0;
436 }
437
438 /******************************************************************************/
439 int
a8r8g8b8_to_nv12_box(const uint8_t * s8,int src_stride,uint8_t * d8_y,int dst_stride_y,uint8_t * d8_uv,int dst_stride_uv,int width,int height)440 a8r8g8b8_to_nv12_box(const uint8_t *s8, int src_stride,
441 uint8_t *d8_y, int dst_stride_y,
442 uint8_t *d8_uv, int dst_stride_uv,
443 int width, int height)
444 {
445 int index;
446 int jndex;
447 int R;
448 int G;
449 int B;
450 int Y;
451 int U;
452 int V;
453 int U_sum;
454 int V_sum;
455 int pixel;
456 const uint32_t *s32a;
457 const uint32_t *s32b;
458 uint8_t *d8ya;
459 uint8_t *d8yb;
460 uint8_t *d8uv;
461
462 for (jndex = 0; jndex < height; jndex += 2)
463 {
464 s32a = (const uint32_t *) (s8 + src_stride * jndex);
465 s32b = (const uint32_t *) (s8 + src_stride * (jndex + 1));
466 d8ya = d8_y + dst_stride_y * jndex;
467 d8yb = d8_y + dst_stride_y * (jndex + 1);
468 d8uv = d8_uv + dst_stride_uv * (jndex / 2);
469 for (index = 0; index < width; index += 2)
470 {
471 U_sum = 0;
472 V_sum = 0;
473
474 pixel = s32a[0];
475 s32a++;
476 R = (pixel >> 16) & 0xff;
477 G = (pixel >> 8) & 0xff;
478 B = (pixel >> 0) & 0xff;
479 Y = (( 66 * R + 129 * G + 25 * B + 128) >> 8) + 16;
480 U = ((-38 * R - 74 * G + 112 * B + 128) >> 8) + 128;
481 V = ((112 * R - 94 * G - 18 * B + 128) >> 8) + 128;
482 d8ya[0] = RDPCLAMP(Y, 0, 255);
483 d8ya++;
484 U_sum += RDPCLAMP(U, 0, 255);
485 V_sum += RDPCLAMP(V, 0, 255);
486
487 pixel = s32a[0];
488 s32a++;
489 R = (pixel >> 16) & 0xff;
490 G = (pixel >> 8) & 0xff;
491 B = (pixel >> 0) & 0xff;
492 Y = (( 66 * R + 129 * G + 25 * B + 128) >> 8) + 16;
493 U = ((-38 * R - 74 * G + 112 * B + 128) >> 8) + 128;
494 V = ((112 * R - 94 * G - 18 * B + 128) >> 8) + 128;
495 d8ya[0] = RDPCLAMP(Y, 0, 255);
496 d8ya++;
497 U_sum += RDPCLAMP(U, 0, 255);
498 V_sum += RDPCLAMP(V, 0, 255);
499
500 pixel = s32b[0];
501 s32b++;
502 R = (pixel >> 16) & 0xff;
503 G = (pixel >> 8) & 0xff;
504 B = (pixel >> 0) & 0xff;
505 Y = (( 66 * R + 129 * G + 25 * B + 128) >> 8) + 16;
506 U = ((-38 * R - 74 * G + 112 * B + 128) >> 8) + 128;
507 V = ((112 * R - 94 * G - 18 * B + 128) >> 8) + 128;
508 d8yb[0] = RDPCLAMP(Y, 0, 255);
509 d8yb++;
510 U_sum += RDPCLAMP(U, 0, 255);
511 V_sum += RDPCLAMP(V, 0, 255);
512
513 pixel = s32b[0];
514 s32b++;
515 R = (pixel >> 16) & 0xff;
516 G = (pixel >> 8) & 0xff;
517 B = (pixel >> 0) & 0xff;
518 Y = (( 66 * R + 129 * G + 25 * B + 128) >> 8) + 16;
519 U = ((-38 * R - 74 * G + 112 * B + 128) >> 8) + 128;
520 V = ((112 * R - 94 * G - 18 * B + 128) >> 8) + 128;
521 d8yb[0] = RDPCLAMP(Y, 0, 255);
522 d8yb++;
523 U_sum += RDPCLAMP(U, 0, 255);
524 V_sum += RDPCLAMP(V, 0, 255);
525
526 d8uv[0] = (U_sum + 2) / 4;
527 d8uv++;
528 d8uv[0] = (V_sum + 2) / 4;
529 d8uv++;
530 }
531 }
532 return 0;
533 }
534
535 /******************************************************************************/
536 /* copy rects with no error checking */
537 static int
rdpCopyBox_a8r8g8b8_to_nv12(rdpClientCon * clientCon,const uint8_t * src,int src_stride,int srcx,int srcy,uint8_t * dst_y,int dst_stride_y,uint8_t * dst_uv,int dst_stride_uv,int dstx,int dsty,BoxPtr rects,int num_rects)538 rdpCopyBox_a8r8g8b8_to_nv12(rdpClientCon *clientCon,
539 const uint8_t *src, int src_stride, int srcx, int srcy,
540 uint8_t *dst_y, int dst_stride_y,
541 uint8_t *dst_uv, int dst_stride_uv,
542 int dstx, int dsty,
543 BoxPtr rects, int num_rects)
544 {
545 const uint8_t *s8;
546 uint8_t *d8_y;
547 uint8_t *d8_uv;
548 int index;
549 int width;
550 int height;
551 BoxPtr box;
552
553 for (index = 0; index < num_rects; index++)
554 {
555 box = rects + index;
556 s8 = src + (box->y1 - srcy) * src_stride;
557 s8 += (box->x1 - srcx) * 4;
558 d8_y = dst_y + (box->y1 - dsty) * dst_stride_y;
559 d8_y += (box->x1 - dstx) * 1;
560 d8_uv = dst_uv + ((box->y1 - dsty) / 2) * dst_stride_uv;
561 d8_uv += (box->x1 - dstx) * 1;
562 width = box->x2 - box->x1;
563 height = box->y2 - box->y1;
564 clientCon->dev->a8r8g8b8_to_nv12_box(s8, src_stride,
565 d8_y, dst_stride_y,
566 d8_uv, dst_stride_uv,
567 width, height);
568 }
569 return 0;
570 }
571
572 /******************************************************************************/
573 static Bool
rdpCapture0(rdpClientCon * clientCon,RegionPtr in_reg,BoxPtr * out_rects,int * num_out_rects,struct image_data * id)574 rdpCapture0(rdpClientCon *clientCon, RegionPtr in_reg, BoxPtr *out_rects,
575 int *num_out_rects, struct image_data *id)
576 {
577 BoxPtr psrc_rects;
578 BoxRec rect;
579 int num_rects;
580 int i;
581 Bool rv;
582 const uint8_t *src;
583 uint8_t *dst;
584 int src_stride;
585 int dst_stride;
586 int dst_format;
587
588 LLOGLN(10, ("rdpCapture0:"));
589
590 if (clientCon->shmemstatus == SHM_UNINITIALIZED || clientCon->shmemstatus == SHM_RESIZING) {
591 LLOGLN(0, ("rdpCapture0: WARNING -- Shared memory is not configured. Aborting capture!"));
592 return FALSE;
593 }
594
595 rv = TRUE;
596
597
598 num_rects = REGION_NUM_RECTS(in_reg);
599 psrc_rects = REGION_RECTS(in_reg);
600
601 if (num_rects < 1)
602 {
603 return FALSE;
604 }
605
606 *num_out_rects = num_rects;
607
608 *out_rects = g_new(BoxRec, num_rects);
609 for (i = 0; i < num_rects; i++)
610 {
611 rect = psrc_rects[i];
612 (*out_rects)[i] = rect;
613 }
614
615 src = id->pixels;
616 dst = id->shmem_pixels;
617 dst_format = clientCon->rdp_format;
618 src_stride = id->lineBytes;
619 dst_stride = clientCon->cap_stride_bytes;
620
621 if (dst_format == XRDP_a8r8g8b8)
622 {
623 rdpCopyBox_a8r8g8b8_to_a8r8g8b8(clientCon,
624 src, src_stride, 0, 0,
625 dst, dst_stride, 0, 0,
626 psrc_rects, num_rects);
627 }
628 else if (dst_format == XRDP_a8b8g8r8)
629 {
630 rdpCopyBox_a8r8g8b8_to_a8b8g8r8(clientCon,
631 src, src_stride, 0, 0,
632 dst, dst_stride, 0, 0,
633 psrc_rects, num_rects);
634 }
635 else if (dst_format == XRDP_r5g6b5)
636 {
637 rdpCopyBox_a8r8g8b8_to_r5g6b5(clientCon,
638 src, src_stride, 0, 0,
639 dst, dst_stride, 0, 0,
640 psrc_rects, num_rects);
641 }
642 else if (dst_format == XRDP_a1r5g5b5)
643 {
644 rdpCopyBox_a8r8g8b8_to_a1r5g5b5(clientCon,
645 src, src_stride, 0, 0,
646 dst, dst_stride, 0, 0,
647 psrc_rects, num_rects);
648 }
649 else if (dst_format == XRDP_r3g3b2)
650 {
651 rdpCopyBox_a8r8g8b8_to_r3g3b2(clientCon,
652 src, src_stride, 0, 0,
653 dst, dst_stride, 0, 0,
654 psrc_rects, num_rects);
655 }
656 else
657 {
658 LLOGLN(0, ("rdpCapture0: unimplemented color conversion"));
659 }
660 return rv;
661 }
662
663 /******************************************************************************/
664 /* make out_rects always multiple of 16 width and height */
665 static Bool
rdpCapture1(rdpClientCon * clientCon,RegionPtr in_reg,BoxPtr * out_rects,int * num_out_rects,struct image_data * id)666 rdpCapture1(rdpClientCon *clientCon, RegionPtr in_reg, BoxPtr *out_rects,
667 int *num_out_rects, struct image_data *id)
668 {
669 BoxPtr psrc_rects;
670 BoxRec rect;
671 BoxRec srect;
672 const uint8_t *src_rect;
673 uint8_t *dst_rect;
674 int num_rects;
675 int src_bytespp;
676 int dst_bytespp;
677 int width;
678 int height;
679 int src_offset;
680 int dst_offset;
681 int index;
682 int jndex;
683 int kndex;
684 int red;
685 int green;
686 int blue;
687 int ex;
688 int ey;
689 Bool rv;
690 const uint32_t *s32;
691 uint32_t *d32;
692 const uint8_t *src;
693 uint8_t *dst;
694 int src_stride;
695 int dst_stride;
696 int dst_format;
697
698 LLOGLN(10, ("rdpCapture1:"));
699
700 if (clientCon->shmemstatus == SHM_UNINITIALIZED || clientCon->shmemstatus == SHM_RESIZING) {
701 LLOGLN(0, ("rdpCapture1: WARNING -- Shared memory is not configured. Aborting capture!"));
702 return FALSE;
703 }
704
705 rv = TRUE;
706
707 num_rects = REGION_NUM_RECTS(in_reg);
708 psrc_rects = REGION_RECTS(in_reg);
709
710 if (num_rects < 1)
711 {
712 return FALSE;
713 }
714
715 srect.x1 = clientCon->cap_left;
716 srect.y1 = clientCon->cap_top;
717 srect.x2 = clientCon->cap_left + clientCon->cap_width;
718 srect.y2 = clientCon->cap_top + clientCon->cap_height;
719
720 *num_out_rects = num_rects;
721
722 *out_rects = g_new(BoxRec, num_rects * 4);
723 index = 0;
724 while (index < num_rects)
725 {
726 rect = psrc_rects[index];
727 width = rect.x2 - rect.x1;
728 height = rect.y2 - rect.y1;
729 ex = ((width + 15) & ~15) - width;
730 if (ex != 0)
731 {
732 rect.x2 += ex;
733 if (rect.x2 > srect.x2)
734 {
735 rect.x1 -= rect.x2 - srect.x2;
736 rect.x2 = srect.x2;
737 }
738 if (rect.x1 < srect.x1)
739 {
740 rect.x1 += 16;
741 }
742 }
743 ey = ((height + 15) & ~15) - height;
744 if (ey != 0)
745 {
746 rect.y2 += ey;
747 if (rect.y2 > srect.y2)
748 {
749 rect.y1 -= rect.y2 - srect.y2;
750 rect.y2 = srect.y2;
751 }
752 if (rect.y1 < srect.y1)
753 {
754 rect.y1 += 16;
755 }
756 }
757 (*out_rects)[index] = rect;
758 index++;
759 }
760
761 src = id->pixels;
762 dst = id->shmem_pixels;
763 dst_format = clientCon->rdp_format;
764 src_stride = id->lineBytes;
765 dst_stride = clientCon->cap_stride_bytes;
766
767 if (dst_format == XRDP_a8b8g8r8)
768 {
769 src_bytespp = 4;
770 dst_bytespp = 4;
771
772 for (index = 0; index < num_rects; index++)
773 {
774 /* get rect to copy */
775 rect = (*out_rects)[index];
776
777 /* get rect dimensions */
778 width = rect.x2 - rect.x1;
779 height = rect.y2 - rect.y1;
780
781 /* point to start of each rect in respective memory */
782 src_offset = rect.y1 * src_stride + rect.x1 * src_bytespp;
783 dst_offset = rect.y1 * dst_stride + rect.x1 * dst_bytespp;
784 src_rect = src + src_offset;
785 dst_rect = dst + dst_offset;
786
787 /* copy one line at a time */
788 for (jndex = 0; jndex < height; jndex++)
789 {
790 s32 = (const uint32_t *) src_rect;
791 d32 = (uint32_t *) dst_rect;
792 for (kndex = 0; kndex < width; kndex++)
793 {
794 SPLITCOLOR32(red, green, blue, *s32);
795 *d32 = COLOR24(red, green, blue);
796 s32++;
797 d32++;
798 }
799 src_rect += src_stride;
800 dst_rect += dst_stride;
801 }
802 }
803 }
804 else
805 {
806 LLOGLN(0, ("rdpCapture1: unimplemented color conversion"));
807 }
808 return rv;
809 }
810
811 /******************************************************************************/
812 static Bool
rdpCapture2(rdpClientCon * clientCon,RegionPtr in_reg,BoxPtr * out_rects,int * num_out_rects,struct image_data * id)813 rdpCapture2(rdpClientCon *clientCon, RegionPtr in_reg, BoxPtr *out_rects,
814 int *num_out_rects, struct image_data *id)
815 {
816 int x;
817 int y;
818 int out_rect_index;
819 int num_rects;
820 int rcode;
821 BoxRec rect;
822 BoxRec extents_rect;
823 BoxPtr rects;
824 RegionRec tile_reg;
825 const uint8_t *src;
826 uint8_t *dst;
827 uint8_t *crc_dst;
828 int src_stride;
829 int dst_stride;
830 int crc_offset;
831 int crc_stride;
832 int crc;
833 int num_crcs;
834
835 LLOGLN(10, ("rdpCapture2:"));
836
837 if (clientCon->shmemstatus != SHM_RFX_ACTIVE) {
838 LLOGLN(0, ("rdpCapture2: WARNING -- Shared memory is not configured for RFX. Aborting capture!"));
839 return FALSE;
840 }
841
842 *out_rects = g_new(BoxRec, RDP_MAX_TILES);
843 if (*out_rects == NULL)
844 {
845 return FALSE;
846 }
847 out_rect_index = 0;
848
849 src = id->pixels;
850 dst = id->shmem_pixels;
851 src_stride = id->lineBytes;
852 dst_stride = clientCon->cap_stride_bytes;
853
854 crc_stride = (clientCon->dev->width + 63) / 64;
855 num_crcs = crc_stride * ((clientCon->dev->height + 63) / 64);
856 if (num_crcs != clientCon->num_rfx_crcs_alloc)
857 {
858 /* resize the crc list */
859 clientCon->num_rfx_crcs_alloc = num_crcs;
860 free(clientCon->rfx_crcs);
861 clientCon->rfx_crcs = g_new0(int, num_crcs);
862 }
863
864 extents_rect = *rdpRegionExtents(in_reg);
865 y = extents_rect.y1 & ~63;
866 while (y < extents_rect.y2)
867 {
868 x = extents_rect.x1 & ~63;
869 while (x < extents_rect.x2)
870 {
871 rect.x1 = x;
872 rect.y1 = y;
873 rect.x2 = rect.x1 + 64;
874 rect.y2 = rect.y1 + 64;
875 rcode = rdpRegionContainsRect(in_reg, &rect);
876 LLOGLN(10, ("rdpCapture2: rcode %d", rcode));
877
878 if (rcode != rgnOUT)
879 {
880 crc = crc_start();
881 if (rcode == rgnPART)
882 {
883 LLOGLN(10, ("rdpCapture2: rgnPART"));
884 rdpFillBox_yuvalp(x, y, dst, dst_stride);
885 rdpRegionInit(&tile_reg, &rect, 0);
886 rdpRegionIntersect(&tile_reg, in_reg, &tile_reg);
887 rects = REGION_RECTS(&tile_reg);
888 num_rects = REGION_NUM_RECTS(&tile_reg);
889 crc = crc_process_data(crc, rects,
890 num_rects * sizeof(BoxRec));
891 rdpCopyBox_a8r8g8b8_to_yuvalp(x, y,
892 src, src_stride,
893 dst, dst_stride,
894 rects, num_rects);
895 rdpRegionUninit(&tile_reg);
896 }
897 else /* rgnIN */
898 {
899 LLOGLN(10, ("rdpCapture2: rgnIN"));
900 rdpCopyBox_a8r8g8b8_to_yuvalp(x, y,
901 src, src_stride,
902 dst, dst_stride,
903 &rect, 1);
904 }
905 crc_dst = dst + (y << 8) * (dst_stride >> 8) + (x << 8);
906 crc = crc_process_data(crc, crc_dst, 64 * 64 * 4);
907 crc = crc_end(crc);
908 crc_offset = (y / 64) * crc_stride + (x / 64);
909 LLOGLN(10, ("rdpCapture2: crc 0x%8.8x 0x%8.8x",
910 crc, clientCon->rfx_crcs[crc_offset]));
911 if (crc == clientCon->rfx_crcs[crc_offset])
912 {
913 LLOGLN(10, ("rdpCapture2: crc skip at x %d y %d", x, y));
914 }
915 else
916 {
917 clientCon->rfx_crcs[crc_offset] = crc;
918 (*out_rects)[out_rect_index] = rect;
919 out_rect_index++;
920 if (out_rect_index >= RDP_MAX_TILES)
921 {
922 free(*out_rects);
923 *out_rects = NULL;
924 return FALSE;
925 }
926 }
927 }
928 x += 64;
929 }
930 y += 64;
931 }
932 *num_out_rects = out_rect_index;
933 return TRUE;
934 }
935
936 /******************************************************************************/
937 /* make out_rects always multiple of 2 width and height */
938 static Bool
rdpCapture3(rdpClientCon * clientCon,RegionPtr in_reg,BoxPtr * out_rects,int * num_out_rects,struct image_data * id)939 rdpCapture3(rdpClientCon *clientCon, RegionPtr in_reg, BoxPtr *out_rects,
940 int *num_out_rects, struct image_data *id)
941 {
942 BoxPtr psrc_rects;
943 BoxRec rect;
944 int num_rects;
945 int index;
946 uint8_t *dst_uv;
947 Bool rv;
948 const uint8_t *src;
949 uint8_t *dst;
950 int src_stride;
951 int dst_stride;
952 int dst_format;
953
954 LLOGLN(10, ("rdpCapture3:"));
955
956 if (clientCon->shmemstatus == SHM_UNINITIALIZED || clientCon->shmemstatus == SHM_RESIZING) {
957 LLOGLN(0, ("rdpCapture3: WARNING -- Shared memory is not configured. Aborting capture!"));
958 return FALSE;
959 }
960
961 rv = TRUE;
962
963 num_rects = REGION_NUM_RECTS(in_reg);
964 psrc_rects = REGION_RECTS(in_reg);
965
966 if (num_rects < 1)
967 {
968 return FALSE;
969 }
970
971 *num_out_rects = num_rects;
972
973 *out_rects = g_new(BoxRec, num_rects * 4);
974 index = 0;
975 while (index < num_rects)
976 {
977 rect = psrc_rects[index];
978 LLOGLN(10, ("old x1 %d y1 %d x2 %d y2 %d", rect.x1, rect.x2,
979 rect.x2, rect.y2));
980 rect.x1 -= rect.x1 & 1;
981 rect.y1 -= rect.y1 & 1;
982 rect.x2 += rect.x2 & 1;
983 rect.y2 += rect.y2 & 1;
984 LLOGLN(10, ("new x1 %d y1 %d x2 %d y2 %d", rect.x1, rect.x2,
985 rect.x2, rect.y2));
986 (*out_rects)[index] = rect;
987 index++;
988 }
989
990 src = id->pixels;
991 dst = id->shmem_pixels;
992 dst_format = clientCon->rdp_format;
993 src_stride = id->lineBytes;
994 dst_stride = clientCon->cap_stride_bytes;
995
996 if (dst_format == XRDP_a8r8g8b8)
997 {
998 rdpCopyBox_a8r8g8b8_to_a8r8g8b8(clientCon,
999 src, src_stride, 0, 0,
1000 dst, dst_stride, 0, 0,
1001 *out_rects, num_rects);
1002 }
1003 else if (dst_format == XRDP_nv12)
1004 {
1005 dst_uv = dst;
1006 dst_uv += clientCon->cap_width * clientCon->cap_height;
1007 rdpCopyBox_a8r8g8b8_to_nv12(clientCon,
1008 src, src_stride, 0, 0,
1009 dst, dst_stride,
1010 dst_uv, dst_stride,
1011 0, 0,
1012 *out_rects, num_rects);
1013 }
1014 else
1015 {
1016 LLOGLN(0, ("rdpCapture3: unimplemented color conversion"));
1017 }
1018
1019 return rv;
1020 }
1021
1022 #if defined(XORGXRDP_GLAMOR)
1023 /******************************************************************************/
1024 static int
copy_vmem(rdpPtr dev,RegionPtr in_reg)1025 copy_vmem(rdpPtr dev, RegionPtr in_reg)
1026 {
1027 PixmapPtr hwPixmap;
1028 PixmapPtr swPixmap;
1029 BoxPtr pbox;
1030 ScreenPtr pScreen;
1031 GCPtr copyGC;
1032 ChangeGCVal tmpval[1];
1033 int count;
1034 int index;
1035 int left;
1036 int top;
1037 int width;
1038 int height;
1039
1040 /* copy the dirty area from the screen hw pixmap to a sw pixmap
1041 this should do a dma */
1042 pScreen = dev->pScreen;
1043 hwPixmap = pScreen->GetScreenPixmap(pScreen);
1044 swPixmap = dev->screenSwPixmap;
1045 copyGC = GetScratchGC(dev->depth, pScreen);
1046 if (copyGC != NULL)
1047 {
1048 tmpval[0].val = GXcopy;
1049 ChangeGC(NullClient, copyGC, GCFunction, tmpval);
1050 ValidateGC(&(hwPixmap->drawable), copyGC);
1051 count = REGION_NUM_RECTS(in_reg);
1052 pbox = REGION_RECTS(in_reg);
1053 for (index = 0; index < count; index++)
1054 {
1055 left = pbox[index].x1;
1056 top = pbox[index].y1;
1057 width = pbox[index].x2 - pbox[index].x1;
1058 height = pbox[index].y2 - pbox[index].y1;
1059 if ((width > 0) && (height > 0))
1060 {
1061 LLOGLN(10, ("copy_vmem: hwPixmap tex 0x%8.8x "
1062 "swPixmap tex 0x%8.8x",
1063 glamor_get_pixmap_texture(hwPixmap),
1064 glamor_get_pixmap_texture(swPixmap)));
1065 copyGC->ops->CopyArea(&(hwPixmap->drawable),
1066 &(swPixmap->drawable),
1067 copyGC, left, top,
1068 width, height, left, top);
1069 }
1070 }
1071 FreeScratchGC(copyGC);
1072 }
1073 else
1074 {
1075 return 1;
1076 }
1077 return 0;
1078 }
1079 #endif
1080
1081 /**
1082 * Copy an array of rectangles from one memory area to another
1083 *****************************************************************************/
1084 Bool
rdpCapture(rdpClientCon * clientCon,RegionPtr in_reg,BoxPtr * out_rects,int * num_out_rects,struct image_data * id)1085 rdpCapture(rdpClientCon *clientCon, RegionPtr in_reg, BoxPtr *out_rects,
1086 int *num_out_rects, struct image_data *id)
1087 {
1088 int mode;
1089
1090 LLOGLN(10, ("rdpCapture:"));
1091 mode = clientCon->client_info.capture_code;
1092 if (clientCon->dev->glamor)
1093 {
1094 #if defined(XORGXRDP_GLAMOR)
1095 if (mode == 2)
1096 {
1097 return rdpEglCaptureRfx(clientCon, in_reg, out_rects,
1098 num_out_rects, id);
1099 }
1100 copy_vmem(clientCon->dev, in_reg);
1101 #endif
1102 }
1103 switch (mode)
1104 {
1105 case 0:
1106 return rdpCapture0(clientCon, in_reg, out_rects, num_out_rects, id);
1107 case 1:
1108 return rdpCapture1(clientCon, in_reg, out_rects, num_out_rects, id);
1109 case 2:
1110 /* used for remotefx capture */
1111 return rdpCapture2(clientCon, in_reg, out_rects, num_out_rects, id);
1112 case 3:
1113 /* used for even align capture */
1114 return rdpCapture3(clientCon, in_reg, out_rects, num_out_rects, id);
1115 default:
1116 LLOGLN(0, ("rdpCapture: mode %d not implemented", mode));
1117 break;
1118 }
1119 return FALSE;
1120 }
1121