/* * 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 class Stage { public: Stage() : fIsInitialized{false} {} ~Stage(); template void initStage(Next* next, Args&& ... args); template void initSink(Args&& ... args); template 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(&fSpace); } Base* operator->() const { return this->get(); } Base& operator*() const { return *(this->get()); } private: std::function fStageCloner; struct SK_STRUCT_ALIGN(16) Space { char space[kSize]; }; bool fIsInitialized; mutable Space fSpace; }; /////////////////////////////////////////////////////////////////////////////////////////////////// // PolyMemory template class PolyMemory { public: PolyMemory() : fIsInitialized{false} { } ~PolyMemory() { if (fIsInitialized) { this->get()->~Base(); } } template void init(Args&& ... args) { SkASSERTF(sizeof(Variant) <= sizeof(fSpace), "Size Variant: %d, Space: %d", sizeof(Variant), sizeof(fSpace)); new (&fSpace) Variant(std::forward(args)...); fIsInitialized = true; } Base* get() const { return reinterpret_cast(&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; using TileStage = Stage; using SampleStage = Stage; using BlenderStage = Stage; using Accessor = PolyMemory; 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 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)...}; } 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