LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/jumper - SkJumper.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 27 50 54.0 %
Date: 2017-07-14 16:53:18 Functions: 3 7 42.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright 2017 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             : #include "SkColorPriv.h"
       9             : #include "SkCpu.h"
      10             : #include "SkJumper.h"
      11             : #include "SkRasterPipeline.h"
      12             : #include "SkTemplates.h"
      13             : 
      14             : // A debugging mode that helps prioritize porting stages to SkJumper.
      15             : #if 0
      16             :     #include "SkOnce.h"
      17             :     #include <atomic>
      18             : 
      19             :     #define M(st) {0},
      20             :     static std::atomic<int> gMissing[] = { SK_RASTER_PIPELINE_STAGES(M) };
      21             :     #undef M
      22             : 
      23             :     #define M(st) #st,
      24             :     static const char* gNames[] = { SK_RASTER_PIPELINE_STAGES(M) };
      25             :     #undef M
      26             : 
      27             :     #define WHATS_NEXT
      28             : #endif
      29             : 
      30             : // We'll use __has_feature(memory_sanitizer) to detect MSAN.
      31             : // SkJumper_generated.S is not compiled with MSAN, so MSAN would yell really loud.
      32             : #if !defined(__has_feature)
      33             :     #define __has_feature(x) 0
      34             : #endif
      35             : 
      36             : // Stages expect these constants to be set to these values.
      37             : // It's fine to rearrange and add new ones if you update SkJumper_constants.
      38             : using K = const SkJumper_constants;
      39             : static K kConstants = {
      40             :     {0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f},
      41             : };
      42             : 
      43             : #define STAGES(M)         \
      44             :     M(seed_shader)        \
      45             :     M(constant_color)     \
      46             :     M(clear)              \
      47             :     M(srcatop)            \
      48             :     M(dstatop)            \
      49             :     M(srcin)              \
      50             :     M(dstin)              \
      51             :     M(srcout)             \
      52             :     M(dstout)             \
      53             :     M(srcover)            \
      54             :     M(dstover)            \
      55             :     M(modulate)           \
      56             :     M(multiply)           \
      57             :     M(plus_)              \
      58             :     M(screen)             \
      59             :     M(xor_)               \
      60             :     M(darken)             \
      61             :     M(lighten)            \
      62             :     M(difference)         \
      63             :     M(exclusion)          \
      64             :     M(colorburn)          \
      65             :     M(colordodge)         \
      66             :     M(hardlight)          \
      67             :     M(overlay)            \
      68             :     M(softlight)          \
      69             :     M(clamp_0)            \
      70             :     M(clamp_1)            \
      71             :     M(clamp_a)            \
      72             :     M(set_rgb)            \
      73             :     M(swap_rb)            \
      74             :     M(swap)               \
      75             :     M(move_src_dst)       \
      76             :     M(move_dst_src)       \
      77             :     M(premul)             \
      78             :     M(unpremul)           \
      79             :     M(from_srgb)          \
      80             :     M(to_srgb)            \
      81             :     M(from_2dot2)         \
      82             :     M(to_2dot2)           \
      83             :     M(rgb_to_hsl)         \
      84             :     M(hsl_to_rgb)         \
      85             :     M(scale_1_float)      \
      86             :     M(scale_u8)           \
      87             :     M(lerp_1_float)       \
      88             :     M(lerp_u8)            \
      89             :     M(lerp_565)           \
      90             :     M(load_tables)        \
      91             :     M(byte_tables)        \
      92             :     M(byte_tables_rgb)    \
      93             :     M(load_a8)            \
      94             :     M(gather_a8)          \
      95             :     M(store_a8)           \
      96             :     M(load_g8)            \
      97             :     M(gather_g8)          \
      98             :     M(gather_i8)          \
      99             :     M(load_565)           \
     100             :     M(gather_565)         \
     101             :     M(store_565)          \
     102             :     M(load_4444)          \
     103             :     M(gather_4444)        \
     104             :     M(store_4444)         \
     105             :     M(load_8888)          \
     106             :     M(gather_8888)        \
     107             :     M(store_8888)         \
     108             :     M(load_f16)           \
     109             :     M(gather_f16)         \
     110             :     M(store_f16)          \
     111             :     M(load_u16_be)        \
     112             :     M(store_u16_be)       \
     113             :     M(load_f32)           \
     114             :     M(store_f32)          \
     115             :     M(luminance_to_alpha) \
     116             :     M(matrix_2x3)         \
     117             :     M(matrix_3x4)         \
     118             :     M(matrix_4x5)         \
     119             :     M(matrix_perspective) \
     120             :     M(clamp_x)            \
     121             :     M(clamp_y)            \
     122             :     M(repeat_x)           \
     123             :     M(repeat_y)           \
     124             :     M(mirror_x)           \
     125             :     M(mirror_y)           \
     126             :     M(save_xy)            \
     127             :     M(accumulate)         \
     128             :     M(bilinear_nx) M(bilinear_px) M(bilinear_ny) M(bilinear_py)  \
     129             :     M(bicubic_n3x) M(bicubic_n1x) M(bicubic_p1x) M(bicubic_p3x)  \
     130             :     M(bicubic_n3y) M(bicubic_n1y) M(bicubic_p1y) M(bicubic_p3y)  \
     131             :     M(linear_gradient)    \
     132             :     M(linear_gradient_2stops)
     133             : 
     134             : // We can't express the real types of most stage functions portably, so we use a stand-in.
     135             : // We'll only ever call start_pipeline(), which then chains into the rest for us.
     136             : using StageFn = void(void);
     137             : 
     138             : // Some platforms expect C "name" maps to asm "_name", others to "name".
     139             : #if defined(__APPLE__)
     140             :     #define ASM(name, suffix)  sk_##name##_##suffix
     141             : #else
     142             :     #define ASM(name, suffix) _sk_##name##_##suffix
     143             : #endif
     144             : 
     145             : extern "C" {
     146             : 
     147             : #if __has_feature(memory_sanitizer)
     148             :     // We'll just run portable code.
     149             : 
     150             : #elif defined(__aarch64__)
     151             :     size_t ASM(start_pipeline,aarch64)(size_t, void**, K*, size_t);
     152             :     StageFn ASM(just_return,aarch64);
     153             :     #define M(st) StageFn ASM(st,aarch64);
     154             :         STAGES(M)
     155             :     #undef M
     156             : 
     157             : #elif defined(__arm__)
     158             :     size_t ASM(start_pipeline,vfp4)(size_t, void**, K*, size_t);
     159             :     StageFn ASM(just_return,vfp4);
     160             :     #define M(st) StageFn ASM(st,vfp4);
     161             :         STAGES(M)
     162             :     #undef M
     163             : 
     164             : #elif defined(__x86_64__) || defined(_M_X64)
     165             :     size_t ASM(start_pipeline,hsw  )(size_t, void**, K*, size_t);
     166             :     size_t ASM(start_pipeline,avx  )(size_t, void**, K*, size_t);
     167             :     size_t ASM(start_pipeline,sse41)(size_t, void**, K*, size_t);
     168             :     size_t ASM(start_pipeline,sse2 )(size_t, void**, K*, size_t);
     169             : 
     170             :     StageFn ASM(just_return,hsw),
     171             :             ASM(just_return,avx),
     172             :             ASM(just_return,sse41),
     173             :             ASM(just_return,sse2);
     174             : 
     175             :     #define M(st) StageFn ASM(st,hsw);
     176             :         STAGES(M)
     177             :     #undef M
     178             :     #define M(st) StageFn ASM(st,avx);
     179             :         STAGES(M)
     180             :     #undef M
     181             :     #define M(st) StageFn ASM(st,sse41);
     182             :         STAGES(M)
     183             :     #undef M
     184             :     #define M(st) StageFn ASM(st,sse2);
     185             :         STAGES(M)
     186             :     #undef M
     187             : #endif
     188             : 
     189             :     // Portable, single-pixel stages.
     190             :     size_t sk_start_pipeline(size_t, void**, K*, size_t);
     191             :     StageFn sk_just_return;
     192             :     #define M(st) StageFn sk_##st;
     193             :         STAGES(M)
     194             :     #undef M
     195             : }
     196             : 
     197             : // Translate SkRasterPipeline's StockStage enum to StageFn function pointers.
     198             : 
     199             : #if __has_feature(memory_sanitizer)
     200             :     // We'll just run portable code.
     201             : 
     202             : #elif defined(__aarch64__)
     203             :     static StageFn* lookup_aarch64(SkRasterPipeline::StockStage st) {
     204             :         switch (st) {
     205             :             default: return nullptr;
     206             :         #define M(st) case SkRasterPipeline::st: return ASM(st,aarch64);
     207             :             STAGES(M)
     208             :         #undef M
     209             :         }
     210             :     }
     211             : 
     212             : #elif defined(__arm__)
     213             :     static StageFn* lookup_vfp4(SkRasterPipeline::StockStage st) {
     214             :         switch (st) {
     215             :             default: return nullptr;
     216             :         #define M(st) case SkRasterPipeline::st: return ASM(st,vfp4);
     217             :             STAGES(M)
     218             :         #undef M
     219             :         }
     220             :     }
     221             : 
     222             : #elif defined(__x86_64__) || defined(_M_X64)
     223         170 :     static StageFn* lookup_hsw(SkRasterPipeline::StockStage st) {
     224         170 :         switch (st) {
     225             :             default:
     226             :         #ifdef WHATS_NEXT
     227             :                 gMissing[st]++;
     228             :         #endif
     229           0 :                 return nullptr;
     230             :         #define M(st) case SkRasterPipeline::st: return ASM(st,hsw);
     231           0 :             STAGES(M)
     232             :         #undef M
     233             :         }
     234             :     }
     235           0 :     static StageFn* lookup_avx(SkRasterPipeline::StockStage st) {
     236           0 :         switch (st) {
     237             :             default:
     238             :         #ifdef WHATS_NEXT
     239             :                 gMissing[st]++;
     240             :         #endif
     241           0 :                 return nullptr;
     242             :         #define M(st) case SkRasterPipeline::st: return ASM(st,avx);
     243           0 :             STAGES(M)
     244             :         #undef M
     245             :         }
     246             :     }
     247           0 :     static StageFn* lookup_sse41(SkRasterPipeline::StockStage st) {
     248           0 :         switch (st) {
     249             :             default:
     250             :         #ifdef WHATS_NEXT
     251             :                 gMissing[st]++;
     252             :         #endif
     253           0 :                 return nullptr;
     254             :         #define M(st) case SkRasterPipeline::st: return ASM(st,sse41);
     255           0 :             STAGES(M)
     256             :         #undef M
     257             :         }
     258             :     }
     259           0 :     static StageFn* lookup_sse2(SkRasterPipeline::StockStage st) {
     260           0 :         switch (st) {
     261           0 :             default: return nullptr;
     262             :         #define M(st) case SkRasterPipeline::st: return ASM(st,sse2);
     263           0 :             STAGES(M)
     264             :         #undef M
     265             :         }
     266             :     }
     267             : #endif
     268             : 
     269           0 : static StageFn* lookup_portable(SkRasterPipeline::StockStage st) {
     270           0 :     switch (st) {
     271           0 :         default: return nullptr;
     272             :     #define M(st) case SkRasterPipeline::st: return sk_##st;
     273           0 :         STAGES(M)
     274             :     #undef M
     275             :     }
     276             : }
     277             : 
     278          31 : bool SkRasterPipeline::run_with_jumper(size_t x, size_t n) const {
     279             : #ifdef WHATS_NEXT
     280             :     static SkOnce once;
     281             :     once([] {
     282             :         atexit([] {
     283             :             for (int i = 0; i < (int)SK_ARRAY_COUNT(gMissing); i++) {
     284             :                 if (int n = gMissing[i].load()) {
     285             :                     SkDebugf("%10d %s\n", n, gNames[i]);
     286             :                 }
     287             :             }
     288             :         });
     289             :     });
     290             : #endif
     291             : 
     292          62 :     SkAutoSTMalloc<64, void*> program(2*fStages.size() + 1);
     293          31 :     const size_t limit = x+n;
     294             : 
     295             :     auto build_and_run = [&](size_t   min_stride,
     296             :                              StageFn* (*lookup)(SkRasterPipeline::StockStage),
     297             :                              StageFn* just_return,
     298         155 :                              size_t   (*start_pipeline)(size_t, void**, K*, size_t)) {
     299         217 :         if (x + min_stride <= limit) {
     300          62 :             void** ip = program.get();
     301         201 :             for (auto&& st : fStages) {
     302         170 :                 auto fn = lookup(st.stage);
     303         170 :                 if (!fn) {
     304           0 :                     return false;
     305             :                 }
     306         170 :                 *ip++ = (void*)fn;
     307         170 :                 if (st.ctx) {
     308         116 :                     *ip++ = st.ctx;
     309             :                 }
     310             :             }
     311          31 :             *ip = (void*)just_return;
     312             : 
     313          93 :             x = start_pipeline(x, program.get(), &kConstants, limit);
     314             :         }
     315         155 :         return true;
     316          31 :     };
     317             : 
     318             :     // While possible, build and run at full vector stride.
     319             : #if __has_feature(memory_sanitizer)
     320             :     // We'll just run portable code.
     321             : 
     322             : #elif defined(__aarch64__)
     323             :     if (!build_and_run(4, lookup_aarch64, ASM(just_return,aarch64), ASM(start_pipeline,aarch64))) {
     324             :         return false;
     325             :     }
     326             : 
     327             : #elif defined(__arm__)
     328             :     if (1 && SkCpu::Supports(SkCpu::NEON|SkCpu::NEON_FMA|SkCpu::VFP_FP16)) {
     329             :         if (!build_and_run(2, lookup_vfp4, ASM(just_return,vfp4), ASM(start_pipeline,vfp4))) {
     330             :             return false;
     331             :         }
     332             :     }
     333             : 
     334             : #elif defined(__x86_64__) || defined(_M_X64)
     335          31 :     if (1 && SkCpu::Supports(SkCpu::HSW)) {
     336          31 :         if (!build_and_run(1, lookup_hsw, ASM(just_return,hsw), ASM(start_pipeline,hsw))) {
     337           0 :             return false;
     338             :         }
     339             :     }
     340          31 :     if (1 && SkCpu::Supports(SkCpu::AVX)) {
     341          31 :         if (!build_and_run(1, lookup_avx, ASM(just_return,avx), ASM(start_pipeline,avx))) {
     342           0 :             return false;
     343             :         }
     344             :     }
     345          31 :     if (1 && SkCpu::Supports(SkCpu::SSE41)) {
     346          31 :         if (!build_and_run(4, lookup_sse41, ASM(just_return,sse41), ASM(start_pipeline,sse41))) {
     347           0 :             return false;
     348             :         }
     349             :     }
     350          31 :     if (1 && SkCpu::Supports(SkCpu::SSE2)) {
     351          31 :         if (!build_and_run(4, lookup_sse2, ASM(just_return,sse2), ASM(start_pipeline,sse2))) {
     352           0 :             return false;
     353             :         }
     354             :     }
     355             : #endif
     356             : 
     357             :     // Finish up any leftover with portable code one pixel at a time.
     358          31 :     return build_and_run(1, lookup_portable, sk_just_return, sk_start_pipeline);
     359             : }

Generated by: LCOV version 1.13