86a6c6d8bd
This CL has several parts that are intertwined: * move pin/wrap functionality into BilerpSampler. * remove the nearest neighbor and bilerp tilers * create a simplified general tiler * remove the pipeline virtual calls bilerpEdge and bilerpSpan because everything works of sample points now. * redo all the bilerp sampling to use the new local to methods to wrap/pin. * introduce a new medium rate sample that handles spans with 1 < |dx| < 2. This change improves the performance as displayed below: Most of top 25 desktop improves or are the same. A few are worse, but close to the noise floor. In addition, this change has about 3% smaller code. old time new time new/old 13274693 8414645 0.633886 top25desk_google_com_search_q_c.skp_1 4946466 3258018 0.658656 top25desk_wordpress.skp_1 6977187 5737584 0.822335 top25desk_youtube_com.skp_1 3770021 3296831 0.874486 top25desk_google_com__hl_en_q_b.skp_1 8890813 8600143 0.967307 top25desk_answers_yahoo_com.skp_1 3178974 3094300 0.973364 top25desk_facebook.skp_1 8871835 8711260 0.981901 top25desk_twitter.skp_1 838509 829290 0.989005 top25desk_blogger.skp_1 2821870 2801111 0.992644 top25desk_plus_google_com_11003.skp_1 511978 509530 0.995219 top25desk_techcrunch_com.skp_1 2408588 2397435 0.995369 top25desk_ebay_com.skp_1 4446919 4448004 1.00024 top25desk_espn.skp_1 2863241 2875696 1.00435 top25desk_google_com_calendar_.skp_1 7170086 7208447 1.00535 top25desk_booking_com.skp_1 7356109 7417776 1.00838 top25desk_pinterest.skp_1 5265591 5340392 1.01421 top25desk_weather_com.skp_1 5675244 5774144 1.01743 top25desk_sports_yahoo_com_.skp_1 1048531 1067663 1.01825 top25desk_games_yahoo_com.skp_1 2075501 2115131 1.01909 top25desk_amazon_com.skp_1 4262170 4370441 1.0254 top25desk_news_yahoo_com.skp_1 3789319 3897996 1.02868 top25desk_docs___1_open_documen.skp_1 919336 949979 1.03333 top25desk_wikipedia__1_tab_.skp_1 4274454 4489369 1.05028 top25desk_mail_google_com_mail_.skp_1 4149326 4376556 1.05476 top25desk_linkedin.skp_1 BUG=skia:5566 GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2134893002 CQ_INCLUDE_TRYBOTS=client.skia:Test-Ubuntu-GCC-GCE-CPU-AVX2-x86_64-Release-SKNX_NO_SIMD-Trybot;master.client.skia:Test-Ubuntu-GCC-GCE-CPU-AVX2-x86_64-Release-SKNX_NO_SIMD-Trybot Committed: https://skia.googlesource.com/skia/+/8602ede5fdfa721dcad4dcb11db028c1c24265f1 Review-Url: https://codereview.chromium.org/2134893002
182 lines
6.2 KiB
C++
182 lines
6.2 KiB
C++
/*
|
|
* Copyright 2016 Google Inc.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
|
|
#ifndef SkLinearBitmapPipeline_DEFINED
|
|
#define SkLinearBitmapPipeline_DEFINED
|
|
|
|
#include "SkColor.h"
|
|
#include "SkImageInfo.h"
|
|
#include "SkMatrix.h"
|
|
#include "SkShader.h"
|
|
|
|
class SkEmbeddableLinearPipeline;
|
|
|
|
enum SkGammaType {
|
|
kLinear_SkGammaType,
|
|
kSRGB_SkGammaType,
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// SkLinearBitmapPipeline - encapsulates all the machinery for doing floating point pixel
|
|
// processing in a linear color space.
|
|
// Note: this class has unusual alignment requirements due to its use of SIMD instructions. The
|
|
// class SkEmbeddableLinearPipeline below manages these requirements.
|
|
class SkLinearBitmapPipeline {
|
|
public:
|
|
SkLinearBitmapPipeline(
|
|
const SkMatrix& inverse,
|
|
SkFilterQuality filterQuality,
|
|
SkShader::TileMode xTile, SkShader::TileMode yTile,
|
|
SkColor paintColor,
|
|
const SkPixmap& srcPixmap);
|
|
|
|
SkLinearBitmapPipeline(
|
|
const SkLinearBitmapPipeline& pipeline,
|
|
const SkPixmap& srcPixmap,
|
|
SkXfermode::Mode xferMode,
|
|
const SkImageInfo& dstInfo);
|
|
|
|
static bool ClonePipelineForBlitting(
|
|
SkEmbeddableLinearPipeline* pipelineStorage,
|
|
const SkLinearBitmapPipeline& pipeline,
|
|
SkMatrix::TypeMask matrixMask,
|
|
SkShader::TileMode xTileMode,
|
|
SkShader::TileMode yTileMode,
|
|
SkFilterQuality filterQuality,
|
|
const SkPixmap& srcPixmap,
|
|
float finalAlpha,
|
|
SkXfermode::Mode xferMode,
|
|
const SkImageInfo& dstInfo);
|
|
|
|
~SkLinearBitmapPipeline();
|
|
|
|
void shadeSpan4f(int x, int y, SkPM4f* dst, int count);
|
|
void blitSpan(int32_t x, int32_t y, void* dst, int count);
|
|
|
|
template<typename Base, size_t kSize, typename Next = void>
|
|
class Stage {
|
|
public:
|
|
Stage() : fIsInitialized{false} {}
|
|
~Stage();
|
|
|
|
template<typename Variant, typename... Args>
|
|
void initStage(Next* next, Args&& ... args);
|
|
|
|
template<typename Variant, typename... Args>
|
|
void initSink(Args&& ... args);
|
|
|
|
template <typename To, typename From>
|
|
To* getInterface();
|
|
|
|
// Copy this stage to `cloneToStage` with `next` as its next stage
|
|
// (not necessarily the same as our next, you see), returning `cloneToStage`.
|
|
// Note: There is no cloneSinkTo method because the code usually places the top part of
|
|
// the pipeline on a new sampler.
|
|
Base* cloneStageTo(Next* next, Stage* cloneToStage) const;
|
|
|
|
Base* get() const { return reinterpret_cast<Base*>(&fSpace); }
|
|
Base* operator->() const { return this->get(); }
|
|
Base& operator*() const { return *(this->get()); }
|
|
|
|
private:
|
|
std::function<void (Next*, void*)> fStageCloner;
|
|
struct SK_STRUCT_ALIGN(16) Space {
|
|
char space[kSize];
|
|
};
|
|
bool fIsInitialized;
|
|
mutable Space fSpace;
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// PolyMemory
|
|
template <typename Base, size_t kSize>
|
|
class PolyMemory {
|
|
public:
|
|
PolyMemory() : fIsInitialized{false} { }
|
|
~PolyMemory() {
|
|
if (fIsInitialized) {
|
|
this->get()->~Base();
|
|
}
|
|
}
|
|
template<typename Variant, typename... Args>
|
|
void init(Args&& ... args) {
|
|
SkASSERTF(sizeof(Variant) <= sizeof(fSpace),
|
|
"Size Variant: %d, Space: %d", sizeof(Variant), sizeof(fSpace));
|
|
|
|
new (&fSpace) Variant(std::forward<Args>(args)...);
|
|
fIsInitialized = true;
|
|
}
|
|
|
|
Base* get() const { return reinterpret_cast<Base*>(&fSpace); }
|
|
Base* operator->() const { return this->get(); }
|
|
Base& operator*() const { return *(this->get()); }
|
|
|
|
private:
|
|
struct SK_STRUCT_ALIGN(16) Space {
|
|
char space[kSize];
|
|
};
|
|
mutable Space fSpace;
|
|
bool fIsInitialized;
|
|
|
|
};
|
|
|
|
class PointProcessorInterface;
|
|
class SampleProcessorInterface;
|
|
class BlendProcessorInterface;
|
|
class DestinationInterface;
|
|
class PixelAccessorInterface;
|
|
|
|
// These values were generated by the assert above in Stage::init{Sink|Stage}.
|
|
using MatrixStage = Stage<PointProcessorInterface, 160, PointProcessorInterface>;
|
|
using TileStage = Stage<PointProcessorInterface, 160, SampleProcessorInterface>;
|
|
using SampleStage = Stage<SampleProcessorInterface, 160, BlendProcessorInterface>;
|
|
using BlenderStage = Stage<BlendProcessorInterface, 40>;
|
|
using Accessor = PolyMemory<PixelAccessorInterface, 64>;
|
|
|
|
private:
|
|
PointProcessorInterface* fFirstStage;
|
|
MatrixStage fMatrixStage;
|
|
TileStage fTileStage;
|
|
SampleStage fSampleStage;
|
|
BlenderStage fBlenderStage;
|
|
DestinationInterface* fLastStage;
|
|
Accessor fAccessor;
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// SkEmbeddableLinearPipeline - manage stricter alignment needs for SkLinearBitmapPipeline.
|
|
class SkEmbeddableLinearPipeline {
|
|
public:
|
|
SkEmbeddableLinearPipeline() { }
|
|
~SkEmbeddableLinearPipeline() {
|
|
if (get() != nullptr) {
|
|
get()->~SkLinearBitmapPipeline();
|
|
}
|
|
}
|
|
|
|
template <typename... Args>
|
|
void init(Args&&... args) {
|
|
// Ensure that our pipeline is created at a 16 byte aligned address.
|
|
fPipeline = (SkLinearBitmapPipeline*)SkAlign16((intptr_t)fPipelineStorage);
|
|
new (fPipeline) SkLinearBitmapPipeline{std::forward<Args>(args)...};
|
|
}
|
|
|
|
SkLinearBitmapPipeline* get() const { return fPipeline; }
|
|
SkLinearBitmapPipeline& operator*() const { return *this->get(); }
|
|
SkLinearBitmapPipeline* operator->() const { return this->get(); }
|
|
|
|
private:
|
|
enum {
|
|
kActualSize = sizeof(SkLinearBitmapPipeline),
|
|
kPaddedSize = SkAlignPtr(kActualSize + 12),
|
|
};
|
|
void* fPipelineStorage[kPaddedSize / sizeof(void*)];
|
|
SkLinearBitmapPipeline* fPipeline{nullptr};
|
|
};
|
|
|
|
#endif // SkLinearBitmapPipeline_DEFINED
|