stop using bitmapcontroller
This moves all shaders to a common utility for resolve the mip-level request. Change-Id: I26709d5a55adf97cb4c61473527a9bbbdc689aa5 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/339897 Reviewed-by: Mike Klein <mtklein@google.com> Commit-Queue: Mike Reed <reed@google.com>
This commit is contained in:
parent
f5e1bf9f01
commit
8c1ad7e8d3
@ -11,7 +11,6 @@
|
||||
#include "src/core/SkArenaAlloc.h"
|
||||
#include "src/core/SkBitmapCache.h"
|
||||
#include "src/core/SkBitmapController.h"
|
||||
#include "src/core/SkMatrixPriv.h"
|
||||
#include "src/core/SkMipmap.h"
|
||||
#include "src/image/SkImage_Base.h"
|
||||
|
||||
@ -27,86 +26,6 @@ static sk_sp<const SkMipmap> try_load_mips(const SkImage_Base* image) {
|
||||
return mips;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SkBitmapController::State* SkBitmapController::RequestBitmap(const SkImage_Base* image,
|
||||
const SkMatrix& inv,
|
||||
const SkSamplingOptions& sampling,
|
||||
SkArenaAlloc* alloc) {
|
||||
auto* state = alloc->make<SkBitmapController::State>(image, inv, sampling);
|
||||
|
||||
return state->pixmap().addr() ? state : nullptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Modulo internal errors, this should always succeed *if* the matrix is downscaling
|
||||
* (in this case, we have the inverse, so it succeeds if fInvMatrix is upscaling)
|
||||
*/
|
||||
bool SkBitmapController::State::extractMipLevel(const SkImage_Base* image) {
|
||||
SkASSERT(!fSampling.useCubic);
|
||||
if (fSampling.mipmap != SkMipmapMode::kNearest) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We will extract the right level here, so mark fSampling to know that has already happened.
|
||||
fSampling = SkSamplingOptions(fSampling.filter, SkMipmapMode::kNone);
|
||||
|
||||
SkSize invScaleSize;
|
||||
if (!fInvMatrix.decomposeScale(&invScaleSize, nullptr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (invScaleSize.width() > SK_Scalar1 || invScaleSize.height() > SK_Scalar1) {
|
||||
fCurrMip = try_load_mips(image);
|
||||
if (!fCurrMip) {
|
||||
return false;
|
||||
}
|
||||
// diagnostic for a crasher...
|
||||
SkASSERT_RELEASE(fCurrMip->data());
|
||||
|
||||
const SkSize scale = SkSize::Make(SkScalarInvert(invScaleSize.width()),
|
||||
SkScalarInvert(invScaleSize.height()));
|
||||
SkMipmap::Level level;
|
||||
if (fCurrMip->extractLevel(scale, &level)) {
|
||||
const SkSize& invScaleFixup = level.fScale;
|
||||
fInvMatrix.postScale(invScaleFixup.width(), invScaleFixup.height());
|
||||
|
||||
// todo: if we could wrap the fCurrMip in a pixelref, then we could just install
|
||||
// that here, and not need to explicitly track it ourselves.
|
||||
return fResultBitmap.installPixels(level.fPixmap);
|
||||
} else {
|
||||
// failed to extract, so release the mipmap
|
||||
fCurrMip.reset(nullptr);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
SkBitmapController::State::State(const SkImage_Base* image,
|
||||
const SkMatrix& inv,
|
||||
const SkSamplingOptions& sampling)
|
||||
: fInvMatrix(inv)
|
||||
, fSampling(sampling)
|
||||
{
|
||||
if (fSampling.useCubic &&
|
||||
SkMatrixPriv::AdjustHighQualityFilterLevel(fInvMatrix, true) != kHigh_SkFilterQuality)
|
||||
{
|
||||
fSampling = SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNearest);
|
||||
}
|
||||
|
||||
if (!fSampling.useCubic && this->extractMipLevel(image)) {
|
||||
SkASSERT(fResultBitmap.getPixels());
|
||||
} else {
|
||||
(void)image->getROPixels(nullptr, &fResultBitmap);
|
||||
}
|
||||
|
||||
// fResultBitmap.getPixels() may be null, but our caller knows to check fPixmap.addr()
|
||||
// and will destroy us if it is nullptr.
|
||||
fPixmap.reset(fResultBitmap.info(), fResultBitmap.getPixels(), fResultBitmap.rowBytes());
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SkMipmapAccessor::SkMipmapAccessor(const SkImage_Base* image, const SkMatrix& inv,
|
||||
SkMipmapMode requestedMode) {
|
||||
fResolvedMode = requestedMode;
|
||||
@ -134,6 +53,11 @@ SkMipmapAccessor::SkMipmapAccessor(const SkImage_Base* image, const SkMatrix& in
|
||||
}
|
||||
}
|
||||
|
||||
auto post_scale = [image, inv](const SkPixmap& pm) {
|
||||
return SkMatrix::Scale(SkIntToScalar(pm.width()) / image->width(),
|
||||
SkIntToScalar(pm.height()) / image->height()) * inv;
|
||||
};
|
||||
|
||||
int levelNum = sk_float_floor2int(level);
|
||||
float lowerWeight = level - levelNum; // fract(level)
|
||||
SkASSERT(levelNum >= 0);
|
||||
@ -164,10 +88,12 @@ SkMipmapAccessor::SkMipmapAccessor(const SkImage_Base* image, const SkMatrix& in
|
||||
if (fCurrMip->getLevel(levelNum, &levelRec)) {
|
||||
fLower = levelRec.fPixmap;
|
||||
fLowerWeight = lowerWeight;
|
||||
fLowerInv = post_scale(fLower);
|
||||
} else {
|
||||
fResolvedMode = SkMipmapMode::kNearest;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fUpperInv = post_scale(fUpper);
|
||||
}
|
||||
|
@ -9,62 +9,35 @@
|
||||
#define SkBitmapController_DEFINED
|
||||
|
||||
#include "include/core/SkBitmap.h"
|
||||
#include "include/core/SkFilterQuality.h"
|
||||
#include "include/core/SkImage.h"
|
||||
#include "include/core/SkMatrix.h"
|
||||
#include "src/core/SkBitmapCache.h"
|
||||
#include "src/core/SkMipmap.h"
|
||||
#include <tuple>
|
||||
|
||||
class SkImage_Base;
|
||||
|
||||
/**
|
||||
* Handles request to scale, filter, and lock a bitmap to be rasterized.
|
||||
*/
|
||||
class SkBitmapController : ::SkNoncopyable {
|
||||
public:
|
||||
class State : ::SkNoncopyable {
|
||||
public:
|
||||
State(const SkImage_Base*, const SkMatrix& inv, const SkSamplingOptions&);
|
||||
|
||||
const SkPixmap& pixmap() const { return fPixmap; }
|
||||
const SkMatrix& invMatrix() const { return fInvMatrix; }
|
||||
const SkSamplingOptions& sampling() const { return fSampling; }
|
||||
|
||||
private:
|
||||
bool extractMipLevel(const SkImage_Base*);
|
||||
|
||||
SkPixmap fPixmap;
|
||||
SkMatrix fInvMatrix;
|
||||
SkSamplingOptions fSampling;
|
||||
|
||||
// Pixmap storage.
|
||||
SkBitmap fResultBitmap;
|
||||
sk_sp<const SkMipmap> fCurrMip;
|
||||
|
||||
};
|
||||
|
||||
static State* RequestBitmap(const SkImage_Base*, const SkMatrix& inverse,
|
||||
const SkSamplingOptions&, SkArenaAlloc*);
|
||||
|
||||
private:
|
||||
SkBitmapController() = delete;
|
||||
};
|
||||
|
||||
class SkMipmapAccessor : ::SkNoncopyable {
|
||||
public:
|
||||
SkMipmapAccessor(const SkImage_Base*, const SkMatrix& inv, SkMipmapMode requestedMode);
|
||||
|
||||
const SkPixmap& level() const { return fUpper; }
|
||||
// only valid if mode() == kLinear
|
||||
const SkPixmap& lowerLevel() const { return fLower; }
|
||||
// 0....1. Will be 1.0 if there is no lowerLevel
|
||||
float lowerWeight() const { return fLowerWeight; }
|
||||
SkMipmapMode mode() const { return fResolvedMode; }
|
||||
std::pair<SkPixmap, SkMatrix> level() const { return std::make_pair(fUpper, fUpperInv); }
|
||||
|
||||
std::pair<SkPixmap, SkMatrix> lowerLevel() const {
|
||||
SkASSERT(this->mode() == SkMipmapMode::kLinear);
|
||||
return std::make_pair(fLower, fLowerInv);
|
||||
}
|
||||
|
||||
// 0....1. Will be 0 if there is no lowerLevel
|
||||
float lowerWeight() const { return fLowerWeight; }
|
||||
|
||||
SkMipmapMode mode() const { return fResolvedMode; }
|
||||
|
||||
private:
|
||||
SkPixmap fUpper,
|
||||
fLower; // only valid for mip_linear
|
||||
float fLowerWeight; // lower * weight + upper * (1 - weight)
|
||||
SkMatrix fUpperInv,
|
||||
fLowerInv;
|
||||
SkMipmapMode fResolvedMode;
|
||||
|
||||
// these manage lifetime for the buffers
|
||||
|
@ -143,10 +143,8 @@ SkBitmapProcState::SkBitmapProcState(const SkImage_Base* image, SkTileMode tmx,
|
||||
: fImage(image)
|
||||
, fTileModeX(tmx)
|
||||
, fTileModeY(tmy)
|
||||
, fBMState(nullptr)
|
||||
{}
|
||||
|
||||
|
||||
// true iff the matrix has a scale and no more than an optional translate.
|
||||
static bool matrix_only_scale_translate(const SkMatrix& m) {
|
||||
return (m.getType() & ~SkMatrix::kTranslate_Mask) == SkMatrix::kScale_Mask;
|
||||
@ -187,23 +185,22 @@ bool SkBitmapProcState::init(const SkMatrix& inv, SkColor paintColor,
|
||||
const SkSamplingOptions& sampling) {
|
||||
SkASSERT(!inv.hasPerspective());
|
||||
SkASSERT(SkOpts::S32_alpha_D32_filter_DXDY || inv.isScaleTranslate());
|
||||
SkASSERT(!sampling.useCubic);
|
||||
SkASSERT(sampling.mipmap != SkMipmapMode::kLinear);
|
||||
|
||||
fPixmap.reset();
|
||||
fInvMatrix = inv;
|
||||
fBilerp = false;
|
||||
|
||||
fBMState = SkBitmapController::RequestBitmap(fImage, inv, sampling, &fAlloc);
|
||||
auto* access = fAlloc.make<SkMipmapAccessor>(fImage, inv, sampling.mipmap);
|
||||
std::tie(fPixmap, fInvMatrix) = access->level();
|
||||
|
||||
// Note : we allow the controller to return an empty (zero-dimension) result. Should we?
|
||||
if (nullptr == fBMState || fBMState->pixmap().info().isEmpty()) {
|
||||
// Do we need this check?
|
||||
if (fPixmap.info().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
fPixmap = fBMState->pixmap();
|
||||
fInvMatrix = fBMState->invMatrix();
|
||||
fPaintColor = paintColor;
|
||||
SkASSERT(!fBMState->sampling().useCubic);
|
||||
SkASSERT(fBMState->sampling().mipmap == SkMipmapMode::kNone);
|
||||
fBilerp = fBMState->sampling().filter == SkFilterMode::kLinear;
|
||||
fBilerp = sampling.filter == SkFilterMode::kLinear;
|
||||
SkASSERT(fPixmap.addr());
|
||||
|
||||
bool integral_translate_only = just_trans_integral(fInvMatrix);
|
||||
|
@ -91,7 +91,6 @@ private:
|
||||
kBMStateSize = 136 // found by inspection. if too small, we will call new/delete
|
||||
};
|
||||
SkSTArenaAlloc<kBMStateSize> fAlloc;
|
||||
SkBitmapController::State* fBMState;
|
||||
|
||||
ShaderProc32 fShaderProc32; // chooseProcs
|
||||
// These are used if the shaderproc is nullptr
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "src/core/SkBitmapController.h"
|
||||
#include "src/core/SkColorSpacePriv.h"
|
||||
#include "src/core/SkColorSpaceXformSteps.h"
|
||||
#include "src/core/SkMatrixPriv.h"
|
||||
#include "src/core/SkMatrixProvider.h"
|
||||
#include "src/core/SkOpts.h"
|
||||
#include "src/core/SkRasterPipeline.h"
|
||||
@ -629,16 +630,14 @@ bool SkImageShader::doStages(const SkStageRec& rec, SkImageStageUpdater* updater
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto* state = SkBitmapController::RequestBitmap(as_IB(fImage.get()),
|
||||
matrix, sampling, alloc);
|
||||
if (!state) {
|
||||
return false;
|
||||
if (sampling.useCubic &&
|
||||
SkMatrixPriv::AdjustHighQualityFilterLevel(matrix, true) != kHigh_SkFilterQuality)
|
||||
{
|
||||
sampling = SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNearest);
|
||||
}
|
||||
|
||||
const SkPixmap& pm = state->pixmap();
|
||||
matrix = state->invMatrix();
|
||||
sampling = state->sampling();
|
||||
auto info = pm.info();
|
||||
auto* access = alloc->make<SkMipmapAccessor>(as_IB(fImage.get()), matrix, sampling.mipmap);
|
||||
SkPixmap pm;
|
||||
std::tie(pm, matrix) = access->level();
|
||||
|
||||
p->append(SkRasterPipeline::seed_shader);
|
||||
|
||||
@ -701,7 +700,7 @@ bool SkImageShader::doStages(const SkStageRec& rec, SkImageStageUpdater* updater
|
||||
}
|
||||
|
||||
void* ctx = gather;
|
||||
switch (info.colorType()) {
|
||||
switch (pm.colorType()) {
|
||||
case kAlpha_8_SkColorType: p->append(SkRasterPipeline::gather_a8, ctx); break;
|
||||
case kA16_unorm_SkColorType: p->append(SkRasterPipeline::gather_a16, ctx); break;
|
||||
case kA16_float_SkColorType: p->append(SkRasterPipeline::gather_af16, ctx); break;
|
||||
@ -745,11 +744,11 @@ bool SkImageShader::doStages(const SkStageRec& rec, SkImageStageUpdater* updater
|
||||
};
|
||||
|
||||
auto append_misc = [&] {
|
||||
SkColorSpace* cs = info.colorSpace();
|
||||
SkAlphaType at = info.alphaType();
|
||||
SkColorSpace* cs = pm.colorSpace();
|
||||
SkAlphaType at = pm.alphaType();
|
||||
|
||||
// Color for A8 images comes from the paint. TODO: all alpha images? none?
|
||||
if (info.colorType() == kAlpha_8_SkColorType) {
|
||||
if (pm.colorType() == kAlpha_8_SkColorType) {
|
||||
SkColor4f rgb = rec.fPaint.getColor4f();
|
||||
p->append_set_rgb(alloc, rgb);
|
||||
|
||||
@ -774,7 +773,7 @@ bool SkImageShader::doStages(const SkStageRec& rec, SkImageStageUpdater* updater
|
||||
};
|
||||
|
||||
// Check for fast-path stages.
|
||||
auto ct = info.colorType();
|
||||
auto ct = pm.colorType();
|
||||
if (true
|
||||
&& (ct == kRGBA_8888_SkColorType || ct == kBGRA_8888_SkColorType)
|
||||
&& !sampling.useCubic && sampling.filter == SkFilterMode::kLinear
|
||||
@ -901,40 +900,28 @@ skvm::Color SkImageShader::onProgram(skvm::Builder* p,
|
||||
}
|
||||
baseInv.normalizePerspective();
|
||||
|
||||
const SkPixmap *upper = nullptr,
|
||||
*lower = nullptr;
|
||||
SkMatrix upperInv;
|
||||
float lowerWeight = 0;
|
||||
|
||||
auto post_scale = [&](SkISize level, const SkMatrix& base) {
|
||||
return SkMatrix::Scale(SkIntToScalar(level.width()) / fImage->width(),
|
||||
SkIntToScalar(level.height()) / fImage->height())
|
||||
* base;
|
||||
};
|
||||
|
||||
auto sampling = fUseSamplingOptions ? fSampling : SkSamplingOptions(paintQuality);
|
||||
if (sampling.useCubic) {
|
||||
auto* access = alloc->make<SkMipmapAccessor>(as_IB(fImage.get()), baseInv,
|
||||
SkMipmapMode::kNone);
|
||||
upper = &access->level();
|
||||
upperInv = post_scale(upper->dimensions(), baseInv);
|
||||
} else {
|
||||
auto* access = alloc->make<SkMipmapAccessor>(as_IB(fImage.get()), baseInv,
|
||||
sampling.mipmap);
|
||||
upper = &access->level();
|
||||
upperInv = post_scale(upper->dimensions(), baseInv);
|
||||
lowerWeight = access->lowerWeight();
|
||||
if (lowerWeight > 0) {
|
||||
lower = &access->lowerLevel();
|
||||
}
|
||||
auto* access = alloc->make<SkMipmapAccessor>(as_IB(fImage.get()), baseInv, sampling.mipmap);
|
||||
|
||||
auto [upper, upperInv] = access->level();
|
||||
if (!sampling.useCubic) {
|
||||
sampling = tweak_filter_and_inv_matrix(sampling, &upperInv);
|
||||
}
|
||||
|
||||
SkPixmap lowerPixmap;
|
||||
SkMatrix lowerInv;
|
||||
SkPixmap* lower = nullptr;
|
||||
float lowerWeight = access->lowerWeight();
|
||||
if (lowerWeight > 0) {
|
||||
std::tie(lowerPixmap, lowerInv) = access->lowerLevel();
|
||||
lower = &lowerPixmap;
|
||||
}
|
||||
|
||||
skvm::Coord upperLocal = SkShaderBase::ApplyMatrix(p, upperInv, origLocal, uniforms);
|
||||
|
||||
// All existing SkColorTypes pass these checks. We'd only fail here adding new ones.
|
||||
skvm::PixelFormat unused;
|
||||
if (true && !SkColorType_to_PixelFormat(upper->colorType(), &unused)) {
|
||||
if (true && !SkColorType_to_PixelFormat(upper.colorType(), &unused)) {
|
||||
return {};
|
||||
}
|
||||
if (lower && !SkColorType_to_PixelFormat(lower->colorType(), &unused)) {
|
||||
@ -942,8 +929,8 @@ skvm::Color SkImageShader::onProgram(skvm::Builder* p,
|
||||
}
|
||||
|
||||
// We can exploit image opacity to skip work unpacking alpha channels.
|
||||
const bool input_is_opaque = SkAlphaTypeIsOpaque(upper->alphaType())
|
||||
|| SkColorTypeIsAlwaysOpaque(upper->colorType());
|
||||
const bool input_is_opaque = SkAlphaTypeIsOpaque(upper.alphaType())
|
||||
|| SkColorTypeIsAlwaysOpaque(upper.colorType());
|
||||
|
||||
// Each call to sample() will try to rewrite the same uniforms over and over,
|
||||
// so remember where we start and reset back there each time. That way each
|
||||
@ -1121,9 +1108,8 @@ skvm::Color SkImageShader::onProgram(skvm::Builder* p,
|
||||
}
|
||||
};
|
||||
|
||||
skvm::Color c = sample_level(*upper, upperInv, upperLocal);
|
||||
skvm::Color c = sample_level(upper, upperInv, upperLocal);
|
||||
if (lower) {
|
||||
auto lowerInv = post_scale(lower->dimensions(), baseInv);
|
||||
auto lowerLocal = SkShaderBase::ApplyMatrix(p, lowerInv, origLocal, uniforms);
|
||||
// lower * weight + upper * (1 - weight)
|
||||
c = lerp(c,
|
||||
@ -1140,9 +1126,9 @@ skvm::Color SkImageShader::onProgram(skvm::Builder* p,
|
||||
}
|
||||
|
||||
// Alpha-only images get their color from the paint (already converted to dst color space).
|
||||
SkColorSpace* cs = upper->colorSpace();
|
||||
SkAlphaType at = upper->alphaType();
|
||||
if (SkColorTypeIsAlphaOnly(upper->colorType())) {
|
||||
SkColorSpace* cs = upper.colorSpace();
|
||||
SkAlphaType at = upper.alphaType();
|
||||
if (SkColorTypeIsAlphaOnly(upper.colorType())) {
|
||||
c.r = paint.r;
|
||||
c.g = paint.g;
|
||||
c.b = paint.b;
|
||||
|
Loading…
Reference in New Issue
Block a user