19 #include <freerdp/config.h>
24 #include <winpr/synch.h>
25 #include <winpr/sysinfo.h>
26 #include <winpr/crypto.h>
27 #include <freerdp/primitives.h>
29 #include "prim_internal.h"
31 #include <freerdp/log.h>
32 #define TAG FREERDP_TAG("primitives")
35 static primitive_hints primitivesHints = PRIMITIVES_AUTODETECT;
36 static BOOL primitives_init_optimized(
primitives_t* prims);
38 void primitives_set_hints(primitive_hints hints)
40 primitivesHints = hints;
43 primitive_hints primitives_get_hints(
void)
45 return primitivesHints;
50 static INIT_ONCE generic_primitives_InitOnce = INIT_ONCE_STATIC_INIT;
52 #if defined(HAVE_CPU_OPTIMIZED_PRIMITIVES)
54 static INIT_ONCE cpu_primitives_InitOnce = INIT_ONCE_STATIC_INIT;
57 #if defined(WITH_OPENCL)
59 static INIT_ONCE gpu_primitives_InitOnce = INIT_ONCE_STATIC_INIT;
63 static INIT_ONCE auto_primitives_InitOnce = INIT_ONCE_STATIC_INIT;
70 primitives_init_add(prims);
71 primitives_init_andor(prims);
72 primitives_init_alphaComp(prims);
73 primitives_init_copy(prims);
74 primitives_init_set(prims);
75 primitives_init_shift(prims);
76 primitives_init_sign(prims);
77 primitives_init_colors(prims);
78 primitives_init_YCoCg(prims);
79 primitives_init_YUV(prims);
84 static BOOL CALLBACK primitives_init_generic_cb(
PINIT_ONCE once, PVOID param, PVOID* context)
88 WINPR_UNUSED(context);
89 return primitives_init_generic(&pPrimitivesGeneric);
92 static BOOL primitives_init_optimized(
primitives_t* prims)
94 primitives_init_generic(prims);
96 #if defined(HAVE_CPU_OPTIMIZED_PRIMITIVES)
97 primitives_init_add_opt(prims);
98 primitives_init_andor_opt(prims);
99 primitives_init_alphaComp_opt(prims);
100 primitives_init_copy_opt(prims);
101 primitives_init_set_opt(prims);
102 primitives_init_shift_opt(prims);
103 primitives_init_sign_opt(prims);
104 primitives_init_colors_opt(prims);
105 primitives_init_YCoCg_opt(prims);
106 primitives_init_YUV_opt(prims);
107 prims->flags |= PRIM_FLAGS_HAVE_EXTCPU;
120 } primitives_YUV_benchmark;
122 static void primitives_YUV_benchmark_free(primitives_YUV_benchmark* bench)
127 free(bench->outputBuffer);
129 for (
int i = 0; i < 3; i++)
130 free(bench->channels[i]);
131 memset(bench, 0,
sizeof(primitives_YUV_benchmark));
134 static primitives_YUV_benchmark* primitives_YUV_benchmark_init(primitives_YUV_benchmark* ret)
140 memset(ret, 0,
sizeof(primitives_YUV_benchmark));
144 ret->outputStride = roi->width * 4;
145 ret->testedFormat = PIXEL_FORMAT_BGRA32;
147 ret->outputBuffer = calloc(ret->outputStride, roi->height);
148 if (!ret->outputBuffer)
151 for (
int i = 0; i < 3; i++)
153 BYTE* buf = ret->channels[i] = calloc(roi->width, roi->height);
157 winpr_RAND(buf, 1ull * roi->width * roi->height);
158 ret->steps[i] = roi->width;
164 primitives_YUV_benchmark_free(ret);
168 static BOOL primitives_YUV_benchmark_run(primitives_YUV_benchmark* bench,
primitives_t* prims,
169 UINT64 runTime, UINT32* computations)
171 ULONGLONG dueDate = 0;
172 const BYTE* channels[3] = { 0 };
173 pstatus_t status = 0;
177 for (
size_t i = 0; i < 3; i++)
178 channels[i] = bench->channels[i];
181 status = prims->YUV420ToRGB_8u_P3AC4R(channels, bench->steps, bench->outputBuffer,
182 bench->outputStride, bench->testedFormat, &bench->roi);
183 if (status != PRIMITIVES_SUCCESS)
187 dueDate = GetTickCount64() + runTime;
188 while (GetTickCount64() < dueDate)
191 prims->YUV420ToRGB_8u_P3AC4R(channels, bench->steps, bench->outputBuffer,
192 bench->outputStride, bench->testedFormat, &bench->roi);
193 if (cstatus != PRIMITIVES_SUCCESS)
195 *computations = *computations + 1;
200 static BOOL primitives_autodetect_best(
primitives_t* prims)
203 struct prim_benchmark
211 struct prim_benchmark testcases[] =
213 {
"generic", NULL, PRIMITIVES_PURE_SOFT, 0 },
214 #if defined(HAVE_CPU_OPTIMIZED_PRIMITIVES)
215 {
"optimized", NULL, PRIMITIVES_ONLY_CPU, 0 },
217 #if defined(WITH_OPENCL)
218 {
"opencl", NULL, PRIMITIVES_ONLY_GPU, 0 },
221 const struct prim_benchmark* best = NULL;
223 #if !defined(HAVE_CPU_OPTIMIZED_PRIMITIVES) && !defined(WITH_OPENCL)
225 struct prim_benchmark* cur = &testcases[0];
226 cur->prims = primitives_get_by_type(cur->flags);
229 WLog_WARN(TAG,
"Failed to initialize %s primitives", cur->name);
232 WLog_DBG(TAG,
"primitives benchmark: only one backend, skipping...");
237 UINT64 benchDuration = 150;
238 primitives_YUV_benchmark bench = { 0 };
239 primitives_YUV_benchmark* yuvBench = primitives_YUV_benchmark_init(&bench);
243 WLog_DBG(TAG,
"primitives benchmark result:");
244 for (
size_t x = 0; x < ARRAYSIZE(testcases); x++)
246 struct prim_benchmark* cur = &testcases[x];
247 cur->prims = primitives_get_by_type(cur->flags);
250 WLog_WARN(TAG,
"Failed to initialize %s primitives", cur->name);
253 if (!primitives_YUV_benchmark_run(yuvBench, cur->prims, benchDuration, &cur->count))
255 WLog_WARN(TAG,
"error running %s YUV bench", cur->name);
259 WLog_DBG(TAG,
" * %s= %" PRIu32, cur->name, cur->count);
260 if (!best || (best->count < cur->count))
263 primitives_YUV_benchmark_free(yuvBench);
269 WLog_ERR(TAG,
"No primitives to test, aborting.");
273 *prims = *best->prims;
275 WLog_DBG(TAG,
"primitives autodetect, using %s", best->name);
279 *prims = pPrimitivesGeneric;
284 #if defined(WITH_OPENCL)
285 static BOOL CALLBACK primitives_init_gpu_cb(
PINIT_ONCE once, PVOID param, PVOID* context)
289 WINPR_UNUSED(context);
291 if (!primitives_init_opencl(&pPrimitivesGpu))
298 #if defined(HAVE_CPU_OPTIMIZED_PRIMITIVES)
299 static BOOL CALLBACK primitives_init_cpu_cb(
PINIT_ONCE once, PVOID param, PVOID* context)
303 WINPR_UNUSED(context);
305 if (!primitives_init_optimized(&pPrimitivesCpu))
312 static BOOL CALLBACK primitives_auto_init_cb(
PINIT_ONCE once, PVOID param, PVOID* context)
316 WINPR_UNUSED(context);
318 return primitives_init(&pPrimitives, primitivesHints);
321 BOOL primitives_init(
primitives_t* p, primitive_hints hints)
325 case PRIMITIVES_AUTODETECT:
326 return primitives_autodetect_best(p);
327 case PRIMITIVES_PURE_SOFT:
328 *p = pPrimitivesGeneric;
330 case PRIMITIVES_ONLY_CPU:
331 #if defined(HAVE_CPU_OPTIMIZED_PRIMITIVES)
335 case PRIMITIVES_ONLY_GPU:
336 #if defined(WITH_OPENCL)
341 WLog_ERR(TAG,
"unknown hint %d", hints);
346 void primitives_uninit(
void)
348 #if defined(WITH_OPENCL)
349 if (pPrimitivesGpu.uninit)
350 pPrimitivesGpu.uninit();
352 #if defined(HAVE_CPU_OPTIMIZED_PRIMITIVES)
353 if (pPrimitivesCpu.uninit)
354 pPrimitivesCpu.uninit();
356 if (pPrimitivesGeneric.uninit)
357 pPrimitivesGeneric.uninit();
361 static void setup(
void)
363 InitOnceExecuteOnce(&generic_primitives_InitOnce, primitives_init_generic_cb, NULL, NULL);
364 #if defined(HAVE_CPU_OPTIMIZED_PRIMITIVES)
365 InitOnceExecuteOnce(&cpu_primitives_InitOnce, primitives_init_cpu_cb, NULL, NULL);
367 #if defined(WITH_OPENCL)
368 InitOnceExecuteOnce(&gpu_primitives_InitOnce, primitives_init_gpu_cb, NULL, NULL);
370 InitOnceExecuteOnce(&auto_primitives_InitOnce, primitives_auto_init_cb, NULL, NULL);
381 InitOnceExecuteOnce(&generic_primitives_InitOnce, primitives_init_generic_cb, NULL, NULL);
382 return &pPrimitivesGeneric;
387 InitOnceExecuteOnce(&generic_primitives_InitOnce, primitives_init_generic_cb, NULL, NULL);
391 case PRIMITIVES_ONLY_GPU:
392 #if defined(WITH_OPENCL)
393 if (!InitOnceExecuteOnce(&gpu_primitives_InitOnce, primitives_init_gpu_cb, NULL, NULL))
395 return &pPrimitivesGpu;
397 case PRIMITIVES_ONLY_CPU:
398 #if defined(HAVE_CPU_OPTIMIZED_PRIMITIVES)
399 if (!InitOnceExecuteOnce(&cpu_primitives_InitOnce, primitives_init_cpu_cb, NULL, NULL))
401 return &pPrimitivesCpu;
403 case PRIMITIVES_PURE_SOFT:
405 return &pPrimitivesGeneric;