blob: 28cafd2d8b17e30ba85d583256e2395c16d9066a [file]
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// -----------------------------------------------------------------------------
//
// Rasterization for preview
//
// Author: Skal (pascal.massimino@gmail.com)
#include <cassert>
#include <cstdint>
#include "src/dsp/dsp.h"
namespace WP2 {
namespace {
//------------------------------------------------------------------------------
// C version
static void RasterAdvance_C(grad_t grads[3 * 4], grad_t dX, grad_t cur[4]) {
cur[0] = grads[8] + grads[0] * dX;
cur[1] = grads[9] + grads[1] * dX;
cur[2] = grads[10] + grads[2] * dX;
cur[3] = grads[11] + grads[3] * dX;
grads[8] += grads[4];
grads[9] += grads[5];
grads[10] += grads[6];
grads[11] += grads[7];
}
static uint32_t Square(int32_t v, uint8_t b) {
v = (v >> kRasterPrec) - b;
return v * v;
}
static void RasterLoss_C(const uint8_t* src, uint32_t size,
const grad_t value[4], const grad_t gradient[4],
uint32_t loss[4]) {
grad_t cur[4] = {value[0], value[1], value[2], value[3]};
for (uint32_t x = 0; x < size; ++x, src += 4) {
loss[0] += Square(cur[0], src[0]);
loss[1] += Square(cur[1], src[1]);
loss[2] += Square(cur[2], src[2]);
loss[3] += Square(cur[3], src[3]);
cur[0] += gradient[0];
cur[1] += gradient[1];
cur[2] += gradient[2];
cur[3] += gradient[3];
}
}
static uint8_t FloorToUInt8(int32_t v) {
v >>= kRasterPrec;
return (v < 0) ? 0u : (v > 255) ? 255u : v;
}
static void RasterDraw_C(const grad_t value[4], const grad_t gradient[4],
uint8_t* dst, uint32_t size) {
grad_t cur[4] = {value[0], value[1], value[2], value[3]};
for (uint32_t x = 0; x < size; ++x, dst += 4) {
dst[0] = FloorToUInt8(cur[0]);
dst[1] = FloorToUInt8(cur[1]);
dst[2] = FloorToUInt8(cur[2]);
dst[3] = FloorToUInt8(cur[3]);
cur[0] += gradient[0];
cur[1] += gradient[1];
cur[2] += gradient[2];
cur[3] += gradient[3];
}
}
//------------------------------------------------------------------------------
// SSE version
#if defined(WP2_USE_SSE)
static void RasterAdvance_SSE(grad_t grads[3 * 4], grad_t dX, grad_t cur[4]) {
const __m128i A = _mm_loadu_si128((const __m128i*)&grads[0]);
const __m128i B = _mm_loadu_si128((const __m128i*)&grads[4]);
const __m128i C = _mm_loadu_si128((const __m128i*)&grads[8]);
const __m128i D = _mm_mullo_epi32(A, _mm_set1_epi32(dX));
const __m128i E = _mm_add_epi32(C, D);
_mm_storeu_si128((__m128i*)cur, E);
const __m128i F = _mm_add_epi32(C, B);
_mm_storeu_si128((__m128i*)&grads[8], F);
}
static void RasterLoss_SSE(const uint8_t* src, uint32_t size,
const grad_t value[4], const grad_t gradient[4],
uint32_t loss[4]) {
const __m128i grad = _mm_loadu_si128((const __m128i*)gradient);
__m128i C = _mm_loadu_si128((const __m128i*)value);
__m128i L = _mm_loadu_si128((const __m128i*)loss);
const __m128i zero = _mm_setzero_si128();
for (uint32_t x = 0; x < size; ++x, src += 4) {
const __m128i C1 = _mm_srai_epi32(C, kRasterPrec);
C = _mm_add_epi32(C, grad);
const __m128i D = _mm_cvtsi32_si128(*(int32_t*)src);
const __m128i E = _mm_unpacklo_epi8(D, zero);
const __m128i F = _mm_unpacklo_epi16(E, zero);
const __m128i G = _mm_sub_epi32(C1, F);
const __m128i H = _mm_mullo_epi32(G, G);
L = _mm_add_epi32(L, H);
}
_mm_storeu_si128((__m128i*)loss, L);
}
static void RasterDraw_SSE(const grad_t value[4], const grad_t gradient[4],
uint8_t* dst, uint32_t size) {
const __m128i grad = _mm_loadu_si128((const __m128i*)gradient);
__m128i A = _mm_loadu_si128((const __m128i*)value);
for (uint32_t x = 0; x < size; ++x, dst += 4) {
const __m128i B = _mm_srai_epi32(A, kRasterPrec);
A = _mm_add_epi32(A, grad);
const __m128i C = _mm_packs_epi32(B, B);
const __m128i D = _mm_packus_epi16(C, C);
*(int*)dst = _mm_cvtsi128_si32(D);
}
}
#endif // WP2_USE_SSE
//------------------------------------------------------------------------------
} // namespace
void (*RasterAdvance)(grad_t grads[3 * 4], grad_t dX, grad_t cur[4]) = nullptr;
void (*RasterLoss)(const uint8_t* src, uint32_t size, const grad_t value[4],
const grad_t gradient[4], uint32_t loss[4]) = nullptr;
void (*RasterDraw)(const grad_t value[4], const grad_t gradient[4],
uint8_t* dst, uint32_t size) = nullptr;
static volatile WP2CPUInfo raster_last_cpuinfo_used =
(WP2CPUInfo)&raster_last_cpuinfo_used;
WP2_TSAN_IGNORE_FUNCTION void RasterInit() {
if (raster_last_cpuinfo_used == WP2GetCPUInfo) return;
RasterAdvance = RasterAdvance_C;
RasterLoss = RasterLoss_C;
RasterDraw = RasterDraw_C;
if (WP2GetCPUInfo != nullptr) {
#if defined(WP2_USE_SSE)
if (WP2GetCPUInfo(kSSE)) {
RasterAdvance = RasterAdvance_SSE;
RasterLoss = RasterLoss_SSE;
RasterDraw = RasterDraw_SSE;
}
#endif
}
raster_last_cpuinfo_used = WP2GetCPUInfo;
}
//------------------------------------------------------------------------------
} // namespace WP2