xref: /aosp_15_r20/external/skia/src/core/SkOpts.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2015 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #ifndef SkOpts_DEFINED
9 #define SkOpts_DEFINED
10 
11 #include "include/private/base/SkSpan_impl.h"
12 #include "src/core/SkRasterPipelineOpList.h"
13 
14 #include <cstddef>
15 #include <cstdint>
16 
17 struct SkRasterPipeline_MemoryCtxPatch;
18 
19 /**
20  * SkOpts (short for SkOptimizations) is a mechanism where we can ship with multiple implementations
21  * of a set of functions and dynamically choose the best one at runtime (e.g. the call to
22  * SkGraphics::Init(), which calls SkOpts::Init()) depending on the detected CPU features. This is
23  * also referred to as having "specializations" of a given function.
24  *
25  * For example, Skia might be compiled to support CPUs that only have the sse2 instruction set
26  * (https://en.wikipedia.org/wiki/X86_instruction_listings#SSE2_instructions)
27  * but may be run on a more modern CPU that supports AVX2 instructions.
28  * (https://en.wikipedia.org/wiki/Advanced_Vector_Extensions)
29  * SkOpts allow Skia to have two versions of a row-blitting function, one that uses normal C++
30  * code (e.g. loops, scalar integer math) and one that makes use of the AVX2 vector types and
31  * intrinsic functions. This function is declared here in the SkOpts namespace, and then the
32  * implementation (see SkOpts.cpp) is deferred to a function of the same name in the sse2::
33  * namespace (the minimum Skia is compiled with) using DEFINE_DEFAULT.
34  *
35  * All implementations of this blit function are done in a header file file in //src/opts
36  * (e.g. //src/opts/SkBlitRow_opts.h). ifdefs guard each of the implementations, such that only
37  * one implementation is possible for a given SK_CPU_SSE_LEVEL. This header will be compiled
38  * *multiple* times with a different SK_CPU_SSE_LEVEL each compilation.
39  *
40  * Each CPU instruction set that we want specializations for has a .cpp file in //src/opts which
41  * defines an Init() function that replaces the function pointers in the SkOpts namespace with the
42  * ones from the specialized namespace (e.g. hsw::). These .cpp files don't implement the
43  * specializations, they just refer to the specialization created in the header files (e.g.
44  * SkBlitRow_opts.h).
45  *
46  * At compile time:
47  *   - SkOpts.cpp is compiled with the minimum CPU level (e.g. SSE2). Because this
48  *     file includes all the headers in //src/opts/, those headers add "the default implementation"
49  *     of all their functions to the SK_OPTS_NS namespace (e.g. sse2::blit_row_color32).
50  *   - Each of the specialized .cpp files in //src/opts/ are compiled with their respective
51  *     compiler flags. Because the specialized .cpp file includes the headers that implement the
52  *     functions using intrinsics or other CPU-specific code, those specialized functions end up
53  *     in the specialized namespace, e.g. (hsw::blit_row_color32).
54  *
55  * At link time, the default implementations and all specializations of all SkOpts functions are
56  * included in the resulting library/binary file.
57  *
58  * At runtime, SkOpts::Init() will run the appropriate Init functions that the current CPU level
59  * supports specializations for (e.g. Init_hsw, Init_ssse3). Note multiple Init functions can
60  * be called as CPU instruction sets are typically super sets of older instruction sets
61  */
62 
63 struct SkRasterPipelineStage;
64 
65 namespace SkOpts {
66     // Call to replace pointers to portable functions with pointers to CPU-specific functions.
67     // Thread-safe and idempotent.
68     // Called by SkGraphics::Init().
69     void Init();
70 
71     // We can't necessarily express the type of SkRasterPipeline stage functions here,
72     // so we just use this void(*)(void) as a stand-in.
73     using StageFn = void(*)(void);
74     extern StageFn ops_highp[kNumRasterPipelineHighpOps], just_return_highp;
75     extern StageFn ops_lowp [kNumRasterPipelineLowpOps ], just_return_lowp;
76 
77     extern void (*start_pipeline_highp)(size_t,size_t,size_t,size_t, SkRasterPipelineStage*,
78                                         SkSpan<SkRasterPipeline_MemoryCtxPatch>,
79                                         uint8_t*);
80     extern void (*start_pipeline_lowp )(size_t,size_t,size_t,size_t, SkRasterPipelineStage*,
81                                         SkSpan<SkRasterPipeline_MemoryCtxPatch>,
82                                         uint8_t*);
83 
84     extern size_t raster_pipeline_lowp_stride;
85     extern size_t raster_pipeline_highp_stride;
86 }  // namespace SkOpts
87 
88 #endif // SkOpts_DEFINED
89