网页升级

This commit is contained in:
2026-08-11 06:21:51 +08:00
parent f50e9f7c1e
commit feb7c72e94
40 changed files with 6490 additions and 98 deletions
+87 -14
View File
@@ -3,6 +3,9 @@
#include <algorithm>
#include <cstring>
#include <limits>
#if defined(_M_X64) || defined(__x86_64__)
#include <tmmintrin.h>
#endif
namespace renderive::web {
namespace {
@@ -23,6 +26,24 @@ std::uint8_t flatten(std::uint8_t premultiplied, std::uint8_t alpha,
} // namespace
Pixel_Frame_Copy copy_pixel_frame(Image_View image) {
Pixel_Frame_Copy copy;
if (image.empty() || image.format != Pixel_Format::Premultiplied_32 ||
image.stride < image.width * static_cast<int>(sizeof(Pixel))) {
return copy;
}
copy.width = image.width;
copy.height = image.height;
copy.pixels.resize(static_cast<std::size_t>(image.width) *
static_cast<std::size_t>(image.height));
for (int y = 0; y < image.height; ++y) {
const auto* source = image.data + static_cast<std::ptrdiff_t>(y) * image.stride;
std::memcpy(copy.pixels.data() + static_cast<std::size_t>(y) * image.width,
source, static_cast<std::size_t>(image.width) * sizeof(Pixel));
}
return copy;
}
std::string encode_pixel_frame(Image_View image, Color background) {
if (image.empty() || image.format != Pixel_Format::Premultiplied_32 ||
image.stride < image.width * static_cast<int>(sizeof(Pixel))) {
@@ -46,23 +67,75 @@ std::string encode_pixel_frame(Image_View image, Color background) {
write_u32_le(frame.data() + 12,
static_cast<std::uint32_t>(image.width * static_cast<int>(sizeof(Pixel))));
auto* output = reinterpret_cast<std::uint8_t*>(frame.data() + pixel_frame_header_size);
for (int y = 0; y < image.height; ++y) {
const auto* row = image.data + static_cast<std::ptrdiff_t>(y) * image.stride;
for (int x = 0; x < image.width; ++x) {
Pixel pixel{};
std::memcpy(&pixel, row + static_cast<std::ptrdiff_t>(x) * sizeof(Pixel), sizeof(pixel));
const auto alpha = static_cast<std::uint8_t>((pixel >> 24U) & 0xffU);
const auto red = static_cast<std::uint8_t>((pixel >> 16U) & 0xffU);
const auto green = static_cast<std::uint8_t>((pixel >> 8U) & 0xffU);
const auto blue = static_cast<std::uint8_t>(pixel & 0xffU);
*output++ = flatten(red, alpha, background.r);
*output++ = flatten(green, alpha, background.g);
*output++ = flatten(blue, alpha, background.b);
*output++ = 255;
auto* output = reinterpret_cast<std::uint32_t*>(frame.data() + pixel_frame_header_size);
const std::uint32_t opaque_background =
static_cast<std::uint32_t>(background.r) |
(static_cast<std::uint32_t>(background.g) << 8U) |
(static_cast<std::uint32_t>(background.b) << 16U) |
0xff000000U;
const auto convert_pixel = [background, opaque_background](Pixel pixel) {
const auto alpha = static_cast<std::uint8_t>((pixel >> 24U) & 0xffU);
if (alpha == 0)
return opaque_background;
const auto red = static_cast<std::uint8_t>((pixel >> 16U) & 0xffU);
const auto green = static_cast<std::uint8_t>((pixel >> 8U) & 0xffU);
const auto blue = static_cast<std::uint8_t>(pixel & 0xffU);
if (alpha == 255) {
return static_cast<std::uint32_t>(red) |
(static_cast<std::uint32_t>(green) << 8U) |
(static_cast<std::uint32_t>(blue) << 16U) |
0xff000000U;
}
return static_cast<std::uint32_t>(flatten(red, alpha, background.r)) |
(static_cast<std::uint32_t>(flatten(green, alpha, background.g)) << 8U) |
(static_cast<std::uint32_t>(flatten(blue, alpha, background.b)) << 16U) |
0xff000000U;
};
#if defined(_M_X64) || defined(__x86_64__)
const __m128i rgba_shuffle = _mm_setr_epi8(
2, 1, 0, 3, 6, 5, 4, 7, 10, 9, 8, 11, 14, 13, 12, 15);
const __m128i background_pixels = _mm_set1_epi32(static_cast<int>(opaque_background));
#endif
for (int y = 0; y < image.height; ++y) {
const auto* row = reinterpret_cast<const Pixel*>(
image.data + static_cast<std::ptrdiff_t>(y) * image.stride);
int x{};
#if defined(_M_X64) || defined(__x86_64__)
for (; x + 4 <= image.width; x += 4) {
const Pixel alpha_union = row[x] | row[x + 1] | row[x + 2] | row[x + 3];
if ((alpha_union & 0xff000000U) == 0) {
_mm_storeu_si128(reinterpret_cast<__m128i*>(output), background_pixels);
output += 4;
continue;
}
const Pixel alpha_intersection = row[x] & row[x + 1] & row[x + 2] & row[x + 3];
if ((alpha_intersection & 0xff000000U) == 0xff000000U) {
const __m128i bgra =
_mm_loadu_si128(reinterpret_cast<const __m128i*>(row + x));
_mm_storeu_si128(reinterpret_cast<__m128i*>(output),
_mm_shuffle_epi8(bgra, rgba_shuffle));
output += 4;
continue;
}
*output++ = convert_pixel(row[x]);
*output++ = convert_pixel(row[x + 1]);
*output++ = convert_pixel(row[x + 2]);
*output++ = convert_pixel(row[x + 3]);
}
#endif
for (; x < image.width; ++x)
*output++ = convert_pixel(row[x]);
}
return frame;
}
std::string encode_pixel_frame(const Pixel_Frame_Copy& image, Color background) {
if (image.empty())
return {};
return encode_pixel_frame(
{reinterpret_cast<const std::byte*>(image.pixels.data()), image.width, image.height,
image.width * static_cast<int>(sizeof(Pixel)), Pixel_Format::Premultiplied_32},
background);
}
} // namespace renderive::web