Skip to content

Commit 3162fcc

Browse files
authored
Merge pull request #2067 from Starbuck5/destination-alpha0
Enforce dest_alpha->0 in opaque dest blitter
2 parents bcfab19 + ad13d70 commit 3162fcc

File tree

2 files changed

+56
-8
lines changed

2 files changed

+56
-8
lines changed

src_c/simd_blitters_avx2.c

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,11 @@ alphablit_alpha_avx2_argb_no_surf_alpha_opaque_dst(SDL_BlitInfo *info)
201201

202202
__m256i src_alpha, temp;
203203

204+
/* The location of the destination's missing alpha channel can be masked
205+
* out by composing all the other channels' masks. */
206+
__m256i mask_out_alpha = _mm256_set1_epi32(
207+
(info->dst->Rmask | info->dst->Gmask | info->dst->Bmask));
208+
204209
/* Original 'Straight Alpha' blending equation:
205210
--------------------------------------------
206211
dstRGB = (srcRGB * srcA) + (dstRGB * (1-srcA))
@@ -237,14 +242,21 @@ alphablit_alpha_avx2_argb_no_surf_alpha_opaque_dst(SDL_BlitInfo *info)
237242
dstRGBA >>= 8
238243
*/
239244

240-
RUN_AVX2_BLITTER(RUN_16BIT_SHUFFLE_OUT(
241-
src_alpha = _mm256_shuffle_epi8(shuff_src, shuff_out_alpha);
242-
temp = _mm256_sub_epi16(shuff_src, shuff_dst);
243-
temp = _mm256_mullo_epi16(temp, src_alpha);
244-
shuff_dst = _mm256_slli_epi16(shuff_dst, 8);
245-
shuff_dst = _mm256_add_epi16(shuff_dst, temp);
246-
shuff_dst = _mm256_add_epi16(shuff_dst, shuff_src);
247-
shuff_dst = _mm256_srli_epi16(shuff_dst, 8);))
245+
RUN_AVX2_BLITTER(
246+
RUN_16BIT_SHUFFLE_OUT(
247+
src_alpha = _mm256_shuffle_epi8(shuff_src, shuff_out_alpha);
248+
temp = _mm256_sub_epi16(shuff_src, shuff_dst);
249+
temp = _mm256_mullo_epi16(temp, src_alpha);
250+
shuff_dst = _mm256_slli_epi16(shuff_dst, 8);
251+
shuff_dst = _mm256_add_epi16(shuff_dst, temp);
252+
shuff_dst = _mm256_add_epi16(shuff_dst, shuff_src);
253+
shuff_dst = _mm256_srli_epi16(shuff_dst, 8););
254+
255+
/* It seems like the destination pixel alpha shouldn't matter, since
256+
* it is RGBX, but it has to be zero. I suspect this is a weak spot
257+
* in the other blitting routines, that they need alpha 0 from these
258+
* surfaces. */
259+
pixels_dst = _mm256_and_si256(pixels_dst, mask_out_alpha);)
248260
}
249261
#else
250262
void

test/surface_test.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import gc
1919
import weakref
2020
import ctypes
21+
import itertools
2122

2223
IS_PYPY = "PyPy" == platform.python_implementation()
2324

@@ -1084,6 +1085,41 @@ def test_blit__SRCALPHA32_to_8(self):
10841085
source.set_at((0, 0), test_color)
10851086
target.blit(source, (0, 0))
10861087

1088+
def test_blit__SCALPHA32_TO_OPAQUE32(self):
1089+
# Apparently these types of blits need to write 0 to the destination's
1090+
# alpha channel (it's not really an alpha channel but it's treated like one)
1091+
# See https://github.com/pygame-community/pygame-ce/pull/2067
1092+
1093+
alphas = [0, 10, 50, 122, 240, 255]
1094+
1095+
combinations = list(itertools.combinations_with_replacement(alphas, 2))
1096+
width = len(combinations)
1097+
1098+
# masks explicitly specified so direct pixel access of bytes below is
1099+
# gauranteed to be stable
1100+
surf1 = pygame.Surface((width, 1), depth=32, masks=(0xFF0000, 0xFF00, 0xFF, 0))
1101+
surf2 = pygame.Surface(
1102+
(width, 1),
1103+
pygame.SRCALPHA,
1104+
depth=32,
1105+
masks=(0xFF0000, 0xFF00, 0xFF, 0xFF000000),
1106+
)
1107+
1108+
for i in range(width):
1109+
alpha1, alpha2 = combinations[i]
1110+
surf1.set_at((i, 0), (0, 0, 0, alpha1))
1111+
surf2.set_at((i, 0), (0, 0, 0, alpha2))
1112+
1113+
surf1.blit(surf2, (0, 0))
1114+
1115+
# Why use get_buffer?
1116+
# get_at for RGBX surfaces seems to always think A=255, regardless
1117+
# of bytes in surface, which makes sense.
1118+
surf1_bytes = surf1.get_buffer().raw
1119+
for i in range(width):
1120+
# +3 gets the "alpha channel" in this pixel format
1121+
assert surf1_bytes[i * 4 + 3] == 0
1122+
10871123

10881124
class GeneralSurfaceTests(unittest.TestCase):
10891125
@unittest.skipIf(

0 commit comments

Comments
 (0)