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;
49static primitives_t pPrimitivesGeneric = WINPR_C_ARRAY_INIT;
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);
80 prims->uninit =
nullptr;
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 if (winpr_RAND(buf, 1ull * roi->width * roi->height) < 0)
160 ret->steps[i] = roi->width;
166 primitives_YUV_benchmark_free(ret);
170static BOOL primitives_YUV_benchmark_run(primitives_YUV_benchmark* bench,
primitives_t* prims,
171 UINT64 runTime, UINT32* computations)
173 ULONGLONG dueDate = 0;
174 const BYTE* channels[3] = WINPR_C_ARRAY_INIT;
175 pstatus_t status = 0;
179 for (
size_t i = 0; i < 3; i++)
180 channels[i] = bench->channels[i];
183 status = prims->YUV420ToRGB_8u_P3AC4R(channels, bench->steps, bench->outputBuffer,
184 bench->outputStride, bench->testedFormat, &bench->roi);
185 if (status != PRIMITIVES_SUCCESS)
189 dueDate = GetTickCount64() + runTime;
190 while (GetTickCount64() < dueDate)
193 prims->YUV420ToRGB_8u_P3AC4R(channels, bench->steps, bench->outputBuffer,
194 bench->outputStride, bench->testedFormat, &bench->roi);
195 if (cstatus != PRIMITIVES_SUCCESS)
197 *computations = *computations + 1;
203static BOOL primitives_autodetect_best(
primitives_t* prims)
206 struct prim_benchmark
210 primitive_hints flags;
214 struct prim_benchmark testcases[] = {
215 {
"generic",
nullptr, PRIMITIVES_PURE_SOFT, 0 },
216#if defined(HAVE_CPU_OPTIMIZED_PRIMITIVES)
217 {
"optimized",
nullptr, PRIMITIVES_ONLY_CPU, 0 },
219#if defined(WITH_OPENCL)
220 {
"opencl",
nullptr, PRIMITIVES_ONLY_GPU, 0 },
223 const struct prim_benchmark* best =
nullptr;
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 = WINPR_C_ARRAY_INIT;
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 return primitives_init_opencl(&pPrimitivesGpu);
301#if defined(HAVE_CPU_OPTIMIZED_PRIMITIVES)
302static BOOL CALLBACK primitives_init_cpu_cb(
PINIT_ONCE once, PVOID param, PVOID* context)
306 WINPR_UNUSED(context);
308 return (primitives_init_optimized(&pPrimitivesCpu));
312static BOOL CALLBACK primitives_auto_init_cb(
PINIT_ONCE once, PVOID param, PVOID* context)
316 WINPR_UNUSED(context);
318 return primitives_init(&pPrimitives, primitivesHints);
321BOOL 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 %u", hints);
346void 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();
361static void setup(
void)
363 if (!InitOnceExecuteOnce(&generic_primitives_InitOnce, primitives_init_generic_cb,
nullptr,
366#if defined(HAVE_CPU_OPTIMIZED_PRIMITIVES)
367 if (!InitOnceExecuteOnce(&cpu_primitives_InitOnce, primitives_init_cpu_cb,
nullptr,
nullptr))
370#if defined(WITH_OPENCL)
371 if (!InitOnceExecuteOnce(&gpu_primitives_InitOnce, primitives_init_gpu_cb,
nullptr,
nullptr))
374 if (!InitOnceExecuteOnce(&auto_primitives_InitOnce, primitives_auto_init_cb,
nullptr,
nullptr))
386 if (!InitOnceExecuteOnce(&generic_primitives_InitOnce, primitives_init_generic_cb,
nullptr,
389 return &pPrimitivesGeneric;
392primitives_t* primitives_get_by_type(primitive_hints type)
394 if (!InitOnceExecuteOnce(&generic_primitives_InitOnce, primitives_init_generic_cb,
nullptr,
400 case PRIMITIVES_ONLY_GPU:
401#if defined(WITH_OPENCL)
402 if (!InitOnceExecuteOnce(&gpu_primitives_InitOnce, primitives_init_gpu_cb,
nullptr,
405 return &pPrimitivesGpu;
407 case PRIMITIVES_ONLY_CPU:
408#if defined(HAVE_CPU_OPTIMIZED_PRIMITIVES)
409 if (!InitOnceExecuteOnce(&cpu_primitives_InitOnce, primitives_init_cpu_cb,
nullptr,
412 return &pPrimitivesCpu;
414 case PRIMITIVES_PURE_SOFT:
416 return &pPrimitivesGeneric;
425const char* primitives_avc444_frame_type_str(avc444_frame_type type)
430 return "AVC444_LUMA";
431 case AVC444_CHROMAv1:
432 return "AVC444_CHROMAv1";
433 case AVC444_CHROMAv2:
434 return "AVC444_CHROMAv2";
436 return "INVALID_FRAME_TYPE";
440const char* primtives_hint_str(primitive_hints hint)
444 case PRIMITIVES_PURE_SOFT:
445 return "PRIMITIVES_PURE_SOFT";
446 case PRIMITIVES_ONLY_CPU:
447 return "PRIMITIVES_ONLY_CPU";
448 case PRIMITIVES_ONLY_GPU:
449 return "PRIMITIVES_ONLY_GPU";
450 case PRIMITIVES_AUTODETECT:
451 return "PRIMITIVES_AUTODETECT";
453 return "PRIMITIVES_UNKNOWN";