Skip to content

Commit eca72dc

Browse files
committed
fix(wgc): build the BGRA to NV12 converter without SSE2 on ARM64
c729834 vectorised the converter with SSE2, and MSVC's emmintrin.h is an #error on ARM64, so the helper no longer built for Windows on ARM. The SSE2 loops now compile on x86/x64 only; ARM64 runs the scalar loops that already handled the row tails. mf_encoder_color_test passes natively on ARM64 (18/18, colours exact to the code value) at 3.5 ms per 1080p frame.
1 parent 683901f commit eca72dc

1 file changed

Lines changed: 14 additions & 0 deletions

File tree

‎electron/native/wgc-capture/src/mf_encoder.cpp‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,13 @@
1010
#include <mferror.h>
1111
#include <propvarutil.h>
1212

13+
// SSE2 only where it exists. On ARM64 MSVC's emmintrin.h is an #error unless the
14+
// soft-intrinsics emulation is linked in, so the converter below falls back to its
15+
// scalar loops there, which the colour test checks against BT.709 the same way.
16+
#if defined(_M_X64) || defined(_M_IX86)
17+
#define OPENSCREEN_NV12_SSE2 1
1318
#include <emmintrin.h>
19+
#endif
1420

1521
#include <algorithm>
1622
#include <cstring>
@@ -608,6 +614,7 @@ void convertBgraToNv12Bt709(const BYTE* bgra, int stride, int width, int height,
608614
// Luma four pixels at a time in SSE2, which every x64 CPU has: this runs on
609615
// the video writer's thread for every frame, and the scalar loop alone cost
610616
// 2.5 ms a 1080p frame. 15-bit coefficients so they fit madd's int16 lanes.
617+
#ifdef OPENSCREEN_NV12_SSE2
611618
const __m128i zero = _mm_setzero_si128();
612619
const __m128i lumaCoefficients = _mm_setr_epi16(2032, 20127, 5983, 0, 2032, 20127, 5983, 0);
613620
const __m128i lumaRounding = _mm_set1_epi32(16384);
@@ -617,10 +624,12 @@ void convertBgraToNv12Bt709(const BYTE* bgra, int stride, int width, int height,
617624
const __m128i products = _mm_madd_epi16(pixels, lumaCoefficients);
618625
return _mm_add_epi32(products, _mm_shuffle_epi32(products, _MM_SHUFFLE(2, 3, 0, 1)));
619626
};
627+
#endif
620628
for (int y = 0; y < height; y += 1) {
621629
const BYTE* row = bgra + static_cast<size_t>(y) * stride;
622630
BYTE* out = luma + static_cast<size_t>(y) * width;
623631
int x = 0;
632+
#ifdef OPENSCREEN_NV12_SSE2
624633
for (; x + 4 <= width; x += 4) {
625634
const __m128i pixels = _mm_loadu_si128(reinterpret_cast<const __m128i*>(row + x * 4));
626635
const __m128i first = lumaOfTwo(_mm_unpacklo_epi8(pixels, zero));
@@ -632,6 +641,7 @@ void convertBgraToNv12Bt709(const BYTE* bgra, int stride, int width, int height,
632641
const int packed = _mm_cvtsi128_si32(bytes);
633642
std::memcpy(out + x, &packed, 4);
634643
}
644+
#endif
635645
for (; x < width; x += 1) {
636646
const int b = row[x * 4];
637647
const int g = row[x * 4 + 1];
@@ -641,6 +651,7 @@ void convertBgraToNv12Bt709(const BYTE* bgra, int stride, int width, int height,
641651
}
642652
// Chroma the same way, two 2x2 blocks at a time: the four pixels of each
643653
// block summed in int16 lanes (at most 1020), then one madd per channel.
654+
#ifdef OPENSCREEN_NV12_SSE2
644655
const __m128i cbCoefficients = _mm_setr_epi16(28784, -22189, -6596, 0, 28784, -22189, -6596, 0);
645656
const __m128i crCoefficients = _mm_setr_epi16(-2642, -26142, 28784, 0, -2642, -26142, 28784, 0);
646657
const __m128i chromaRounding = _mm_set1_epi32(131072);
@@ -650,11 +661,13 @@ void convertBgraToNv12Bt709(const BYTE* bgra, int stride, int width, int height,
650661
const __m128i sums = _mm_add_epi32(products, _mm_shuffle_epi32(products, _MM_SHUFFLE(2, 3, 0, 1)));
651662
return _mm_shuffle_epi32(sums, _MM_SHUFFLE(2, 0, 2, 0));
652663
};
664+
#endif
653665
for (int y = 0; y < height; y += 2) {
654666
const BYTE* top = bgra + static_cast<size_t>(y) * stride;
655667
const BYTE* bottom = y + 1 < height ? top + stride : top;
656668
BYTE* out = chroma + static_cast<size_t>(y / 2) * width;
657669
int x = 0;
670+
#ifdef OPENSCREEN_NV12_SSE2
658671
for (; x + 4 <= width; x += 4) {
659672
const __m128i upper = _mm_loadu_si128(reinterpret_cast<const __m128i*>(top + x * 4));
660673
const __m128i lower = _mm_loadu_si128(reinterpret_cast<const __m128i*>(bottom + x * 4));
@@ -669,6 +682,7 @@ void convertBgraToNv12Bt709(const BYTE* bgra, int stride, int width, int height,
669682
const int packed = _mm_cvtsi128_si32(_mm_packus_epi16(_mm_packs_epi32(values, zero), zero));
670683
std::memcpy(out + x, &packed, 4);
671684
}
685+
#endif
672686
for (; x < width; x += 2) {
673687
const int right = (x + 1 < width ? x + 1 : x) * 4;
674688
const int left = x * 4;

0 commit comments

Comments
 (0)