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;
31IGNORE_UNINITIALIZED_WARNING_START
32template <BlitterMode mode, Blitter_32bppSSE2::ReadMode read_mode, Blitter_32bppSSE2::BlockType bt_last,
bool translucent,
bool animated>
34inline
void Blitter_32bppSSE4_Anim::Draw(const BlitterParams *bp,
ZoomLevel zoom)
36 const uint8_t *
const remap = bp->remap;
37 Colour *dst_line = (
Colour *) bp->dst + bp->top * bp->pitch + bp->left;
38 uint16_t *anim_line = this->anim_buf + this->ScreenToAnimOffset((uint32_t *)bp->dst) + bp->top * this->anim_buf_pitch + bp->left;
39 int effective_width = bp->width;
42 const Blitter_32bppSSE_Base::SpriteData *
const sd = (
const Blitter_32bppSSE_Base::SpriteData *) bp->sprite;
43 const SpriteInfo *
const si = &sd->infos[zoom];
44 const MapValue *src_mv_line = (
const MapValue *) &sd->data[si->mv_offset] + bp->skip_top * si->sprite_width;
45 const Colour *src_rgba_line = (
const Colour *) ((
const uint8_t *) &sd->data[si->sprite_offset] + bp->skip_top * si->sprite_line_size);
47 if (read_mode != RM_WITH_MARGIN) {
48 src_rgba_line += bp->skip_left;
49 src_mv_line += bp->skip_left;
51 const MapValue *src_mv = src_mv_line;
54 const __m128i a_cm = ALPHA_CONTROL_MASK;
55 const __m128i pack_low_cm = PACK_LOW_CONTROL_MASK;
56 const __m128i tr_nom_base = TRANSPARENT_NOM_BASE;
57 const __m128i a_am = ALPHA_AND_MASK;
59 for (
int y = bp->height; y != 0; y--) {
61 const Colour *src = src_rgba_line + META_LENGTH;
63 uint16_t *anim = anim_line;
65 if (read_mode == RM_WITH_MARGIN) {
66 assert(bt_last == BT_NONE);
67 anim += src_rgba_line[0].
data;
68 src += src_rgba_line[0].
data;
69 dst += src_rgba_line[0].
data;
71 const int width_diff = si->sprite_width - bp->width;
72 effective_width = bp->width - (int) src_rgba_line[0].data;
73 const int delta_diff = (int) src_rgba_line[1].data - width_diff;
74 const int new_width = effective_width - delta_diff;
75 effective_width = delta_diff > 0 ? new_width : effective_width;
76 if (effective_width <= 0)
goto next_line;
82 for (uint x = (uint) effective_width; x > 0; x--) {
85 *anim = *(
const uint16_t*) src_mv;
86 *dst = (src_mv->m >=
PALETTE_ANIM_START) ? AdjustBrightneSSE(this->LookupColourInPalette(src_mv->m), src_mv->v) : src->data;
92 if (animated) src_mv++;
100 for (uint x = (uint) effective_width/2; x != 0; x--) {
101 uint32_t mvX2 = *((uint32_t *)
const_cast<MapValue *
>(src_mv));
102 __m128i srcABCD = _mm_loadl_epi64((
const __m128i*) src);
103 __m128i dstABCD = _mm_loadl_epi64((__m128i*) dst);
107 const uint8_t m0 = mvX2;
109 const Colour c0 = (this->LookupColourInPalette(m0).data & 0x00FFFFFF) | (src[0].data & 0xFF000000);
110 InsertFirstUint32(AdjustBrightneSSE(c0, (uint8_t) (mvX2 >> 8)).data, srcABCD);
112 const uint8_t m1 = mvX2 >> 16;
114 const Colour c1 = (this->LookupColourInPalette(m1).data & 0x00FFFFFF) | (src[1].data & 0xFF000000);
115 InsertSecondUint32(AdjustBrightneSSE(c1, (uint8_t) (mvX2 >> 24)).data, srcABCD);
119 const uint8_t a0 = src[0].a;
120 const uint8_t a1 = src[1].a;
124 *(uint32_t*) anim = mvX2;
125 goto bmno_full_opacity;
127 anim01 = (uint16_t) mvX2;
128 }
else if (a0 == 0) {
130 goto bmno_full_transparency;
132 if (a1 == 255) anim[1] = (uint16_t) (mvX2 >> 16);
133 goto bmno_alpha_blend;
137 if (a1 == 255) anim01 |= mvX2 & 0xFFFF0000;
138 *(uint32_t*) anim = anim01;
140 anim[0] = (uint16_t) anim01;
143 if (src[0].a) anim[0] = 0;
144 if (src[1].a) anim[1] = 0;
149 srcABCD = AlphaBlendTwoPixels(srcABCD, dstABCD, a_cm, pack_low_cm, a_am);
151 _mm_storel_epi64((__m128i *) dst, srcABCD);
152bmno_full_transparency:
159 if ((bt_last == BT_NONE && effective_width & 1) || bt_last == BT_ODD) {
162 }
else if (src->a == 255) {
163 *anim = *(
const uint16_t*) src_mv;
164 *dst = (src_mv->m >=
PALETTE_ANIM_START) ? AdjustBrightneSSE(LookupColourInPalette(src_mv->m), src_mv->v) : *src;
168 __m128i dstABCD = _mm_cvtsi32_si128(dst->
data);
170 Colour colour = AdjustBrightneSSE(LookupColourInPalette(src_mv->m), src_mv->v);
172 srcABCD = _mm_cvtsi32_si128(colour.
data);
174 srcABCD = _mm_cvtsi32_si128(src->
data);
176 dst->
data = _mm_cvtsi128_si32(AlphaBlendTwoPixels(srcABCD, dstABCD, a_cm, pack_low_cm, a_am));
182 for (uint x = (uint) effective_width / 2; x != 0; x--) {
183 uint32_t mvX2 = *((uint32_t *)
const_cast<MapValue *
>(src_mv));
184 __m128i srcABCD = _mm_loadl_epi64((
const __m128i*) src);
185 __m128i dstABCD = _mm_loadl_epi64((__m128i*) dst);
188 const uint m0 = (uint8_t) mvX2;
189 const uint r0 = remap[m0];
190 const uint m1 = (uint8_t) (mvX2 >> 16);
191 const uint r1 = remap[m1];
192 if (mvX2 & 0x00FF00FF) {
193 #define CMOV_REMAP(m_colour, m_colour_init, m_src, m_m) \
195 Colour m_colour = m_colour_init; \
197 const Colour srcm = (Colour) (m_src); \
198 const uint m = (uint8_t) (m_m); \
199 const uint r = remap[m]; \
200 const Colour cmap = (this->LookupColourInPalette(r).data & 0x00FFFFFF) | (srcm.data & 0xFF000000); \
201 m_colour = r == 0 ? m_colour : cmap; \
202 m_colour = m != 0 ? m_colour : srcm; \
204#ifdef POINTER_IS_64BIT
205 uint64_t srcs = _mm_cvtsi128_si64(srcABCD);
207 if (animated) dsts = _mm_cvtsi128_si64(dstABCD);
208 uint64_t remapped_src = 0;
209 CMOV_REMAP(c0, animated ? dsts : 0, srcs, mvX2);
210 remapped_src = c0.
data;
211 CMOV_REMAP(c1, animated ? dsts >> 32 : 0, srcs >> 32, mvX2 >> 16);
212 remapped_src |= (uint64_t) c1.
data << 32;
213 srcABCD = _mm_cvtsi64_si128(remapped_src);
216 CMOV_REMAP(c0, animated ? _mm_cvtsi128_si32(dstABCD) : 0, _mm_cvtsi128_si32(srcABCD), mvX2);
217 remapped_src[0] = c0.
data;
218 CMOV_REMAP(c1, animated ? dst[1] : 0, src[1], mvX2 >> 16);
219 remapped_src[1] = c1.
data;
220 srcABCD = _mm_loadl_epi64((__m128i*) &remapped_src);
223 if ((mvX2 & 0xFF00FF00) != 0x80008000) srcABCD = AdjustBrightnessOfTwoPixels(srcABCD, mvX2);
228 const uint8_t a0 = src[0].a;
229 const uint8_t a1 = src[1].a;
230 uint32_t anim01 = mvX2 & 0xFF00FF00;
234 *(uint32_t*) anim = anim01 | (r1 << 16);
235 goto bmcr_full_opacity;
237 }
else if (a0 == 0) {
239 goto bmcr_full_transparency;
242 anim[1] = r1 | (anim01 >> 16);
244 goto bmcr_alpha_blend;
248 if (a1 == 255) anim01 |= r1 << 16;
249 *(uint32_t*) anim = anim01;
251 anim[0] = (uint16_t) anim01;
254 if (src[0].a) anim[0] = 0;
255 if (src[1].a) anim[1] = 0;
260 srcABCD = AlphaBlendTwoPixels(srcABCD, dstABCD, a_cm, pack_low_cm, a_am);
262 _mm_storel_epi64((__m128i *) dst, srcABCD);
263bmcr_full_transparency:
270 if ((bt_last == BT_NONE && effective_width & 1) || bt_last == BT_ODD) {
273 if (src->a == 0)
break;
275 const uint r = remap[src_mv->m];
276 *anim = (animated && src->a == 255) ? r | ((uint16_t) src_mv->v << 8 ) : 0;
278 Colour remapped_colour = AdjustBrightneSSE(this->LookupColourInPalette(r), src_mv->v);
280 *dst = remapped_colour;
282 remapped_colour.a = src->a;
283 srcABCD = _mm_cvtsi32_si128(remapped_colour.
data);
284 goto bmcr_alpha_blend_single;
289 srcABCD = _mm_cvtsi32_si128(src->
data);
291bmcr_alpha_blend_single:
292 __m128i dstABCD = _mm_cvtsi32_si128(dst->
data);
293 srcABCD = AlphaBlendTwoPixels(srcABCD, dstABCD, a_cm, pack_low_cm, a_am);
295 dst->
data = _mm_cvtsi128_si32(srcABCD);
302 for (uint x = (uint) bp->width / 2; x > 0; x--) {
303 __m128i srcABCD = _mm_loadl_epi64((
const __m128i*) src);
304 __m128i dstABCD = _mm_loadl_epi64((__m128i*) dst);
305 _mm_storel_epi64((__m128i *) dst, DarkenTwoPixels(srcABCD, dstABCD, a_cm, tr_nom_base));
309 if (src[-2].a) anim[-2] = 0;
310 if (src[-1].a) anim[-1] = 0;
313 if ((bt_last == BT_NONE && bp->width & 1) || bt_last == BT_ODD) {
314 __m128i srcABCD = _mm_cvtsi32_si128(src->
data);
315 __m128i dstABCD = _mm_cvtsi32_si128(dst->data);
316 dst->data = _mm_cvtsi128_si32(DarkenTwoPixels(srcABCD, dstABCD, a_cm, tr_nom_base));
317 if (src[0].a) anim[0] = 0;
323 for (uint x = (uint) bp->width; x > 0; x--) {
337 for (uint x = (uint) bp->width; x > 0; x--) {
338 if (src_mv->m == 0) {
340 uint8_t g = MakeDark(src->r, src->g, src->
b);
341 *dst = ComposeColourRGBA(g, g, g, src->a, *dst);
345 uint r = remap[src_mv->m];
346 if (r != 0) *dst = ComposeColourPANoCheck(this->AdjustBrightness(this->LookupColourInPalette(r), src_mv->v), src->a, *dst);
356 for (uint x = (uint) bp->width; x > 0; x--) {
371 src_rgba_line = (
const Colour*) ((
const uint8_t*) src_rgba_line + si->sprite_line_size);
372 dst_line += bp->pitch;
373 anim_line += this->anim_buf_pitch;
376IGNORE_UNINITIALIZED_WARNING_STOP
389 Blitter_32bppSSE4::Draw(bp, mode, zoom);
393 const Blitter_32bppSSE_Base::SpriteFlags sprite_flags = ((
const Blitter_32bppSSE_Base::SpriteData *) bp->
sprite)->flags;
398 const BlockType bt_last = (BlockType) (bp->
width & 1);
399 if (bt_last == BT_EVEN) {
400 if (sprite_flags & SF_NO_ANIM) Draw<BM_NORMAL, RM_WITH_SKIP, BT_EVEN, true, false>(bp, zoom);
401 else Draw<BM_NORMAL, RM_WITH_SKIP, BT_EVEN, true, true>(bp, zoom);
403 if (sprite_flags & SF_NO_ANIM) Draw<BM_NORMAL, RM_WITH_SKIP, BT_ODD, true, false>(bp, zoom);
404 else Draw<BM_NORMAL, RM_WITH_SKIP, BT_ODD, true, true>(bp, zoom);
407#ifdef POINTER_IS_64BIT
408 if (sprite_flags & SF_TRANSLUCENT) {
409 if (sprite_flags & SF_NO_ANIM) Draw<BM_NORMAL, RM_WITH_MARGIN, BT_NONE, true, false>(bp, zoom);
410 else Draw<BM_NORMAL, RM_WITH_MARGIN, BT_NONE, true, true>(bp, zoom);
412 if (sprite_flags & SF_NO_ANIM) Draw<BM_NORMAL, RM_WITH_MARGIN, BT_NONE, false, false>(bp, zoom);
413 else Draw<BM_NORMAL, RM_WITH_MARGIN, BT_NONE, false, true>(bp, zoom);
416 if (sprite_flags & SF_NO_ANIM) Draw<BM_NORMAL, RM_WITH_MARGIN, BT_NONE, true, false>(bp, zoom);
417 else Draw<BM_NORMAL, RM_WITH_MARGIN, BT_NONE, true, true>(bp, zoom);
423 if (sprite_flags & SF_NO_REMAP)
goto bm_normal;
425 if (sprite_flags & SF_NO_ANIM) Draw<BM_COLOUR_REMAP, RM_WITH_SKIP, BT_NONE, true, false>(bp, zoom);
426 else Draw<BM_COLOUR_REMAP, RM_WITH_SKIP, BT_NONE, true, true>(bp, zoom);
428 if (sprite_flags & SF_NO_ANIM) Draw<BM_COLOUR_REMAP, RM_WITH_MARGIN, BT_NONE, true, false>(bp, zoom);
429 else Draw<BM_COLOUR_REMAP, RM_WITH_MARGIN, BT_NONE, true, true>(bp, zoom);
432 case BM_TRANSPARENT: Draw<BM_TRANSPARENT, RM_NONE, BT_NONE, true, true>(bp, zoom);
return;
433 case BM_TRANSPARENT_REMAP: Draw<BM_TRANSPARENT_REMAP, RM_NONE, BT_NONE, true, true>(bp, zoom);
return;
434 case BM_CRASH_REMAP: Draw<BM_CRASH_REMAP, RM_NONE, BT_NONE, true, true>(bp, zoom);
return;
435 case BM_BLACK_REMAP: Draw<BM_BLACK_REMAP, RM_NONE, BT_NONE, true, true>(bp, zoom);
return;
A SSE4 32 bpp blitter with animation support.
Functions related to SSE 32 bpp blitter.
BlitterMode
The modes of blitting we can do.
@ BM_BLACK_REMAP
Perform remapping to a completely blackened sprite.
@ BM_COLOUR_REMAP
Perform a colour remapping.
@ BM_TRANSPARENT_REMAP
Perform transparency colour remapping.
@ BM_TRANSPARENT
Perform transparency darkening remapping.
@ BM_CRASH_REMAP
Perform a crash 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.
Structure to access the alpha, red, green, and blue channels from a 32 bit number.
uint32_t data
Conversion of the channel information to a 32 bit number.
uint8_t b
colour channels in BE order
ZoomLevel
All zoom levels we know.