18a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/*
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2008 The Android Open Source Project
38a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
68a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com */
78a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
98a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifndef SkDither_DEFINED
108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define SkDither_DEFINED
118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkColorPriv.h"
138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define SK_DitherValueMax4444   15
158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define SK_DitherValueMax565    7
168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/*  need to use macros for bit-counts for each component, and then
188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    move these into SkColorPriv.h
198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com*/
208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define SkDITHER_R32_FOR_565_MACRO(r, d)    (r + d - (r >> 5))
228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define SkDITHER_G32_FOR_565_MACRO(g, d)    (g + (d >> 1) - (g >> 6))
238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define SkDITHER_B32_FOR_565_MACRO(b, d)    (b + d - (b >> 5))
248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define SkDITHER_A32_FOR_4444_MACRO(a, d)    (a + 15 - (a >> 4))
268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define SkDITHER_R32_FOR_4444_MACRO(r, d)    (r + d - (r >> 4))
278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define SkDITHER_G32_FOR_4444_MACRO(g, d)    (g + d - (g >> 4))
288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define SkDITHER_B32_FOR_4444_MACRO(b, d)    (b + d - (b >> 4))
298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef SK_DEBUG
318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    inline unsigned SkDITHER_R32_FOR_565(unsigned r, unsigned d)
328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    {
338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(d <= SK_DitherValueMax565);
348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkA32Assert(r);
358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        r = SkDITHER_R32_FOR_565_MACRO(r, d);
368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkA32Assert(r);
378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return r;
388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    inline unsigned SkDITHER_G32_FOR_565(unsigned g, unsigned d)
408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    {
418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(d <= SK_DitherValueMax565);
428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkG32Assert(g);
438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        g = SkDITHER_G32_FOR_565_MACRO(g, d);
448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkG32Assert(g);
458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return g;
468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    inline unsigned SkDITHER_B32_FOR_565(unsigned b, unsigned d)
488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    {
498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(d <= SK_DitherValueMax565);
508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkB32Assert(b);
518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        b = SkDITHER_B32_FOR_565_MACRO(b, d);
528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkB32Assert(b);
538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return b;
548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#else
568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    #define SkDITHER_R32_FOR_565(r, d)  SkDITHER_R32_FOR_565_MACRO(r, d)
578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    #define SkDITHER_G32_FOR_565(g, d)  SkDITHER_G32_FOR_565_MACRO(g, d)
588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    #define SkDITHER_B32_FOR_565(b, d)  SkDITHER_B32_FOR_565_MACRO(b, d)
598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define SkDITHER_R32To565(r, d)  SkR32ToR16(SkDITHER_R32_FOR_565(r, d))
628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define SkDITHER_G32To565(g, d)  SkG32ToG16(SkDITHER_G32_FOR_565(g, d))
638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define SkDITHER_B32To565(b, d)  SkB32ToB16(SkDITHER_B32_FOR_565(b, d))
648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define SkDITHER_A32To4444(a, d)  SkA32To4444(SkDITHER_A32_FOR_4444_MACRO(a, d))
668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define SkDITHER_R32To4444(r, d)  SkR32To4444(SkDITHER_R32_FOR_4444_MACRO(r, d))
678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define SkDITHER_G32To4444(g, d)  SkG32To4444(SkDITHER_G32_FOR_4444_MACRO(g, d))
688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define SkDITHER_B32To4444(b, d)  SkB32To4444(SkDITHER_B32_FOR_4444_MACRO(b, d))
698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic inline SkPMColor SkDitherARGB32For565(SkPMColor c, unsigned dither)
718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(dither <= SK_DitherValueMax565);
73fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    unsigned sa = SkGetPackedA32(c);
758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    dither = SkAlphaMul(dither, SkAlpha255To256(sa));
768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    unsigned sr = SkGetPackedR32(c);
788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    unsigned sg = SkGetPackedG32(c);
798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    unsigned sb = SkGetPackedB32(c);
808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    sr = SkDITHER_R32_FOR_565(sr, dither);
818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    sg = SkDITHER_G32_FOR_565(sg, dither);
828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    sb = SkDITHER_B32_FOR_565(sb, dither);
83fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return SkPackARGB32(sa, sr, sg, sb);
858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic inline SkPMColor SkDitherRGB32For565(SkPMColor c, unsigned dither)
888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(dither <= SK_DitherValueMax565);
90fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    unsigned sr = SkGetPackedR32(c);
928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    unsigned sg = SkGetPackedG32(c);
938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    unsigned sb = SkGetPackedB32(c);
948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    sr = SkDITHER_R32_FOR_565(sr, dither);
958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    sg = SkDITHER_G32_FOR_565(sg, dither);
968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    sb = SkDITHER_B32_FOR_565(sb, dither);
97fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return SkPackARGB32(0xFF, sr, sg, sb);
998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic inline uint16_t SkDitherRGBTo565(U8CPU r, U8CPU g, U8CPU b,
1028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                              unsigned dither)
1038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
1048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(dither <= SK_DitherValueMax565);
1058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    r = SkDITHER_R32To565(r, dither);
1068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    g = SkDITHER_G32To565(g, dither);
1078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    b = SkDITHER_B32To565(b, dither);
1088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return SkPackRGB16(r, g, b);
1098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic inline uint16_t SkDitherRGB32To565(SkPMColor c, unsigned dither)
1128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
1138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(dither <= SK_DitherValueMax565);
114fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
1158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    unsigned sr = SkGetPackedR32(c);
1168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    unsigned sg = SkGetPackedG32(c);
1178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    unsigned sb = SkGetPackedB32(c);
1188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    sr = SkDITHER_R32To565(sr, dither);
1198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    sg = SkDITHER_G32To565(sg, dither);
1208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    sb = SkDITHER_B32To565(sb, dither);
121fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
1228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return SkPackRGB16(sr, sg, sb);
1238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic inline uint16_t SkDitherARGB32To565(U8CPU sa, SkPMColor c, unsigned dither)
1268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
127fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com    SkASSERT(dither <= SK_DitherValueMax565);
1288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    dither = SkAlphaMul(dither, SkAlpha255To256(sa));
129fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
1308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    unsigned sr = SkGetPackedR32(c);
1318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    unsigned sg = SkGetPackedG32(c);
1328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    unsigned sb = SkGetPackedB32(c);
1338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    sr = SkDITHER_R32To565(sr, dither);
1348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    sg = SkDITHER_G32To565(sg, dither);
1358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    sb = SkDITHER_B32To565(sb, dither);
136fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
1378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return SkPackRGB16(sr, sg, sb);
1388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////// 4444
1418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic inline SkPMColor16 SkDitherARGB32To4444(U8CPU a, U8CPU r, U8CPU g,
1438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                               U8CPU b, unsigned dither)
1448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
1458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    dither = SkAlphaMul(dither, SkAlpha255To256(a));
1468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    a = SkDITHER_A32To4444(a, dither);
1488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    r = SkDITHER_R32To4444(r, dither);
1498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    g = SkDITHER_G32To4444(g, dither);
1508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    b = SkDITHER_B32To4444(b, dither);
151fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
1528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return SkPackARGB4444(a, r, g, b);
1538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic inline SkPMColor16 SkDitherARGB32To4444(SkPMColor c, unsigned dither)
1568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
1578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    unsigned a = SkGetPackedA32(c);
1588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    unsigned r = SkGetPackedR32(c);
1598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    unsigned g = SkGetPackedG32(c);
1608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    unsigned b = SkGetPackedB32(c);
1618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    dither = SkAlphaMul(dither, SkAlpha255To256(a));
1638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    a = SkDITHER_A32To4444(a, dither);
1658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    r = SkDITHER_R32To4444(r, dither);
1668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    g = SkDITHER_G32To4444(g, dither);
1678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    b = SkDITHER_B32To4444(b, dither);
168fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
1698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return SkPackARGB4444(a, r, g, b);
1708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// TODO: need dither routines for 565 -> 4444
1738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// this toggles between a 4x4 and a 1x4 array
1758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com//#define ENABLE_DITHER_MATRIX_4X4
1768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef ENABLE_DITHER_MATRIX_4X4
1788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    extern const uint8_t gDitherMatrix_4Bit_4X4[4][4];
1798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    extern const uint8_t gDitherMatrix_3Bit_4X4[4][4];
1808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    #define DITHER_4444_SCAN(y) const uint8_t* dither_scan = gDitherMatrix_4Bit_4X4[(y) & 3]
1828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    #define DITHER_565_SCAN(y)  const uint8_t* dither_scan = gDitherMatrix_3Bit_4X4[(y) & 3]
1838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    #define DITHER_VALUE(x) dither_scan[(x) & 3]
1858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#else
1868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    extern const uint16_t gDitherMatrix_4Bit_16[4];
1878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    extern const uint16_t gDitherMatrix_3Bit_16[4];
1888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    #define DITHER_4444_SCAN(y) const uint16_t dither_scan = gDitherMatrix_4Bit_16[(y) & 3]
1908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    #define DITHER_565_SCAN(y)  const uint16_t dither_scan = gDitherMatrix_3Bit_16[(y) & 3]
1918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    #define DITHER_VALUE(x) ((dither_scan >> (((x) & 3) << 2)) & 0xF)
1938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
1948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define DITHER_INC_X(x) ++(x)
1968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
198