| /* |
| * 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 |