FreeRDP
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Modules Pages
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 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/* ------------------------------------------------------------------------- */
61static 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
77static 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
100static size_t runcount = 0;
101
102static 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
179fail:
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
193static 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
225int 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 defined(TEST_ALL_FLAGS)
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[] = { PIXEL_FORMAT_BGRA32,
256 PIXEL_FORMAT_BGRX32,
257 PIXEL_FORMAT_BGR24
258#if defined(TEST_ALL_FLAGS) /* Only the previous 3 have SIMD optimizations, so skip the rest */
259 ,
260 PIXEL_FORMAT_RGB24,
261 PIXEL_FORMAT_ABGR32,
262 PIXEL_FORMAT_ARGB32,
263 PIXEL_FORMAT_XBGR32,
264 PIXEL_FORMAT_XRGB32,
265 PIXEL_FORMAT_RGBA32,
266 PIXEL_FORMAT_RGBX32
267#endif
268 };
269
270 int rc = 0;
271 for (size_t z = 0; z < ARRAYSIZE(flags); z++)
272 {
273 const UINT32 flag = flags[z];
274 for (size_t x = 0; x < ARRAYSIZE(formats); x++)
275 {
276 const UINT32 sformat = formats[x];
277 for (size_t y = 0; y < ARRAYSIZE(formats); y++)
278 {
279 const UINT32 dformat = formats[y];
280
281 if (!test_copy_no_overlap(verbose, sformat, dformat, flag, 21, 17))
282 rc = -1;
283 }
284 }
285 }
286
287 if (verbose)
288 (void)fprintf(stderr, "runcount=%" PRIuz "\n", runcount);
289
290 return rc;
291}
fn_copy_no_overlap_t copy_no_overlap
Definition primitives.h:304