blob: 3735d4353f0398432b04c4080a96fd032b3c26e2 [file]
/*
* Copyright 2026 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "src/gpu/GradientBitmap.h"
#include "include/core/SkAlphaType.h"
#include "include/core/SkColor.h"
#include "include/core/SkColorType.h"
#include "include/core/SkImageInfo.h"
#include "include/core/SkRect.h"
#include "include/private/SkAssert.h"
#include "src/core/SkHalf.h"
#include <cmath>
namespace skgpu {
bool EncodeGradientStopToHalf(float offset, float* mantissa, float* exponent) {
int exp;
float mant = std::frexp(offset, &exp);
SkHalf halfE = SkFloatToHalf(static_cast<float>(exp));
if (static_cast<int>(SkHalfToFloat(halfE)) != exp) {
return false;
}
#if defined(SK_DEBUG)
SkHalf halfM = SkFloatToHalf(mant);
float restored = std::ldexp(SkHalfToFloat(halfM), exp);
SkASSERT(std::abs(restored - offset) < 0.001f);
#endif
*mantissa = mant;
*exponent = static_cast<float>(exp);
return true;
}
SkBitmap CreateGradientColorAndOffsetBitmap(int numStops,
const SkPMColor4f* colors,
const float* offsets) {
SkBitmap colorsAndOffsetsBitmap;
if (!colorsAndOffsetsBitmap.tryAllocPixels(
SkImageInfo::Make(numStops, 2, kRGBA_F16_SkColorType, kPremul_SkAlphaType))) {
return {};
}
for (int i = 0; i < numStops; i++) {
// TODO: there should be a way to directly set a premul pixel in a bitmap with
// a premul color.
SkColor4f unpremulColor = colors[i].unpremul();
colorsAndOffsetsBitmap.erase(unpremulColor, SkIRect::MakeXYWH(i, 0, 1, 1));
float offset = offsets ? offsets[i] : SkIntToFloat(i) / (numStops - 1);
SkASSERT(offset >= 0.0f && offset <= 1.0f);
float mantissa, exponent;
if (!EncodeGradientStopToHalf(offset, &mantissa, &exponent)) {
return {};
}
// TODO: we're only using 2 of the f16s here. The encoding could be altered to better
// preserve precision. This encoding yields < 0.001f error for 2^20 evenly spaced stops.
colorsAndOffsetsBitmap.erase(SkColor4f{mantissa, exponent, 0, 1},
SkIRect::MakeXYWH(i, 1, 1, 1));
}
return colorsAndOffsetsBitmap;
}
} // namespace skgpu