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/core/SkTypes.h" 12 #include "include/private/SkOpts_spi.h" 13 #include "src/core/SkRasterPipelineOpList.h" 14 #include "src/core/SkXfermodePriv.h" 15 16 /** 17 * SkOpts (short for SkOptimizations) is a mechanism where we can ship with multiple implementations 18 * of a set of functions and dynamically choose the best one at runtime (e.g. the call to 19 * SkGraphics::Init(), which calls SkOpts::Init()) depending on the detected CPU features. This is 20 * also referred to as having "specializations" of a given function. 21 * 22 * For example, Skia might be compiled to support CPUs that only have the sse2 instruction set 23 * (https://en.wikipedia.org/wiki/X86_instruction_listings#SSE2_instructions) 24 * but may be run on a more modern CPU that supports sse42 instructions. 25 * (https://en.wikipedia.org/wiki/SSE4) 26 * SkOpts allow Skia to have two versions of a CRC32 checksum function, one that uses normal C++ 27 * code (e.g. loops, bit operations, table lookups) and one that makes use of the _mm_crc32_u64 28 * intrinsic function which uses the SSE4.2 crc32 machine instruction under the hood. This hash 29 * function is declared here in the SkOpts namespace, and then the implementation (see SkOpts.cpp) 30 * is deferred to a function of the same name in the sse2:: namespace (the minimum Skia is compiled 31 * with) using DEFINE_DEFAULT. 32 * 33 * All implementations of this hash function are done in a header file file in //src/opts 34 * (e.g. //src/opts/SkChecksum_opts.h). ifdefs guard each of the implementations, such that only 35 * one implementation is possible for a given SK_CPU_SSE_LEVEL. This header will be compiled 36 * *multiple* times with a different SK_CPU_SSE_LEVEL each compilation. 37 * 38 * Each CPU instruction set that we want specializations for has a .cpp file in //src/opts which 39 * defines an Init() function that replaces the function pointers in the SkOpts namespace with the 40 * ones from the specialized namespace (e.g. sse42::). These .cpp files don't implement the 41 * specializations, they just refer to the specialization created in the header files (e.g. 42 * SkChecksum_opts.h). 43 * 44 * At compile time: 45 * - SkOpts.cpp is compiled with the minimum CPU level (e.g. SSE2). Because this 46 * file includes all the headers in //src/opts/, those headers add "the default implementation" 47 * of all their functions to the SK_OPTS_NS namespace (e.g. sse2::hash_fn). 48 * - Each of the specialized .cpp files in //src/opts/ are compiled with their respective 49 * compiler flags. Because the specialized .cpp file includes the headers that implement the 50 * functions using intrinsics or other CPU-specific code, those specialized functions end up 51 * in the specialized namespace, e.g. (sse42::hash_fn). 52 * 53 * At link time, the default implementations and all specializations of all SkOpts functions are 54 * included in the resulting library/binary file. 55 * 56 * At runtime, SkOpts::Init() will run the appropriate Init functions that the current CPU level 57 * supports specializations for (e.g. Init_sse42, Init_ssse3). Note multiple Init functions can 58 * be called as CPU instruction sets are typically super sets of older instruction sets 59 */ 60 61 struct SkBitmapProcState; 62 struct SkRasterPipelineStage; 63 namespace skvm { 64 struct InterpreterInstruction; 65 class TraceHook; 66 } 67 68 namespace SkOpts { 69 // Call to replace pointers to portable functions with pointers to CPU-specific functions. 70 // Thread-safe and idempotent. 71 // Called by SkGraphics::Init(). 72 void Init(); 73 74 // Declare function pointers here... 75 76 // May return nullptr if we haven't specialized the given Mode. 77 extern SkXfermode* (*create_xfermode)(SkBlendMode); 78 79 extern void (*blit_mask_d32_a8)(SkPMColor*, size_t, const SkAlpha*, size_t, SkColor, int, int); 80 extern void (*blit_row_color32)(SkPMColor*, const SkPMColor*, int, SkPMColor); 81 extern void (*blit_row_s32a_opaque)(SkPMColor*, const SkPMColor*, int, U8CPU); 82 83 // Swizzle input into some sort of 8888 pixel, {premul,unpremul} x {rgba,bgra}. 84 typedef void (*Swizzle_8888_u32)(uint32_t*, const uint32_t*, int); 85 extern Swizzle_8888_u32 RGBA_to_BGRA, // i.e. just swap RB 86 RGBA_to_rgbA, // i.e. just premultiply 87 RGBA_to_bgrA, // i.e. swap RB and premultiply 88 inverted_CMYK_to_RGB1, // i.e. convert color space 89 inverted_CMYK_to_BGR1; // i.e. convert color space 90 91 typedef void (*Swizzle_8888_u8)(uint32_t*, const uint8_t*, int); 92 extern Swizzle_8888_u8 RGB_to_RGB1, // i.e. insert an opaque alpha 93 RGB_to_BGR1, // i.e. swap RB and insert an opaque alpha 94 gray_to_RGB1, // i.e. expand to color channels + an opaque alpha 95 grayA_to_RGBA, // i.e. expand to color channels 96 grayA_to_rgbA; // i.e. expand to color channels and premultiply 97 98 extern void (*memset16)(uint16_t[], uint16_t, int); 99 extern void (*memset32)(uint32_t[], uint32_t, int); 100 extern void (*memset64)(uint64_t[], uint64_t, int); 101 102 extern void (*rect_memset16)(uint16_t[], uint16_t, int, size_t, int); 103 extern void (*rect_memset32)(uint32_t[], uint32_t, int, size_t, int); 104 extern void (*rect_memset64)(uint64_t[], uint64_t, int, size_t, int); 105 106 extern float (*cubic_solver)(float, float, float, float); 107 108 static inline uint32_t hash(const void* data, size_t bytes, uint32_t seed=0) { 109 // hash_fn is defined in SkOpts_spi.h so it can be used by //modules 110 return hash_fn(data, bytes, seed); 111 } 112 113 // SkBitmapProcState optimized Shader, Sample, or Matrix procs. 114 extern void (*S32_alpha_D32_filter_DX)(const SkBitmapProcState&, 115 const uint32_t* xy, int count, SkPMColor*); 116 extern void (*S32_alpha_D32_filter_DXDY)(const SkBitmapProcState&, 117 const uint32_t* xy, int count, SkPMColor*); 118 119 // We can't necessarily express the type of SkRasterPipeline stage functions here, 120 // so we just use this void(*)(void) as a stand-in. 121 using StageFn = void(*)(void); 122 extern StageFn ops_highp[kNumRasterPipelineHighpOps], just_return_highp; 123 extern StageFn ops_lowp [kNumRasterPipelineLowpOps ], just_return_lowp; 124 125 extern void (*start_pipeline_highp)(size_t,size_t,size_t,size_t, SkRasterPipelineStage*); 126 extern void (*start_pipeline_lowp )(size_t,size_t,size_t,size_t, SkRasterPipelineStage*); 127 128 extern size_t raster_pipeline_lowp_stride; 129 extern size_t raster_pipeline_highp_stride; 130 131 extern void (*interpret_skvm)(const skvm::InterpreterInstruction insts[], int ninsts, 132 int nregs, int loop, const int strides[], 133 skvm::TraceHook* traceHooks[], int nTraceHooks, 134 int nargs, int n, void* args[]); 135 } // namespace SkOpts 136 137 #endif // SkOpts_DEFINED 138