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