add support for new bitmapshader context
BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1757993002 Review URL: https://codereview.chromium.org/1757993002
This commit is contained in:
parent
1610835624
commit
19cef56344
@ -60,7 +60,7 @@ static void draw_rect_orig(SkCanvas* canvas, const SkRect& r, SkColor c, const S
|
||||
SkAutoTUnref<SkImage> image{SkImage::NewRasterCopy(
|
||||
info, pmsrc.addr32(), pmsrc.rowBytes())};
|
||||
SkPaint paint;
|
||||
int32_t storage[200];
|
||||
int32_t storage[300];
|
||||
SkShader* shader = image->newShader(SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
|
||||
if (useBilerp) {
|
||||
paint.setFilterQuality(SkFilterQuality::kLow_SkFilterQuality);
|
||||
|
@ -27,8 +27,7 @@ static bool only_scale_and_translate(const SkMatrix& matrix) {
|
||||
|
||||
class BitmapProcInfoContext : public SkShader::Context {
|
||||
public:
|
||||
// The context takes ownership of the info. It will call its destructor
|
||||
// but will NOT free the memory.
|
||||
// The info has been allocated elsewhere, but we are responsible for calling its destructor.
|
||||
BitmapProcInfoContext(const SkShader& shader, const SkShader::ContextRec& rec,
|
||||
SkBitmapProcInfo* info)
|
||||
: INHERITED(shader, rec)
|
||||
@ -45,8 +44,6 @@ public:
|
||||
}
|
||||
|
||||
~BitmapProcInfoContext() override {
|
||||
// The bitmap proc state has been created outside of the context on memory that will be freed
|
||||
// elsewhere. Only call the destructor but leave the freeing of the memory to the caller.
|
||||
fInfo->~SkBitmapProcInfo();
|
||||
}
|
||||
|
||||
@ -63,8 +60,6 @@ private:
|
||||
|
||||
class BitmapProcShaderContext : public BitmapProcInfoContext {
|
||||
public:
|
||||
// The context takes ownership of the state. It will call its destructor
|
||||
// but will NOT free the memory.
|
||||
BitmapProcShaderContext(const SkShader& shader, const SkShader::ContextRec& rec,
|
||||
SkBitmapProcState* state)
|
||||
: INHERITED(shader, rec, state)
|
||||
@ -116,11 +111,80 @@ private:
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#include "SkLinearBitmapPipeline.h"
|
||||
#include "SkPM4f.h"
|
||||
#include "SkXfermode.h"
|
||||
|
||||
size_t SkBitmapProcShader::ContextSize(const ContextRec& rec) {
|
||||
// The SkBitmapProcState is stored outside of the context object, with the context holding
|
||||
// a pointer to it.
|
||||
return sizeof(BitmapProcShaderContext) + sizeof(SkBitmapProcState);
|
||||
class LinearPipelineContext : public BitmapProcInfoContext {
|
||||
public:
|
||||
LinearPipelineContext(const SkShader& shader, const SkShader::ContextRec& rec,
|
||||
SkBitmapProcInfo* info)
|
||||
: INHERITED(shader, rec, info)
|
||||
, fPipeline(info->fInvMatrix, info->fFilterQuality, info->fTileModeX, info->fTileModeY,
|
||||
info->fPixmap)
|
||||
{
|
||||
// To implement the old shadeSpan entry-point, we need to efficiently convert our native
|
||||
// floats into SkPMColor. The SkXfermode::D32Procs do exactly that.
|
||||
//
|
||||
sk_sp<SkXfermode> xfer(SkXfermode::Create(SkXfermode::kSrc_Mode));
|
||||
fXferProc = SkXfermode::GetD32Proc(xfer.get(), 0);
|
||||
}
|
||||
|
||||
void shadeSpan4f(int x, int y, SkPM4f dstC[], int count) override {
|
||||
fPipeline.shadeSpan4f(x, y, dstC, count);
|
||||
}
|
||||
|
||||
void shadeSpan(int x, int y, SkPMColor dstC[], int count) override {
|
||||
const int N = 128;
|
||||
SkPM4f tmp[N];
|
||||
|
||||
while (count > 0) {
|
||||
const int n = SkTMin(count, N);
|
||||
fPipeline.shadeSpan4f(x, y, tmp, n);
|
||||
fXferProc(nullptr, dstC, tmp, n, nullptr);
|
||||
dstC += n;
|
||||
x += n;
|
||||
count -= n;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
SkLinearBitmapPipeline fPipeline;
|
||||
SkXfermode::D32Proc fXferProc;
|
||||
|
||||
typedef BitmapProcInfoContext INHERITED;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static bool choose_linear_pipeline(const SkShader::ContextRec& rec, const SkImageInfo& srcInfo) {
|
||||
// These src attributes are not supported in the new 4f context (yet)
|
||||
//
|
||||
if (srcInfo.bytesPerPixel() < 4 ||
|
||||
kRGBA_F16_SkColorType == srcInfo.colorType()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#if 0 // later we may opt-in to the new code even if the client hasn't requested it...
|
||||
// These src attributes are only supported in the new 4f context
|
||||
//
|
||||
if (srcInfo.isSRGB() ||
|
||||
kUnpremul_SkAlphaType == srcInfo.alphaType() ||
|
||||
(4 == srcInfo.bytesPerPixel() && kN32_SkColorType != srcInfo.colorType()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// If we get here, we can reasonably use either context, respect the caller's preference
|
||||
//
|
||||
return SkShader::ContextRec::kPM4f_DstType == rec.fPreferredDstType;
|
||||
}
|
||||
|
||||
size_t SkBitmapProcShader::ContextSize(const ContextRec& rec, const SkImageInfo& srcInfo) {
|
||||
size_t size0 = sizeof(BitmapProcShaderContext) + sizeof(SkBitmapProcState);
|
||||
size_t size1 = sizeof(LinearPipelineContext) + sizeof(SkBitmapProcInfo);
|
||||
return SkTMax(size0, size1);
|
||||
}
|
||||
|
||||
SkShader::Context* SkBitmapProcShader::MakeContext(const SkShader& shader,
|
||||
@ -133,16 +197,32 @@ SkShader::Context* SkBitmapProcShader::MakeContext(const SkShader& shader,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void* stateStorage = (char*)storage + sizeof(BitmapProcShaderContext);
|
||||
SkBitmapProcState* state = new (stateStorage) SkBitmapProcState(provider, tmx, tmy);
|
||||
|
||||
SkASSERT(state);
|
||||
if (!state->setup(totalInverse, *rec.fPaint)) {
|
||||
state->~SkBitmapProcState();
|
||||
return nullptr;
|
||||
// Decide if we can/want to use the new linear pipeine
|
||||
bool useLinearPipeline = choose_linear_pipeline(rec, provider.info());
|
||||
if (SkShader::kMirror_TileMode == tmx || SkShader::kMirror_TileMode == tmy) {
|
||||
useLinearPipeline = false;
|
||||
}
|
||||
if (totalInverse.hasPerspective()) {
|
||||
useLinearPipeline = false;
|
||||
}
|
||||
|
||||
return new (storage) BitmapProcShaderContext(shader, rec, state);
|
||||
if (useLinearPipeline) {
|
||||
void* infoStorage = (char*)storage + sizeof(LinearPipelineContext);
|
||||
SkBitmapProcInfo* info = new (infoStorage) SkBitmapProcInfo(provider, tmx, tmy);
|
||||
if (!info->init(totalInverse, *rec.fPaint)) {
|
||||
info->~SkBitmapProcInfo();
|
||||
return nullptr;
|
||||
}
|
||||
return new (storage) LinearPipelineContext(shader, rec, info);
|
||||
} else {
|
||||
void* stateStorage = (char*)storage + sizeof(BitmapProcShaderContext);
|
||||
SkBitmapProcState* state = new (stateStorage) SkBitmapProcState(provider, tmx, tmy);
|
||||
if (!state->setup(totalInverse, *rec.fPaint)) {
|
||||
state->~SkBitmapProcState();
|
||||
return nullptr;
|
||||
}
|
||||
return new (storage) BitmapProcShaderContext(shader, rec, state);
|
||||
}
|
||||
}
|
||||
|
||||
SkShader::Context* SkBitmapProcShader::onCreateContext(const ContextRec& rec, void* storage) const {
|
||||
|
@ -21,7 +21,9 @@ public:
|
||||
|
||||
bool isOpaque() const override;
|
||||
|
||||
size_t contextSize(const ContextRec& rec) const override { return ContextSize(rec); }
|
||||
size_t contextSize(const ContextRec& rec) const override {
|
||||
return ContextSize(rec, fRawBitmap.info());
|
||||
}
|
||||
|
||||
SK_TO_STRING_OVERRIDE()
|
||||
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkBitmapProcShader)
|
||||
@ -36,13 +38,13 @@ protected:
|
||||
Context* onCreateContext(const ContextRec&, void* storage) const override;
|
||||
bool onIsABitmap(SkBitmap*, SkMatrix*, TileMode*) const override;
|
||||
|
||||
SkBitmap fRawBitmap; // experimental for RLE encoding
|
||||
SkBitmap fRawBitmap;
|
||||
uint8_t fTileModeX, fTileModeY;
|
||||
|
||||
private:
|
||||
friend class SkImageShader;
|
||||
|
||||
static size_t ContextSize(const ContextRec&);
|
||||
static size_t ContextSize(const ContextRec&, const SkImageInfo& srcInfo);
|
||||
static Context* MakeContext(const SkShader&, TileMode tmx, TileMode tmy,
|
||||
const SkBitmapProvider&, const ContextRec&, void* storage);
|
||||
|
||||
@ -54,7 +56,7 @@ private:
|
||||
// an Sk3DBlitter in SkDraw.cpp
|
||||
// Note that some contexts may contain other contexts (e.g. for compose shaders), but we've not
|
||||
// yet found a situation where the size below isn't big enough.
|
||||
typedef SkSmallAllocator<3, 1500> SkTBlitterAllocator;
|
||||
typedef SkSmallAllocator<3, 2100> SkTBlitterAllocator;
|
||||
|
||||
// If alloc is non-nullptr, it will be used to allocate the returned SkShader, and MUST outlive
|
||||
// the SkShader.
|
||||
|
@ -31,9 +31,9 @@ SkComposeShader::~SkComposeShader() {
|
||||
}
|
||||
|
||||
size_t SkComposeShader::contextSize(const ContextRec& rec) const {
|
||||
return sizeof(ComposeShaderContext)
|
||||
+ fShaderA->contextSize(rec)
|
||||
+ fShaderB->contextSize(rec);
|
||||
return SkAlign16(sizeof(ComposeShaderContext))
|
||||
+ SkAlign16(fShaderA->contextSize(rec))
|
||||
+ SkAlign16(fShaderB->contextSize(rec));
|
||||
}
|
||||
|
||||
class SkAutoAlphaRestore {
|
||||
@ -76,8 +76,8 @@ template <typename T> void safe_call_destructor(T* obj) {
|
||||
}
|
||||
|
||||
SkShader::Context* SkComposeShader::onCreateContext(const ContextRec& rec, void* storage) const {
|
||||
char* aStorage = (char*) storage + sizeof(ComposeShaderContext);
|
||||
char* bStorage = aStorage + fShaderA->contextSize(rec);
|
||||
char* aStorage = (char*) storage + SkAlign16(sizeof(ComposeShaderContext));
|
||||
char* bStorage = aStorage + SkAlign16(fShaderA->contextSize(rec));
|
||||
|
||||
// we preconcat our localMatrix (if any) with the device matrix
|
||||
// before calling our sub-shaders
|
||||
|
@ -86,6 +86,9 @@ bool SkShader::asLuminanceColor(SkColor* colorPtr) const {
|
||||
}
|
||||
|
||||
SkShader::Context* SkShader::createContext(const ContextRec& rec, void* storage) const {
|
||||
// We currently require 16byte alignment for some of our subclasses, so assert that here.
|
||||
SkASSERT(SkIsAlign16((intptr_t)storage));
|
||||
|
||||
if (!this->computeTotalInverse(rec, nullptr)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ bool SkImageShader::isOpaque() const {
|
||||
}
|
||||
|
||||
size_t SkImageShader::contextSize(const ContextRec& rec) const {
|
||||
return SkBitmapProcShader::ContextSize(rec);
|
||||
return SkBitmapProcShader::ContextSize(rec, SkBitmapProvider(fImage).info());
|
||||
}
|
||||
|
||||
SkShader::Context* SkImageShader::onCreateContext(const ContextRec& rec, void* storage) const {
|
||||
|
@ -149,7 +149,7 @@ DEF_TEST(Color4f_shader, reporter) {
|
||||
|
||||
SkPaint paint;
|
||||
for (const auto& rec : recs) {
|
||||
uint32_t storage[200];
|
||||
uint32_t storage[300];
|
||||
paint.setShader(rec.fFact())->unref();
|
||||
// Encourage 4f context selection. At some point we may need
|
||||
// to instantiate two separate contexts for optimal 4b/4f selection.
|
||||
|
Loading…
Reference in New Issue
Block a user