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")
35static primitive_hints primitivesHints = PRIMITIVES_AUTODETECT;
36static BOOL primitives_init_optimized(
primitives_t* prims);
38void primitives_set_hints(primitive_hints hints)
40 primitivesHints = hints;
43primitive_hints primitives_get_hints(
void)
45 return primitivesHints;
50static INIT_ONCE generic_primitives_InitOnce = INIT_ONCE_STATIC_INIT;
52#if defined(HAVE_CPU_OPTIMIZED_PRIMITIVES)
54static INIT_ONCE cpu_primitives_InitOnce = INIT_ONCE_STATIC_INIT;
57#if defined(WITH_OPENCL)
59static INIT_ONCE gpu_primitives_InitOnce = INIT_ONCE_STATIC_INIT;
63static 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);
84static BOOL CALLBACK primitives_init_generic_cb(
PINIT_ONCE once, PVOID param, PVOID* context)
88 WINPR_UNUSED(context);
89 return primitives_init_generic(&pPrimitivesGeneric);
92static 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;
112#if defined(HAVE_CPU_OPTIMIZED_PRIMITIVES) && defined(WITH_OPENCL)
121} primitives_YUV_benchmark;
123static void primitives_YUV_benchmark_free(primitives_YUV_benchmark* bench)
128 free(bench->outputBuffer);
130 for (
int i = 0; i < 3; i++)
131 free(bench->channels[i]);
132 memset(bench, 0,
sizeof(primitives_YUV_benchmark));
135static primitives_YUV_benchmark* primitives_YUV_benchmark_init(primitives_YUV_benchmark* ret)
141 memset(ret, 0,
sizeof(primitives_YUV_benchmark));
145 ret->outputStride = roi->width * 4;
146 ret->testedFormat = PIXEL_FORMAT_BGRA32;
148 ret->outputBuffer = calloc(ret->outputStride, roi->height);
149 if (!ret->outputBuffer)
152 for (
int i = 0; i < 3; i++)
154 BYTE* buf = ret->channels[i] = calloc(roi->width, roi->height);
158 winpr_RAND(buf, 1ull * roi->width * roi->height);
159 ret->steps[i] = roi->width;
165 primitives_YUV_benchmark_free(ret);
169static BOOL primitives_YUV_benchmark_run(primitives_YUV_benchmark* bench,
primitives_t* prims,
170 UINT64 runTime, UINT32* computations)
172 ULONGLONG dueDate = 0;
173 const BYTE* channels[3] = { 0 };
174 pstatus_t status = 0;
178 for (
size_t i = 0; i < 3; i++)
179 channels[i] = bench->channels[i];
182 status = prims->YUV420ToRGB_8u_P3AC4R(channels, bench->steps, bench->outputBuffer,
183 bench->outputStride, bench->testedFormat, &bench->roi);
184 if (status != PRIMITIVES_SUCCESS)
188 dueDate = GetTickCount64() + runTime;
189 while (GetTickCount64() < dueDate)
192 prims->YUV420ToRGB_8u_P3AC4R(channels, bench->steps, bench->outputBuffer,
193 bench->outputStride, bench->testedFormat, &bench->roi);
194 if (cstatus != PRIMITIVES_SUCCESS)
196 *computations = *computations + 1;
202static BOOL primitives_autodetect_best(
primitives_t* prims)
205 struct prim_benchmark
213 struct prim_benchmark testcases[] =
215 {
"generic", NULL, PRIMITIVES_PURE_SOFT, 0 },
216#if defined(HAVE_CPU_OPTIMIZED_PRIMITIVES)
217 {
"optimized", NULL, PRIMITIVES_ONLY_CPU, 0 },
219#if defined(WITH_OPENCL)
220 {
"opencl", NULL, PRIMITIVES_ONLY_GPU, 0 },
223 const struct prim_benchmark* best = NULL;
225#if !defined(HAVE_CPU_OPTIMIZED_PRIMITIVES) || !defined(WITH_OPENCL)
227#if defined(HAVE_CPU_OPTIMIZED_PRIMITIVES) || defined(WITH_OPENCL)
228 struct prim_benchmark* cur = &testcases[1];
230 struct prim_benchmark* cur = &testcases[0];
232 cur->prims = primitives_get_by_type(cur->flags);
235 WLog_WARN(TAG,
"Failed to initialize %s primitives", cur->name);
238 WLog_DBG(TAG,
"primitives benchmark: only one backend, skipping...");
243 UINT64 benchDuration = 150;
244 primitives_YUV_benchmark bench = { 0 };
245 primitives_YUV_benchmark* yuvBench = primitives_YUV_benchmark_init(&bench);
249 WLog_DBG(TAG,
"primitives benchmark result:");
250 for (
size_t x = 0; x < ARRAYSIZE(testcases); x++)
252 struct prim_benchmark* cur = &testcases[x];
253 cur->prims = primitives_get_by_type(cur->flags);
256 WLog_WARN(TAG,
"Failed to initialize %s primitives", cur->name);
259 if (!primitives_YUV_benchmark_run(yuvBench, cur->prims, benchDuration, &cur->count))
261 WLog_WARN(TAG,
"error running %s YUV bench", cur->name);
265 WLog_DBG(TAG,
" * %s= %" PRIu32, cur->name, cur->count);
266 if (!best || (best->count < cur->count))
269 primitives_YUV_benchmark_free(yuvBench);
275 WLog_ERR(TAG,
"No primitives to test, aborting.");
279 *prims = *best->prims;
281 WLog_DBG(TAG,
"primitives autodetect, using %s", best->name);
285 *prims = pPrimitivesGeneric;
290#if defined(WITH_OPENCL)
291static BOOL CALLBACK primitives_init_gpu_cb(
PINIT_ONCE once, PVOID param, PVOID* context)
295 WINPR_UNUSED(context);
297 if (!primitives_init_opencl(&pPrimitivesGpu))
304#if defined(HAVE_CPU_OPTIMIZED_PRIMITIVES)
305static BOOL CALLBACK primitives_init_cpu_cb(
PINIT_ONCE once, PVOID param, PVOID* context)
309 WINPR_UNUSED(context);
311 if (!primitives_init_optimized(&pPrimitivesCpu))
318static BOOL CALLBACK primitives_auto_init_cb(
PINIT_ONCE once, PVOID param, PVOID* context)
322 WINPR_UNUSED(context);
324 return primitives_init(&pPrimitives, primitivesHints);
327BOOL primitives_init(
primitives_t* p, primitive_hints hints)
331 case PRIMITIVES_AUTODETECT:
332 return primitives_autodetect_best(p);
333 case PRIMITIVES_PURE_SOFT:
334 *p = pPrimitivesGeneric;
336 case PRIMITIVES_ONLY_CPU:
337#if defined(HAVE_CPU_OPTIMIZED_PRIMITIVES)
341 case PRIMITIVES_ONLY_GPU:
342#if defined(WITH_OPENCL)
347 WLog_ERR(TAG,
"unknown hint %d", hints);
352void primitives_uninit(
void)
354#if defined(WITH_OPENCL)
355 if (pPrimitivesGpu.uninit)
356 pPrimitivesGpu.uninit();
358#if defined(HAVE_CPU_OPTIMIZED_PRIMITIVES)
359 if (pPrimitivesCpu.uninit)
360 pPrimitivesCpu.uninit();
362 if (pPrimitivesGeneric.uninit)
363 pPrimitivesGeneric.uninit();
367static void setup(
void)
369 InitOnceExecuteOnce(&generic_primitives_InitOnce, primitives_init_generic_cb, NULL, NULL);
370#if defined(HAVE_CPU_OPTIMIZED_PRIMITIVES)
371 InitOnceExecuteOnce(&cpu_primitives_InitOnce, primitives_init_cpu_cb, NULL, NULL);
373#if defined(WITH_OPENCL)
374 InitOnceExecuteOnce(&gpu_primitives_InitOnce, primitives_init_gpu_cb, NULL, NULL);
376 InitOnceExecuteOnce(&auto_primitives_InitOnce, primitives_auto_init_cb, NULL, NULL);
387 InitOnceExecuteOnce(&generic_primitives_InitOnce, primitives_init_generic_cb, NULL, NULL);
388 return &pPrimitivesGeneric;
391primitives_t* primitives_get_by_type(primitive_hints type)
393 InitOnceExecuteOnce(&generic_primitives_InitOnce, primitives_init_generic_cb, NULL, NULL);
397 case PRIMITIVES_ONLY_GPU:
398#if defined(WITH_OPENCL)
399 if (!InitOnceExecuteOnce(&gpu_primitives_InitOnce, primitives_init_gpu_cb, NULL, NULL))
401 return &pPrimitivesGpu;
403 case PRIMITIVES_ONLY_CPU:
404#if defined(HAVE_CPU_OPTIMIZED_PRIMITIVES)
405 if (!InitOnceExecuteOnce(&cpu_primitives_InitOnce, primitives_init_cpu_cb, NULL, NULL))
407 return &pPrimitivesCpu;
409 case PRIMITIVES_PURE_SOFT:
411 return &pPrimitivesGeneric;
420const char* primitives_avc444_frame_type_str(avc444_frame_type type)
425 return "AVC444_LUMA";
426 case AVC444_CHROMAv1:
427 return "AVC444_CHROMAv1";
428 case AVC444_CHROMAv2:
429 return "AVC444_CHROMAv2";
431 return "INVALID_FRAME_TYPE";
435const char* primtives_hint_str(primitive_hints hint)
439 case PRIMITIVES_PURE_SOFT:
440 return "PRIMITIVES_PURE_SOFT";
441 case PRIMITIVES_ONLY_CPU:
442 return "PRIMITIVES_ONLY_CPU";
443 case PRIMITIVES_ONLY_GPU:
444 return "PRIMITIVES_ONLY_GPU";
445 case PRIMITIVES_AUTODETECT:
446 return "PRIMITIVES_AUTODETECT";
448 return "PRIMITIVES_UNKNOWN";