13#include "../palette_func.h"
14#include "../video/video_driver.hpp"
15#include "../table/sprites.h"
19#include "../safeguards.h"
22static FBlitter_32bppSSE4_Anim iFBlitter_32bppSSE4_Anim;
31template <BlitterMode mode, Blitter_32bppSSE2::ReadMode read_mode, Blitter_32bppSSE2::BlockType bt_last,
bool translucent,
bool animated>
33inline
void Blitter_32bppSSE4_Anim::Draw(const BlitterParams *bp,
ZoomLevel zoom)
35 const uint8_t *
const remap = bp->remap;
36 Colour *dst_line = (Colour *) bp->dst + bp->top * bp->pitch + bp->left;
37 uint16_t *anim_line = this->anim_buf + this->ScreenToAnimOffset((uint32_t *)bp->dst) + bp->top * this->anim_buf_pitch + bp->left;
38 int effective_width = bp->width;
41 const Blitter_32bppSSE_Base::SpriteData *
const sd = (
const Blitter_32bppSSE_Base::SpriteData *) bp->sprite;
42 const SpriteInfo *
const si = &sd->infos[zoom];
43 const MapValue *src_mv_line = (
const MapValue *) &sd->data[si->mv_offset] + bp->skip_top * si->sprite_width;
44 const Colour *src_rgba_line = (
const Colour *) ((
const uint8_t *) &sd->data[si->sprite_offset] + bp->skip_top * si->sprite_line_size);
46 if (read_mode != RM_WITH_MARGIN) {
47 src_rgba_line += bp->skip_left;
48 src_mv_line += bp->skip_left;
50 const MapValue *src_mv = src_mv_line;
53 const __m128i a_cm = ALPHA_CONTROL_MASK;
54 const __m128i pack_low_cm = PACK_LOW_CONTROL_MASK;
55 const __m128i tr_nom_base = TRANSPARENT_NOM_BASE;
56 const __m128i a_am = ALPHA_AND_MASK;
58 for (
int y = bp->height; y != 0; y--) {
59 Colour *dst = dst_line;
60 const Colour *src = src_rgba_line + META_LENGTH;
62 uint16_t *anim = anim_line;
64 if (read_mode == RM_WITH_MARGIN) {
65 assert(bt_last == BT_NONE);
66 anim += src_rgba_line[0].data;
67 src += src_rgba_line[0].data;
68 dst += src_rgba_line[0].data;
70 const int width_diff = si->sprite_width - bp->width;
71 effective_width = bp->width - (int) src_rgba_line[0].data;
72 const int delta_diff = (int) src_rgba_line[1].data - width_diff;
73 const int new_width = effective_width - delta_diff;
74 effective_width = delta_diff > 0 ? new_width : effective_width;
75 if (effective_width <= 0)
goto next_line;
81 for (uint x = (uint) effective_width; x > 0; x--) {
84 *anim = *(
const uint16_t*) src_mv;
85 *dst = (src_mv->m >=
PALETTE_ANIM_START) ? AdjustBrightneSSE(this->LookupColourInPalette(src_mv->m), src_mv->v) : src->data;
91 if (animated) src_mv++;
99 for (uint x = (uint) effective_width/2; x != 0; x--) {
100 uint32_t mvX2 = *((uint32_t *)
const_cast<MapValue *
>(src_mv));
101 __m128i srcABCD = _mm_loadl_epi64((
const __m128i*) src);
102 __m128i dstABCD = _mm_loadl_epi64((__m128i*) dst);
106 const uint8_t m0 = mvX2;
108 const Colour c0 = (this->LookupColourInPalette(m0).data & 0x00FFFFFF) | (src[0].data & 0xFF000000);
109 InsertFirstUint32(AdjustBrightneSSE(c0, (uint8_t) (mvX2 >> 8)).data, srcABCD);
111 const uint8_t m1 = mvX2 >> 16;
113 const Colour c1 = (this->LookupColourInPalette(m1).data & 0x00FFFFFF) | (src[1].data & 0xFF000000);
114 InsertSecondUint32(AdjustBrightneSSE(c1, (uint8_t) (mvX2 >> 24)).data, srcABCD);
118 const uint8_t a0 = src[0].a;
119 const uint8_t a1 = src[1].a;
123 *(uint32_t*) anim = mvX2;
124 goto bmno_full_opacity;
126 anim01 = (uint16_t) mvX2;
127 }
else if (a0 == 0) {
129 goto bmno_full_transparency;
131 if (a1 == 255) anim[1] = (uint16_t) (mvX2 >> 16);
132 goto bmno_alpha_blend;
136 if (a1 == 255) anim01 |= mvX2 & 0xFFFF0000;
137 *(uint32_t*) anim = anim01;
139 anim[0] = (uint16_t) anim01;
142 if (src[0].a) anim[0] = 0;
143 if (src[1].a) anim[1] = 0;
148 srcABCD = AlphaBlendTwoPixels(srcABCD, dstABCD, a_cm, pack_low_cm, a_am);
150 _mm_storel_epi64((__m128i *) dst, srcABCD);
151bmno_full_transparency:
158 if ((bt_last == BT_NONE && effective_width & 1) || bt_last == BT_ODD) {
161 }
else if (src->a == 255) {
162 *anim = *(
const uint16_t*) src_mv;
163 *dst = (src_mv->m >=
PALETTE_ANIM_START) ? AdjustBrightneSSE(LookupColourInPalette(src_mv->m), src_mv->v) : *src;
167 __m128i dstABCD = _mm_cvtsi32_si128(dst->data);
169 Colour colour = AdjustBrightneSSE(LookupColourInPalette(src_mv->m), src_mv->v);
171 srcABCD = _mm_cvtsi32_si128(colour.data);
173 srcABCD = _mm_cvtsi32_si128(src->data);
175 dst->data = _mm_cvtsi128_si32(AlphaBlendTwoPixels(srcABCD, dstABCD, a_cm, pack_low_cm, a_am));
181 for (uint x = (uint) effective_width / 2; x != 0; x--) {
182 uint32_t mvX2 = *((uint32_t *)
const_cast<MapValue *
>(src_mv));
183 __m128i srcABCD = _mm_loadl_epi64((
const __m128i*) src);
184 __m128i dstABCD = _mm_loadl_epi64((__m128i*) dst);
187 const uint m0 = (uint8_t) mvX2;
188 const uint r0 = remap[m0];
189 const uint m1 = (uint8_t) (mvX2 >> 16);
190 const uint r1 = remap[m1];
191 if (mvX2 & 0x00FF00FF) {
193 #define CMOV_REMAP(m_colour, m_colour_init, m_src, m_m) \
194 Colour m_colour = m_colour_init; \
196 const Colour srcm = (Colour) (m_src); \
197 const uint m = (uint8_t) (m_m); \
198 const uint r = remap[m]; \
199 const Colour cmap = (this->LookupColourInPalette(r).data & 0x00FFFFFF) | (srcm.data & 0xFF000000); \
200 m_colour = r == 0 ? m_colour : cmap; \
201 m_colour = m != 0 ? m_colour : srcm; \
203#ifdef POINTER_IS_64BIT
204 uint64_t srcs = _mm_cvtsi128_si64(srcABCD);
206 if (animated) dsts = _mm_cvtsi128_si64(dstABCD);
207 uint64_t remapped_src = 0;
208 CMOV_REMAP(c0, animated ? dsts : 0, srcs, mvX2);
209 remapped_src = c0.data;
210 CMOV_REMAP(c1, animated ? dsts >> 32 : 0, srcs >> 32, mvX2 >> 16);
211 remapped_src |= (uint64_t) c1.data << 32;
212 srcABCD = _mm_cvtsi64_si128(remapped_src);
214 Colour remapped_src[2];
215 CMOV_REMAP(c0, animated ? _mm_cvtsi128_si32(dstABCD) : 0, _mm_cvtsi128_si32(srcABCD), mvX2);
216 remapped_src[0] = c0.data;
217 CMOV_REMAP(c1, animated ? dst[1] : 0, src[1], mvX2 >> 16);
218 remapped_src[1] = c1.data;
219 srcABCD = _mm_loadl_epi64((__m128i*) &remapped_src);
222 if ((mvX2 & 0xFF00FF00) != 0x80008000) srcABCD = AdjustBrightnessOfTwoPixels(srcABCD, mvX2);
227 const uint8_t a0 = src[0].a;
228 const uint8_t a1 = src[1].a;
229 uint32_t anim01 = mvX2 & 0xFF00FF00;
233 *(uint32_t*) anim = anim01 | (r1 << 16);
234 goto bmcr_full_opacity;
236 }
else if (a0 == 0) {
238 goto bmcr_full_transparency;
241 anim[1] = r1 | (anim01 >> 16);
243 goto bmcr_alpha_blend;
247 if (a1 == 255) anim01 |= r1 << 16;
248 *(uint32_t*) anim = anim01;
250 anim[0] = (uint16_t) anim01;
253 if (src[0].a) anim[0] = 0;
254 if (src[1].a) anim[1] = 0;
259 srcABCD = AlphaBlendTwoPixels(srcABCD, dstABCD, a_cm, pack_low_cm, a_am);
261 _mm_storel_epi64((__m128i *) dst, srcABCD);
262bmcr_full_transparency:
269 if ((bt_last == BT_NONE && effective_width & 1) || bt_last == BT_ODD) {
272 if (src->a == 0)
break;
274 const uint r = remap[src_mv->m];
275 *anim = (animated && src->a == 255) ? r | ((uint16_t) src_mv->v << 8 ) : 0;
277 Colour remapped_colour = AdjustBrightneSSE(this->LookupColourInPalette(r), src_mv->v);
279 *dst = remapped_colour;
281 remapped_colour.a = src->a;
282 srcABCD = _mm_cvtsi32_si128(remapped_colour.data);
283 goto bmcr_alpha_blend_single;
288 srcABCD = _mm_cvtsi32_si128(src->data);
290bmcr_alpha_blend_single:
291 __m128i dstABCD = _mm_cvtsi32_si128(dst->data);
292 srcABCD = AlphaBlendTwoPixels(srcABCD, dstABCD, a_cm, pack_low_cm, a_am);
294 dst->data = _mm_cvtsi128_si32(srcABCD);
301 for (uint x = (uint) bp->width / 2; x > 0; x--) {
302 __m128i srcABCD = _mm_loadl_epi64((
const __m128i*) src);
303 __m128i dstABCD = _mm_loadl_epi64((__m128i*) dst);
304 _mm_storel_epi64((__m128i *) dst, DarkenTwoPixels(srcABCD, dstABCD, a_cm, tr_nom_base));
308 if (src[-2].a) anim[-2] = 0;
309 if (src[-1].a) anim[-1] = 0;
312 if ((bt_last == BT_NONE && bp->width & 1) || bt_last == BT_ODD) {
313 __m128i srcABCD = _mm_cvtsi32_si128(src->data);
314 __m128i dstABCD = _mm_cvtsi32_si128(dst->data);
315 dst->data = _mm_cvtsi128_si32(DarkenTwoPixels(srcABCD, dstABCD, a_cm, tr_nom_base));
316 if (src[0].a) anim[0] = 0;
322 for (uint x = (uint) bp->width; x > 0; x--) {
336 for (uint x = (uint) bp->width; x > 0; x--) {
337 if (src_mv->m == 0) {
339 uint8_t g = MakeDark(src->r, src->g, src->b);
340 *dst = ComposeColourRGBA(g, g, g, src->a, *dst);
344 uint r = remap[src_mv->m];
345 if (r != 0) *dst = ComposeColourPANoCheck(AdjustBrightness(this->LookupColourInPalette(r), src_mv->v), src->a, *dst);
355 for (uint x = (uint) bp->width; x > 0; x--) {
357 *dst = Colour(0, 0, 0);
370 src_rgba_line = (
const Colour*) ((
const uint8_t*) src_rgba_line + si->sprite_line_size);
371 dst_line += bp->pitch;
372 anim_line += this->anim_buf_pitch;
387 Blitter_32bppSSE4::Draw(bp, mode, zoom);
391 const Blitter_32bppSSE_Base::SpriteFlags sprite_flags = ((
const Blitter_32bppSSE_Base::SpriteData *) bp->
sprite)->flags;
396 const BlockType bt_last = (BlockType) (bp->
width & 1);
397 if (bt_last == BT_EVEN) {
398 if (sprite_flags.Test(SpriteFlag::NoAnim)) Draw<BlitterMode::Normal, RM_WITH_SKIP, BT_EVEN, true, false>(bp, zoom);
399 else Draw<BlitterMode::Normal, RM_WITH_SKIP, BT_EVEN, true, true>(bp, zoom);
401 if (sprite_flags.Test(SpriteFlag::NoAnim)) Draw<BlitterMode::Normal, RM_WITH_SKIP, BT_ODD, true, false>(bp, zoom);
402 else Draw<BlitterMode::Normal, RM_WITH_SKIP, BT_ODD, true, true>(bp, zoom);
405#ifdef POINTER_IS_64BIT
406 if (sprite_flags.Test(SpriteFlag::Translucent)) {
407 if (sprite_flags.Test(SpriteFlag::NoAnim)) Draw<BlitterMode::Normal, RM_WITH_MARGIN, BT_NONE, true, false>(bp, zoom);
408 else Draw<BlitterMode::Normal, RM_WITH_MARGIN, BT_NONE, true, true>(bp, zoom);
410 if (sprite_flags.Test(SpriteFlag::NoAnim)) Draw<BlitterMode::Normal, RM_WITH_MARGIN, BT_NONE, false, false>(bp, zoom);
411 else Draw<BlitterMode::Normal, RM_WITH_MARGIN, BT_NONE, false, true>(bp, zoom);
414 if (sprite_flags.Test(SpriteFlag::NoAnim)) Draw<BlitterMode::Normal, RM_WITH_MARGIN, BT_NONE, true, false>(bp, zoom);
415 else Draw<BlitterMode::Normal, RM_WITH_MARGIN, BT_NONE, true, true>(bp, zoom);
421 if (sprite_flags.Test(SpriteFlag::NoRemap))
goto bm_normal;
423 if (sprite_flags.Test(SpriteFlag::NoAnim)) Draw<BlitterMode::ColourRemap, RM_WITH_SKIP, BT_NONE, true, false>(bp, zoom);
424 else Draw<BlitterMode::ColourRemap, RM_WITH_SKIP, BT_NONE, true, true>(bp, zoom);
426 if (sprite_flags.Test(SpriteFlag::NoAnim)) Draw<BlitterMode::ColourRemap, RM_WITH_MARGIN, BT_NONE, true, false>(bp, zoom);
427 else Draw<BlitterMode::ColourRemap, RM_WITH_MARGIN, BT_NONE, true, true>(bp, zoom);
A SSE4 32 bpp blitter with animation support.
Functions related to SSE 32 bpp blitter.
BlitterMode
The modes of blitting we can do.
@ Transparent
Perform transparency darkening remapping.
@ CrashRemap
Perform a crash remapping.
@ BlackRemap
Perform remapping to a completely blackened sprite.
@ TransparentRemap
Perform transparency colour remapping.
@ ColourRemap
Perform a colour remapping.
bool _screen_disable_anim
Disable palette animation (important for 32bpp-anim blitter during giant screenshot)
static constexpr uint8_t PALETTE_ANIM_START
Index in the _palettes array from which all animations are taking places (table/palettes....
uint8_t GetNearestColourIndex(uint8_t r, uint8_t g, uint8_t b)
Get nearest colour palette index from an RGB colour.
Parameters related to blitting.
int skip_left
How much pixels of the source to skip on the left (based on zoom of dst)
int width
The width in pixels that needs to be drawn to dst.
const void * sprite
Pointer to the sprite how ever the encoder stored it.
ZoomLevel
All zoom levels we know.