mirror of
https://github.com/genodelabs/genode.git
synced 2025-03-03 21:20:41 +00:00
blit: Blit::blend_xrgb_a
This commit adds support for SIMD-based alpha blending, which speeds up the alpha-compositing of the nitpicker GUI server by circa 300% on ARM Neon and x86_64 using SSE4.1 Issue #5428
This commit is contained in:
parent
19717ab74e
commit
21acbed65b
@ -57,6 +57,15 @@ namespace Blit {
|
|||||||
{
|
{
|
||||||
_b2f<Slow>(surface, texture, rect, rotate, flip);
|
_b2f<Slow>(surface, texture, rect, rotate, flip);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Blend a sequence of pixels to 'dst' according to discrete alpha values
|
||||||
|
*/
|
||||||
|
static inline void blend_xrgb_a(uint32_t *dst, unsigned n,
|
||||||
|
uint32_t const *pixel, uint8_t const *alpha)
|
||||||
|
{
|
||||||
|
Slow::Blend::xrgb_a(dst, n, pixel, alpha);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* _INCLUDE__BLIT_H_ */
|
#endif /* _INCLUDE__BLIT_H_ */
|
||||||
|
@ -31,6 +31,16 @@ namespace Blit { struct Neon; }
|
|||||||
|
|
||||||
struct Blit::Neon
|
struct Blit::Neon
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Helper for printing the raw lower 64 bits of a vector via Genode::Output
|
||||||
|
*/
|
||||||
|
template <typename T> union Printable
|
||||||
|
{
|
||||||
|
Genode::uint64_t u64; T vec;
|
||||||
|
Printable(T vec) : vec(vec) { }
|
||||||
|
void print(Output &out) const { Genode::print(out, Hex(u64)); }
|
||||||
|
};
|
||||||
|
|
||||||
static inline uint32x4_t _reversed(uint32x4_t const v)
|
static inline uint32x4_t _reversed(uint32x4_t const v)
|
||||||
{
|
{
|
||||||
return vrev64q_u32(vcombine_u32(vget_high_u32(v), vget_low_u32(v)));
|
return vrev64q_u32(vcombine_u32(vget_high_u32(v), vget_low_u32(v)));
|
||||||
@ -163,6 +173,7 @@ struct Blit::Neon
|
|||||||
|
|
||||||
struct B2f;
|
struct B2f;
|
||||||
struct B2f_flip;
|
struct B2f_flip;
|
||||||
|
struct Blend;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -291,4 +302,83 @@ void Blit::Neon::B2f_flip::r270(uint32_t *dst, unsigned const dst_w,
|
|||||||
_rotate(src_ptr4, dst_ptr4, steps, w, h);
|
_rotate(src_ptr4, dst_ptr4, steps, w, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct Blit::Neon::Blend
|
||||||
|
{
|
||||||
|
static inline void xrgb_a(uint32_t *, unsigned, uint32_t const *, uint8_t const *);
|
||||||
|
|
||||||
|
__attribute__((optimize("-O3")))
|
||||||
|
static inline uint32_t _mix(uint32_t bg, uint32_t fg, uint8_t alpha)
|
||||||
|
{
|
||||||
|
if (__builtin_expect(alpha == 0, false))
|
||||||
|
return bg;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compute r, g, b in the lower 3 16-bit lanes.
|
||||||
|
* The upper 5 lanes are unused.
|
||||||
|
*/
|
||||||
|
uint16x8_t const
|
||||||
|
a = vmovl_u8(vdup_n_u8(alpha)),
|
||||||
|
s = vmovl_u8(vcreate_u8(fg)),
|
||||||
|
d = vmovl_u8(vcreate_u8(bg)),
|
||||||
|
ar = vaddq_u16(vdupq_n_u16(1), a), /* for rounding up */
|
||||||
|
nar = vsubq_u16(vdupq_n_u16(256), a), /* 1.0 - alpha */
|
||||||
|
res = vaddq_u16(vmulq_u16(s, ar), vmulq_u16(d, nar));
|
||||||
|
|
||||||
|
return uint32_t(::uint64_t(vshrn_n_u16(res, 8)));
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((optimize("-O3")))
|
||||||
|
static inline void _mix_8(uint32_t *bg, uint32_t const *fg, uint8_t const *alpha)
|
||||||
|
{
|
||||||
|
/* fetch 8 alpha values */
|
||||||
|
uint16x8_t const a = vmovl_u8(*(uint8x8_t *)alpha);
|
||||||
|
|
||||||
|
/* skip block if entirely transparent */
|
||||||
|
if (__builtin_expect(vmaxvq_u16(a) == 0, false))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* load 8 source and destination pixels */
|
||||||
|
uint8x8x4_t const s = vld4_u8((uint8_t const *)fg);
|
||||||
|
uint8x8x4_t d = vld4_u8((uint8_t const *)bg);
|
||||||
|
|
||||||
|
/* extend r, g, b components from uint8_t to uint16_t */
|
||||||
|
uint16x8x4_t const
|
||||||
|
s_rgb { vmovl_u8(s.val[0]), vmovl_u8(s.val[1]), vmovl_u8(s.val[2]) },
|
||||||
|
d_rgb { vmovl_u8(d.val[0]), vmovl_u8(d.val[1]), vmovl_u8(d.val[2]) };
|
||||||
|
|
||||||
|
/* load 8 alpha values, prepare as factors for source and destination */
|
||||||
|
uint16x8_t const
|
||||||
|
sa = vaddq_u16(vdupq_n_u16(1), a),
|
||||||
|
da = vsubq_u16(vdupq_n_u16(256), a); /* 1.0 - alpha */
|
||||||
|
|
||||||
|
/* mix components, keeping only their upper 8 bits */
|
||||||
|
for (unsigned i = 0; i < 3; i++)
|
||||||
|
d.val[i] = vshrn_n_u16(vaddq_u16(vmulq_u16(d_rgb.val[i], da),
|
||||||
|
vmulq_u16(s_rgb.val[i], sa)), 8);
|
||||||
|
/* write 8 pixels */
|
||||||
|
vst4_u8((uint8_t *)bg, d);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
__attribute__((optimize("-O3")))
|
||||||
|
void Blit::Neon::Blend::xrgb_a(uint32_t *dst, unsigned n,
|
||||||
|
uint32_t const *pixel, uint8_t const *alpha)
|
||||||
|
{
|
||||||
|
int const prefetch_distance = 16; /* cache line / 32-bit pixel size */
|
||||||
|
for (; n > prefetch_distance; n -= 8, dst += 8, pixel += 8, alpha += 8) {
|
||||||
|
__builtin_prefetch(dst + prefetch_distance);
|
||||||
|
__builtin_prefetch(pixel + prefetch_distance);
|
||||||
|
__builtin_prefetch(alpha + prefetch_distance);
|
||||||
|
_mix_8(dst, pixel, alpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; n > 7; n -= 8, dst += 8, pixel += 8, alpha += 8)
|
||||||
|
_mix_8(dst, pixel, alpha);
|
||||||
|
|
||||||
|
for (; n--; dst++, pixel++, alpha++)
|
||||||
|
*dst = _mix(*dst, *pixel, *alpha);
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* _INCLUDE__BLIT__INTERNAL__NEON_H_ */
|
#endif /* _INCLUDE__BLIT__INTERNAL__NEON_H_ */
|
||||||
|
@ -44,6 +44,7 @@ struct Blit::Slow
|
|||||||
{
|
{
|
||||||
struct B2f;
|
struct B2f;
|
||||||
struct B2f_flip;
|
struct B2f_flip;
|
||||||
|
struct Blend;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -128,4 +129,33 @@ void Blit::Slow::B2f_flip::r270(uint32_t *dst, unsigned dst_w,
|
|||||||
_write_lines(src, src_w, dst, w, h, -8*dst_w, -1);
|
_write_lines(src, src_w, dst, w, h, -8*dst_w, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct Blit::Slow::Blend
|
||||||
|
{
|
||||||
|
static inline void xrgb_a(uint32_t *, unsigned, uint32_t const *, uint8_t const *);
|
||||||
|
|
||||||
|
__attribute__((optimize("-O3")))
|
||||||
|
static inline uint32_t _blend(uint32_t xrgb, unsigned alpha)
|
||||||
|
{
|
||||||
|
return (alpha * ((xrgb & 0xff00) >> 8) & 0xff00)
|
||||||
|
| (((alpha * (xrgb & 0xff00ff)) >> 8) & 0xff00ff);
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((optimize("-O3")))
|
||||||
|
static inline uint32_t _mix(uint32_t bg, uint32_t fg, unsigned alpha)
|
||||||
|
{
|
||||||
|
return (__builtin_expect(alpha == 0, false))
|
||||||
|
? bg : _blend(bg, 256 - alpha) + _blend(fg, alpha + 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
__attribute__((optimize("-O3")))
|
||||||
|
void Blit::Slow::Blend::xrgb_a(uint32_t *dst, unsigned n,
|
||||||
|
uint32_t const *pixel, uint8_t const *alpha)
|
||||||
|
{
|
||||||
|
for (; n--; dst++, pixel++, alpha++)
|
||||||
|
*dst = _mix(*dst, *pixel, *alpha);
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* _INCLUDE__BLIT__INTERNAL__SLOW_H_ */
|
#endif /* _INCLUDE__BLIT__INTERNAL__SLOW_H_ */
|
||||||
|
@ -36,6 +36,31 @@ namespace Blit { struct Sse4; };
|
|||||||
|
|
||||||
struct Blit::Sse4
|
struct Blit::Sse4
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Padded hex output utility
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
struct Phex : Hex { explicit Phex(T v) : Hex(v, OMIT_PREFIX, PAD) { } };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vector output utility
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
union Vec_as
|
||||||
|
{
|
||||||
|
__m128i v;
|
||||||
|
static constexpr unsigned N = 128/(8*sizeof(T));
|
||||||
|
T u[N];
|
||||||
|
|
||||||
|
Vec_as(__m128i v) : v(v) { }
|
||||||
|
|
||||||
|
void print(Output &out) const
|
||||||
|
{
|
||||||
|
for (unsigned i = 0; i < N; i++)
|
||||||
|
Genode::print(out, Phex(u[i]), i < (N-1) ? "." : "");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
union Tile_4x4 { __m128i pi[4]; __m128 ps[4]; };
|
union Tile_4x4 { __m128i pi[4]; __m128 ps[4]; };
|
||||||
|
|
||||||
struct Src_ptr4
|
struct Src_ptr4
|
||||||
@ -132,6 +157,7 @@ struct Blit::Sse4
|
|||||||
|
|
||||||
struct B2f;
|
struct B2f;
|
||||||
struct B2f_flip;
|
struct B2f_flip;
|
||||||
|
struct Blend;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -260,4 +286,93 @@ void Blit::Sse4::B2f_flip::r270(uint32_t *dst, unsigned dst_w,
|
|||||||
_rotate(src_ptr4, dst_ptr4, steps, w, h);
|
_rotate(src_ptr4, dst_ptr4, steps, w, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* _INCLUDE__BLIT__INTERNAL__SSE4_H_ */
|
|
||||||
|
struct Blit::Sse4::Blend
|
||||||
|
{
|
||||||
|
static inline void xrgb_a(uint32_t *, unsigned, uint32_t const *, uint8_t const *);
|
||||||
|
|
||||||
|
__attribute__((optimize("-O3")))
|
||||||
|
static inline uint32_t _blend(uint32_t xrgb, unsigned alpha)
|
||||||
|
{
|
||||||
|
return (alpha * ((xrgb & 0xff00) >> 8) & 0xff00)
|
||||||
|
| (((alpha * (xrgb & 0xff00ff)) >> 8) & 0xff00ff);
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((optimize("-O3")))
|
||||||
|
static inline uint32_t _mix(uint32_t bg, uint32_t fg, unsigned alpha)
|
||||||
|
{
|
||||||
|
return (__builtin_expect(alpha == 0, false))
|
||||||
|
? bg : _blend(bg, 256 - alpha) + _blend(fg, alpha + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Mix_masks
|
||||||
|
{
|
||||||
|
/* masks for distributing alpha values to 16-bit r, g, b lanes */
|
||||||
|
__m128i const a01 = _mm_set_epi32(0x03020302, 0x03020302, 0x01000100, 0x01000100);
|
||||||
|
__m128i const a23 = _mm_set_epi32(0x07060706, 0x07060706, 0x05040504, 0x05040504);
|
||||||
|
};
|
||||||
|
|
||||||
|
__attribute__((optimize("-O3")))
|
||||||
|
static inline void _mix_4(uint32_t *, uint32_t const *, uint8_t const *, Mix_masks const);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
__attribute__((optimize("-O3")))
|
||||||
|
void Blit::Sse4::Blend::_mix_4(uint32_t *bg, uint32_t const *fg, uint8_t const *alpha, Mix_masks const masks)
|
||||||
|
{
|
||||||
|
uint32_t const a_u8_x4 = *(uint32_t const *)alpha;
|
||||||
|
|
||||||
|
if (__builtin_expect(a_u8_x4 == 0, false))
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto upper_half = [&] (__m128i const v) { return _mm_shuffle_epi32(v, 2 + (3<<2)); };
|
||||||
|
|
||||||
|
__m128i const
|
||||||
|
/* load four foreground pixel, background pixel, and alpha values */
|
||||||
|
fg_u8_4x4 = _mm_loadu_si128((__m128i const *)fg),
|
||||||
|
bg_u8_4x4 = _mm_loadu_si128((__m128i const *)bg),
|
||||||
|
|
||||||
|
/* extract first and second pair of pixel values */
|
||||||
|
fg01_u16_4x2 = _mm_cvtepu8_epi16(fg_u8_4x4),
|
||||||
|
fg23_u16_4x2 = _mm_cvtepu8_epi16(upper_half(fg_u8_4x4)),
|
||||||
|
bg01_u16_4x2 = _mm_cvtepu8_epi16(bg_u8_4x4),
|
||||||
|
bg23_u16_4x2 = _mm_cvtepu8_epi16(upper_half(bg_u8_4x4)),
|
||||||
|
|
||||||
|
/* prepare 4 destination and source alpha values */
|
||||||
|
a_u16_x4 = _mm_cvtepu8_epi16(_mm_set1_epi32(a_u8_x4)),
|
||||||
|
da_u16_x4 = _mm_sub_epi16(_mm_set1_epi16(256), a_u16_x4),
|
||||||
|
sa_u16_x4 = _mm_add_epi16(a_u16_x4, _mm_set1_epi16(1)),
|
||||||
|
|
||||||
|
/* mix first pixel pair */
|
||||||
|
da01_u16_4x2 = _mm_shuffle_epi8(da_u16_x4, masks.a01),
|
||||||
|
sa01_u16_4x2 = _mm_shuffle_epi8(sa_u16_x4, masks.a01),
|
||||||
|
mixed01 = _mm_add_epi16(_mm_mullo_epi16(fg01_u16_4x2, sa01_u16_4x2),
|
||||||
|
_mm_mullo_epi16(bg01_u16_4x2, da01_u16_4x2)),
|
||||||
|
|
||||||
|
/* mix second pixel pair */
|
||||||
|
da23_u16_4x2 = _mm_shuffle_epi8(da_u16_x4, masks.a23),
|
||||||
|
sa23_u16_4x2 = _mm_shuffle_epi8(sa_u16_x4, masks.a23),
|
||||||
|
mixed23 = _mm_add_epi16(_mm_mullo_epi16(fg23_u16_4x2, sa23_u16_4x2),
|
||||||
|
_mm_mullo_epi16(bg23_u16_4x2, da23_u16_4x2)),
|
||||||
|
|
||||||
|
result_4x4 = _mm_packus_epi16(_mm_srli_epi16(mixed01, 8),
|
||||||
|
_mm_srli_epi16(mixed23, 8));
|
||||||
|
|
||||||
|
_mm_storeu_si128((__m128i *)bg, result_4x4);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
__attribute__((optimize("-O3")))
|
||||||
|
void Blit::Sse4::Blend::xrgb_a(uint32_t *dst, unsigned n,
|
||||||
|
uint32_t const *pixel, uint8_t const *alpha)
|
||||||
|
{
|
||||||
|
Mix_masks const mix_masks { };
|
||||||
|
|
||||||
|
for (; n > 3; n -= 4, dst += 4, pixel += 4, alpha += 4)
|
||||||
|
_mix_4(dst, pixel, alpha, mix_masks);
|
||||||
|
|
||||||
|
for (; n--; dst++, pixel++, alpha++)
|
||||||
|
*dst = _mix(*dst, *pixel, *alpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _INCLUDE__BLIT__INTERNAL__SSE3_H_ */
|
||||||
|
@ -16,10 +16,12 @@
|
|||||||
|
|
||||||
#include <blit/types.h>
|
#include <blit/types.h>
|
||||||
#include <blit/internal/neon.h>
|
#include <blit/internal/neon.h>
|
||||||
|
#include <blit/internal/slow.h>
|
||||||
|
|
||||||
namespace Blit {
|
namespace Blit {
|
||||||
|
|
||||||
static inline void back2front(auto &&... args) { _b2f<Neon>(args...); }
|
static inline void back2front (auto &&... args) { _b2f<Neon>(args...); }
|
||||||
|
static inline void blend_xrgb_a(auto &&... args) { Neon::Blend::xrgb_a(args...); }
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* _INCLUDE__SPEC__ARM_64__BLIT_H_ */
|
#endif /* _INCLUDE__SPEC__ARM_64__BLIT_H_ */
|
||||||
|
@ -16,10 +16,12 @@
|
|||||||
|
|
||||||
#include <blit/types.h>
|
#include <blit/types.h>
|
||||||
#include <blit/internal/sse4.h>
|
#include <blit/internal/sse4.h>
|
||||||
|
#include <blit/internal/slow.h>
|
||||||
|
|
||||||
namespace Blit {
|
namespace Blit {
|
||||||
|
|
||||||
static inline void back2front(auto &&... args) { _b2f<Sse4>(args...); }
|
static inline void back2front (auto &&... args) { _b2f<Sse4>(args...); }
|
||||||
|
static inline void blend_xrgb_a(auto &&... args) { Sse4::Blend::xrgb_a(args...); }
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* _INCLUDE__SPEC__X86_64__BLIT_H_ */
|
#endif /* _INCLUDE__SPEC__X86_64__BLIT_H_ */
|
||||||
|
@ -197,7 +197,7 @@ namespace Blit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void test_b2f_dispatch()
|
static inline void test_b2f_dispatch()
|
||||||
{
|
{
|
||||||
Texture<Pixel_rgb888> texture_landscape { nullptr, nullptr, { 640, 480 } };
|
Texture<Pixel_rgb888> texture_landscape { nullptr, nullptr, { 640, 480 } };
|
||||||
Texture<Pixel_rgb888> texture_portrait { nullptr, nullptr, { 480, 640 } };
|
Texture<Pixel_rgb888> texture_portrait { nullptr, nullptr, { 480, 640 } };
|
||||||
@ -274,15 +274,110 @@ static void test_b2f_dispatch()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename SIMD>
|
||||||
|
static inline void test_simd_blend_mix()
|
||||||
|
{
|
||||||
|
struct Rgb : Genode::Hex
|
||||||
|
{
|
||||||
|
explicit Rgb(uint32_t v) : Hex(v, OMIT_PREFIX, PAD) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Mix_test
|
||||||
|
{
|
||||||
|
uint32_t bg, fg; uint8_t a; uint32_t expected;
|
||||||
|
|
||||||
|
void print(Output &out) const
|
||||||
|
{
|
||||||
|
Genode::print(out, "bg=", Rgb(bg), " fg=", Rgb(fg), " a=", a);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Mix_test mix_test[] {
|
||||||
|
{ .bg = 0x000000, .fg = 0x000000, .a = 0, .expected = 0x000000 },
|
||||||
|
{ .bg = 0x000000, .fg = 0xffffff, .a = 0, .expected = 0x000000 },
|
||||||
|
{ .bg = 0xffffff, .fg = 0x000000, .a = 0, .expected = 0xffffff },
|
||||||
|
{ .bg = 0xffffff, .fg = 0xffffff, .a = 0, .expected = 0xffffff },
|
||||||
|
|
||||||
|
{ .bg = 0x000000, .fg = 0x000000, .a = 255, .expected = 0x000000 },
|
||||||
|
{ .bg = 0x000000, .fg = 0xffffff, .a = 255, .expected = 0xffffff },
|
||||||
|
{ .bg = 0xffffff, .fg = 0x000000, .a = 255, .expected = 0x000000 },
|
||||||
|
{ .bg = 0xffffff, .fg = 0xffffff, .a = 255, .expected = 0xffffff },
|
||||||
|
};
|
||||||
|
|
||||||
|
for (Mix_test const &test : mix_test) {
|
||||||
|
uint32_t slow = Slow::Blend::_mix(test.bg, test.fg, test.a);
|
||||||
|
uint32_t simd = SIMD::Blend::_mix(test.bg, test.fg, test.a);
|
||||||
|
if (slow == test.expected && slow == simd) {
|
||||||
|
log("mix ", test, " -> slow=", Rgb(slow), " simd=", Rgb(simd));
|
||||||
|
} else {
|
||||||
|
error("mix ", test, " -> slow=", Rgb(slow), " simd=", Rgb(simd),
|
||||||
|
" expected=", Rgb(test.expected));
|
||||||
|
throw 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Xrgb_8x
|
||||||
|
{
|
||||||
|
uint32_t values[8];
|
||||||
|
|
||||||
|
void print(Output &out) const
|
||||||
|
{
|
||||||
|
for (unsigned i = 0; i < 8; i++)
|
||||||
|
Genode::print(out, (i == 0) ? "" : ".", Rgb(values[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator != (Xrgb_8x const &other) const
|
||||||
|
{
|
||||||
|
for (unsigned i = 0; i < 8; i++)
|
||||||
|
if (values[i] != other.values[i])
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
uint32_t const ca = 0xaaaaaa, cb = 0xbbbbbb, cc = 0xcccccc, cd = 0xdddddd,
|
||||||
|
white = 0xffffff;
|
||||||
|
|
||||||
|
Xrgb_8x black_bg { };
|
||||||
|
Xrgb_8x white_bg { { white, white, white, white, white, white, white, white } };
|
||||||
|
|
||||||
|
Xrgb_8x fg { { 0x001020, 0x405060, 0x8090a0, 0xc0d0e0, ca, cb, cc, cd } };
|
||||||
|
uint8_t alpha[8] { 63, 127, 191, 255 , 64, 64, 64, 64 };
|
||||||
|
|
||||||
|
auto test_mix_8 = [&] (auto msg, Xrgb_8x &bg, Xrgb_8x const &fg,
|
||||||
|
uint8_t const *alpha, Xrgb_8x const &expected)
|
||||||
|
{
|
||||||
|
log("fg : ", fg);
|
||||||
|
log("bg : ", bg);
|
||||||
|
SIMD::Blend::xrgb_a(bg.values, 8, fg.values, alpha);
|
||||||
|
log(msg, " : ", bg);
|
||||||
|
if (expected != bg) {
|
||||||
|
error("expected ", expected);
|
||||||
|
throw 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
test_mix_8("blackened", black_bg, fg, alpha, { {
|
||||||
|
0x00000408, 0x00202830, 0x00606c78, 0x00c0d0e0,
|
||||||
|
0x002b2b2b, 0x002f2f2f, 0x00333333, 0x00383838 } });
|
||||||
|
|
||||||
|
test_mix_8("whitened ", white_bg, fg, alpha, { {
|
||||||
|
0x00c0c4c8, 0x00a0a8b0, 0x00a0acb8, 0x00c0d0e0,
|
||||||
|
0x00eaeaea, 0x00eeeeee, 0x00f3f3f3, 0x00f7f7f7 } });
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Component::construct(Genode::Env &)
|
void Component::construct(Genode::Env &)
|
||||||
{
|
{
|
||||||
#ifdef _INCLUDE__BLIT__INTERNAL__NEON_H_
|
#ifdef _INCLUDE__BLIT__INTERNAL__NEON_H_
|
||||||
log("-- ARM Neon --");
|
log("-- ARM Neon --");
|
||||||
test_simd_b2f<Neon>();
|
test_simd_b2f<Neon>();
|
||||||
|
test_simd_blend_mix<Neon>();
|
||||||
#endif
|
#endif
|
||||||
#ifdef _INCLUDE__BLIT__INTERNAL__SSE4_H_
|
#ifdef _INCLUDE__BLIT__INTERNAL__SSE4_H_
|
||||||
log("-- SSE4 --");
|
log("-- SSE4 --");
|
||||||
test_simd_b2f<Sse4>();
|
test_simd_b2f<Sse4>();
|
||||||
|
test_simd_blend_mix<Sse4>();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
test_b2f_dispatch();
|
test_b2f_dispatch();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user