Rework ChoosePylonPosition to simplify the loop
[openttd/fttd.git] / src / blitter / 32bpp_sse_common.h
blob1b171f7897e3f65e3a4d400712a728eb5981182f
1 /*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6 */
8 /** @file 32bpp_sse_common.h Code common to all SSE 32 bpp blitters. */
10 #ifndef BLITTER_32BPP_SSE_COMMON_H
11 #define BLITTER_32BPP_SSE_COMMON_H
13 #define META_LENGTH 2 ///< Number of uint32 inserted before each line of pixels in a sprite.
14 #define MARGIN_NORMAL_THRESHOLD (zoom == ZOOM_LVL_OUT_32X ? 8 : 4) ///< Minimum width to use margins with BM_NORMAL.
15 #define MARGIN_REMAP_THRESHOLD 4 ///< Minimum width to use margins with BM_COLOUR_REMAP.
17 #define CLEAR_HIGH_BYTE_MASK _mm_setr_epi8(-1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0)
18 #define ALPHA_CONTROL_MASK _mm_setr_epi8( 6, 7, 6, 7, 6, 7, -1, -1, 14, 15, 14, 15, 14, 15, -1, -1)
19 #define PACK_LOW_CONTROL_MASK _mm_setr_epi8( 0, 2, 4, -1, 8, 10, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1)
20 #define PACK_HIGH_CONTROL_MASK _mm_setr_epi8(-1, -1, -1, -1, -1, -1, -1, -1, 0, 2, 4, -1, 8, 10, 12, -1)
21 #define BRIGHTNESS_LOW_CONTROL_MASK _mm_setr_epi8( 1, 2, 1, 2, 1, 2, 0, 2, 3, 2, 3, 2, 3, 2, 0, 2)
22 #define BRIGHTNESS_DIV_CLEANER _mm_setr_epi8(-1, 1, -1, 1, -1, 1, -1, 0, -1, 1, -1, 1, -1, 1, -1, 0)
23 #define OVERBRIGHT_PRESENCE_MASK _mm_setr_epi8( 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0)
24 #define OVERBRIGHT_VALUE_MASK _mm_setr_epi8(-1, 0, -1, 0, -1, 0, 0, 0, -1, 0, -1, 0, -1, 0, 0, 0)
25 #define OVERBRIGHT_CONTROL_MASK _mm_setr_epi8( 0, 1, 0, 1, 0, 1, 7, 7, 2, 3, 2, 3, 2, 3, 7, 7)
26 #define TRANSPARENT_NOM_BASE _mm_setr_epi16(256, 256, 256, 256, 256, 256, 256, 256)
28 template <class T>
29 static inline __m128i AlphaBlendTwoPixels(__m128i src, __m128i dst, const __m128i &distribution_mask, const __m128i &pack_mask)
31 __m128i srcAB = _mm_unpacklo_epi8(src, _mm_setzero_si128()); // PUNPCKLBW, expand each uint8 into uint16
32 __m128i dstAB = _mm_unpacklo_epi8(dst, _mm_setzero_si128());
34 __m128i alphaAB = _mm_cmpgt_epi16(srcAB, _mm_setzero_si128()); // PCMPGTW, if (alpha > 0) a++;
35 alphaAB = _mm_srli_epi16(alphaAB, 15);
36 alphaAB = _mm_add_epi16(alphaAB, srcAB);
37 alphaAB = T::distribute_alpha (alphaAB, distribution_mask);
39 srcAB = _mm_sub_epi16(srcAB, dstAB); // PSUBW, (r - Cr)
40 srcAB = _mm_mullo_epi16(srcAB, alphaAB); // PMULLW, a*(r - Cr)
41 srcAB = _mm_srli_epi16(srcAB, 8); // PSRLW, a*(r - Cr)/256
42 srcAB = _mm_add_epi16(srcAB, dstAB); // PADDW, a*(r - Cr)/256 + Cr
43 return T::pack_unsaturated (srcAB, pack_mask);
46 /* Darken 2 pixels.
47 * rgb = rgb * ((256/4) * 4 - (alpha/4)) / ((256/4) * 4)
49 template <class T>
50 static inline __m128i DarkenTwoPixels(__m128i src, __m128i dst, const __m128i &distribution_mask, const __m128i &tr_nom_base)
52 __m128i srcAB = _mm_unpacklo_epi8(src, _mm_setzero_si128());
53 __m128i dstAB = _mm_unpacklo_epi8(dst, _mm_setzero_si128());
54 __m128i alphaAB = T::distribute_alpha (srcAB, distribution_mask);
55 alphaAB = _mm_srli_epi16(alphaAB, 2); // Reduce to 64 levels of shades so the max value fits in 16 bits.
56 __m128i nom = _mm_sub_epi16(tr_nom_base, alphaAB);
57 dstAB = _mm_mullo_epi16(dstAB, nom);
58 dstAB = _mm_srli_epi16(dstAB, 8);
59 return _mm_packus_epi16(dstAB, dstAB);
62 IGNORE_UNINITIALIZED_WARNING_START
63 template <class T>
64 static Colour ReallyAdjustBrightness(Colour colour, uint8 brightness)
66 uint64 c16 = colour.b | (uint64) colour.g << 16 | (uint64) colour.r << 32;
67 c16 *= brightness;
68 uint64 c16_ob = c16; // Helps out of order execution.
69 c16 /= Blitter_32bppBase::DEFAULT_BRIGHTNESS;
70 c16 &= 0x01FF01FF01FFULL;
72 /* Sum overbright (maximum for each rgb is 508, 9 bits, -255 is changed in -256 so we just have to take the 8 lower bits into account). */
73 c16_ob = (((c16_ob >> (8 + 7)) & 0x0100010001ULL) * 0xFF) & c16;
74 const uint ob = ((uint16) c16_ob + (uint16) (c16_ob >> 16) + (uint16) (c16_ob >> 32)) / 2;
76 const uint32 alpha32 = colour.data & 0xFF000000;
77 __m128i ret;
78 T::load_u64 (c16, ret);
79 if (ob != 0) {
80 __m128i ob128 = _mm_cvtsi32_si128(ob);
81 ob128 = _mm_shufflelo_epi16(ob128, 0xC0);
82 __m128i white = OVERBRIGHT_VALUE_MASK;
83 __m128i c128 = ret;
84 ret = _mm_subs_epu16(white, c128); // PSUBUSW, (255 - rgb)
85 ret = _mm_mullo_epi16(ret, ob128); // PMULLW, ob*(255 - rgb)
86 ret = _mm_srli_epi16(ret, 8); // PSRLW, ob*(255 - rgb)/256
87 ret = _mm_add_epi16(ret, c128); // PADDW, ob*(255 - rgb)/256 + rgb
90 ret = _mm_packus_epi16(ret, ret); // PACKUSWB, saturate and pack.
91 return alpha32 | _mm_cvtsi128_si32(ret);
93 IGNORE_UNINITIALIZED_WARNING_STOP
95 /** ReallyAdjustBrightness() is not called that often.
96 * Inlining this function implies a far jump, which has a huge latency.
98 template <class T>
99 static inline Colour AdjustBrightneSSE(Colour colour, uint8 brightness)
101 /* Shortcut for normal brightness. */
102 if (brightness == Blitter_32bppBase::DEFAULT_BRIGHTNESS) return colour;
104 return ReallyAdjustBrightness<T> (colour, brightness);
107 template <class T>
108 static inline __m128i AdjustBrightnessOfTwoPixels(__m128i from, uint32 brightness)
110 /* The following dataflow differs from the one of AdjustBrightness() only for alpha.
111 * In order to keep alpha in colAB, insert a 1 in a unused brightness byte (a*1->a).
112 * OK, not a 1 but DEFAULT_BRIGHTNESS to compensate the div.
114 brightness &= 0xFF00FF00;
115 brightness += Blitter_32bppBase::DEFAULT_BRIGHTNESS;
117 __m128i colAB = _mm_unpacklo_epi8(from, _mm_setzero_si128());
118 __m128i briAB = _mm_cvtsi32_si128(brightness);
119 briAB = T::shuffle_epi8 (briAB, BRIGHTNESS_LOW_CONTROL_MASK); // DEFAULT_BRIGHTNESS in 0, 0x00 in 2.
120 colAB = _mm_mullo_epi16(colAB, briAB);
121 __m128i colAB_ob = _mm_srli_epi16(colAB, 8 + 7);
122 colAB = _mm_srli_epi16(colAB, 7);
124 /* Sum overbright.
125 * Maximum for each rgb is 508 => 9 bits. The highest bit tells if there is overbright.
126 * -255 is changed in -256 so we just have to take the 8 lower bits into account.
128 colAB = _mm_and_si128(colAB, BRIGHTNESS_DIV_CLEANER);
129 colAB_ob = _mm_and_si128(colAB_ob, OVERBRIGHT_PRESENCE_MASK);
130 colAB_ob = _mm_mullo_epi16(colAB_ob, OVERBRIGHT_VALUE_MASK);
131 colAB_ob = _mm_and_si128(colAB_ob, colAB);
132 __m128i obAB = T::hadd_epi16 (T::hadd_epi16 (colAB_ob, _mm_setzero_si128()), _mm_setzero_si128());
134 obAB = _mm_srli_epi16(obAB, 1); // Reduce overbright strength.
135 obAB = T::shuffle_epi8 (obAB, OVERBRIGHT_CONTROL_MASK);
136 __m128i retAB = OVERBRIGHT_VALUE_MASK; // ob_mask is equal to white.
137 retAB = _mm_subs_epu16(retAB, colAB); // (255 - rgb)
138 retAB = _mm_mullo_epi16(retAB, obAB); // ob*(255 - rgb)
139 retAB = _mm_srli_epi16(retAB, 8); // ob*(255 - rgb)/256
140 retAB = _mm_add_epi16(retAB, colAB); // ob*(255 - rgb)/256 + rgb
142 return _mm_packus_epi16(retAB, retAB);
145 #endif /* BLITTER_32BPP_SSE_COMMON_H */