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