FreeRDP
TestPrimitivesCopy.c
1 /* test_copy.c
2  * vi:ts=4 sw=4
3  *
4  * (c) Copyright 2012 Hewlett-Packard Development Company, L.P.
5  * Licensed under the Apache License, Version 2.0 (the "License"); you may
6  * not use this file except in compliance with the License. You may obtain
7  * a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
8  * Unless required by applicable law or agreed to in writing, software
9  * distributed under the License is distributed on an "AS IS" BASIS,
10  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11  * or implied. See the License for the specific language governing
12  * permissions and limitations under the License.
13  */
14 
15 #include <stdio.h>
16 
17 #include <freerdp/config.h>
18 #include <winpr/crypto.h>
19 
20 #include <winpr/sysinfo.h>
21 #include "prim_test.h"
22 
23 #define COPY_TESTSIZE (256 * 2 + 16 * 2 + 15 + 15)
24 
25 /* ------------------------------------------------------------------------- */
26 static BOOL test_copy8u_func(void)
27 {
28  primitives_t* prims = primitives_get();
29  BYTE ALIGN(data[COPY_TESTSIZE + 15]) = { 0 };
30  winpr_RAND(data, sizeof(data));
31 
32  for (int soff = 0; soff < 16; ++soff)
33  {
34  for (int doff = 0; doff < 16; ++doff)
35  {
36  for (int length = 1; length <= COPY_TESTSIZE - doff; ++length)
37  {
38  BYTE ALIGN(dest[COPY_TESTSIZE + 15]) = { 0 };
39 
40  if (prims->copy_8u(data + soff, dest + doff, length) != PRIMITIVES_SUCCESS)
41  return FALSE;
42 
43  for (int i = 0; i < length; ++i)
44  {
45  if (dest[i + doff] != data[i + soff])
46  {
47  printf("COPY8U FAIL: off=%d len=%d, dest[%d]=0x%02" PRIx8 ""
48  "data[%d]=0x%02" PRIx8 "\n",
49  doff, length, i + doff, dest[i + doff], i + soff, data[i + soff]);
50  return FALSE;
51  }
52  }
53  }
54  }
55  }
56 
57  return TRUE;
58 }
59 
60 /* ------------------------------------------------------------------------- */
61 static BOOL test_copy8u_speed(void)
62 {
63  BYTE ALIGN(src[MAX_TEST_SIZE + 4]);
64  BYTE ALIGN(dst[MAX_TEST_SIZE + 4]);
65 
66  if (!speed_test("copy_8u", "aligned", g_Iterations, (speed_test_fkt)generic->copy_8u,
67  (speed_test_fkt)optimized->copy_8u, src, dst, MAX_TEST_SIZE))
68  return FALSE;
69 
70  if (!speed_test("copy_8u", "unaligned", g_Iterations, (speed_test_fkt)generic->copy_8u,
71  (speed_test_fkt)optimized->copy_8u, src + 1, dst + 1, MAX_TEST_SIZE))
72  return FALSE;
73 
74  return TRUE;
75 }
76 
77 static BYTE* rand_alloc(size_t w, size_t h, size_t bpp, size_t pad, BYTE** copy)
78 {
79  const size_t s = w * bpp + pad;
80  BYTE* ptr = calloc(s, h);
81  if (!ptr)
82  return NULL;
83 
84  winpr_RAND(ptr, s * h);
85 
86  if (copy)
87  {
88  BYTE* ptr2 = calloc(s, h);
89  if (!ptr2)
90  {
91  free(ptr);
92  return NULL;
93  }
94  memcpy(ptr2, ptr, s * h);
95  *copy = ptr2;
96  }
97  return ptr;
98 }
99 
100 static size_t runcount = 0;
101 
102 static BOOL test_copy_no_overlap_off(BOOL verbose, UINT32 srcFormat, UINT32 dstFormat, UINT32 flags,
103  UINT32 pad, UINT32 w, UINT32 h, UINT32 dxoff, UINT32 dyoff,
104  UINT32 sxoff, UINT32 syoff)
105 {
106  BOOL rc = FALSE;
107  primitives_t* gen = primitives_get_generic();
108  primitives_t* prims = primitives_get();
109  if (!gen || !prims)
110  return FALSE;
111 
112  runcount++;
113 
114  WINPR_ASSERT(dxoff < w);
115  WINPR_ASSERT(sxoff < w);
116  WINPR_ASSERT(dyoff < h);
117  WINPR_ASSERT(syoff < h);
118 
119  const UINT32 sbpp = FreeRDPGetBytesPerPixel(srcFormat);
120  const UINT32 dbpp = FreeRDPGetBytesPerPixel(dstFormat);
121 
122  if (verbose)
123  {
124  (void)fprintf(stderr,
125  "run src: %s, dst: %s [flags 0x%08" PRIx32 "] %" PRIu32 "x%" PRIu32
126  ", soff=%" PRIu32 "x%" PRIu32 ", doff=%" PRIu32 "x%" PRIu32 ", pad=%" PRIu32
127  "\n",
128  FreeRDPGetColorFormatName(srcFormat), FreeRDPGetColorFormatName(dstFormat),
129  flags, w, h, sxoff, syoff, dxoff, dyoff, pad);
130  }
131 
132  const UINT32 sstride = (w + sxoff) * sbpp + pad;
133  const UINT32 dstride = (w + dxoff) * dbpp + pad;
134  BYTE* dst2 = NULL;
135  BYTE* src2 = NULL;
136  BYTE* dst1 = rand_alloc(w + dxoff, h + dyoff, dbpp, pad, &dst2);
137  BYTE* src1 = rand_alloc(w + sxoff, h + syoff, sbpp, pad, &src2);
138  if (!dst1 || !dst2 || !src1 || !src2)
139  goto fail;
140 
141  if (gen->copy_no_overlap(dst1, dstFormat, dstride, dxoff, dyoff, w, h, src1, srcFormat, sstride,
142  sxoff, syoff, NULL, flags) != PRIMITIVES_SUCCESS)
143  goto fail;
144 
145  if (memcmp(src1, src2, 1ULL * sstride * h) != 0)
146  goto fail;
147 
148  if (prims->copy_no_overlap(dst2, dstFormat, dstride, dxoff, dyoff, w, h, src1, srcFormat,
149  sstride, sxoff, syoff, NULL, flags) != PRIMITIVES_SUCCESS)
150  goto fail;
151 
152  if (memcmp(src1, src2, 1ULL * sstride * h) != 0)
153  goto fail;
154 
155  if (memcmp(dst1, dst2, 1ULL * dstride * h) != 0)
156  goto fail;
157 
158  if (flags == FREERDP_KEEP_DST_ALPHA)
159  {
160  for (size_t y = 0; y < h; y++)
161  {
162  const BYTE* d1 = &dst1[(y + dyoff) * dstride];
163  const BYTE* d2 = &dst2[(y + dyoff) * dstride];
164  for (size_t x = 0; x < w; x++)
165  {
166  const UINT32 c1 = FreeRDPReadColor(&d1[(x + dxoff) * dbpp], dstFormat);
167  const UINT32 c2 = FreeRDPReadColor(&d2[(x + dxoff) * dbpp], dstFormat);
168  BYTE a1 = 0;
169  BYTE a2 = 0;
170  FreeRDPSplitColor(c1, dstFormat, NULL, NULL, NULL, &a1, NULL);
171  FreeRDPSplitColor(c2, dstFormat, NULL, NULL, NULL, &a2, NULL);
172  if (a1 != a2)
173  goto fail;
174  }
175  }
176  }
177  rc = TRUE;
178 
179 fail:
180  if (!rc)
181  {
182  (void)fprintf(stderr, "failed to compare copy_no_overlap(%s -> %s [0x%08" PRIx32 "])\n",
183  FreeRDPGetColorFormatName(srcFormat), FreeRDPGetColorFormatName(dstFormat),
184  flags);
185  }
186  free(dst1);
187  free(dst2);
188  free(src1);
189  free(src2);
190  return rc;
191 }
192 
193 static BOOL test_copy_no_overlap(BOOL verbose, UINT32 srcFormat, UINT32 dstFormat, UINT32 flags,
194  UINT32 width, UINT32 height)
195 {
196  BOOL rc = TRUE;
197  const UINT32 mw = 4;
198  const UINT32 mh = 4;
199  for (UINT32 dxoff = 0; dxoff < mw; dxoff++)
200  {
201  for (UINT32 dyoff = 0; dyoff <= mh; dyoff++)
202  {
203  for (UINT32 sxoff = 0; sxoff <= mw; sxoff++)
204  {
205  for (UINT32 syoff = 0; syoff <= mh; syoff++)
206  {
207  /* We need minimum alignment of 8 bytes.
208  * AVX2 can read 8 pixels (at most 8x4=32 bytes) per step
209  * if we have 24bpp input that is 24 bytes with 8 bytes read
210  * out of bound */
211  for (UINT32 pad = 8; pad <= 12; pad++)
212  {
213  if (!test_copy_no_overlap_off(verbose, srcFormat, dstFormat, flags, pad,
214  width, height, dxoff, dyoff, sxoff, syoff))
215  rc = FALSE;
216  }
217  }
218  }
219  }
220  }
221 
222  return rc;
223 }
224 
225 int TestPrimitivesCopy(int argc, char* argv[])
226 {
227  WINPR_UNUSED(argc);
228  WINPR_UNUSED(argv);
229 
230  const BOOL verbose = argc > 1;
231 
232  prim_test_setup(FALSE);
233 
234  if (!test_copy8u_func())
235  return 1;
236 
237  if (g_TestPrimitivesPerformance)
238  {
239  if (!test_copy8u_speed())
240  return 1;
241  }
242 
243  const UINT32 flags[] = {
244  FREERDP_FLIP_NONE,
245  FREERDP_KEEP_DST_ALPHA,
246  FREERDP_FLIP_HORIZONTAL,
247  FREERDP_KEEP_DST_ALPHA | FREERDP_FLIP_HORIZONTAL,
248 #if 0
249  FREERDP_FLIP_VERTICAL,
250  FREERDP_FLIP_VERTICAL | FREERDP_FLIP_HORIZONTAL,
251  FREERDP_KEEP_DST_ALPHA | FREERDP_FLIP_VERTICAL,
252  FREERDP_KEEP_DST_ALPHA | FREERDP_FLIP_VERTICAL | FREERDP_FLIP_HORIZONTAL
253 #endif
254  };
255  const UINT32 formats[] = {
256  PIXEL_FORMAT_BGRA32,
257  PIXEL_FORMAT_BGRX32,
258  PIXEL_FORMAT_BGR24
259 #if 0 /* Only the previous 3 have SIMD optimizations, so skip the rest */
260  , PIXEL_FORMAT_RGB24,
261  PIXEL_FORMAT_ABGR32, PIXEL_FORMAT_ARGB32, PIXEL_FORMAT_XBGR32,
262  PIXEL_FORMAT_XRGB32, PIXEL_FORMAT_RGBA32, PIXEL_FORMAT_RGBX32
263 #endif
264  };
265 
266  int rc = 0;
267  for (size_t z = 0; z < ARRAYSIZE(flags); z++)
268  {
269  const UINT32 flag = flags[z];
270  for (size_t x = 0; x < ARRAYSIZE(formats); x++)
271  {
272  const UINT32 sformat = formats[x];
273  for (size_t y = 0; y < ARRAYSIZE(formats); y++)
274  {
275  const UINT32 dformat = formats[y];
276 
277  if (!test_copy_no_overlap(verbose, sformat, dformat, flag, 21, 17))
278  rc = -1;
279  }
280  }
281  }
282 
283  if (verbose)
284  (void)fprintf(stderr, "runcount=%" PRIuz "\n", runcount);
285 
286  return rc;
287 }
__copy_no_overlap_t copy_no_overlap
Definition: primitives.h:258