diff options
author | Bo Liu <boliu@google.com> | 2014-05-01 10:38:38 -0700 |
---|---|---|
committer | Bo Liu <boliu@google.com> | 2014-05-01 10:38:38 -0700 |
commit | 27ab20dffff01006f5d20fdb2b3f4ea503d69114 (patch) | |
tree | f8a42f1186f835772ed0c20a7f9095392e124b04 | |
parent | 51512eaae8128a677f92e2689d8df720dca13d32 (diff) | |
parent | 2e8705638185600b128f867809b6cd034225451c (diff) | |
download | src-idea133-weekly-release.tar.gz |
Merge from Chromium at DEPS revision 267519idea133-weekly-release
This commit was generated by merge_to_master.py.
Change-Id: Ic063600f0ecbd8d3c74d2d514eaf91c1a33c9f07
133 files changed, 2722 insertions, 2582 deletions
diff --git a/animator/SkDrawBlur.cpp b/animator/SkDrawBlur.cpp index 5f388c93..36d64528 100644 --- a/animator/SkDrawBlur.cpp +++ b/animator/SkDrawBlur.cpp @@ -22,11 +22,12 @@ DEFINE_GET_MEMBER(SkDrawBlur); SkDrawBlur::SkDrawBlur() : fSigma(-1) - , fBlurStyle(SkBlurMaskFilter::kNormal_BlurStyle) { + , fBlurStyle(kNormal_SkBlurStyle) { } SkMaskFilter* SkDrawBlur::getMaskFilter() { - if (fSigma < 0) + if (fSigma <= 0) { return NULL; - return SkBlurMaskFilter::Create((SkBlurMaskFilter::BlurStyle) fBlurStyle, fSigma); + } + return SkBlurMaskFilter::Create((SkBlurStyle)fBlurStyle, fSigma); } diff --git a/animator/SkDrawBlur.h b/animator/SkDrawBlur.h index 462a0413..75075922 100644 --- a/animator/SkDrawBlur.h +++ b/animator/SkDrawBlur.h @@ -17,7 +17,7 @@ class SkDrawBlur : public SkDrawMaskFilter { virtual SkMaskFilter* getMaskFilter() SK_OVERRIDE; protected: SkScalar fSigma; - int /*SkBlurMaskFilter::BlurStyle*/ fBlurStyle; + int /*SkBlurStyle*/ fBlurStyle; typedef SkDrawMaskFilter INHERITED; }; diff --git a/animator/SkDrawGradient.cpp b/animator/SkDrawGradient.cpp index 1b158f23..c1155958 100644 --- a/animator/SkDrawGradient.cpp +++ b/animator/SkDrawGradient.cpp @@ -175,9 +175,9 @@ SkShader* SkDrawLinearGradient::getShader() { if (addPrelude() == 0 || points.count() != 4) return NULL; SkShader* shader = SkGradientShader::CreateLinear((SkPoint*)points.begin(), - fColors.begin(), offsets.begin(), fColors.count(), (SkShader::TileMode) tileMode, fUnitMapper); + fColors.begin(), offsets.begin(), fColors.count(), (SkShader::TileMode) tileMode, + fUnitMapper, 0, getMatrix()); SkAutoTDelete<SkShader> autoDel(shader); - addPostlude(shader); (void)autoDel.detach(); return shader; } @@ -210,9 +210,9 @@ SkShader* SkDrawRadialGradient::getShader() { if (addPrelude() == 0) return NULL; SkShader* shader = SkGradientShader::CreateRadial(center, - radius, fColors.begin(), offsets.begin(), fColors.count(), (SkShader::TileMode) tileMode, fUnitMapper); + radius, fColors.begin(), offsets.begin(), fColors.count(), (SkShader::TileMode) tileMode, + fUnitMapper, 0, getMatrix()); SkAutoTDelete<SkShader> autoDel(shader); - addPostlude(shader); (void)autoDel.detach(); return shader; } diff --git a/animator/SkDrawShader.cpp b/animator/SkDrawShader.cpp index e3aa4da0..f9f379bf 100644 --- a/animator/SkDrawShader.cpp +++ b/animator/SkDrawShader.cpp @@ -36,9 +36,8 @@ bool SkDrawShader::add() { return false; } -void SkDrawShader::addPostlude(SkShader* shader) { - if (matrix) - shader->setLocalMatrix(matrix->getMatrix()); +SkMatrix* SkDrawShader::getMatrix() { + return matrix ? &matrix->getMatrix() : NULL; } #if SK_USE_CONDENSED_INFO == 0 @@ -75,9 +74,9 @@ SkShader* SkDrawBitmapShader::getShader() { // draw-time from the paint SkShader* shader = SkShader::CreateBitmapShader(image->fBitmap, (SkShader::TileMode) tileMode, - (SkShader::TileMode) tileMode); + (SkShader::TileMode) tileMode, + getMatrix()); SkAutoTDelete<SkShader> autoDel(shader); - addPostlude(shader); (void)autoDel.detach(); return shader; } diff --git a/animator/SkPaintPart.h b/animator/SkPaintPart.h index a6154e5d..6f33cb4c 100644 --- a/animator/SkPaintPart.h +++ b/animator/SkPaintPart.h @@ -51,7 +51,7 @@ class SkDrawShader : public SkPaintPart { virtual SkShader* getShader(); protected: virtual bool add(); - void addPostlude(SkShader* shader); + SkMatrix* getMatrix(); // returns NULL if matrix is NULL SkDrawMatrix* matrix; int /*SkShader::TileMode*/ tileMode; }; diff --git a/core/SkBBoxHierarchyRecord.cpp b/core/SkBBoxHierarchyRecord.cpp index 16ade774..f0382e64 100644 --- a/core/SkBBoxHierarchyRecord.cpp +++ b/core/SkBBoxHierarchyRecord.cpp @@ -9,10 +9,11 @@ #include "SkBBoxHierarchyRecord.h" #include "SkPictureStateTree.h" -SkBBoxHierarchyRecord::SkBBoxHierarchyRecord(const SkISize& size, +SkBBoxHierarchyRecord::SkBBoxHierarchyRecord(SkPicture* picture, + const SkISize& size, uint32_t recordFlags, SkBBoxHierarchy* h) - : INHERITED(size, recordFlags) { + : INHERITED(picture, size, recordFlags) { fStateTree = SkNEW(SkPictureStateTree); fBoundingHierarchy = h; fBoundingHierarchy->ref(); diff --git a/core/SkBBoxHierarchyRecord.h b/core/SkBBoxHierarchyRecord.h index 51fce0d8..f6fac180 100644 --- a/core/SkBBoxHierarchyRecord.h +++ b/core/SkBBoxHierarchyRecord.h @@ -19,7 +19,8 @@ class SkBBoxHierarchyRecord : public SkBBoxRecord, public SkBBoxHierarchyClient { public: /** This will take a ref of h */ - SkBBoxHierarchyRecord(const SkISize& size, uint32_t recordFlags, SkBBoxHierarchy* h); + SkBBoxHierarchyRecord(SkPicture* picture, const SkISize& size, + uint32_t recordFlags, SkBBoxHierarchy* h); virtual void handleBBox(const SkRect& bounds) SK_OVERRIDE; diff --git a/core/SkBBoxRecord.h b/core/SkBBoxRecord.h index 3a0c53bf..f2e9d8d2 100644 --- a/core/SkBBoxRecord.h +++ b/core/SkBBoxRecord.h @@ -19,7 +19,9 @@ class SkBBoxRecord : public SkPictureRecord { public: - SkBBoxRecord(const SkISize& size, uint32_t recordFlags) : INHERITED(size, recordFlags) {} + SkBBoxRecord(SkPicture* picture, const SkISize& size, uint32_t recordFlags) + : INHERITED(picture, size, recordFlags) { + } virtual ~SkBBoxRecord() { } /** diff --git a/core/SkBitmapDevice.cpp b/core/SkBitmapDevice.cpp index c2b633e1..311e72f5 100644 --- a/core/SkBitmapDevice.cpp +++ b/core/SkBitmapDevice.cpp @@ -381,11 +381,11 @@ void SkBitmapDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, // construct a shader, so we can call drawRect with the dst SkShader* s = SkShader::CreateBitmapShader(*bitmapPtr, SkShader::kClamp_TileMode, - SkShader::kClamp_TileMode); + SkShader::kClamp_TileMode, + &matrix); if (NULL == s) { return; } - s->setLocalMatrix(matrix); SkPaint paintWithShader(paint); paintWithShader.setStyle(SkPaint::kFill_Style); diff --git a/core/SkBitmapProcShader.cpp b/core/SkBitmapProcShader.cpp index 5f5eb186..44bdc6d3 100644 --- a/core/SkBitmapProcShader.cpp +++ b/core/SkBitmapProcShader.cpp @@ -31,8 +31,9 @@ bool SkBitmapProcShader::CanDo(const SkBitmap& bm, TileMode tx, TileMode ty) { return false; } -SkBitmapProcShader::SkBitmapProcShader(const SkBitmap& src, - TileMode tmx, TileMode tmy) { +SkBitmapProcShader::SkBitmapProcShader(const SkBitmap& src, TileMode tmx, TileMode tmy, + const SkMatrix* localMatrix) + : INHERITED(localMatrix) { fRawBitmap = src; fTileModeX = (uint8_t)tmx; fTileModeY = (uint8_t)tmy; @@ -347,7 +348,7 @@ static bool bitmapIsTooBig(const SkBitmap& bm) { } SkShader* CreateBitmapShader(const SkBitmap& src, SkShader::TileMode tmx, - SkShader::TileMode tmy, SkTBlitterAllocator* allocator) { + SkShader::TileMode tmy, const SkMatrix* localMatrix, SkTBlitterAllocator* allocator) { SkShader* shader; SkColor color; if (src.isNull() || bitmapIsTooBig(src)) { @@ -365,9 +366,9 @@ SkShader* CreateBitmapShader(const SkBitmap& src, SkShader::TileMode tmx, } } else { if (NULL == allocator) { - shader = SkNEW_ARGS(SkBitmapProcShader, (src, tmx, tmy)); + shader = SkNEW_ARGS(SkBitmapProcShader, (src, tmx, tmy, localMatrix)); } else { - shader = allocator->createT<SkBitmapProcShader>(src, tmx, tmy); + shader = allocator->createT<SkBitmapProcShader>(src, tmx, tmy, localMatrix); } } return shader; diff --git a/core/SkBitmapProcShader.h b/core/SkBitmapProcShader.h index e0c78b8e..78b46ce6 100644 --- a/core/SkBitmapProcShader.h +++ b/core/SkBitmapProcShader.h @@ -16,7 +16,8 @@ class SkBitmapProcShader : public SkShader { public: - SkBitmapProcShader(const SkBitmap& src, TileMode tx, TileMode ty); + SkBitmapProcShader(const SkBitmap& src, TileMode tx, TileMode ty, + const SkMatrix* localMatrix = NULL); // overrides from SkShader virtual bool isOpaque() const SK_OVERRIDE; @@ -91,6 +92,6 @@ typedef SkSmallAllocator<3, sizeof(SkBitmapProcShader) + // If alloc is non-NULL, it will be used to allocate the returned SkShader, and MUST outlive // the SkShader. SkShader* CreateBitmapShader(const SkBitmap& src, SkShader::TileMode, SkShader::TileMode, - SkTBlitterAllocator* alloc); + const SkMatrix* localMatrix, SkTBlitterAllocator* alloc); #endif diff --git a/core/SkBlitter.cpp b/core/SkBlitter.cpp index 7243f521..41f37e65 100644 --- a/core/SkBlitter.cpp +++ b/core/SkBlitter.cpp @@ -928,8 +928,9 @@ SkBlitter* SkBlitter::Choose(const SkBitmap& device, if (NULL == shader) { if (mode) { // xfermodes (and filters) require shaders for our current blitters - shader = SkNEW(SkColorShader); + shader = SkNEW_ARGS(SkColorShader, (paint->getColor())); paint.writable()->setShader(shader)->unref(); + paint.writable()->setAlpha(0xFF); } else if (cf) { // if no shader && no xfermode, we just apply the colorfilter to // our color and move on. diff --git a/core/SkCanvas.cpp b/core/SkCanvas.cpp index e3451cde..6c0fc884 100644 --- a/core/SkCanvas.cpp +++ b/core/SkCanvas.cpp @@ -834,6 +834,11 @@ void SkCanvas::willSave(SaveFlags) { // Do nothing. Subclasses may do something. } +int SkCanvas::save() { + this->willSave(kMatrixClip_SaveFlag); + return this->internalSave(kMatrixClip_SaveFlag); +} + int SkCanvas::save(SaveFlags flags) { this->willSave(flags); // call shared impl @@ -898,9 +903,13 @@ SkCanvas::SaveLayerStrategy SkCanvas::willSaveLayer(const SkRect*, const SkPaint return kFullLayer_SaveLayerStrategy; } +int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) { + SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag); + return this->internalSaveLayer(bounds, paint, kARGB_ClipLayer_SaveFlag, false, strategy); +} + int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags) { - // Overriding classes may return false to signal that we don't need to create a layer. SaveLayerStrategy strategy = this->willSaveLayer(bounds, paint, flags); return this->internalSaveLayer(bounds, paint, flags, false, strategy); } @@ -975,6 +984,10 @@ int SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, Save return count; } +int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) { + return this->saveLayerAlpha(bounds, alpha, kARGB_ClipLayer_SaveFlag); +} + int SkCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha, SaveFlags flags) { if (0xFF == alpha) { @@ -2343,7 +2356,7 @@ void SkCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint iter.fDevice->drawPosText(iter, text, byteLength, &pos->fX, 0, 2, dfp.paint()); } - + LOOPER_END } @@ -2356,7 +2369,7 @@ void SkCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScala iter.fDevice->drawPosText(iter, text, byteLength, xpos, constY, 1, dfp.paint()); } - + LOOPER_END } @@ -2368,7 +2381,7 @@ void SkCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPat iter.fDevice->drawTextOnPath(iter, text, byteLength, path, matrix, looper.paint()); } - + LOOPER_END } diff --git a/core/SkComposeShader.cpp b/core/SkComposeShader.cpp index 77bc46f3..2c27c9e7 100644 --- a/core/SkComposeShader.cpp +++ b/core/SkComposeShader.cpp @@ -30,11 +30,11 @@ SkComposeShader::SkComposeShader(SkReadBuffer& buffer) : INHERITED(buffer) { fShaderA = buffer.readShader(); if (NULL == fShaderA) { - fShaderA = SkNEW_ARGS(SkColorShader, (0)); + fShaderA = SkNEW_ARGS(SkColorShader, ((SkColor)0)); } fShaderB = buffer.readShader(); if (NULL == fShaderB) { - fShaderB = SkNEW_ARGS(SkColorShader, (0)); + fShaderB = SkNEW_ARGS(SkColorShader, ((SkColor)0)); } fMode = buffer.readXfermode(); } diff --git a/core/SkDraw.cpp b/core/SkDraw.cpp index 6ddd0d27..f9e06e52 100644 --- a/core/SkDraw.cpp +++ b/core/SkDraw.cpp @@ -72,11 +72,12 @@ private: */ class SkAutoBitmapShaderInstall : SkNoncopyable { public: - SkAutoBitmapShaderInstall(const SkBitmap& src, const SkPaint& paint) + SkAutoBitmapShaderInstall(const SkBitmap& src, const SkPaint& paint, + const SkMatrix* localMatrix = NULL) : fPaint(paint) /* makes a copy of the paint */ { fPaint.setShader(CreateBitmapShader(src, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode, - &fAllocator)); + localMatrix, &fAllocator)); // we deliberately left the shader with an owner-count of 2 SkASSERT(2 == fPaint.getShader()->getRefCnt()); } @@ -1374,18 +1375,16 @@ void SkDraw::drawSprite(const SkBitmap& bitmap, int x, int y, } } - SkAutoBitmapShaderInstall install(bitmap, paint); - const SkPaint& shaderPaint = install.paintWithShader(); - SkMatrix matrix; SkRect r; // get a scalar version of our rect r.set(bounds); - // tell the shader our offset + // create shader with offset matrix.setTranslate(r.fLeft, r.fTop); - shaderPaint.getShader()->setLocalMatrix(matrix); + SkAutoBitmapShaderInstall install(bitmap, paint, &matrix); + const SkPaint& shaderPaint = install.paintWithShader(); SkDraw draw(*this); matrix.reset(); diff --git a/core/SkDrawLooper.cpp b/core/SkDrawLooper.cpp index c620cd08..d18d1271 100644 --- a/core/SkDrawLooper.cpp +++ b/core/SkDrawLooper.cpp @@ -59,3 +59,7 @@ void SkDrawLooper::computeFastBounds(const SkPaint& paint, const SkRect& src, } } } + +bool SkDrawLooper::asABlurShadow(BlurShadowRec*) const { + return false; +} diff --git a/core/SkGlyphCache.cpp b/core/SkGlyphCache.cpp index 7b57e2f5..cb7c1b0a 100755 --- a/core/SkGlyphCache.cpp +++ b/core/SkGlyphCache.cpp @@ -11,6 +11,7 @@ #include "SkGlyphCache_Globals.h" #include "SkDistanceFieldGen.h" #include "SkGraphics.h" +#include "SkOnce.h" #include "SkPaint.h" #include "SkPath.h" #include "SkTemplates.h" @@ -22,11 +23,17 @@ bool gSkSuppressFontCachePurgeSpew; +static void create_globals(SkGlyphCache_Globals** globals) { + *globals = SkNEW_ARGS(SkGlyphCache_Globals, (SkGlyphCache_Globals::kYes_UseMutex)); +} + // Returns the shared globals static SkGlyphCache_Globals& getSharedGlobals() { // we leak this, so we don't incur any shutdown cost of the destructor - static SkGlyphCache_Globals* gGlobals = SkNEW_ARGS(SkGlyphCache_Globals, - (SkGlyphCache_Globals::kYes_UseMutex)); + static SkGlyphCache_Globals* gGlobals = NULL; + SK_DECLARE_STATIC_ONCE(once); + SkOnce(&once, create_globals, &gGlobals); + SkASSERT(NULL != gGlobals); return *gGlobals; } diff --git a/core/SkMaskFilter.cpp b/core/SkMaskFilter.cpp index 9b023d0d..8b9792c2 100644 --- a/core/SkMaskFilter.cpp +++ b/core/SkMaskFilter.cpp @@ -26,6 +26,10 @@ bool SkMaskFilter::filterMask(SkMask*, const SkMask&, const SkMatrix&, return false; } +bool SkMaskFilter::asABlur(BlurRec*) const { + return false; +} + static void extractMaskSubset(const SkMask& src, SkMask* dst) { SkASSERT(src.fBounds.contains(dst->fBounds)); diff --git a/core/SkPicture.cpp b/core/SkPicture.cpp index 316994a2..3b04906e 100644 --- a/core/SkPicture.cpp +++ b/core/SkPicture.cpp @@ -31,6 +31,10 @@ #include "GrContext.h" #endif +template <typename T> int SafeCount(const T* obj) { + return obj ? obj->count() : 0; +} + #define DUMP_BUFFER_SIZE 65536 //#define ENABLE_TIME_DRAW // dumps milliseconds for each draw @@ -118,17 +122,18 @@ static void validateMatrix(const SkMatrix* matrix) { /////////////////////////////////////////////////////////////////////////////// -SkPicture::SkPicture() { +SkPicture::SkPicture() + : fAccelData(NULL) { this->needsNewGenID(); fRecord = NULL; fPlayback = NULL; fWidth = fHeight = 0; - fAccelData = NULL; } SkPicture::SkPicture(const SkPicture& src) : INHERITED() - , fAccelData(NULL) { + , fAccelData(NULL) + , fContentInfo(src.fContentInfo) { this->needsNewGenID(); fWidth = src.fWidth; fHeight = src.fHeight; @@ -139,17 +144,48 @@ SkPicture::SkPicture(const SkPicture& src) it (since it is destructive, and we don't want to change src). */ if (src.fPlayback) { - fPlayback = SkNEW_ARGS(SkPicturePlayback, (*src.fPlayback)); + fPlayback = SkNEW_ARGS(SkPicturePlayback, (this, *src.fPlayback)); SkASSERT(NULL == src.fRecord); fUniqueID = src.uniqueID(); // need to call method to ensure != 0 } else if (src.fRecord) { SkPictInfo info; this->createHeader(&info); // here we do a fake src.endRecording() - fPlayback = SkNEW_ARGS(SkPicturePlayback, (*src.fRecord, info)); + fPlayback = SkNEW_ARGS(SkPicturePlayback, (this, *src.fRecord, info)); } else { fPlayback = NULL; } + + fPathHeap.reset(SkSafeRef(src.fPathHeap.get())); +} + +const SkPath& SkPicture::getPath(int index) const { + return (*fPathHeap.get())[index]; +} + +int SkPicture::addPathToHeap(const SkPath& path) { + if (NULL == fPathHeap) { + fPathHeap.reset(SkNEW(SkPathHeap)); + } +#ifdef SK_DEDUP_PICTURE_PATHS + return fPathHeap->insert(path); +#else + return fPathHeap->append(path); +#endif +} + +void SkPicture::initForPlayback() const { + // ensure that the paths bounds are pre-computed + if (NULL != fPathHeap.get()) { + for (int i = 0; i < fPathHeap->count(); i++) { + (*fPathHeap.get())[i].updateBoundsCache(); + } + } +} + +void SkPicture::dumpSize() const { + SkDebugf("--- picture size: paths=%d\n", + SafeCount(fPathHeap.get())); } SkPicture::~SkPicture() { @@ -171,6 +207,8 @@ void SkPicture::swap(SkPicture& other) { SkTSwap(fAccelData, other.fAccelData); SkTSwap(fWidth, other.fWidth); SkTSwap(fHeight, other.fHeight); + fPathHeap.swap(&other.fPathHeap); + fContentInfo.swap(&other.fContentInfo); } SkPicture* SkPicture::clone() const { @@ -179,6 +217,26 @@ SkPicture* SkPicture::clone() const { return clonedPicture; } +static bool needs_deep_copy(const SkPaint& paint) { + /* + * These fields are known to be immutable, and so can be shallow-copied + * + * getTypeface() + * getAnnotation() + * paint.getColorFilter() + * getXfermode() + * getPathEffect() + * getMaskFilter() + */ + + return paint.getShader() || +#ifdef SK_SUPPORT_LEGACY_LAYERRASTERIZER_API + paint.getRasterizer() || +#endif + paint.getLooper() || // needs to hide its addLayer... + paint.getImageFilter(); +} + void SkPicture::clone(SkPicture* pictures, int count) const { SkPictCopyInfo copyInfo; SkPictInfo info; @@ -192,21 +250,66 @@ void SkPicture::clone(SkPicture* pictures, int count) const { clone->fHeight = fHeight; SkSafeSetNull(clone->fRecord); SkDELETE(clone->fPlayback); + clone->fContentInfo.set(fContentInfo); /* We want to copy the src's playback. However, if that hasn't been built yet, we need to fake a call to endRecording() without actually calling it (since it is destructive, and we don't want to change src). */ if (fPlayback) { - clone->fPlayback = SkNEW_ARGS(SkPicturePlayback, (*fPlayback, ©Info)); + if (!copyInfo.initialized) { + int paintCount = SafeCount(fPlayback->fPaints); + + /* The alternative to doing this is to have a clone method on the paint and have it + * make the deep copy of its internal structures as needed. The holdup to doing + * that is at this point we would need to pass the SkBitmapHeap so that we don't + * unnecessarily flatten the pixels in a bitmap shader. + */ + copyInfo.paintData.setCount(paintCount); + + /* Use an SkBitmapHeap to avoid flattening bitmaps in shaders. If there already is + * one, use it. If this SkPicturePlayback was created from a stream, fBitmapHeap + * will be NULL, so create a new one. + */ + if (fPlayback->fBitmapHeap.get() == NULL) { + // FIXME: Put this on the stack inside SkPicture::clone. + SkBitmapHeap* heap = SkNEW(SkBitmapHeap); + copyInfo.controller.setBitmapStorage(heap); + heap->unref(); + } else { + copyInfo.controller.setBitmapStorage(fPlayback->fBitmapHeap); + } + + SkDEBUGCODE(int heapSize = SafeCount(fPlayback->fBitmapHeap.get());) + for (int i = 0; i < paintCount; i++) { + if (needs_deep_copy(fPlayback->fPaints->at(i))) { + copyInfo.paintData[i] = + SkFlatData::Create<SkPaint::FlatteningTraits>(©Info.controller, + fPlayback->fPaints->at(i), 0); + + } else { + // this is our sentinel, which we use in the unflatten loop + copyInfo.paintData[i] = NULL; + } + } + SkASSERT(SafeCount(fPlayback->fBitmapHeap.get()) == heapSize); + + // needed to create typeface playback + copyInfo.controller.setupPlaybacks(); + copyInfo.initialized = true; + } + + clone->fPlayback = SkNEW_ARGS(SkPicturePlayback, (clone, *fPlayback, ©Info)); SkASSERT(NULL == fRecord); clone->fUniqueID = this->uniqueID(); // need to call method to ensure != 0 } else if (fRecord) { // here we do a fake src.endRecording() - clone->fPlayback = SkNEW_ARGS(SkPicturePlayback, (*fRecord, info, true)); + clone->fPlayback = SkNEW_ARGS(SkPicturePlayback, (clone, *fRecord, info, true)); } else { clone->fPlayback = NULL; } + + clone->fPathHeap.reset(SkSafeRef(fPathHeap.get())); } } @@ -233,6 +336,7 @@ SkCanvas* SkPicture::beginRecording(int width, int height, } SkSafeUnref(fAccelData); SkSafeSetNull(fRecord); + fContentInfo.reset(); this->needsNewGenID(); @@ -245,10 +349,10 @@ SkCanvas* SkPicture::beginRecording(int width, int height, if (recordingFlags & kOptimizeForClippedPlayback_RecordingFlag) { SkBBoxHierarchy* tree = this->createBBoxHierarchy(); SkASSERT(NULL != tree); - fRecord = SkNEW_ARGS(SkBBoxHierarchyRecord, (size, recordingFlags, tree)); + fRecord = SkNEW_ARGS(SkBBoxHierarchyRecord, (this, size, recordingFlags, tree)); tree->unref(); } else { - fRecord = SkNEW_ARGS(SkPictureRecord, (size, recordingFlags)); + fRecord = SkNEW_ARGS(SkPictureRecord, (this, size, recordingFlags)); } fRecord->beginRecording(); @@ -266,6 +370,8 @@ SkCanvas* SkPicture::beginRecording(int width, int height, } SkSafeUnref(fAccelData); SkSafeSetNull(fRecord); + SkASSERT(NULL == fPathHeap); + fContentInfo.reset(); this->needsNewGenID(); @@ -277,12 +383,12 @@ SkCanvas* SkPicture::beginRecording(int width, int height, if (NULL != bbhFactory) { SkAutoTUnref<SkBBoxHierarchy> tree((*bbhFactory)(width, height)); SkASSERT(NULL != tree); - fRecord = SkNEW_ARGS(SkBBoxHierarchyRecord, (size, + fRecord = SkNEW_ARGS(SkBBoxHierarchyRecord, (this, size, recordingFlags| kOptimizeForClippedPlayback_RecordingFlag, tree.get())); } else { - fRecord = SkNEW_ARGS(SkPictureRecord, (size, recordingFlags)); + fRecord = SkNEW_ARGS(SkPictureRecord, (this, size, recordingFlags)); } fRecord->beginRecording(); @@ -323,7 +429,7 @@ void SkPicture::endRecording() { fRecord->endRecording(); SkPictInfo info; this->createHeader(&info); - fPlayback = SkNEW_ARGS(SkPicturePlayback, (*fRecord, info)); + fPlayback = SkNEW_ARGS(SkPicturePlayback, (this, *fRecord, info)); SkSafeSetNull(fRecord); } } @@ -424,18 +530,20 @@ SkPicture* SkPicture::CreateFromStream(SkStream* stream, InstallPixelRefProc pro return NULL; } - SkPicturePlayback* playback; + SkPicture* newPict = SkNEW_ARGS(SkPicture, (NULL, info.fWidth, info.fHeight)); + // Check to see if there is a playback to recreate. if (stream->readBool()) { - playback = SkPicturePlayback::CreateFromStream(stream, info, proc); + SkPicturePlayback* playback = SkPicturePlayback::CreateFromStream(newPict, stream, + info, proc); if (NULL == playback) { + SkDELETE(newPict); return NULL; } - } else { - playback = NULL; + newPict->fPlayback = playback; } - return SkNEW_ARGS(SkPicture, (playback, info.fWidth, info.fHeight)); + return newPict; } SkPicture* SkPicture::CreateFromBuffer(SkReadBuffer& buffer) { @@ -445,18 +553,19 @@ SkPicture* SkPicture::CreateFromBuffer(SkReadBuffer& buffer) { return NULL; } - SkPicturePlayback* playback; + SkPicture* newPict = SkNEW_ARGS(SkPicture, (NULL, info.fWidth, info.fHeight)); + // Check to see if there is a playback to recreate. if (buffer.readBool()) { - playback = SkPicturePlayback::CreateFromBuffer(buffer, info); + SkPicturePlayback* playback = SkPicturePlayback::CreateFromBuffer(newPict, buffer, info); if (NULL == playback) { + SkDELETE(newPict); return NULL; } - } else { - playback = NULL; + newPict->fPlayback = playback; } - return SkNEW_ARGS(SkPicture, (playback, info.fWidth, info.fHeight)); + return newPict; } void SkPicture::createHeader(SkPictInfo* info) const { @@ -484,7 +593,7 @@ void SkPicture::serialize(SkWStream* stream, EncodeBitmap encoder) const { SkPictInfo info; this->createHeader(&info); if (NULL == playback && fRecord) { - playback = SkNEW_ARGS(SkPicturePlayback, (*fRecord, info)); + playback = SkNEW_ARGS(SkPicturePlayback, (this, *fRecord, info)); } stream->write(&info, sizeof(info)); @@ -500,13 +609,49 @@ void SkPicture::serialize(SkWStream* stream, EncodeBitmap encoder) const { } } +void SkPicture::WriteTagSize(SkWriteBuffer& buffer, uint32_t tag, size_t size) { + buffer.writeUInt(tag); + buffer.writeUInt(SkToU32(size)); +} + +void SkPicture::WriteTagSize(SkWStream* stream, uint32_t tag, size_t size) { + stream->write32(tag); + stream->write32(SkToU32(size)); +} + +bool SkPicture::parseBufferTag(SkReadBuffer& buffer, + uint32_t tag, + uint32_t size) { + switch (tag) { + case SK_PICT_PATH_BUFFER_TAG: + if (size > 0) { + fPathHeap.reset(SkNEW_ARGS(SkPathHeap, (buffer))); + } + break; + default: + // The tag was invalid. + return false; + } + + return true; // success +} + +void SkPicture::flattenToBuffer(SkWriteBuffer& buffer) const { + int n; + + if ((n = SafeCount(fPathHeap.get())) > 0) { + WriteTagSize(buffer, SK_PICT_PATH_BUFFER_TAG, n); + fPathHeap->flatten(buffer); + } +} + void SkPicture::flatten(SkWriteBuffer& buffer) const { SkPicturePlayback* playback = fPlayback; SkPictInfo info; this->createHeader(&info); if (NULL == playback && fRecord) { - playback = SkNEW_ARGS(SkPicturePlayback, (*fRecord, info)); + playback = SkNEW_ARGS(SkPicturePlayback, (this, *fRecord, info)); } buffer.writeByteArray(&info, sizeof(info)); @@ -524,8 +669,14 @@ void SkPicture::flatten(SkWriteBuffer& buffer) const { #if SK_SUPPORT_GPU bool SkPicture::suitableForGpuRasterization(GrContext* context) const { - // Stub for now; never veto GPu rasterization. - return true; + // TODO: the heuristic used here needs to be refined + static const int kNumPaintWithPathEffectUsesTol = 1; + static const int kNumAAConcavePaths = 5; + + SkASSERT(this->numAAHairlineConcavePaths() <= this->numAAConcavePaths()); + + return this->numPaintWithPathEffectUses() < kNumPaintWithPathEffectUsesTol && + (this->numAAConcavePaths()-this->numAAHairlineConcavePaths()) < kNumAAConcavePaths; } #endif diff --git a/core/SkPicturePlayback.cpp b/core/SkPicturePlayback.cpp index 514769db..291774b8 100644 --- a/core/SkPicturePlayback.cpp +++ b/core/SkPicturePlayback.cpp @@ -23,14 +23,18 @@ template <typename T> int SafeCount(const T* obj) { */ #define SPEW_CLIP_SKIPPINGx -SkPicturePlayback::SkPicturePlayback(const SkPictInfo& info) : fInfo(info) { +SkPicturePlayback::SkPicturePlayback(const SkPicture* picture, const SkPictInfo& info) + : fPicture(picture) + , fInfo(info) { this->init(); } -SkPicturePlayback::SkPicturePlayback(const SkPictureRecord& record, +SkPicturePlayback::SkPicturePlayback(const SkPicture* picture, + const SkPictureRecord& record, const SkPictInfo& info, bool deepCopy) - : fInfo(info) { + : fPicture(picture) + , fInfo(info) { #ifdef SK_DEBUG_SIZE size_t overallBytes, bitmapBytes, matricesBytes, paintBytes, pathBytes, pictureBytes, regionBytes; @@ -95,14 +99,8 @@ SkPicturePlayback::SkPicturePlayback(const SkPictureRecord& record, fPaints = record.fPaints.unflattenToArray(); fBitmapHeap.reset(SkSafeRef(record.fBitmapHeap)); - fPathHeap.reset(SkSafeRef(record.fPathHeap)); - // ensure that the paths bounds are pre-computed - if (fPathHeap.get()) { - for (int i = 0; i < fPathHeap->count(); i++) { - (*fPathHeap)[i].updateBoundsCache(); - } - } + picture->initForPlayback(); const SkTDArray<SkPicture* >& pictures = record.getPictureRefs(); fPictureCount = pictures.count(); @@ -140,32 +138,13 @@ SkPicturePlayback::SkPicturePlayback(const SkPictureRecord& record, #endif } -static bool needs_deep_copy(const SkPaint& paint) { - /* - * These fields are known to be immutable, and so can be shallow-copied - * - * getTypeface() - * getAnnotation() - * paint.getColorFilter() - * getXfermode() - * getPathEffect() - * getMaskFilter() - */ - - return paint.getShader() || -#ifdef SK_SUPPORT_LEGACY_LAYERRASTERIZER_API - paint.getRasterizer() || -#endif - paint.getLooper() || // needs to hide its addLayer... - paint.getImageFilter(); -} - -SkPicturePlayback::SkPicturePlayback(const SkPicturePlayback& src, SkPictCopyInfo* deepCopyInfo) - : fInfo(src.fInfo) { +SkPicturePlayback::SkPicturePlayback(const SkPicture* picture, const SkPicturePlayback& src, + SkPictCopyInfo* deepCopyInfo) + : fPicture(picture) + , fInfo(src.fInfo) { this->init(); fBitmapHeap.reset(SkSafeRef(src.fBitmapHeap.get())); - fPathHeap.reset(SkSafeRef(src.fPathHeap.get())); fOpData = SkSafeRef(src.fOpData); @@ -176,53 +155,14 @@ SkPicturePlayback::SkPicturePlayback(const SkPicturePlayback& src, SkPictCopyInf SkSafeRef(fStateTree); if (deepCopyInfo) { + SkASSERT(deepCopyInfo->initialized); + int paintCount = SafeCount(src.fPaints); if (src.fBitmaps) { fBitmaps = SkTRefArray<SkBitmap>::Create(src.fBitmaps->begin(), src.fBitmaps->count()); } - if (!deepCopyInfo->initialized) { - /* The alternative to doing this is to have a clone method on the paint and have it make - * the deep copy of its internal structures as needed. The holdup to doing that is at - * this point we would need to pass the SkBitmapHeap so that we don't unnecessarily - * flatten the pixels in a bitmap shader. - */ - deepCopyInfo->paintData.setCount(paintCount); - - /* Use an SkBitmapHeap to avoid flattening bitmaps in shaders. If there already is one, - * use it. If this SkPicturePlayback was created from a stream, fBitmapHeap will be - * NULL, so create a new one. - */ - if (fBitmapHeap.get() == NULL) { - // FIXME: Put this on the stack inside SkPicture::clone. Further, is it possible to - // do the rest of this initialization in SkPicture::clone as well? - SkBitmapHeap* heap = SkNEW(SkBitmapHeap); - deepCopyInfo->controller.setBitmapStorage(heap); - heap->unref(); - } else { - deepCopyInfo->controller.setBitmapStorage(fBitmapHeap); - } - - SkDEBUGCODE(int heapSize = SafeCount(fBitmapHeap.get());) - for (int i = 0; i < paintCount; i++) { - if (needs_deep_copy(src.fPaints->at(i))) { - deepCopyInfo->paintData[i] = - SkFlatData::Create<SkPaint::FlatteningTraits>(&deepCopyInfo->controller, - src.fPaints->at(i), 0); - - } else { - // this is our sentinel, which we use in the unflatten loop - deepCopyInfo->paintData[i] = NULL; - } - } - SkASSERT(SafeCount(fBitmapHeap.get()) == heapSize); - - // needed to create typeface playback - deepCopyInfo->controller.setupPlaybacks(); - deepCopyInfo->initialized = true; - } - fPaints = SkTRefArray<SkPaint>::Create(paintCount); SkASSERT(deepCopyInfo->paintData.count() == paintCount); SkBitmapHeap* bmHeap = deepCopyInfo->controller.getBitmapHeap(); @@ -286,11 +226,11 @@ SkPicturePlayback::~SkPicturePlayback() { } void SkPicturePlayback::dumpSize() const { - SkDebugf("--- picture size: ops=%d bitmaps=%d [%d] paints=%d [%d] paths=%d\n", + SkDebugf("--- picture size: ops=%d bitmaps=%d [%d] paints=%d [%d]\n", fOpData->size(), SafeCount(fBitmaps), SafeCount(fBitmaps) * sizeof(SkBitmap), - SafeCount(fPaints), SafeCount(fPaints) * sizeof(SkPaint), - SafeCount(fPathHeap.get())); + SafeCount(fPaints), SafeCount(fPaints) * sizeof(SkPaint)); + fPicture->dumpSize(); } bool SkPicturePlayback::containsBitmaps() const { @@ -310,16 +250,6 @@ bool SkPicturePlayback::containsBitmaps() const { #include "SkStream.h" -static void write_tag_size(SkWriteBuffer& buffer, uint32_t tag, size_t size) { - buffer.writeUInt(tag); - buffer.writeUInt(SkToU32(size)); -} - -static void write_tag_size(SkWStream* stream, uint32_t tag, size_t size) { - stream->write32(tag); - stream->write32(SkToU32(size)); -} - static size_t compute_chunk_size(SkFlattenable::Factory* array, int count) { size_t size = 4; // for 'count' @@ -337,7 +267,7 @@ static size_t compute_chunk_size(SkFlattenable::Factory* array, int count) { return size; } -static void write_factories(SkWStream* stream, const SkFactorySet& rec) { +void SkPicturePlayback::WriteFactories(SkWStream* stream, const SkFactorySet& rec) { int count = rec.count(); SkAutoSTMalloc<16, SkFlattenable::Factory> storage(count); @@ -347,7 +277,7 @@ static void write_factories(SkWStream* stream, const SkFactorySet& rec) { size_t size = compute_chunk_size(array, count); // TODO: write_tag_size should really take a size_t - write_tag_size(stream, SK_PICT_FACTORY_TAG, (uint32_t) size); + SkPicture::WriteTagSize(stream, SK_PICT_FACTORY_TAG, (uint32_t) size); SkDEBUGCODE(size_t start = stream->bytesWritten()); stream->write32(count); @@ -366,10 +296,10 @@ static void write_factories(SkWStream* stream, const SkFactorySet& rec) { SkASSERT(size == (stream->bytesWritten() - start)); } -static void write_typefaces(SkWStream* stream, const SkRefCntSet& rec) { +void SkPicturePlayback::WriteTypefaces(SkWStream* stream, const SkRefCntSet& rec) { int count = rec.count(); - write_tag_size(stream, SK_PICT_TYPEFACE_TAG, count); + SkPicture::WriteTagSize(stream, SK_PICT_TYPEFACE_TAG, count); SkAutoSTMalloc<16, SkTypeface*> storage(count); SkTypeface** array = (SkTypeface**)storage.get(); @@ -384,32 +314,29 @@ void SkPicturePlayback::flattenToBuffer(SkWriteBuffer& buffer) const { int i, n; if ((n = SafeCount(fBitmaps)) > 0) { - write_tag_size(buffer, SK_PICT_BITMAP_BUFFER_TAG, n); + SkPicture::WriteTagSize(buffer, SK_PICT_BITMAP_BUFFER_TAG, n); for (i = 0; i < n; i++) { buffer.writeBitmap((*fBitmaps)[i]); } } if ((n = SafeCount(fPaints)) > 0) { - write_tag_size(buffer, SK_PICT_PAINT_BUFFER_TAG, n); + SkPicture::WriteTagSize(buffer, SK_PICT_PAINT_BUFFER_TAG, n); for (i = 0; i < n; i++) { buffer.writePaint((*fPaints)[i]); } } - if ((n = SafeCount(fPathHeap.get())) > 0) { - write_tag_size(buffer, SK_PICT_PATH_BUFFER_TAG, n); - fPathHeap->flatten(buffer); - } + fPicture->flattenToBuffer(buffer); } void SkPicturePlayback::serialize(SkWStream* stream, SkPicture::EncodeBitmap encoder) const { - write_tag_size(stream, SK_PICT_READER_TAG, fOpData->size()); + SkPicture::WriteTagSize(stream, SK_PICT_READER_TAG, fOpData->size()); stream->write(fOpData->bytes(), fOpData->size()); if (fPictureCount > 0) { - write_tag_size(stream, SK_PICT_PICTURE_TAG, fPictureCount); + SkPicture::WriteTagSize(stream, SK_PICT_PICTURE_TAG, fPictureCount); for (int i = 0; i < fPictureCount; i++) { fPictureRefs[i]->serialize(stream, encoder); } @@ -431,10 +358,10 @@ void SkPicturePlayback::serialize(SkWStream* stream, // We have to write these two sets into the stream *before* we write // the buffer, since parsing that buffer will require that we already // have these sets available to use. - write_factories(stream, factSet); - write_typefaces(stream, typefaceSet); + WriteFactories(stream, factSet); + WriteTypefaces(stream, typefaceSet); - write_tag_size(stream, SK_PICT_BUFFER_SIZE_TAG, buffer.bytesWritten()); + SkPicture::WriteTagSize(stream, SK_PICT_BUFFER_SIZE_TAG, buffer.bytesWritten()); buffer.writeToStream(stream); } @@ -442,11 +369,11 @@ void SkPicturePlayback::serialize(SkWStream* stream, } void SkPicturePlayback::flatten(SkWriteBuffer& buffer) const { - write_tag_size(buffer, SK_PICT_READER_TAG, fOpData->size()); + SkPicture::WriteTagSize(buffer, SK_PICT_READER_TAG, fOpData->size()); buffer.writeByteArray(fOpData->bytes(), fOpData->size()); if (fPictureCount > 0) { - write_tag_size(buffer, SK_PICT_PICTURE_TAG, fPictureCount); + SkPicture::WriteTagSize(buffer, SK_PICT_PICTURE_TAG, fPictureCount); for (int i = 0; i < fPictureCount; i++) { fPictureRefs[i]->flatten(buffer); } @@ -482,7 +409,8 @@ static uint32_t pictInfoFlagsToReadBufferFlags(uint32_t pictInfoFlags) { return rbMask; } -bool SkPicturePlayback::parseStreamTag(SkStream* stream, +bool SkPicturePlayback::parseStreamTag(SkPicture* picture, + SkStream* stream, uint32_t tag, uint32_t size, SkPicture::InstallPixelRefProc proc) { @@ -584,7 +512,7 @@ bool SkPicturePlayback::parseStreamTag(SkStream* stream, while (!buffer.eof()) { tag = buffer.readUInt(); size = buffer.readUInt(); - if (!this->parseBufferTag(buffer, tag, size)) { + if (!this->parseBufferTag(picture, buffer, tag, size)) { return false; } } @@ -594,7 +522,8 @@ bool SkPicturePlayback::parseStreamTag(SkStream* stream, return true; // success } -bool SkPicturePlayback::parseBufferTag(SkReadBuffer& buffer, +bool SkPicturePlayback::parseBufferTag(SkPicture* picture, + SkReadBuffer& buffer, uint32_t tag, uint32_t size) { switch (tag) { case SK_PICT_BITMAP_BUFFER_TAG: { @@ -614,9 +543,7 @@ bool SkPicturePlayback::parseBufferTag(SkReadBuffer& buffer, } } break; case SK_PICT_PATH_BUFFER_TAG: - if (size > 0) { - fPathHeap.reset(SkNEW_ARGS(SkPathHeap, (buffer))); - } + picture->parseBufferTag(buffer, tag, size); break; case SK_PICT_READER_TAG: { SkAutoMalloc storage(size); @@ -660,29 +587,32 @@ bool SkPicturePlayback::parseBufferTag(SkReadBuffer& buffer, return true; // success } -SkPicturePlayback* SkPicturePlayback::CreateFromStream(SkStream* stream, +SkPicturePlayback* SkPicturePlayback::CreateFromStream(SkPicture* picture, + SkStream* stream, const SkPictInfo& info, SkPicture::InstallPixelRefProc proc) { - SkAutoTDelete<SkPicturePlayback> playback(SkNEW_ARGS(SkPicturePlayback, (info))); + SkAutoTDelete<SkPicturePlayback> playback(SkNEW_ARGS(SkPicturePlayback, (picture, info))); - if (!playback->parseStream(stream, proc)) { + if (!playback->parseStream(picture, stream, proc)) { return NULL; } return playback.detach(); } -SkPicturePlayback* SkPicturePlayback::CreateFromBuffer(SkReadBuffer& buffer, +SkPicturePlayback* SkPicturePlayback::CreateFromBuffer(SkPicture* picture, + SkReadBuffer& buffer, const SkPictInfo& info) { - SkAutoTDelete<SkPicturePlayback> playback(SkNEW_ARGS(SkPicturePlayback, (info))); + SkAutoTDelete<SkPicturePlayback> playback(SkNEW_ARGS(SkPicturePlayback, (picture, info))); buffer.setPictureVersion(info.fVersion); - if (!playback->parseBuffer(buffer)) { + if (!playback->parseBuffer(picture, buffer)) { return NULL; } return playback.detach(); } -bool SkPicturePlayback::parseStream(SkStream* stream, +bool SkPicturePlayback::parseStream(SkPicture* picture, + SkStream* stream, SkPicture::InstallPixelRefProc proc) { for (;;) { uint32_t tag = stream->readU32(); @@ -691,14 +621,14 @@ bool SkPicturePlayback::parseStream(SkStream* stream, } uint32_t size = stream->readU32(); - if (!this->parseStreamTag(stream, tag, size, proc)) { + if (!this->parseStreamTag(picture, stream, tag, size, proc)) { return false; // we're invalid } } return true; } -bool SkPicturePlayback::parseBuffer(SkReadBuffer& buffer) { +bool SkPicturePlayback::parseBuffer(SkPicture* picture, SkReadBuffer& buffer) { for (;;) { uint32_t tag = buffer.readUInt(); if (SK_PICT_EOF_TAG == tag) { @@ -706,7 +636,7 @@ bool SkPicturePlayback::parseBuffer(SkReadBuffer& buffer) { } uint32_t size = buffer.readUInt(); - if (!this->parseBufferTag(buffer, tag, size)) { + if (!this->parseBufferTag(picture, buffer, tag, size)) { return false; // we're invalid } } diff --git a/core/SkPicturePlayback.h b/core/SkPicturePlayback.h index cae8841f..28fdd632 100644 --- a/core/SkPicturePlayback.h +++ b/core/SkPicturePlayback.h @@ -75,12 +75,17 @@ struct SkPictCopyInfo { class SkPicturePlayback { public: - SkPicturePlayback(const SkPicturePlayback& src, SkPictCopyInfo* deepCopyInfo = NULL); - SkPicturePlayback(const SkPictureRecord& record, const SkPictInfo&, bool deepCopy = false); - static SkPicturePlayback* CreateFromStream(SkStream*, + SkPicturePlayback(const SkPicture* picture, const SkPicturePlayback& src, + SkPictCopyInfo* deepCopyInfo = NULL); + SkPicturePlayback(const SkPicture* picture, const SkPictureRecord& record, const SkPictInfo&, + bool deepCopy = false); + static SkPicturePlayback* CreateFromStream(SkPicture* picture, + SkStream*, const SkPictInfo&, SkPicture::InstallPixelRefProc); - static SkPicturePlayback* CreateFromBuffer(SkReadBuffer&, const SkPictInfo&); + static SkPicturePlayback* CreateFromBuffer(SkPicture* picture, + SkReadBuffer&, + const SkPictInfo&); virtual ~SkPicturePlayback(); @@ -105,10 +110,10 @@ public: void resetOpID() { fCurOffset = 0; } protected: - explicit SkPicturePlayback(const SkPictInfo& info); + explicit SkPicturePlayback(const SkPicture* picture, const SkPictInfo& info); - bool parseStream(SkStream*, SkPicture::InstallPixelRefProc); - bool parseBuffer(SkReadBuffer& buffer); + bool parseStream(SkPicture* picture, SkStream*, SkPicture::InstallPixelRefProc); + bool parseBuffer(SkPicture* picture, SkReadBuffer& buffer); #ifdef SK_DEVELOPER virtual bool preDraw(int opIndex, int type); virtual void postDraw(int opIndex); @@ -139,7 +144,7 @@ private: } const SkPath& getPath(SkReader32& reader) { - return (*fPathHeap)[reader.readInt() - 1]; + return fPicture->getPath(reader.readInt() - 1); } SkPicture& getPicture(SkReader32& reader) { @@ -215,17 +220,22 @@ public: #endif private: // these help us with reading/writing - bool parseStreamTag(SkStream*, uint32_t tag, uint32_t size, SkPicture::InstallPixelRefProc); - bool parseBufferTag(SkReadBuffer&, uint32_t tag, uint32_t size); + bool parseStreamTag(SkPicture* picture, SkStream*, uint32_t tag, uint32_t size, + SkPicture::InstallPixelRefProc); + bool parseBufferTag(SkPicture* picture, SkReadBuffer&, uint32_t tag, uint32_t size); void flattenToBuffer(SkWriteBuffer&) const; private: + friend class SkPicture; + + // The picture that owns this SkPicturePlayback object + const SkPicture* fPicture; + // Only used by getBitmap() if the passed in index is SkBitmapHeap::INVALID_SLOT. This empty // bitmap allows playback to draw nothing and move on. SkBitmap fBadBitmap; SkAutoTUnref<SkBitmapHeap> fBitmapHeap; - SkAutoTUnref<SkPathHeap> fPathHeap; SkTRefArray<SkBitmap>* fBitmaps; SkTRefArray<SkPaint>* fPaints; @@ -269,6 +279,9 @@ private: const SkPictInfo fInfo; + static void WriteFactories(SkWStream* stream, const SkFactorySet& rec); + static void WriteTypefaces(SkWStream* stream, const SkRefCntSet& rec); + #ifdef SK_BUILD_FOR_ANDROID SkMutex fDrawMutex; bool fAbortCurrentPlayback; diff --git a/core/SkPictureRecord.cpp b/core/SkPictureRecord.cpp index c5e329e7..f3d108c4 100644 --- a/core/SkPictureRecord.cpp +++ b/core/SkPictureRecord.cpp @@ -27,7 +27,7 @@ static const uint32_t kSaveSize = 2 * kUInt32Size; static const uint32_t kSaveLayerNoBoundsSize = 4 * kUInt32Size; static const uint32_t kSaveLayerWithBoundsSize = 4 * kUInt32Size + sizeof(SkRect); -SkPictureRecord::SkPictureRecord(const SkISize& dimensions, uint32_t flags) +SkPictureRecord::SkPictureRecord(SkPicture* picture, const SkISize& dimensions, uint32_t flags) : INHERITED(dimensions.width(), dimensions.height()) , fBoundingHierarchy(NULL) , fStateTree(NULL) @@ -40,9 +40,9 @@ SkPictureRecord::SkPictureRecord(const SkISize& dimensions, uint32_t flags) fPointWrites = fRectWrites = fTextWrites = 0; #endif + fPicture = picture; fBitmapHeap = SkNEW(SkBitmapHeap); fFlattenableHeap.setBitmapStorage(fBitmapHeap); - fPathHeap = NULL; // lazy allocate #ifndef SK_COLLAPSE_MATRIX_CLIP_STATE fFirstSavedLayerIndex = kNoSavedLayerIndex; @@ -57,7 +57,6 @@ SkPictureRecord::SkPictureRecord(const SkISize& dimensions, uint32_t flags) SkPictureRecord::~SkPictureRecord() { SkSafeUnref(fBitmapHeap); - SkSafeUnref(fPathHeap); SkSafeUnref(fBoundingHierarchy); SkSafeUnref(fStateTree); fFlattenableHeap.setBitmapStorage(NULL); @@ -1066,6 +1065,15 @@ void SkPictureRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) { + if (paint.isAntiAlias() && !path.isConvex()) { + fPicture->incAAConcavePaths(); + + if (SkPaint::kStroke_Style == paint.getStyle() && + 0 == paint.getStrokeWidth()) { + fPicture->incAAHairlineConcavePaths(); + } + } + #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType); #endif @@ -1579,6 +1587,10 @@ const SkFlatData* SkPictureRecord::getFlatPaintData(const SkPaint& paint) { } const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) { + if (NULL != paint && NULL != paint->getPathEffect()) { + fPicture->incPaintWithPathEffectUses(); + } + const SkFlatData* data = paint ? getFlatPaintData(*paint) : NULL; this->addFlatPaint(data); return data; @@ -1590,14 +1602,7 @@ void SkPictureRecord::addFlatPaint(const SkFlatData* flatPaint) { } int SkPictureRecord::addPathToHeap(const SkPath& path) { - if (NULL == fPathHeap) { - fPathHeap = SkNEW(SkPathHeap); - } -#ifdef SK_DEDUP_PICTURE_PATHS - return fPathHeap->insert(path); -#else - return fPathHeap->append(path); -#endif + return fPicture->addPathToHeap(path); } void SkPictureRecord::addPath(const SkPath& path) { diff --git a/core/SkPictureRecord.h b/core/SkPictureRecord.h index 257bab22..0f0986fb 100644 --- a/core/SkPictureRecord.h +++ b/core/SkPictureRecord.h @@ -33,7 +33,7 @@ class SkPictureStateTree; class SkPictureRecord : public SkCanvas { public: - SkPictureRecord(const SkISize& dimensions, uint32_t recordFlags); + SkPictureRecord(SkPicture* picture, const SkISize& dimensions, uint32_t recordFlags); virtual ~SkPictureRecord(); virtual void clear(SkColor) SK_OVERRIDE; @@ -279,6 +279,9 @@ protected: SkBitmapHeap* fBitmapHeap; private: + // The owning SkPicture + SkPicture* fPicture; + friend class MatrixClipState; // for access to *Impl methods friend class SkMatrixClipStateMgr; // for access to *Impl methods @@ -286,7 +289,6 @@ private: SkPaintDictionary fPaints; - SkPathHeap* fPathHeap; // reference counted SkWriter32 fWriter; // we ref each item in these arrays diff --git a/core/SkPictureShader.cpp b/core/SkPictureShader.cpp index dc5c90b6..466c5e12 100644 --- a/core/SkPictureShader.cpp +++ b/core/SkPictureShader.cpp @@ -91,13 +91,12 @@ SkShader* SkPictureShader::refBitmapShader(const SkMatrix& matrix) const { canvas.scale(tileScale.width(), tileScale.height()); canvas.drawPicture(*fPicture); - fCachedBitmapShader.reset(CreateBitmapShader(bm, fTmx, fTmy)); fCachedTileScale = tileScale; fCachedLocalMatrix = this->getLocalMatrix(); SkMatrix shaderMatrix = this->getLocalMatrix(); shaderMatrix.preScale(1 / tileScale.width(), 1 / tileScale.height()); - fCachedBitmapShader->setLocalMatrix(shaderMatrix); + fCachedBitmapShader.reset(CreateBitmapShader(bm, fTmx, fTmy, &shaderMatrix)); } // Increment the ref counter inside the mutex to ensure the returned pointer is still valid. diff --git a/core/SkPictureStateTree.cpp b/core/SkPictureStateTree.cpp index 20a826aa..f6d54ffe 100644 --- a/core/SkPictureStateTree.cpp +++ b/core/SkPictureStateTree.cpp @@ -123,15 +123,17 @@ uint32_t SkPictureStateTree::Iterator::nextDraw() { for (fCurrentNode = fCurrentNode->fParent; fCurrentNode; fCurrentNode = fCurrentNode->fParent) { - if (fCurrentNode->fFlags & (Node::kSave_Flag | Node::kSaveLayer_Flag)) { + // Note: we call restore() twice when both flags are set. + if (fCurrentNode->fFlags & Node::kSave_Flag) { + fCanvas->restore(); + } + if (fCurrentNode->fFlags & Node::kSaveLayer_Flag) { fCanvas->restore(); } } - // restore back to where we started fCanvas->setMatrix(fPlaybackMatrix); fCurrentMatrix = NULL; - return kDrawComplete; } @@ -174,9 +176,6 @@ uint32_t SkPictureStateTree::Iterator::nextDraw() { fNodes.push(ancestor); ancestor = ancestor->fParent; } - - SkASSERT(NULL != tmp); - SkASSERT(NULL != ancestor); } if (ancestor->fFlags & Node::kSave_Flag) { diff --git a/core/SkQuadTree.cpp b/core/SkQuadTree.cpp index f3436bd5..fb02e68c 100644 --- a/core/SkQuadTree.cpp +++ b/core/SkQuadTree.cpp @@ -8,7 +8,6 @@ #include "SkQuadTree.h" #include "SkTSort.h" #include <stdio.h> -#include <vector> static const int kSplitThreshold = 8; diff --git a/core/SkReadBuffer.cpp b/core/SkReadBuffer.cpp index b60dee3b..b4bc8752 100644 --- a/core/SkReadBuffer.cpp +++ b/core/SkReadBuffer.cpp @@ -321,10 +321,10 @@ SkFlattenable* SkReadBuffer::readFlattenable(SkFlattenable::Type ft) { SkFlattenable* obj = NULL; uint32_t sizeRecorded = fReader.readU32(); if (factory) { - uint32_t offset = fReader.offset(); + size_t offset = fReader.offset(); obj = (*factory)(*this); // check that we read the amount we expected - uint32_t sizeRead = fReader.offset() - offset; + size_t sizeRead = fReader.offset() - offset; if (sizeRecorded != sizeRead) { // we could try to fix up the offset... sk_throw(); diff --git a/core/SkRegion.cpp b/core/SkRegion.cpp index baedf2ae..98670b6b 100644 --- a/core/SkRegion.cpp +++ b/core/SkRegion.cpp @@ -796,7 +796,7 @@ public: fTop = (SkRegion::RunType)(bottom); // just update our bottom } else { start[-2] = (SkRegion::RunType)(bottom); - start[-1] = len >> 1; + start[-1] = SkToS32(len >> 1); fPrevDst = start; fPrevLen = len; } @@ -1212,7 +1212,7 @@ static void compute_bounds(const SkRegion::RunType runs[], const SkRegion::RunType* prev = runs; runs = skip_intervals_slow(runs); - int intervals = (runs - prev) >> 1; + int intervals = SkToInt((runs - prev) >> 1); SkASSERT(prev[-1] == intervals); intervalCount += intervals; diff --git a/core/SkRegionPriv.h b/core/SkRegionPriv.h index f299f3a9..c8f000df 100644 --- a/core/SkRegionPriv.h +++ b/core/SkRegionPriv.h @@ -29,7 +29,7 @@ static int compute_intervalcount(const SkRegion::RunType runs[]) { SkASSERT(curr[1] < SkRegion::kRunTypeSentinel); curr += 2; } - return (curr - runs) >> 1; + return SkToInt((curr - runs) >> 1); } #endif @@ -213,7 +213,7 @@ public: #ifdef SK_DEBUG // +1 to skip the last Y-sentinel - int runCount = runs - this->writable_runs() + 1; + int runCount = SkToInt(runs - this->writable_runs() + 1); SkASSERT(runCount == fRunCount); #endif diff --git a/core/SkScalerContext.cpp b/core/SkScalerContext.cpp index d0d24eeb..fee1ff79 100644 --- a/core/SkScalerContext.cpp +++ b/core/SkScalerContext.cpp @@ -548,8 +548,9 @@ static void packA8ToA1(const SkMask& mask, const uint8_t* src, size_t srcRB) { const int dstPad = mask.fRowBytes - SkAlign8(width)/8; SkASSERT(dstPad >= 0); - const int srcPad = srcRB - width; - SkASSERT(srcPad >= 0); + SkASSERT(width >= 0); + SkASSERT(srcRB >= (size_t)width); + const size_t srcPad = srcRB - width; for (int y = 0; y < height; ++y) { for (int i = 0; i < octs; ++i) { diff --git a/core/SkShader.cpp b/core/SkShader.cpp index 40e52a05..4ddd2915 100644 --- a/core/SkShader.cpp +++ b/core/SkShader.cpp @@ -15,8 +15,12 @@ #include "SkShader.h" #include "SkWriteBuffer.h" -SkShader::SkShader() { - fLocalMatrix.reset(); +SkShader::SkShader(const SkMatrix* localMatrix) { + if (localMatrix) { + fLocalMatrix = *localMatrix; + } else { + fLocalMatrix.reset(); + } } SkShader::SkShader(SkReadBuffer& buffer) @@ -180,9 +184,9 @@ GrEffectRef* SkShader::asNewEffect(GrContext*, const SkPaint&) const { return NULL; } -SkShader* SkShader::CreateBitmapShader(const SkBitmap& src, - TileMode tmx, TileMode tmy) { - return ::CreateBitmapShader(src, tmx, tmy, NULL); +SkShader* SkShader::CreateBitmapShader(const SkBitmap& src, TileMode tmx, TileMode tmy, + const SkMatrix* localMatrix) { + return ::CreateBitmapShader(src, tmx, tmy, localMatrix, NULL); } SkShader* SkShader::CreatePictureShader(SkPicture* src, TileMode tmx, TileMode tmy) { @@ -203,37 +207,29 @@ void SkShader::toString(SkString* str) const { #include "SkColorShader.h" #include "SkUtils.h" -SkColorShader::SkColorShader() - : fColor() - , fInheritColor(true) { -} - SkColorShader::SkColorShader(SkColor c) - : fColor(c) - , fInheritColor(false) { + : fColor(c) { } bool SkColorShader::isOpaque() const { - if (fInheritColor) { - return true; // using paint's alpha - } return SkColorGetA(fColor) == 255; } SkColorShader::SkColorShader(SkReadBuffer& b) : INHERITED(b) { - fInheritColor = b.readBool(); - if (fInheritColor) { - return; + // V25_COMPATIBILITY_CODE We had a boolean to make the color shader inherit the paint's + // color. We don't support that any more. + if (b.pictureVersion() < 26 && 0 != b.pictureVersion()) { + if (b.readBool()) { + SkDEBUGFAIL("We shouldn't have pictures that recorded the inherited case."); + fColor = SK_ColorWHITE; + return; + } } fColor = b.readColor(); } void SkColorShader::flatten(SkWriteBuffer& buffer) const { this->INHERITED::flatten(buffer); - buffer.writeBool(fInheritColor); - if (fInheritColor) { - return; - } buffer.writeColor(fColor); } @@ -260,16 +256,8 @@ SkColorShader::ColorShaderContext::ColorShaderContext(const SkColorShader& shade const SkMatrix& matrix) : INHERITED(shader, device, paint, matrix) { - unsigned a; - - SkColor color; - if (shader.fInheritColor) { - color = paint.getColor(); - a = SkColorGetA(color); - } else { - color = shader.fColor; - a = SkAlphaMul(SkColorGetA(color), SkAlpha255To256(paint.getAlpha())); - } + SkColor color = shader.fColor; + unsigned a = SkAlphaMul(SkColorGetA(color), SkAlpha255To256(paint.getAlpha())); unsigned r = SkColorGetR(color); unsigned g = SkColorGetG(color); @@ -327,12 +315,8 @@ SkShader::GradientType SkColorShader::asAGradient(GradientInfo* info) const { void SkColorShader::toString(SkString* str) const { str->append("SkColorShader: ("); - if (fInheritColor) { - str->append("Color: inherited from paint"); - } else { - str->append("Color: "); - str->appendHex(fColor); - } + str->append("Color: "); + str->appendHex(fColor); this->INHERITED::toString(str); diff --git a/core/SkSmallAllocator.h b/core/SkSmallAllocator.h index 8d4b53a7..018705f9 100644 --- a/core/SkSmallAllocator.h +++ b/core/SkSmallAllocator.h @@ -96,6 +96,16 @@ public: return static_cast<T*>(buf); } + template<typename T, typename A1, typename A2, typename A3, typename A4> + T* createT(const A1& a1, const A2& a2, const A3& a3, const A4& a4) { + void* buf = this->reserveT<T>(); + if (NULL == buf) { + return NULL; + } + SkNEW_PLACEMENT_ARGS(buf, T, (a1, a2, a3, a4)); + return static_cast<T*>(buf); + } + /* * Reserve a specified amount of space (must be enough space for one T). * The space will be in fStorage if there is room, or on the heap otherwise. diff --git a/core/SkStream.cpp b/core/SkStream.cpp index c60f2a73..ebaac9ab 100644 --- a/core/SkStream.cpp +++ b/core/SkStream.cpp @@ -161,7 +161,7 @@ bool SkWStream::writePackedUInt(size_t value) { memcpy(&data[1], &value16, 2); len = 3; } else { - uint32_t value32 = value; + uint32_t value32 = SkToU32(value); data[0] = SK_BYTE_SENTINEL_FOR_U32; memcpy(&data[1], &value32, 4); len = 5; @@ -189,7 +189,7 @@ bool SkWStream::writeStream(SkStream* stream, size_t length) { bool SkWStream::writeData(const SkData* data) { if (data) { - this->write32(data->size()); + this->write32(SkToU32(data->size())); this->write(data->data(), data->size()); } else { this->write32(0); @@ -481,11 +481,9 @@ SkMemoryWStream::SkMemoryWStream(void* buffer, size_t size) { } -bool SkMemoryWStream::write(const void* buffer, size_t size) -{ - size = SkMin32(size, fMaxLength - fBytesWritten); - if (size > 0) - { +bool SkMemoryWStream::write(const void* buffer, size_t size) { + size = SkTMin(size, fMaxLength - fBytesWritten); + if (size > 0) { memcpy(fBuffer + fBytesWritten, buffer, size); fBytesWritten += size; return true; @@ -558,7 +556,7 @@ bool SkDynamicMemoryWStream::write(const void* buffer, size_t count) size_t size; if (fTail != NULL && fTail->avail() > 0) { - size = SkMin32(fTail->avail(), count); + size = SkTMin(fTail->avail(), count); buffer = fTail->append(buffer, size); SkASSERT(count >= size); count -= size; @@ -566,7 +564,7 @@ bool SkDynamicMemoryWStream::write(const void* buffer, size_t count) return true; } - size = SkMax32(count, SkDynamicMemoryWStream_MinBlockSize); + size = SkTMax<size_t>(count, SkDynamicMemoryWStream_MinBlockSize); Block* block = (Block*)sk_malloc_throw(sizeof(Block) + size); block->init(size); block->append(buffer, count); diff --git a/core/SkValidatingReadBuffer.cpp b/core/SkValidatingReadBuffer.cpp index 8db2c68b..0112f18e 100644 --- a/core/SkValidatingReadBuffer.cpp +++ b/core/SkValidatingReadBuffer.cpp @@ -91,7 +91,7 @@ int32_t SkValidatingReadBuffer::read32() { } void SkValidatingReadBuffer::readString(SkString* string) { - const size_t len = this->readInt(); + const size_t len = this->readUInt(); const void* ptr = fReader.peek(); const char* cptr = (const char*)ptr; @@ -256,10 +256,10 @@ SkFlattenable* SkValidatingReadBuffer::readFlattenable(SkFlattenable::Type type) SkFlattenable* obj = NULL; uint32_t sizeRecorded = this->readUInt(); if (factory) { - uint32_t offset = fReader.offset(); + size_t offset = fReader.offset(); obj = (*factory)(*this); // check that we read the amount we expected - uint32_t sizeRead = fReader.offset() - offset; + size_t sizeRead = fReader.offset() - offset; this->validate(sizeRecorded == sizeRead); if (fError) { // we could try to fix up the offset... diff --git a/core/SkWriter32.cpp b/core/SkWriter32.cpp index c7bfd92d..00c46368 100644 --- a/core/SkWriter32.cpp +++ b/core/SkWriter32.cpp @@ -14,7 +14,7 @@ */ const char* SkReader32::readString(size_t* outLen) { - size_t len = this->readInt(); + size_t len = this->readU32(); const void* ptr = this->peek(); // skip over the string + '\0' and then pad to a multiple of 4 @@ -47,7 +47,7 @@ void SkWriter32::writeString(const char str[], size_t len) { // [ 4 byte len ] [ str ... ] [1 - 4 \0s] uint32_t* ptr = this->reservePad(sizeof(uint32_t) + len + 1); - *ptr = len; + *ptr = SkToU32(len); char* chars = (char*)(ptr + 1); memcpy(chars, str, len); chars[len] = '\0'; diff --git a/effects/SkBlurDrawLooper.cpp b/effects/SkBlurDrawLooper.cpp index 5cfb8d88..372dcf09 100644 --- a/effects/SkBlurDrawLooper.cpp +++ b/effects/SkBlurDrawLooper.cpp @@ -1,10 +1,10 @@ - /* * Copyright 2011 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ + #include "SkBlurDrawLooper.h" #include "SkBlurMask.h" // just for SkBlurMask::ConvertRadiusToSigma #include "SkBlurMaskFilter.h" @@ -29,34 +29,27 @@ SkBlurDrawLooper::SkBlurDrawLooper(SkColor color, SkScalar sigma, this->init(sigma, dx, dy, color, flags); } -void SkBlurDrawLooper::init(SkScalar sigma, SkScalar dx, SkScalar dy, - SkColor color, uint32_t flags) { - fDx = dx; - fDy = dy; - fBlurColor = color; - fBlurFlags = flags; - - SkASSERT(flags <= kAll_BlurFlag); - if (sigma > 0) { - uint32_t blurFlags = flags & kIgnoreTransform_BlurFlag ? - SkBlurMaskFilter::kIgnoreTransform_BlurFlag : - SkBlurMaskFilter::kNone_BlurFlag; +// only call from constructor +void SkBlurDrawLooper::initEffects() { + SkASSERT(fBlurFlags <= kAll_BlurFlag); + if (fSigma > 0) { + uint32_t flags = fBlurFlags & kIgnoreTransform_BlurFlag ? + SkBlurMaskFilter::kIgnoreTransform_BlurFlag : + SkBlurMaskFilter::kNone_BlurFlag; - blurFlags |= flags & kHighQuality_BlurFlag ? - SkBlurMaskFilter::kHighQuality_BlurFlag : - SkBlurMaskFilter::kNone_BlurFlag; + flags |= fBlurFlags & kHighQuality_BlurFlag ? + SkBlurMaskFilter::kHighQuality_BlurFlag : + SkBlurMaskFilter::kNone_BlurFlag; - fBlur = SkBlurMaskFilter::Create(SkBlurMaskFilter::kNormal_BlurStyle, - sigma, - blurFlags); + fBlur = SkBlurMaskFilter::Create(kNormal_SkBlurStyle, fSigma, flags); } else { fBlur = NULL; } - if (flags & kOverrideColor_BlurFlag) { + if (fBlurFlags & kOverrideColor_BlurFlag) { // Set alpha to 1 for the override since transparency will already // be baked into the blurred mask. - SkColor opaqueColor = SkColorSetA(color, 255); + SkColor opaqueColor = SkColorSetA(fBlurColor, 255); //The SrcIn xfer mode will multiply 'color' by the incoming alpha fColorFilter = SkColorFilter::CreateModeFilter(opaqueColor, SkXfermode::kSrcIn_Mode); @@ -65,32 +58,60 @@ void SkBlurDrawLooper::init(SkScalar sigma, SkScalar dx, SkScalar dy, } } -SkBlurDrawLooper::SkBlurDrawLooper(SkReadBuffer& buffer) -: INHERITED(buffer) { +void SkBlurDrawLooper::init(SkScalar sigma, SkScalar dx, SkScalar dy, + SkColor color, uint32_t flags) { + fSigma = sigma; + fDx = dx; + fDy = dy; + fBlurColor = color; + fBlurFlags = flags; + + this->initEffects(); +} +SkBlurDrawLooper::SkBlurDrawLooper(SkReadBuffer& buffer) : INHERITED(buffer) { + + fSigma = buffer.readScalar(); fDx = buffer.readScalar(); fDy = buffer.readScalar(); fBlurColor = buffer.readColor(); - fBlur = buffer.readMaskFilter(); - fColorFilter = buffer.readColorFilter(); fBlurFlags = buffer.readUInt() & kAll_BlurFlag; -} -SkBlurDrawLooper::~SkBlurDrawLooper() { - SkSafeUnref(fBlur); - SkSafeUnref(fColorFilter); + this->initEffects(); } void SkBlurDrawLooper::flatten(SkWriteBuffer& buffer) const { this->INHERITED::flatten(buffer); + buffer.writeScalar(fSigma); buffer.writeScalar(fDx); buffer.writeScalar(fDy); buffer.writeColor(fBlurColor); - buffer.writeFlattenable(fBlur); - buffer.writeFlattenable(fColorFilter); - buffer.writeUInt(fBlurFlags); + buffer.write32(fBlurFlags); +} + +SkBlurDrawLooper::~SkBlurDrawLooper() { + SkSafeUnref(fBlur); + SkSafeUnref(fColorFilter); +} + +bool SkBlurDrawLooper::asABlurShadow(BlurShadowRec* rec) const { + if (fSigma <= 0 || (fBlurFlags & fBlurFlags & kIgnoreTransform_BlurFlag)) { + return false; + } + + if (rec) { + rec->fSigma = fSigma; + rec->fColor = fBlurColor; + rec->fOffset.set(fDx, fDy); + rec->fStyle = kNormal_SkBlurStyle; + rec->fQuality = (fBlurFlags & kHighQuality_BlurFlag) ? + kHigh_SkBlurQuality : kLow_SkBlurQuality; + } + return true; } +//////////////////////////////////////////////////////////////////////////////////////// + SkDrawLooper::Context* SkBlurDrawLooper::createContext(SkCanvas*, void* storage) const { return SkNEW_PLACEMENT_ARGS(storage, BlurDrawLooperContext, (this)); } @@ -120,7 +141,7 @@ bool SkBlurDrawLooper::BlurDrawLooperContext::next(SkCanvas* canvas, #endif paint->setMaskFilter(fLooper->fBlur); paint->setColorFilter(fLooper->fColorFilter); - canvas->save(SkCanvas::kMatrix_SaveFlag); + canvas->save(); if (fLooper->fBlurFlags & kIgnoreTransform_BlurFlag) { SkMatrix transform(canvas->getTotalMatrix()); transform.postTranslate(fLooper->fDx, fLooper->fDy); diff --git a/effects/SkBlurMask.cpp b/effects/SkBlurMask.cpp index 9712ecc4..bf50845a 100644 --- a/effects/SkBlurMask.cpp +++ b/effects/SkBlurMask.cpp @@ -13,17 +13,21 @@ #include "SkEndian.h" +// This constant approximates the scaling done in the software path's +// "high quality" mode, in SkBlurMask::Blur() (1 / sqrt(3)). +// IMHO, it actually should be 1: we blur "less" than we should do +// according to the CSS and canvas specs, simply because Safari does the same. +// Firefox used to do the same too, until 4.0 where they fixed it. So at some +// point we should probably get rid of these scaling constants and rebaseline +// all the blur tests. +static const SkScalar kBLUR_SIGMA_SCALE = 0.57735f; + SkScalar SkBlurMask::ConvertRadiusToSigma(SkScalar radius) { - // This constant approximates the scaling done in the software path's - // "high quality" mode, in SkBlurMask::Blur() (1 / sqrt(3)). - // IMHO, it actually should be 1: we blur "less" than we should do - // according to the CSS and canvas specs, simply because Safari does the same. - // Firefox used to do the same too, until 4.0 where they fixed it. So at some - // point we should probably get rid of these scaling constants and rebaseline - // all the blur tests. - static const SkScalar kBLUR_SIGMA_SCALE = 0.57735f; - - return radius ? kBLUR_SIGMA_SCALE * radius + 0.5f : 0.0f; + return radius > 0 ? kBLUR_SIGMA_SCALE * radius + 0.5f : 0.0f; +} + +SkScalar SkBlurMask::ConvertSigmaToRadius(SkScalar sigma) { + return sigma > 0.5f ? (sigma - 0.5f) / kBLUR_SIGMA_SCALE : 0.0f; } #define UNROLL_SEPARABLE_LOOPS @@ -435,11 +439,11 @@ static void merge_src_with_blur(uint8_t dst[], int dstRB, static void clamp_with_orig(uint8_t dst[], int dstRowBytes, const uint8_t src[], int srcRowBytes, int sw, int sh, - SkBlurMask::Style style) { + SkBlurStyle style) { int x; while (--sh >= 0) { switch (style) { - case SkBlurMask::kSolid_Style: + case kSolid_SkBlurStyle: for (x = sw - 1; x >= 0; --x) { int s = *src; int d = *dst; @@ -448,7 +452,7 @@ static void clamp_with_orig(uint8_t dst[], int dstRowBytes, src += 1; } break; - case SkBlurMask::kOuter_Style: + case kOuter_SkBlurStyle: for (x = sw - 1; x >= 0; --x) { if (*src) { *dst = SkToU8(SkAlphaMul(*dst, SkAlpha255To256(255 - *src))); @@ -476,20 +480,20 @@ void SkMask_FreeImage(uint8_t* image) { } bool SkBlurMask::BoxBlur(SkMask* dst, const SkMask& src, - SkScalar sigma, Style style, Quality quality, - SkIPoint* margin) { + SkScalar sigma, SkBlurStyle style, SkBlurQuality quality, + SkIPoint* margin, bool force_quality) { if (src.fFormat != SkMask::kA8_Format) { return false; } // Force high quality off for small radii (performance) - if (sigma <= SkIntToScalar(2)) { - quality = kLow_Quality; + if (!force_quality && sigma <= SkIntToScalar(2)) { + quality = kLow_SkBlurQuality; } SkScalar passRadius; - if (kHigh_Quality == quality) { + if (kHigh_SkBlurQuality == quality) { // For the high quality path the 3 pass box blur kernel width is // 6*rad+1 while the full Gaussian width is 6*sigma. passRadius = sigma - (1/6.0f); @@ -502,7 +506,7 @@ bool SkBlurMask::BoxBlur(SkMask* dst, const SkMask& src, // highQuality: use three box blur passes as a cheap way // to approximate a Gaussian blur - int passCount = (kHigh_Quality == quality) ? 3 : 1; + int passCount = (kHigh_SkBlurQuality == quality) ? 3 : 1; int rx = SkScalarCeilToInt(passRadius); int outerWeight = 255 - SkScalarRoundToInt((SkIntToScalar(rx) - passRadius) * 255); @@ -548,7 +552,7 @@ bool SkBlurMask::BoxBlur(SkMask* dst, const SkMask& src, if (outerWeight == 255) { int loRadius, hiRadius; get_adjusted_radii(passRadius, &loRadius, &hiRadius); - if (kHigh_Quality == quality) { + if (kHigh_SkBlurQuality == quality) { // Do three X blurs, with a transpose on the final one. w = boxBlur(sp, src.fRowBytes, tp, loRadius, hiRadius, w, h, false); w = boxBlur(tp, w, dp, hiRadius, loRadius, w, h, false); @@ -562,7 +566,7 @@ bool SkBlurMask::BoxBlur(SkMask* dst, const SkMask& src, h = boxBlur(tp, h, dp, ry, ry, h, w, true); } } else { - if (kHigh_Quality == quality) { + if (kHigh_SkBlurQuality == quality) { // Do three X blurs, with a transpose on the final one. w = boxBlurInterp(sp, src.fRowBytes, tp, rx, w, h, false, outerWeight); w = boxBlurInterp(tp, w, dp, rx, w, h, false, outerWeight); @@ -580,7 +584,7 @@ bool SkBlurMask::BoxBlur(SkMask* dst, const SkMask& src, dst->fImage = dp; // if need be, alloc the "real" dst (same size as src) and copy/merge // the blur into it (applying the src) - if (style == kInner_Style) { + if (style == kInner_SkBlurStyle) { // now we allocate the "real" dst, mirror the size of src size_t srcSize = src.computeImageSize(); if (0 == srcSize) { @@ -592,14 +596,14 @@ bool SkBlurMask::BoxBlur(SkMask* dst, const SkMask& src, dp + passCount * (rx + ry * dst->fRowBytes), dst->fRowBytes, sw, sh); SkMask::FreeImage(dp); - } else if (style != kNormal_Style) { + } else if (style != kNormal_SkBlurStyle) { clamp_with_orig(dp + passCount * (rx + ry * dst->fRowBytes), dst->fRowBytes, sp, src.fRowBytes, sw, sh, style); } (void)autoCall.detach(); } - if (style == kInner_Style) { + if (style == kInner_SkBlurStyle) { dst->fBounds = src.fBounds; // restore trimmed bounds dst->fRowBytes = src.fRowBytes; } @@ -734,7 +738,7 @@ void SkBlurMask::ComputeBlurredScanline(uint8_t *pixels, const uint8_t *profile, } bool SkBlurMask::BlurRect(SkScalar sigma, SkMask *dst, - const SkRect &src, Style style, + const SkRect &src, SkBlurStyle style, SkIPoint *margin, SkMask::CreateMode createMode) { int profile_size = SkScalarCeilToInt(6*sigma); @@ -756,7 +760,7 @@ bool SkBlurMask::BlurRect(SkScalar sigma, SkMask *dst, int sh = SkScalarFloorToInt(src.height()); if (createMode == SkMask::kJustComputeBounds_CreateMode) { - if (style == kInner_Style) { + if (style == kInner_SkBlurStyle) { dst->fBounds.set(SkScalarRoundToInt(src.fLeft), SkScalarRoundToInt(src.fTop), SkScalarRoundToInt(src.fRight), @@ -797,7 +801,7 @@ bool SkBlurMask::BlurRect(SkScalar sigma, SkMask *dst, } } - if (style == kInner_Style) { + if (style == kInner_SkBlurStyle) { // now we allocate the "real" dst, mirror the size of src size_t srcSize = (size_t)(src.width() * src.height()); if (0 == srcSize) { @@ -817,12 +821,12 @@ bool SkBlurMask::BlurRect(SkScalar sigma, SkMask *dst, SkScalarRoundToInt(src.fBottom)); // restore trimmed bounds dst->fRowBytes = sw; - } else if (style == kOuter_Style) { + } else if (style == kOuter_SkBlurStyle) { for (int y = pad ; y < dstHeight-pad ; y++) { uint8_t *dst_scanline = dp + y*dstWidth + pad; memset(dst_scanline, 0, sw); } - } else if (style == kSolid_Style) { + } else if (style == kSolid_SkBlurStyle) { for (int y = pad ; y < dstHeight-pad ; y++) { uint8_t *dst_scanline = dp + y*dstWidth + pad; memset(dst_scanline, 0xff, sw); @@ -835,7 +839,7 @@ bool SkBlurMask::BlurRect(SkScalar sigma, SkMask *dst, } bool SkBlurMask::BlurRRect(SkScalar sigma, SkMask *dst, - const SkRRect &src, Style style, + const SkRRect &src, SkBlurStyle style, SkIPoint *margin, SkMask::CreateMode createMode) { // Temporary for now -- always fail, should cause caller to fall back // to old path. Plumbing just to land API and parallelize effort. @@ -848,7 +852,7 @@ bool SkBlurMask::BlurRRect(SkScalar sigma, SkMask *dst, // useful for correctness comparisons. bool SkBlurMask::BlurGroundTruth(SkScalar sigma, SkMask* dst, const SkMask& src, - Style style, SkIPoint* margin) { + SkBlurStyle style, SkIPoint* margin) { if (src.fFormat != SkMask::kA8_Format) { return false; @@ -964,7 +968,7 @@ bool SkBlurMask::BlurGroundTruth(SkScalar sigma, SkMask* dst, const SkMask& src, dst->fImage = dstPixels; // if need be, alloc the "real" dst (same size as src) and copy/merge // the blur into it (applying the src) - if (style == kInner_Style) { + if (style == kInner_SkBlurStyle) { // now we allocate the "real" dst, mirror the size of src size_t srcSize = src.computeImageSize(); if (0 == srcSize) { @@ -976,14 +980,14 @@ bool SkBlurMask::BlurGroundTruth(SkScalar sigma, SkMask* dst, const SkMask& src, dstPixels + pad*dst->fRowBytes + pad, dst->fRowBytes, srcWidth, srcHeight); SkMask::FreeImage(dstPixels); - } else if (style != kNormal_Style) { + } else if (style != kNormal_SkBlurStyle) { clamp_with_orig(dstPixels + pad*dst->fRowBytes + pad, dst->fRowBytes, srcPixels, src.fRowBytes, srcWidth, srcHeight, style); } (void)autoCall.detach(); } - if (style == kInner_Style) { + if (style == kInner_SkBlurStyle) { dst->fBounds = src.fBounds; // restore trimmed bounds dst->fRowBytes = src.fRowBytes; } diff --git a/effects/SkBlurMask.h b/effects/SkBlurMask.h index eb67d4c9..71f60d91 100644 --- a/effects/SkBlurMask.h +++ b/effects/SkBlurMask.h @@ -1,4 +1,3 @@ - /* * Copyright 2006 The Android Open Source Project * @@ -6,51 +5,44 @@ * found in the LICENSE file. */ - #ifndef SkBlurMask_DEFINED #define SkBlurMask_DEFINED +#include "SkBlurTypes.h" #include "SkShader.h" #include "SkMask.h" #include "SkRRect.h" class SkBlurMask { public: - enum Style { - kNormal_Style, //!< fuzzy inside and outside - kSolid_Style, //!< solid inside, fuzzy outside - kOuter_Style, //!< nothing inside, fuzzy outside - kInner_Style, //!< fuzzy inside, nothing outside - - kStyleCount - }; - - enum Quality { - kLow_Quality, //!< box blur - kHigh_Quality //!< three pass box blur (similar to gaussian) - }; - - static bool BlurRect(SkScalar sigma, SkMask *dst, const SkRect &src, - Style style, + static bool BlurRect(SkScalar sigma, SkMask *dst, const SkRect &src, SkBlurStyle, SkIPoint *margin = NULL, SkMask::CreateMode createMode = SkMask::kComputeBoundsAndRenderImage_CreateMode); - static bool BlurRRect(SkScalar sigma, SkMask *dst, const SkRRect &src, - Style style, + static bool BlurRRect(SkScalar sigma, SkMask *dst, const SkRRect &src, SkBlurStyle, SkIPoint *margin = NULL, SkMask::CreateMode createMode = SkMask::kComputeBoundsAndRenderImage_CreateMode); + + // forceQuality will prevent BoxBlur from falling back to the low quality approach when sigma + // is very small -- this can be used predict the margin bump ahead of time without completely + // replicating the internal logic. This permits not only simpler caching of blurred results, + // but also being able to predict precisely at what pixels the blurred profile of e.g. a + // rectangle will lie. + static bool BoxBlur(SkMask* dst, const SkMask& src, - SkScalar sigma, Style style, Quality quality, - SkIPoint* margin = NULL); + SkScalar sigma, SkBlurStyle style, SkBlurQuality quality, + SkIPoint* margin = NULL, bool force_quality=false); // the "ground truth" blur does a gaussian convolution; it's slow // but useful for comparison purposes. - static bool BlurGroundTruth(SkScalar sigma, SkMask* dst, const SkMask& src, - Style style, + static bool BlurGroundTruth(SkScalar sigma, SkMask* dst, const SkMask& src, SkBlurStyle, SkIPoint* margin = NULL); + // If radius > 0, return the corresponding sigma, else return 0 static SkScalar ConvertRadiusToSigma(SkScalar radius); + // If sigma > 0.5, return the corresponding radius, else return 0 + static SkScalar ConvertSigmaToRadius(SkScalar sigma); /* Helper functions for analytic rectangle blurs */ diff --git a/effects/SkBlurMaskFilter.cpp b/effects/SkBlurMaskFilter.cpp index ff98daf0..5dffd6fd 100644 --- a/effects/SkBlurMaskFilter.cpp +++ b/effects/SkBlurMaskFilter.cpp @@ -25,11 +25,12 @@ #include "effects/GrSimpleTextureEffect.h" #include "GrTBackendEffectFactory.h" #include "SkGrPixelRef.h" +#include "SkDraw.h" #endif class SkBlurMaskFilterImpl : public SkMaskFilter { public: - SkBlurMaskFilterImpl(SkScalar sigma, SkBlurMaskFilter::BlurStyle, uint32_t flags); + SkBlurMaskFilterImpl(SkScalar sigma, SkBlurStyle, uint32_t flags); // overrides from SkMaskFilter virtual SkMask::Format getFormat() const SK_OVERRIDE; @@ -58,6 +59,7 @@ public: #endif virtual void computeFastBounds(const SkRect&, SkRect*) const SK_OVERRIDE; + virtual bool asABlur(BlurRec*) const SK_OVERRIDE; SK_TO_STRING_OVERRIDE() SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkBlurMaskFilterImpl) @@ -82,9 +84,14 @@ private: // a request like 10,000) static const SkScalar kMAX_BLUR_SIGMA; - SkScalar fSigma; - SkBlurMaskFilter::BlurStyle fBlurStyle; - uint32_t fBlurFlags; + SkScalar fSigma; + SkBlurStyle fBlurStyle; + uint32_t fBlurFlags; + + SkBlurQuality getQuality() const { + return (fBlurFlags & SkBlurMaskFilter::kHighQuality_BlurFlag) ? + kHigh_SkBlurQuality : kLow_SkBlurQuality; + } SkBlurMaskFilterImpl(SkReadBuffer&); virtual void flatten(SkWriteBuffer&) const SK_OVERRIDE; @@ -101,50 +108,42 @@ private: const SkScalar SkBlurMaskFilterImpl::kMAX_BLUR_SIGMA = SkIntToScalar(128); -SkMaskFilter* SkBlurMaskFilter::Create(SkScalar radius, - SkBlurMaskFilter::BlurStyle style, - uint32_t flags) { - // use !(radius > 0) instead of radius <= 0 to reject NaN values - if (!(radius > 0) || (unsigned)style >= SkBlurMaskFilter::kBlurStyleCount - || flags > SkBlurMaskFilter::kAll_BlurFlag) { +SkMaskFilter* SkBlurMaskFilter::Create(SkBlurStyle style, SkScalar sigma, uint32_t flags) { + if (!SkScalarIsFinite(sigma) || sigma <= 0) { + return NULL; + } + if ((unsigned)style > (unsigned)kLastEnum_SkBlurStyle) { + return NULL; + } + if (flags > SkBlurMaskFilter::kAll_BlurFlag) { return NULL; } + return SkNEW_ARGS(SkBlurMaskFilterImpl, (sigma, style, flags)); +} +#ifdef SK_SUPPORT_LEGACY_BLURMASKFILTER_STYLE +SkMaskFilter* SkBlurMaskFilter::Create(SkScalar radius, + SkBlurMaskFilter::BlurStyle style, + uint32_t flags) { SkScalar sigma = SkBlurMask::ConvertRadiusToSigma(radius); - - return SkNEW_ARGS(SkBlurMaskFilterImpl, (sigma, style, flags)); + return Create((SkBlurStyle)style, sigma, flags); } SkMaskFilter* SkBlurMaskFilter::Create(SkBlurMaskFilter::BlurStyle style, SkScalar sigma, uint32_t flags) { - // use !(sigma > 0) instead of sigma <= 0 to reject NaN values - if (!(sigma > 0) || (unsigned)style >= SkBlurMaskFilter::kBlurStyleCount - || flags > SkBlurMaskFilter::kAll_BlurFlag) { - return NULL; - } - - return SkNEW_ARGS(SkBlurMaskFilterImpl, (sigma, style, flags)); + return Create((SkBlurStyle)style, sigma, flags); } +#endif /////////////////////////////////////////////////////////////////////////////// -SkBlurMaskFilterImpl::SkBlurMaskFilterImpl(SkScalar sigma, - SkBlurMaskFilter::BlurStyle style, - uint32_t flags) - : fSigma(sigma), fBlurStyle(style), fBlurFlags(flags) { -#if 0 - fGamma = NULL; - if (gammaScale) { - fGamma = new U8[256]; - if (gammaScale > 0) - SkBlurMask::BuildSqrGamma(fGamma, gammaScale); - else - SkBlurMask::BuildSqrtGamma(fGamma, -gammaScale); - } -#endif - SkASSERT(fSigma >= 0); - SkASSERT((unsigned)style < SkBlurMaskFilter::kBlurStyleCount); +SkBlurMaskFilterImpl::SkBlurMaskFilterImpl(SkScalar sigma, SkBlurStyle style, uint32_t flags) + : fSigma(sigma) + , fBlurStyle(style) + , fBlurFlags(flags) { + SkASSERT(fSigma > 0); + SkASSERT((unsigned)style <= kLastEnum_SkBlurStyle); SkASSERT(flags <= SkBlurMaskFilter::kAll_BlurFlag); } @@ -152,17 +151,24 @@ SkMask::Format SkBlurMaskFilterImpl::getFormat() const { return SkMask::kA8_Format; } +bool SkBlurMaskFilterImpl::asABlur(BlurRec* rec) const { + if (fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag) { + return false; + } + + if (rec) { + rec->fSigma = fSigma; + rec->fStyle = fBlurStyle; + rec->fQuality = this->getQuality(); + } + return true; +} + bool SkBlurMaskFilterImpl::filterMask(SkMask* dst, const SkMask& src, const SkMatrix& matrix, SkIPoint* margin) const{ SkScalar sigma = this->computeXformedSigma(matrix); - - SkBlurMask::Quality blurQuality = - (fBlurFlags & SkBlurMaskFilter::kHighQuality_BlurFlag) ? - SkBlurMask::kHigh_Quality : SkBlurMask::kLow_Quality; - - return SkBlurMask::BoxBlur(dst, src, sigma, (SkBlurMask::Style)fBlurStyle, - blurQuality, margin); + return SkBlurMask::BoxBlur(dst, src, sigma, fBlurStyle, this->getQuality(), margin); } bool SkBlurMaskFilterImpl::filterRectMask(SkMask* dst, const SkRect& r, @@ -170,7 +176,7 @@ bool SkBlurMaskFilterImpl::filterRectMask(SkMask* dst, const SkRect& r, SkIPoint* margin, SkMask::CreateMode createMode) const{ SkScalar sigma = computeXformedSigma(matrix); - return SkBlurMask::BlurRect(sigma, dst, r, (SkBlurMask::Style)fBlurStyle, + return SkBlurMask::BlurRect(sigma, dst, r, fBlurStyle, margin, createMode); } @@ -179,7 +185,7 @@ bool SkBlurMaskFilterImpl::filterRRectMask(SkMask* dst, const SkRRect& r, SkIPoint* margin, SkMask::CreateMode createMode) const{ SkScalar sigma = computeXformedSigma(matrix); - return SkBlurMask::BlurRRect(sigma, dst, r, (SkBlurMask::Style)fBlurStyle, + return SkBlurMask::BlurRRect(sigma, dst, r, fBlurStyle, margin, createMode); } @@ -260,9 +266,9 @@ static bool rect_exceeds(const SkRect& r, SkScalar v) { } #ifdef SK_IGNORE_FAST_RRECT_BLUR -SK_CONF_DECLARE( bool, c_analyticBlurRRect, "mask.filter.blur.analyticRRect", false, "Use the faster analytic blur approach for ninepatch rects" ); +SK_CONF_DECLARE( bool, c_analyticBlurRRect, "mask.filter.blur.analyticblurrrect", false, "Use the faster analytic blur approach for ninepatch rects" ); #else -SK_CONF_DECLARE( bool, c_analyticBlurRRect, "mask.filter.blur.analyticRRect", true, "Use the faster analytic blur approach for ninepatch round rects" ); +SK_CONF_DECLARE( bool, c_analyticBlurRRect, "mask.filter.blur.analyticblurrrect", true, "Use the faster analytic blur approach for ninepatch round rects" ); #endif SkMaskFilter::FilterReturn @@ -297,7 +303,7 @@ SkBlurMaskFilterImpl::filterRRectToNine(const SkRRect& rrect, const SkMatrix& ma // TODO: report correct metrics for innerstyle, where we do not grow the // total bounds, but we do need an inset the size of our blur-radius - if (SkBlurMaskFilter::kInner_BlurStyle == fBlurStyle) { + if (kInner_SkBlurStyle == fBlurStyle) { return kUnimplemented_FilterReturn; } @@ -409,8 +415,7 @@ SkBlurMaskFilterImpl::filterRectsToNine(const SkRect rects[], int count, // TODO: report correct metrics for innerstyle, where we do not grow the // total bounds, but we do need an inset the size of our blur-radius - if (SkBlurMaskFilter::kInner_BlurStyle == fBlurStyle || - SkBlurMaskFilter::kOuter_BlurStyle == fBlurStyle) { + if (kInner_SkBlurStyle == fBlurStyle || kOuter_SkBlurStyle == fBlurStyle) { return kUnimplemented_FilterReturn; } @@ -530,10 +535,10 @@ void SkBlurMaskFilterImpl::computeFastBounds(const SkRect& src, SkBlurMaskFilterImpl::SkBlurMaskFilterImpl(SkReadBuffer& buffer) : SkMaskFilter(buffer) { fSigma = buffer.readScalar(); - fBlurStyle = (SkBlurMaskFilter::BlurStyle)buffer.readInt(); + fBlurStyle = (SkBlurStyle)buffer.readInt(); fBlurFlags = buffer.readUInt() & SkBlurMaskFilter::kAll_BlurFlag; - SkASSERT(fSigma >= 0); - SkASSERT((unsigned)fBlurStyle < SkBlurMaskFilter::kBlurStyleCount); + SkASSERT(fSigma > 0); + SkASSERT((unsigned)fBlurStyle <= kLastEnum_SkBlurStyle); } void SkBlurMaskFilterImpl::flatten(SkWriteBuffer& buffer) const { @@ -784,7 +789,7 @@ bool SkBlurMaskFilterImpl::directFilterMaskGPU(GrContext* context, GrPaint* grp, const SkStrokeRec& strokeRec, const SkPath& path) const { - if (fBlurStyle != SkBlurMaskFilter::kNormal_BlurStyle) { + if (fBlurStyle != kNormal_SkBlurStyle) { return false; } @@ -819,11 +824,287 @@ bool SkBlurMaskFilterImpl::directFilterMaskGPU(GrContext* context, return true; } +class GrGLRRectBlurEffect; + +class GrRRectBlurEffect : public GrEffect { +public: + + static GrEffectRef* Create(GrContext* context, float sigma, const SkRRect&); + + virtual ~GrRRectBlurEffect() {}; + static const char* Name() { return "GrRRectBlur"; } + + const SkRRect& getRRect() const { return fRRect; } + float getSigma() const { return fSigma; } + + typedef GrGLRRectBlurEffect GLEffect; + + virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE; + + virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE; + +private: + GrRRectBlurEffect(float sigma, const SkRRect&, GrTexture* profileTexture); + + virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE; + + SkRRect fRRect; + float fSigma; + GrTextureAccess fNinePatchAccess; + + GR_DECLARE_EFFECT_TEST; + + typedef GrEffect INHERITED; +}; + + +GrEffectRef* GrRRectBlurEffect::Create(GrContext* context, float sigma, const SkRRect& rrect) { + if (!rrect.isSimpleCircular()) { + SkDebugf( "not simple circular\n" ); + return NULL; + } + + // Make sure we can successfully ninepatch this rrect -- the blur sigma has to be + // sufficiently small relative to both the size of the corner radius and the + // width (and height) of the rrect. + + unsigned int blurRadius = 3*SkScalarCeilToInt(sigma-1/6.0f); + unsigned int cornerRadius = SkScalarCeilToInt(rrect.getSimpleRadii().x()); + if (cornerRadius + blurRadius > rrect.width()/2 || + cornerRadius + blurRadius > rrect.height()/2) { + return NULL; + } + + static const GrCacheID::Domain gRRectBlurDomain = GrCacheID::GenerateDomain(); + GrCacheID::Key key; + memset(&key, 0, sizeof(key)); + key.fData32[0] = blurRadius; + key.fData32[1] = cornerRadius; + GrCacheID blurRRectNinePatchID(gRRectBlurDomain, key); + + GrTextureParams params; + params.setFilterMode(GrTextureParams::kBilerp_FilterMode); + + unsigned int smallRectSide = 2*(blurRadius + cornerRadius) + 1; + unsigned int texSide = smallRectSide + 2*blurRadius; + GrTextureDesc texDesc; + texDesc.fWidth = texSide; + texDesc.fHeight = texSide; + texDesc.fConfig = kAlpha_8_GrPixelConfig; + + GrTexture *blurNinePatchTexture = context->findAndRefTexture(texDesc, blurRRectNinePatchID, ¶ms); + + if (NULL == blurNinePatchTexture) { + SkMask mask; + + mask.fBounds = SkIRect::MakeWH(smallRectSide, smallRectSide); + mask.fFormat = SkMask::kA8_Format; + mask.fRowBytes = mask.fBounds.width(); + mask.fImage = SkMask::AllocImage(mask.computeTotalImageSize()); + SkAutoMaskFreeImage amfi(mask.fImage); + + memset(mask.fImage, 0, mask.computeTotalImageSize()); + + SkRect smallRect; + smallRect.setWH(SkIntToScalar(smallRectSide), SkIntToScalar(smallRectSide)); + + SkRRect smallRRect; + smallRRect.setRectXY(smallRect, SkIntToScalar(cornerRadius), SkIntToScalar(cornerRadius)); + + SkPath path; + path.addRRect( smallRRect ); + + SkDraw::DrawToMask(path, &mask.fBounds, NULL, NULL, &mask, SkMask::kJustRenderImage_CreateMode, SkPaint::kFill_Style); + + SkMask blurred_mask; + SkBlurMask::BoxBlur(&blurred_mask, mask, sigma, kNormal_SkBlurStyle, kHigh_SkBlurQuality, NULL, true ); + + blurNinePatchTexture = context->createTexture(¶ms, texDesc, blurRRectNinePatchID, blurred_mask.fImage, 0); + SkMask::FreeImage(blurred_mask.fImage); + } + + SkAutoTUnref<GrTexture> blurunref(blurNinePatchTexture); + if (NULL == blurNinePatchTexture) { + return NULL; + } + + return CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(GrRRectBlurEffect, + (sigma, rrect, blurNinePatchTexture)))); +} + +void GrRRectBlurEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const { + *validFlags = 0; +} + +const GrBackendEffectFactory& GrRRectBlurEffect::getFactory() const { + return GrTBackendEffectFactory<GrRRectBlurEffect>::getInstance(); +} + +GrRRectBlurEffect::GrRRectBlurEffect(float sigma, const SkRRect& rrect, GrTexture *ninePatchTexture) + : fRRect(rrect), + fSigma(sigma), + fNinePatchAccess(ninePatchTexture) { + this->addTextureAccess(&fNinePatchAccess); + this->setWillReadFragmentPosition(); +} + +bool GrRRectBlurEffect::onIsEqual(const GrEffect& other) const { + const GrRRectBlurEffect& rrbe = CastEffect<GrRRectBlurEffect>(other); + return fRRect.getSimpleRadii().fX == rrbe.fRRect.getSimpleRadii().fX && fSigma == rrbe.fSigma; +} + +////////////////////////////////////////////////////////////////////////////// + +GR_DEFINE_EFFECT_TEST(GrRRectBlurEffect); + +GrEffectRef* GrRRectBlurEffect::TestCreate(SkRandom* random, + GrContext* context, + const GrDrawTargetCaps& caps, + GrTexture*[]) { + SkScalar w = random->nextRangeScalar(100.f, 1000.f); + SkScalar h = random->nextRangeScalar(100.f, 1000.f); + SkScalar r = random->nextRangeF(1.f, 9.f); + SkScalar sigma = random->nextRangeF(1.f,10.f); + SkRRect rrect; + rrect.setRectXY(SkRect::MakeWH(w, h), r, r); + return GrRRectBlurEffect::Create(context, sigma, rrect); +} + +////////////////////////////////////////////////////////////////////////////// + +class GrGLRRectBlurEffect : public GrGLEffect { +public: + GrGLRRectBlurEffect(const GrBackendEffectFactory&, const GrDrawEffect&); + + virtual void emitCode(GrGLShaderBuilder* builder, + const GrDrawEffect& drawEffect, + EffectKey key, + const char* outputColor, + const char* inputColor, + const TransformedCoordsArray&, + const TextureSamplerArray&) SK_OVERRIDE; + + virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE; + +private: + GrGLUniformManager::UniformHandle fProxyRectUniform; + GrGLUniformManager::UniformHandle fCornerRadiusUniform; + GrGLUniformManager::UniformHandle fBlurRadiusUniform; + typedef GrGLEffect INHERITED; +}; + +GrGLRRectBlurEffect::GrGLRRectBlurEffect(const GrBackendEffectFactory& factory, + const GrDrawEffect& drawEffect) + : INHERITED (factory) { +} + +void GrGLRRectBlurEffect::emitCode(GrGLShaderBuilder* builder, + const GrDrawEffect& drawEffect, + EffectKey key, + const char* outputColor, + const char* inputColor, + const TransformedCoordsArray&, + const TextureSamplerArray& samplers) { + const char *rectName; + const char *cornerRadiusName; + const char *blurRadiusName; + + // The proxy rect has left, top, right, and bottom edges correspond to + // components x, y, z, and w, respectively. + + fProxyRectUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, + kVec4f_GrSLType, + "proxyRect", + &rectName); + fCornerRadiusUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, + kFloat_GrSLType, + "cornerRadius", + &cornerRadiusName); + fBlurRadiusUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, + kFloat_GrSLType, + "blurRadius", + &blurRadiusName); + const char* fragmentPos = builder->fragmentPosition(); + + // warp the fragment position to the appropriate part of the 9patch blur texture + + builder->fsCodeAppendf("\t\tvec2 rectCenter = (%s.xy + %s.zw)/2.0;\n", rectName, rectName); + builder->fsCodeAppendf("\t\tvec2 translatedFragPos = %s.xy - %s.xy;\n", fragmentPos, rectName); + builder->fsCodeAppendf("\t\tfloat threshold = %s + 2.0*%s;\n", cornerRadiusName, blurRadiusName ); + builder->fsCodeAppendf("\t\tvec2 middle = %s.zw - %s.xy - 2.0*threshold;\n", rectName, rectName ); + + builder->fsCodeAppendf("\t\tif (translatedFragPos.x >= threshold && translatedFragPos.x < (middle.x+threshold)) {\n" ); + builder->fsCodeAppendf("\t\t\ttranslatedFragPos.x = threshold;\n"); + builder->fsCodeAppendf("\t\t} else if (translatedFragPos.x >= (middle.x + threshold)) {\n"); + builder->fsCodeAppendf("\t\t\ttranslatedFragPos.x -= middle.x;\n"); + builder->fsCodeAppendf("\t\t}\n"); + + builder->fsCodeAppendf("\t\tif (translatedFragPos.y > threshold && translatedFragPos.y < (middle.y+threshold)) {\n" ); + builder->fsCodeAppendf("\t\t\ttranslatedFragPos.y = threshold;\n"); + builder->fsCodeAppendf("\t\t} else if (translatedFragPos.y >= (middle.y + threshold)) {\n"); + builder->fsCodeAppendf("\t\t\ttranslatedFragPos.y -= middle.y;\n"); + builder->fsCodeAppendf("\t\t}\n"); + + builder->fsCodeAppendf("\t\tvec2 proxyDims = vec2(2.0*threshold+1.0);\n"); + builder->fsCodeAppendf("\t\tvec2 texCoord = translatedFragPos / proxyDims;\n"); + + builder->fsCodeAppendf("\t%s = ", outputColor); + builder->fsAppendTextureLookupAndModulate(inputColor, samplers[0], "texCoord"); + builder->fsCodeAppend(";\n"); +} + +void GrGLRRectBlurEffect::setData(const GrGLUniformManager& uman, + const GrDrawEffect& drawEffect) { + const GrRRectBlurEffect& brre = drawEffect.castEffect<GrRRectBlurEffect>(); + SkRRect rrect = brre.getRRect(); + + float blurRadius = 3.f*SkScalarCeilToScalar(brre.getSigma()-1/6.0f); + uman.set1f(fBlurRadiusUniform, blurRadius); + + SkRect rect = rrect.getBounds(); + rect.outset(blurRadius, blurRadius); + uman.set4f(fProxyRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom); + + SkScalar radius = 0; + SkASSERT(rrect.isSimpleCircular() || rrect.isRect()); + radius = rrect.getSimpleRadii().fX; + uman.set1f(fCornerRadiusUniform, radius); +} + + bool SkBlurMaskFilterImpl::directFilterRRectMaskGPU(GrContext* context, GrPaint* grp, const SkStrokeRec& strokeRec, const SkRRect& rrect) const { - return false; + if (fBlurStyle != kNormal_SkBlurStyle) { + return false; + } + + if (!strokeRec.isFillStyle()) { + return false; + } + + SkRect proxy_rect = rrect.rect(); + SkMatrix ctm = context->getMatrix(); + SkScalar xformedSigma = this->computeXformedSigma(ctm); + float extra=3.f*SkScalarCeilToScalar(xformedSigma-1/6.0f); + proxy_rect.outset(extra, extra); + + SkAutoTUnref<GrEffectRef> effect(GrRRectBlurEffect::Create( + context, xformedSigma, rrect)); + if (!effect) { + return false; + } + + GrContext::AutoMatrix am; + if (!am.setIdentity(context, grp)) { + return false; + } + + grp->addCoverageEffect(effect); + + context->drawRect(*grp, proxy_rect); + return true; } bool SkBlurMaskFilterImpl::canFilterMaskGPU(const SkRect& srcBounds, @@ -879,7 +1160,7 @@ bool SkBlurMaskFilterImpl::filterMaskGPU(GrTexture* src, // If we're doing a normal blur, we can clobber the pathTexture in the // gaussianBlur. Otherwise, we need to save it for later compositing. - bool isNormalBlur = (SkBlurMaskFilter::kNormal_BlurStyle == fBlurStyle); + bool isNormalBlur = (kNormal_SkBlurStyle == fBlurStyle); *result = SkGpuBlurUtils::GaussianBlur(context, src, isNormalBlur && canOverwriteSrc, clipRect, false, xformedSigma, xformedSigma); if (NULL == *result) { @@ -894,14 +1175,14 @@ bool SkBlurMaskFilterImpl::filterMaskGPU(GrTexture* src, // Blend pathTexture over blurTexture. GrContext::AutoRenderTarget art(context, (*result)->asRenderTarget()); paint.addColorEffect(GrSimpleTextureEffect::Create(src, matrix))->unref(); - if (SkBlurMaskFilter::kInner_BlurStyle == fBlurStyle) { + if (kInner_SkBlurStyle == fBlurStyle) { // inner: dst = dst * src paint.setBlendFunc(kDC_GrBlendCoeff, kZero_GrBlendCoeff); - } else if (SkBlurMaskFilter::kSolid_BlurStyle == fBlurStyle) { + } else if (kSolid_SkBlurStyle == fBlurStyle) { // solid: dst = src + dst - src * dst // = (1 - dst) * src + 1 * dst paint.setBlendFunc(kIDC_GrBlendCoeff, kOne_GrBlendCoeff); - } else if (SkBlurMaskFilter::kOuter_BlurStyle == fBlurStyle) { + } else if (kOuter_SkBlurStyle == fBlurStyle) { // outer: dst = dst * (1 - src) // = 0 * src + (1 - src) * dst paint.setBlendFunc(kZero_GrBlendCoeff, kISC_GrBlendCoeff); @@ -923,7 +1204,7 @@ void SkBlurMaskFilterImpl::toString(SkString* str) const { str->appendScalar(fSigma); str->append(" "); - static const char* gStyleName[SkBlurMaskFilter::kBlurStyleCount] = { + static const char* gStyleName[kLastEnum_SkBlurStyle + 1] = { "normal", "solid", "outer", "inner" }; diff --git a/effects/SkEmbossMaskFilter.cpp b/effects/SkEmbossMaskFilter.cpp index 19725f1a..cdd55fcc 100644 --- a/effects/SkEmbossMaskFilter.cpp +++ b/effects/SkEmbossMaskFilter.cpp @@ -1,4 +1,3 @@ - /* * Copyright 2006 The Android Open Source Project * @@ -6,7 +5,6 @@ * found in the LICENSE file. */ - #include "SkEmbossMaskFilter.h" #include "SkBlurMaskFilter.h" #include "SkBlurMask.h" @@ -15,6 +13,10 @@ #include "SkWriteBuffer.h" #include "SkString.h" +SkEmbossMaskFilter* SkEmbossMaskFilter::Create(SkScalar blurSigma, const Light& light) { + return SkNEW_ARGS(SkEmbossMaskFilter, (blurSigma, light)); +} + static inline int pin2byte(int n) { if (n < 0) { n = 0; @@ -76,8 +78,7 @@ bool SkEmbossMaskFilter::filterMask(SkMask* dst, const SkMask& src, const SkMatrix& matrix, SkIPoint* margin) const { SkScalar sigma = matrix.mapRadius(fBlurSigma); - if (!SkBlurMask::BoxBlur(dst, src, sigma, SkBlurMask::kInner_Style, - SkBlurMask::kLow_Quality)) { + if (!SkBlurMask::BoxBlur(dst, src, sigma, kInner_SkBlurStyle, kLow_SkBlurQuality)) { return false; } diff --git a/effects/SkLayerDrawLooper.cpp b/effects/SkLayerDrawLooper.cpp index fa590d2d..aed2c9bb 100644 --- a/effects/SkLayerDrawLooper.cpp +++ b/effects/SkLayerDrawLooper.cpp @@ -153,6 +153,50 @@ bool SkLayerDrawLooper::LayerDrawLooperContext::next(SkCanvas* canvas, return true; } +bool SkLayerDrawLooper::asABlurShadow(BlurShadowRec* bsRec) const { + if (fCount != 2) { + return false; + } + const Rec* rec = fRecs; + + // bottom layer needs to be just blur(maskfilter) + if ((rec->fInfo.fPaintBits & ~kMaskFilter_Bit)) { + return false; + } + if (SkXfermode::kSrc_Mode != rec->fInfo.fColorMode) { + return false; + } + const SkMaskFilter* mf = rec->fPaint.getMaskFilter(); + if (NULL == mf) { + return false; + } + SkMaskFilter::BlurRec maskBlur; + if (!mf->asABlur(&maskBlur)) { + return false; + } + + rec = rec->fNext; + // top layer needs to be "plain" + if (rec->fInfo.fPaintBits) { + return false; + } + if (SkXfermode::kDst_Mode != rec->fInfo.fColorMode) { + return false; + } + if (!rec->fInfo.fOffset.equals(0, 0)) { + return false; + } + + if (bsRec) { + bsRec->fSigma = maskBlur.fSigma; + bsRec->fOffset = fRecs->fInfo.fOffset; + bsRec->fColor = fRecs->fPaint.getColor(); + bsRec->fStyle = maskBlur.fStyle; + bsRec->fQuality = maskBlur.fQuality; + } + return true; +} + /////////////////////////////////////////////////////////////////////////////// void SkLayerDrawLooper::flatten(SkWriteBuffer& buffer) const { diff --git a/effects/SkMatrixConvolutionImageFilter.cpp b/effects/SkMatrixConvolutionImageFilter.cpp index 878cbae7..3c9fc877 100644 --- a/effects/SkMatrixConvolutionImageFilter.cpp +++ b/effects/SkMatrixConvolutionImageFilter.cpp @@ -306,6 +306,19 @@ bool SkMatrixConvolutionImageFilter::onFilterImage(Proxy* proxy, return true; } +bool SkMatrixConvolutionImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm, + SkIRect* dst) const { + SkIRect bounds = src; + bounds.fRight += fKernelSize.width() - 1; + bounds.fBottom += fKernelSize.height() - 1; + bounds.offset(-fKernelOffset); + if (getInput(0) && !getInput(0)->filterBounds(bounds, ctm, &bounds)) { + return false; + } + *dst = bounds; + return true; +} + #if SK_SUPPORT_GPU /////////////////////////////////////////////////////////////////////////////// diff --git a/effects/SkTileImageFilter.cpp b/effects/SkTileImageFilter.cpp index 5496f300..73c0a581 100644 --- a/effects/SkTileImageFilter.cpp +++ b/effects/SkTileImageFilter.cpp @@ -60,12 +60,12 @@ bool SkTileImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src, SkPaint paint; paint.setXfermodeMode(SkXfermode::kSrc_Mode); - SkAutoTUnref<SkShader> shader(SkShader::CreateBitmapShader(subset, - SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode)); SkMatrix shaderMatrix; shaderMatrix.setTranslate(SkIntToScalar(srcOffset.fX), SkIntToScalar(srcOffset.fY)); - shader->setLocalMatrix(shaderMatrix); + SkAutoTUnref<SkShader> shader(SkShader::CreateBitmapShader(subset, + SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, + &shaderMatrix)); paint.setShader(shader); canvas.translate(-dstRect.fLeft, -dstRect.fTop); canvas.drawRect(dstRect, paint); @@ -75,6 +75,17 @@ bool SkTileImageFilter::onFilterImage(Proxy* proxy, const SkBitmap& src, return true; } +bool SkTileImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm, + SkIRect* dst) const { + SkRect srcRect; + ctm.mapRect(&srcRect, fSrcRect); + SkIRect srcIRect; + srcRect.roundOut(&srcIRect); + srcIRect.join(src); + *dst = srcIRect; + return true; +} + SkTileImageFilter::SkTileImageFilter(SkReadBuffer& buffer) : INHERITED(1, buffer) { buffer.readRect(&fSrcRect); diff --git a/effects/gradients/SkGradientShader.cpp b/effects/gradients/SkGradientShader.cpp index 46e0c950..6d753a95 100644 --- a/effects/gradients/SkGradientShader.cpp +++ b/effects/gradients/SkGradientShader.cpp @@ -12,7 +12,9 @@ #include "SkTwoPointConicalGradient.h" #include "SkSweepGradient.h" -SkGradientShaderBase::SkGradientShaderBase(const Descriptor& desc) { +SkGradientShaderBase::SkGradientShaderBase(const Descriptor& desc, const SkMatrix* localMatrix) + : INHERITED(localMatrix) +{ SkASSERT(desc.fCount > 1); fMapper = desc.fMapper; @@ -784,7 +786,8 @@ SkShader* SkGradientShader::CreateLinear(const SkPoint pts[2], const SkScalar pos[], int colorCount, SkShader::TileMode mode, SkUnitMapper* mapper, - uint32_t flags) { + uint32_t flags, + const SkMatrix* localMatrix) { if (NULL == pts || NULL == colors || colorCount < 1) { return NULL; } @@ -792,7 +795,7 @@ SkShader* SkGradientShader::CreateLinear(const SkPoint pts[2], SkGradientShaderBase::Descriptor desc; desc_init(&desc, colors, pos, colorCount, mode, mapper, flags); - return SkNEW_ARGS(SkLinearGradient, (pts, desc)); + return SkNEW_ARGS(SkLinearGradient, (pts, desc, localMatrix)); } SkShader* SkGradientShader::CreateRadial(const SkPoint& center, SkScalar radius, @@ -800,7 +803,8 @@ SkShader* SkGradientShader::CreateRadial(const SkPoint& center, SkScalar radius, const SkScalar pos[], int colorCount, SkShader::TileMode mode, SkUnitMapper* mapper, - uint32_t flags) { + uint32_t flags, + const SkMatrix* localMatrix) { if (radius <= 0 || NULL == colors || colorCount < 1) { return NULL; } @@ -808,7 +812,7 @@ SkShader* SkGradientShader::CreateRadial(const SkPoint& center, SkScalar radius, SkGradientShaderBase::Descriptor desc; desc_init(&desc, colors, pos, colorCount, mode, mapper, flags); - return SkNEW_ARGS(SkRadialGradient, (center, radius, desc)); + return SkNEW_ARGS(SkRadialGradient, (center, radius, desc, localMatrix)); } SkShader* SkGradientShader::CreateTwoPointRadial(const SkPoint& start, @@ -820,7 +824,8 @@ SkShader* SkGradientShader::CreateTwoPointRadial(const SkPoint& start, int colorCount, SkShader::TileMode mode, SkUnitMapper* mapper, - uint32_t flags) { + uint32_t flags, + const SkMatrix* localMatrix) { if (startRadius < 0 || endRadius < 0 || NULL == colors || colorCount < 1) { return NULL; } @@ -829,7 +834,7 @@ SkShader* SkGradientShader::CreateTwoPointRadial(const SkPoint& start, SkGradientShaderBase::Descriptor desc; desc_init(&desc, colors, pos, colorCount, mode, mapper, flags); return SkNEW_ARGS(SkTwoPointRadialGradient, - (start, startRadius, end, endRadius, desc)); + (start, startRadius, end, endRadius, desc, localMatrix)); } SkShader* SkGradientShader::CreateTwoPointConical(const SkPoint& start, @@ -841,7 +846,8 @@ SkShader* SkGradientShader::CreateTwoPointConical(const SkPoint& start, int colorCount, SkShader::TileMode mode, SkUnitMapper* mapper, - uint32_t flags) { + uint32_t flags, + const SkMatrix* localMatrix) { if (startRadius < 0 || endRadius < 0 || NULL == colors || colorCount < 1) { return NULL; } @@ -858,7 +864,7 @@ SkShader* SkGradientShader::CreateTwoPointConical(const SkPoint& start, if (!flipGradient) { desc_init(&desc, colors, pos, colorCount, mode, mapper, flags); return SkNEW_ARGS(SkTwoPointConicalGradient, - (start, startRadius, end, endRadius, flipGradient, desc)); + (start, startRadius, end, endRadius, flipGradient, desc, localMatrix)); } else { SkAutoSTArray<8, SkColor> colorsNew(colorCount); SkAutoSTArray<8, SkScalar> posNew(colorCount); @@ -876,7 +882,7 @@ SkShader* SkGradientShader::CreateTwoPointConical(const SkPoint& start, } return SkNEW_ARGS(SkTwoPointConicalGradient, - (end, endRadius, start, startRadius, flipGradient, desc)); + (end, endRadius, start, startRadius, flipGradient, desc, localMatrix)); } } @@ -884,7 +890,8 @@ SkShader* SkGradientShader::CreateSweep(SkScalar cx, SkScalar cy, const SkColor colors[], const SkScalar pos[], int colorCount, SkUnitMapper* mapper, - uint32_t flags) { + uint32_t flags, + const SkMatrix* localMatrix) { if (NULL == colors || colorCount < 1) { return NULL; } @@ -892,7 +899,7 @@ SkShader* SkGradientShader::CreateSweep(SkScalar cx, SkScalar cy, SkGradientShaderBase::Descriptor desc; desc_init(&desc, colors, pos, colorCount, SkShader::kClamp_TileMode, mapper, flags); - return SkNEW_ARGS(SkSweepGradient, (cx, cy, desc)); + return SkNEW_ARGS(SkSweepGradient, (cx, cy, desc, localMatrix)); } SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkGradientShader) @@ -1109,7 +1116,7 @@ GrGradientEffect::GrGradientEffect(GrContext* ctx, desc.fHeight = 32; desc.fRowHeight = bitmap.height(); desc.fContext = ctx; - desc.fConfig = SkImageInfo2GrPixelConfig(bitmap.colorType(), bitmap.alphaType()); + desc.fConfig = SkImageInfo2GrPixelConfig(bitmap.info()); fAtlas = GrTextureStripAtlas::GetAtlas(desc); SkASSERT(NULL != fAtlas); diff --git a/effects/gradients/SkGradientShaderPriv.h b/effects/gradients/SkGradientShaderPriv.h index 5dec665e..c1e253fd 100644 --- a/effects/gradients/SkGradientShaderPriv.h +++ b/effects/gradients/SkGradientShaderPriv.h @@ -99,7 +99,7 @@ public: }; public: - SkGradientShaderBase(const Descriptor& desc); + SkGradientShaderBase(const Descriptor& desc, const SkMatrix* localMatrix); virtual ~SkGradientShaderBase(); // The cache is initialized on-demand when getCache16/32 is called. diff --git a/effects/gradients/SkLinearGradient.cpp b/effects/gradients/SkLinearGradient.cpp index e660d7cd..70bbbf3b 100644 --- a/effects/gradients/SkLinearGradient.cpp +++ b/effects/gradients/SkLinearGradient.cpp @@ -52,8 +52,9 @@ static void pts_to_unit_matrix(const SkPoint pts[2], SkMatrix* matrix) { /////////////////////////////////////////////////////////////////////////////// -SkLinearGradient::SkLinearGradient(const SkPoint pts[2], const Descriptor& desc) - : SkGradientShaderBase(desc) +SkLinearGradient::SkLinearGradient(const SkPoint pts[2], const Descriptor& desc, + const SkMatrix* localMatrix) + : SkGradientShaderBase(desc, localMatrix) , fStart(pts[0]) , fEnd(pts[1]) { pts_to_unit_matrix(pts, &fPtsToUnit); diff --git a/effects/gradients/SkLinearGradient.h b/effects/gradients/SkLinearGradient.h index 8d806672..699d76ed 100644 --- a/effects/gradients/SkLinearGradient.h +++ b/effects/gradients/SkLinearGradient.h @@ -13,7 +13,7 @@ class SkLinearGradient : public SkGradientShaderBase { public: - SkLinearGradient(const SkPoint pts[2], const Descriptor&); + SkLinearGradient(const SkPoint pts[2], const Descriptor&, const SkMatrix* localMatrix); virtual SkShader::Context* createContext(const SkBitmap&, const SkPaint&, const SkMatrix&, void* storage) const SK_OVERRIDE; diff --git a/effects/gradients/SkRadialGradient.cpp b/effects/gradients/SkRadialGradient.cpp index bc2ea3b9..f13d55c6 100644 --- a/effects/gradients/SkRadialGradient.cpp +++ b/effects/gradients/SkRadialGradient.cpp @@ -146,8 +146,8 @@ void shadeSpan16_radial_repeat(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar d ///////////////////////////////////////////////////////////////////// SkRadialGradient::SkRadialGradient(const SkPoint& center, SkScalar radius, - const Descriptor& desc) - : SkGradientShaderBase(desc), + const Descriptor& desc, const SkMatrix* localMatrix) + : SkGradientShaderBase(desc, localMatrix), fCenter(center), fRadius(radius) { diff --git a/effects/gradients/SkRadialGradient.h b/effects/gradients/SkRadialGradient.h index a3d04b1a..7aafe2d1 100644 --- a/effects/gradients/SkRadialGradient.h +++ b/effects/gradients/SkRadialGradient.h @@ -13,7 +13,8 @@ class SkRadialGradient : public SkGradientShaderBase { public: - SkRadialGradient(const SkPoint& center, SkScalar radius, const Descriptor&); + SkRadialGradient(const SkPoint& center, SkScalar radius, const Descriptor&, + const SkMatrix* localMatrix); virtual SkShader::Context* createContext(const SkBitmap&, const SkPaint&, const SkMatrix&, void* storage) const SK_OVERRIDE; diff --git a/effects/gradients/SkSweepGradient.cpp b/effects/gradients/SkSweepGradient.cpp index 6dff1e71..a65631c6 100644 --- a/effects/gradients/SkSweepGradient.cpp +++ b/effects/gradients/SkSweepGradient.cpp @@ -9,8 +9,8 @@ #include "SkSweepGradient.h" SkSweepGradient::SkSweepGradient(SkScalar cx, SkScalar cy, - const Descriptor& desc) - : SkGradientShaderBase(desc) + const Descriptor& desc, const SkMatrix* localMatrix) + : SkGradientShaderBase(desc, localMatrix) , fCenter(SkPoint::Make(cx, cy)) { fPtsToUnit.setTranslate(-cx, -cy); diff --git a/effects/gradients/SkSweepGradient.h b/effects/gradients/SkSweepGradient.h index 9998ed16..15c5b634 100644 --- a/effects/gradients/SkSweepGradient.h +++ b/effects/gradients/SkSweepGradient.h @@ -13,7 +13,8 @@ class SkSweepGradient : public SkGradientShaderBase { public: - SkSweepGradient(SkScalar cx, SkScalar cy, const Descriptor&); + SkSweepGradient(SkScalar cx, SkScalar cy, const Descriptor&, + const SkMatrix* localMatrix); virtual SkShader::Context* createContext(const SkBitmap&, const SkPaint&, const SkMatrix&, void* storage) const SK_OVERRIDE; diff --git a/effects/gradients/SkTwoPointConicalGradient.cpp b/effects/gradients/SkTwoPointConicalGradient.cpp index b7aba827..9d1f8f1a 100644 --- a/effects/gradients/SkTwoPointConicalGradient.cpp +++ b/effects/gradients/SkTwoPointConicalGradient.cpp @@ -197,8 +197,9 @@ void SkTwoPointConicalGradient::init() { SkTwoPointConicalGradient::SkTwoPointConicalGradient( const SkPoint& start, SkScalar startRadius, const SkPoint& end, SkScalar endRadius, - bool flippedGrad, const Descriptor& desc) - : SkGradientShaderBase(desc), + bool flippedGrad, const Descriptor& desc, + const SkMatrix* localMatrix) + : SkGradientShaderBase(desc, localMatrix), fCenter1(start), fCenter2(end), fRadius1(startRadius), diff --git a/effects/gradients/SkTwoPointConicalGradient.h b/effects/gradients/SkTwoPointConicalGradient.h index 80aa6fa6..13ce3eaf 100644 --- a/effects/gradients/SkTwoPointConicalGradient.h +++ b/effects/gradients/SkTwoPointConicalGradient.h @@ -44,7 +44,8 @@ class SkTwoPointConicalGradient : public SkGradientShaderBase { public: SkTwoPointConicalGradient(const SkPoint& start, SkScalar startRadius, const SkPoint& end, SkScalar endRadius, - bool flippedGrad, const Descriptor&); + bool flippedGrad, const Descriptor&, + const SkMatrix* localMatrix); virtual SkShader::Context* createContext(const SkBitmap&, const SkPaint&, const SkMatrix&, diff --git a/effects/gradients/SkTwoPointRadialGradient.cpp b/effects/gradients/SkTwoPointRadialGradient.cpp index a598c6e0..41e577fb 100644 --- a/effects/gradients/SkTwoPointRadialGradient.cpp +++ b/effects/gradients/SkTwoPointRadialGradient.cpp @@ -170,8 +170,8 @@ void shadeSpan_twopoint_repeat(SkScalar fx, SkScalar dx, SkTwoPointRadialGradient::SkTwoPointRadialGradient( const SkPoint& start, SkScalar startRadius, const SkPoint& end, SkScalar endRadius, - const Descriptor& desc) - : SkGradientShaderBase(desc), + const Descriptor& desc, const SkMatrix* localMatrix) + : SkGradientShaderBase(desc, localMatrix), fCenter1(start), fCenter2(end), fRadius1(startRadius), diff --git a/effects/gradients/SkTwoPointRadialGradient.h b/effects/gradients/SkTwoPointRadialGradient.h index 9ba89f29..1b387e68 100644 --- a/effects/gradients/SkTwoPointRadialGradient.h +++ b/effects/gradients/SkTwoPointRadialGradient.h @@ -15,7 +15,7 @@ class SkTwoPointRadialGradient : public SkGradientShaderBase { public: SkTwoPointRadialGradient(const SkPoint& start, SkScalar startRadius, const SkPoint& end, SkScalar endRadius, - const Descriptor&); + const Descriptor&, const SkMatrix* localMatrix); virtual BitmapType asABitmap(SkBitmap* bitmap, SkMatrix* matrix, diff --git a/gpu/GrGpu.h b/gpu/GrGpu.h index bac92885..c051f912 100644 --- a/gpu/GrGpu.h +++ b/gpu/GrGpu.h @@ -323,7 +323,6 @@ public: void getPathStencilSettingsForFillType(SkPath::FillType fill, GrStencilSettings* outStencilSettings); -protected: enum DrawType { kDrawPoints_DrawType, kDrawLines_DrawType, @@ -333,6 +332,7 @@ protected: kDrawPaths_DrawType, }; +protected: DrawType PrimTypeToDrawType(GrPrimitiveType type) { switch (type) { case kTriangles_GrPrimitiveType: diff --git a/gpu/SkGpuDevice.cpp b/gpu/SkGpuDevice.cpp index 58dd030a..4af16109 100644 --- a/gpu/SkGpuDevice.cpp +++ b/gpu/SkGpuDevice.cpp @@ -239,7 +239,7 @@ SkGpuDevice* SkGpuDevice::Create(GrContext* context, const SkImageInfo& origInfo desc.fFlags = kRenderTarget_GrTextureFlagBit; desc.fWidth = info.width(); desc.fHeight = info.height(); - desc.fConfig = SkImageInfo2GrPixelConfig(info.colorType(), info.alphaType()); + desc.fConfig = SkImageInfo2GrPixelConfig(info); desc.fSampleCnt = sampleCount; SkAutoTUnref<GrTexture> texture(context->createUncachedTexture(desc, NULL, 0)); @@ -286,7 +286,7 @@ bool SkGpuDevice::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size DO_DEFERRED_CLEAR(); // TODO: teach fRenderTarget to take ImageInfo directly to specify the src pixels - GrPixelConfig config = SkImageInfo2GrPixelConfig(dstInfo.colorType(), dstInfo.alphaType()); + GrPixelConfig config = SkImageInfo2GrPixelConfig(dstInfo); if (kUnknown_GrPixelConfig == config) { return false; } @@ -302,7 +302,7 @@ bool SkGpuDevice::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size bool SkGpuDevice::onWritePixels(const SkImageInfo& info, const void* pixels, size_t rowBytes, int x, int y) { // TODO: teach fRenderTarget to take ImageInfo directly to specify the src pixels - GrPixelConfig config = SkImageInfo2GrPixelConfig(info.colorType(), info.alphaType()); + GrPixelConfig config = SkImageInfo2GrPixelConfig(info); if (kUnknown_GrPixelConfig == config) { return false; } @@ -1202,8 +1202,7 @@ void SkGpuDevice::drawBitmapCommon(const SkDraw& draw, SkPaint paintWithShader(paint); paintWithShader.setShader(SkShader::CreateBitmapShader(*bitmapPtr, - SkShader::kClamp_TileMode, SkShader::kClamp_TileMode))->unref(); - paintWithShader.getShader()->setLocalMatrix(localM); + SkShader::kClamp_TileMode, SkShader::kClamp_TileMode, &localM))->unref(); SkRect dstRect = {0, 0, dstSize.fWidth, dstSize.fHeight}; this->drawRect(draw, dstRect, paintWithShader); diff --git a/gpu/SkGr.cpp b/gpu/SkGr.cpp index 754a7be9..2596e966 100644 --- a/gpu/SkGr.cpp +++ b/gpu/SkGr.cpp @@ -97,7 +97,7 @@ static void generate_bitmap_texture_desc(const SkBitmap& bitmap, GrTextureDesc* desc->fFlags = kNone_GrTextureFlags; desc->fWidth = bitmap.width(); desc->fHeight = bitmap.height(); - desc->fConfig = SkBitmapConfig2GrPixelConfig(bitmap.config()); + desc->fConfig = SkImageInfo2GrPixelConfig(bitmap.info()); desc->fSampleCnt = 0; } @@ -169,7 +169,7 @@ static GrTexture* sk_gr_create_bitmap_texture(GrContext* ctx, origBitmap.copyTo(&tmpBitmap, kN32_SkColorType); // now bitmap points to our temp, which has been promoted to 32bits bitmap = &tmpBitmap; - desc.fConfig = SkBitmapConfig2GrPixelConfig(bitmap->config()); + desc.fConfig = SkImageInfo2GrPixelConfig(bitmap->info()); } } diff --git a/gpu/effects/GrTextureStripAtlas.cpp b/gpu/effects/GrTextureStripAtlas.cpp index 877215ec..0aa9dc35 100644 --- a/gpu/effects/GrTextureStripAtlas.cpp +++ b/gpu/effects/GrTextureStripAtlas.cpp @@ -158,7 +158,7 @@ int GrTextureStripAtlas::lockRow(const SkBitmap& data) { fDesc.fContext->writeTexturePixels(fTexture, 0, rowNumber * fDesc.fRowHeight, fDesc.fWidth, fDesc.fRowHeight, - SkBitmapConfig2GrPixelConfig(data.config()), + SkImageInfo2GrPixelConfig(data.info()), data.getPixels(), data.rowBytes(), GrContext::kDontFlush_PixelOpsFlag); diff --git a/gpu/gl/GrGLAssembleInterface.cpp b/gpu/gl/GrGLAssembleInterface.cpp new file mode 100644 index 00000000..aed11e53 --- /dev/null +++ b/gpu/gl/GrGLAssembleInterface.cpp @@ -0,0 +1,289 @@ + +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#include "GrGLAssembleInterface.h" +#include "GrGLUtil.h" + +#define GET_PROC(F) functions->f ## F = (GrGL ## F ## Proc) get(ctx, "gl" #F) +#define GET_PROC_SUFFIX(F, S) functions->f ## F = (GrGL ## F ## Proc) get(ctx, "gl" #F #S) +#define GET_PROC_LOCAL(F) GrGL ## F ## Proc F = (GrGL ## F ## Proc) get(ctx, "gl" #F) + +const GrGLInterface* GrGLAssembleGLInterface(void* ctx, GrGLGetProc get) { + GET_PROC_LOCAL(GetString); + GET_PROC_LOCAL(GetStringi); + GET_PROC_LOCAL(GetIntegerv); + + // GetStringi may be NULL depending on the GL version. + if (NULL == GetString || NULL == GetIntegerv) { + return NULL; + } + + const char* versionString = (const char*) GetString(GR_GL_VERSION); + GrGLVersion glVer = GrGLGetVersionFromString(versionString); + + if (glVer < GR_GL_VER(1,5) || GR_GL_INVALID_VER == glVer) { + // We must have array and element_array buffer objects. + return NULL; + } + + GrGLExtensions extensions; + if (!extensions.init(kGL_GrGLStandard, GetString, GetStringi, GetIntegerv)) { + return NULL; + } + + GrGLInterface* interface = SkNEW(GrGLInterface()); + GrGLInterface::Functions* functions = &interface->fFunctions; + + GET_PROC(ActiveTexture); + GET_PROC(AttachShader); + GET_PROC(BindAttribLocation); + GET_PROC(BindBuffer); + if (glVer >= GR_GL_VER(3,0)) { + GET_PROC(BindFragDataLocation); + } + GET_PROC(BeginQuery); + GET_PROC(BindTexture); + GET_PROC(BlendFunc); + + if (glVer >= GR_GL_VER(1,4) || + extensions.has("GL_ARB_imaging") || + extensions.has("GL_EXT_blend_color")) { + GET_PROC(BlendColor); + } + + GET_PROC(BufferData); + GET_PROC(BufferSubData); + GET_PROC(Clear); + GET_PROC(ClearColor); + GET_PROC(ClearStencil); + GET_PROC(ColorMask); + GET_PROC(CompileShader); + GET_PROC(CompressedTexImage2D); + GET_PROC(CopyTexSubImage2D); + GET_PROC(CreateProgram); + GET_PROC(CreateShader); + GET_PROC(CullFace); + GET_PROC(DeleteBuffers); + GET_PROC(DeleteProgram); + GET_PROC(DeleteQueries); + GET_PROC(DeleteShader); + GET_PROC(DeleteTextures); + GET_PROC(DepthMask); + GET_PROC(Disable); + GET_PROC(DisableVertexAttribArray); + GET_PROC(DrawArrays); + GET_PROC(DrawBuffer); + GET_PROC(DrawBuffers); + GET_PROC(DrawElements); + GET_PROC(Enable); + GET_PROC(EnableVertexAttribArray); + GET_PROC(EndQuery); + GET_PROC(Finish); + GET_PROC(Flush); + GET_PROC(FrontFace); + GET_PROC(GenBuffers); + GET_PROC(GenerateMipmap); + GET_PROC(GetBufferParameteriv); + GET_PROC(GetError); + GET_PROC(GetIntegerv); + GET_PROC(GetQueryObjectiv); + GET_PROC(GetQueryObjectuiv); + if (glVer >= GR_GL_VER(3,3) || extensions.has("GL_ARB_timer_query")) { + GET_PROC(GetQueryObjecti64v); + GET_PROC(GetQueryObjectui64v); + GET_PROC(QueryCounter); + } else if (extensions.has("GL_EXT_timer_query")) { + GET_PROC_SUFFIX(GetQueryObjecti64v, EXT); + GET_PROC_SUFFIX(GetQueryObjectui64v, EXT); + } + GET_PROC(GetQueryiv); + GET_PROC(GetProgramInfoLog); + GET_PROC(GetProgramiv); + GET_PROC(GetShaderInfoLog); + GET_PROC(GetShaderiv); + GET_PROC(GetString); + GET_PROC(GetStringi); + GET_PROC(GetTexLevelParameteriv); + GET_PROC(GenQueries); + GET_PROC(GenTextures); + GET_PROC(GetUniformLocation); + GET_PROC(LineWidth); + GET_PROC(LinkProgram); + GET_PROC(MapBuffer); + if (extensions.has("GL_EXT_direct_state_access")) { + GET_PROC_SUFFIX(MatrixLoadf, EXT); + GET_PROC_SUFFIX(MatrixLoadIdentity, EXT); + } + GET_PROC(PixelStorei); + GET_PROC(ReadBuffer); + GET_PROC(ReadPixels); + GET_PROC(Scissor); + GET_PROC(ShaderSource); + GET_PROC(StencilFunc); + GET_PROC(StencilFuncSeparate); + GET_PROC(StencilMask); + GET_PROC(StencilMaskSeparate); + GET_PROC(StencilOp); + GET_PROC(StencilOpSeparate); + GET_PROC(TexImage2D); + GET_PROC(TexParameteri); + GET_PROC(TexParameteriv); + if (glVer >= GR_GL_VER(4,2) || extensions.has("GL_ARB_texture_storage")) { + GET_PROC(TexStorage2D); + } else if (extensions.has("GL_EXT_texture_storage")) { + GET_PROC_SUFFIX(TexStorage2D, EXT); + } + GET_PROC(TexSubImage2D); + GET_PROC(Uniform1f); + GET_PROC(Uniform1i); + GET_PROC(Uniform1fv); + GET_PROC(Uniform1iv); + GET_PROC(Uniform2f); + GET_PROC(Uniform2i); + GET_PROC(Uniform2fv); + GET_PROC(Uniform2iv); + GET_PROC(Uniform3f); + GET_PROC(Uniform3i); + GET_PROC(Uniform3fv); + GET_PROC(Uniform3iv); + GET_PROC(Uniform4f); + GET_PROC(Uniform4i); + GET_PROC(Uniform4fv); + GET_PROC(Uniform4iv); + GET_PROC(UniformMatrix2fv); + GET_PROC(UniformMatrix3fv); + GET_PROC(UniformMatrix4fv); + GET_PROC(UnmapBuffer); + GET_PROC(UseProgram); + GET_PROC(VertexAttrib4fv); + GET_PROC(VertexAttribPointer); + GET_PROC(Viewport); + GET_PROC(BindFragDataLocationIndexed); + + if (glVer >= GR_GL_VER(3,0) || extensions.has("GL_ARB_vertex_array_object")) { + // no ARB suffix for GL_ARB_vertex_array_object + GET_PROC(BindVertexArray); + GET_PROC(GenVertexArrays); + GET_PROC(DeleteVertexArrays); + } + + // First look for GL3.0 FBO or GL_ARB_framebuffer_object (same since + // GL_ARB_framebuffer_object doesn't use ARB suffix.) + if (glVer >= GR_GL_VER(3,0) || extensions.has("GL_ARB_framebuffer_object")) { + GET_PROC(GenFramebuffers); + GET_PROC(GetFramebufferAttachmentParameteriv); + GET_PROC(GetRenderbufferParameteriv); + GET_PROC(BindFramebuffer); + GET_PROC(FramebufferTexture2D); + GET_PROC(CheckFramebufferStatus); + GET_PROC(DeleteFramebuffers); + GET_PROC(RenderbufferStorage); + GET_PROC(GenRenderbuffers); + GET_PROC(DeleteRenderbuffers); + GET_PROC(FramebufferRenderbuffer); + GET_PROC(BindRenderbuffer); + GET_PROC(RenderbufferStorageMultisample); + GET_PROC(BlitFramebuffer); + } else if (extensions.has("GL_EXT_framebuffer_object")) { + GET_PROC_SUFFIX(GenFramebuffers, EXT); + GET_PROC_SUFFIX(GetFramebufferAttachmentParameteriv, EXT); + GET_PROC_SUFFIX(GetRenderbufferParameteriv, EXT); + GET_PROC_SUFFIX(BindFramebuffer, EXT); + GET_PROC_SUFFIX(FramebufferTexture2D, EXT); + GET_PROC_SUFFIX(CheckFramebufferStatus, EXT); + GET_PROC_SUFFIX(DeleteFramebuffers, EXT); + GET_PROC_SUFFIX(RenderbufferStorage, EXT); + GET_PROC_SUFFIX(GenRenderbuffers, EXT); + GET_PROC_SUFFIX(DeleteRenderbuffers, EXT); + GET_PROC_SUFFIX(FramebufferRenderbuffer, EXT); + GET_PROC_SUFFIX(BindRenderbuffer, EXT); + if (extensions.has("GL_EXT_framebuffer_multisample")) { + GET_PROC_SUFFIX(RenderbufferStorageMultisample, EXT); + } + if (extensions.has("GL_EXT_framebuffer_blit")) { + GET_PROC_SUFFIX(BlitFramebuffer, EXT); + } + } else { + // we must have FBOs + delete interface; + return NULL; + } + + if (extensions.has("GL_NV_path_rendering")) { + GET_PROC_SUFFIX(PathCommands, NV); + GET_PROC_SUFFIX(PathCoords, NV); + GET_PROC_SUFFIX(PathSubCommands, NV); + GET_PROC_SUFFIX(PathSubCoords, NV); + GET_PROC_SUFFIX(PathString, NV); + GET_PROC_SUFFIX(PathGlyphs, NV); + GET_PROC_SUFFIX(PathGlyphRange, NV); + GET_PROC_SUFFIX(WeightPaths, NV); + GET_PROC_SUFFIX(CopyPath, NV); + GET_PROC_SUFFIX(InterpolatePaths, NV); + GET_PROC_SUFFIX(TransformPath, NV); + GET_PROC_SUFFIX(PathParameteriv, NV); + GET_PROC_SUFFIX(PathParameteri, NV); + GET_PROC_SUFFIX(PathParameterfv, NV); + GET_PROC_SUFFIX(PathParameterf, NV); + GET_PROC_SUFFIX(PathDashArray, NV); + GET_PROC_SUFFIX(GenPaths, NV); + GET_PROC_SUFFIX(DeletePaths, NV); + GET_PROC_SUFFIX(IsPath, NV); + GET_PROC_SUFFIX(PathStencilFunc, NV); + GET_PROC_SUFFIX(PathStencilDepthOffset, NV); + GET_PROC_SUFFIX(StencilFillPath, NV); + GET_PROC_SUFFIX(StencilStrokePath, NV); + GET_PROC_SUFFIX(StencilFillPathInstanced, NV); + GET_PROC_SUFFIX(StencilStrokePathInstanced, NV); + GET_PROC_SUFFIX(PathCoverDepthFunc, NV); + GET_PROC_SUFFIX(PathColorGen, NV); + GET_PROC_SUFFIX(PathTexGen, NV); + GET_PROC_SUFFIX(PathFogGen, NV); + GET_PROC_SUFFIX(CoverFillPath, NV); + GET_PROC_SUFFIX(CoverStrokePath, NV); + GET_PROC_SUFFIX(CoverFillPathInstanced, NV); + GET_PROC_SUFFIX(CoverStrokePathInstanced, NV); + GET_PROC_SUFFIX(GetPathParameteriv, NV); + GET_PROC_SUFFIX(GetPathParameterfv, NV); + GET_PROC_SUFFIX(GetPathCommands, NV); + GET_PROC_SUFFIX(GetPathCoords, NV); + GET_PROC_SUFFIX(GetPathDashArray, NV); + GET_PROC_SUFFIX(GetPathMetrics, NV); + GET_PROC_SUFFIX(GetPathMetricRange, NV); + GET_PROC_SUFFIX(GetPathSpacing, NV); + GET_PROC_SUFFIX(GetPathColorGeniv, NV); + GET_PROC_SUFFIX(GetPathColorGenfv, NV); + GET_PROC_SUFFIX(GetPathTexGeniv, NV); + GET_PROC_SUFFIX(GetPathTexGenfv, NV); + GET_PROC_SUFFIX(IsPointInFillPath, NV); + GET_PROC_SUFFIX(IsPointInStrokePath, NV); + GET_PROC_SUFFIX(GetPathLength, NV); + GET_PROC_SUFFIX(PointAlongPath, NV); + } + + if (extensions.has("GL_EXT_debug_marker")) { + GET_PROC_SUFFIX(InsertEventMarker, EXT); + GET_PROC_SUFFIX(PushGroupMarker, EXT); + GET_PROC_SUFFIX(PopGroupMarker, EXT); + } + + if (glVer >= GR_GL_VER(4,3) || extensions.has("GL_ARB_invalidate_subdata")) { + GET_PROC(InvalidateBufferData); + GET_PROC(InvalidateBufferSubData); + GET_PROC(InvalidateFramebuffer); + GET_PROC(InvalidateSubFramebuffer); + GET_PROC(InvalidateTexImage); + GET_PROC(InvalidateTexSubImage); + } + + interface->fStandard = kGL_GrGLStandard; + interface->fExtensions.swap(&extensions); + + return interface; +} diff --git a/gpu/gl/GrGLAssembleInterface.h b/gpu/gl/GrGLAssembleInterface.h new file mode 100644 index 00000000..36a45134 --- /dev/null +++ b/gpu/gl/GrGLAssembleInterface.h @@ -0,0 +1,18 @@ + +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "gl/GrGLInterface.h" + +typedef void(*GrGLFuncPtr)(); +typedef GrGLFuncPtr (*GrGLGetProc)(void* ctx, const char name[]); + +/** + * Generic function for creating a GrGLInterface for an OpenGL (but not GLES) context. It calls + * get() to get each function address. ctx is a generic ptr passed to and interpreted by get(). + */ +const GrGLInterface* GrGLAssembleGLInterface(void* ctx, GrGLGetProc get); diff --git a/gpu/gl/GrGLCaps.cpp b/gpu/gl/GrGLCaps.cpp index e20f932f..501411c0 100644 --- a/gpu/gl/GrGLCaps.cpp +++ b/gpu/gl/GrGLCaps.cpp @@ -45,7 +45,6 @@ void GrGLCaps::reset() { fVertexArrayObjectSupport = false; fUseNonVBOVertexAndIndexDynamicData = false; fIsCoreProfile = false; - fFixedFunctionSupport = false; fFullClearIsFree = false; fDropsTileOnZeroDivide = false; fMapSubSupport = false; @@ -84,7 +83,6 @@ GrGLCaps& GrGLCaps::operator= (const GrGLCaps& caps) { fVertexArrayObjectSupport = caps.fVertexArrayObjectSupport; fUseNonVBOVertexAndIndexDynamicData = caps.fUseNonVBOVertexAndIndexDynamicData; fIsCoreProfile = caps.fIsCoreProfile; - fFixedFunctionSupport = caps.fFixedFunctionSupport; fFullClearIsFree = caps.fFullClearIsFree; fDropsTileOnZeroDivide = caps.fDropsTileOnZeroDivide; fMapSubSupport = caps.fMapSubSupport; @@ -92,11 +90,11 @@ GrGLCaps& GrGLCaps::operator= (const GrGLCaps& caps) { return *this; } -void GrGLCaps::init(const GrGLContextInfo& ctxInfo, const GrGLInterface* gli) { +bool GrGLCaps::init(const GrGLContextInfo& ctxInfo, const GrGLInterface* gli) { this->reset(); if (!ctxInfo.isInitialized()) { - return; + return false; } GrGLStandard standard = ctxInfo.standard(); @@ -120,7 +118,6 @@ void GrGLCaps::init(const GrGLContextInfo& ctxInfo, const GrGLInterface* gli) { fIsCoreProfile = SkToBool(profileMask & GR_GL_CONTEXT_CORE_PROFILE_BIT); } if (!fIsCoreProfile) { - fFixedFunctionSupport = true; GR_GL_GetIntegerv(gli, GR_GL_MAX_TEXTURE_COORDS, &fMaxFixedFunctionTextureCoords); // Sanity check SkASSERT(fMaxFixedFunctionTextureCoords > 0 && fMaxFixedFunctionTextureCoords < 128); @@ -326,8 +323,8 @@ void GrGLCaps::init(const GrGLContextInfo& ctxInfo, const GrGLInterface* gli) { // attachment, hence this min: fMaxRenderTargetSize = SkTMin(fMaxTextureSize, fMaxRenderTargetSize); - fPathRenderingSupport = ctxInfo.hasExtension("GL_NV_path_rendering"); - SkASSERT(!fPathRenderingSupport || fFixedFunctionSupport); + fPathRenderingSupport = ctxInfo.hasExtension("GL_NV_path_rendering") && + ctxInfo.hasExtension("GL_EXT_direct_state_access"); fGpuTracingSupport = ctxInfo.hasExtension("GL_EXT_debug_marker"); @@ -356,6 +353,8 @@ void GrGLCaps::init(const GrGLContextInfo& ctxInfo, const GrGLInterface* gli) { } this->initConfigRenderableTable(ctxInfo); + + return true; } void GrGLCaps::initConfigRenderableTable(const GrGLContextInfo& ctxInfo) { @@ -657,13 +656,12 @@ SkString GrGLCaps::dump() const { GR_STATIC_ASSERT(SK_ARRAY_COUNT(kInvalidateFBTypeStr) == kLast_InvalidateFBType + 1); r.appendf("Core Profile: %s\n", (fIsCoreProfile ? "YES" : "NO")); - r.appendf("Fixed Function Support: %s\n", (fFixedFunctionSupport ? "YES" : "NO")); r.appendf("MSAA Type: %s\n", kMSFBOExtStr[fMSFBOType]); r.appendf("FB Fetch Type: %s\n", kFBFetchTypeStr[fFBFetchType]); r.appendf("Invalidate FB Type: %s\n", kInvalidateFBTypeStr[fInvalidateFBType]); r.appendf("Max FS Uniform Vectors: %d\n", fMaxFragmentUniformVectors); r.appendf("Max FS Texture Units: %d\n", fMaxFragmentTextureUnits); - if (fFixedFunctionSupport) { + if (!fIsCoreProfile) { r.appendf("Max Fixed Function Texture Coords: %d\n", fMaxFixedFunctionTextureCoords); } r.appendf("Max Vertex Attributes: %d\n", fMaxVertexAttributes); diff --git a/gpu/gl/GrGLCaps.h b/gpu/gl/GrGLCaps.h index 1ba21ec7..48925d48 100644 --- a/gpu/gl/GrGLCaps.h +++ b/gpu/gl/GrGLCaps.h @@ -105,7 +105,7 @@ public: * Initializes the GrGLCaps to the set of features supported in the current * OpenGL context accessible via ctxInfo. */ - void init(const GrGLContextInfo& ctxInfo, const GrGLInterface* interface); + bool init(const GrGLContextInfo& ctxInfo, const GrGLInterface* interface); /** * Call to note that a color config has been verified as a valid color @@ -253,7 +253,6 @@ public: bool isCoreProfile() const { return fIsCoreProfile; } - bool fixedFunctionSupport() const { return fFixedFunctionSupport; } bool fullClearIsFree() const { return fFullClearIsFree; } @@ -341,7 +340,6 @@ private: bool fVertexArrayObjectSupport : 1; bool fUseNonVBOVertexAndIndexDynamicData : 1; bool fIsCoreProfile : 1; - bool fFixedFunctionSupport : 1; bool fFullClearIsFree : 1; bool fDropsTileOnZeroDivide : 1; bool fMapSubSupport : 1; diff --git a/gpu/gl/GrGLContext.cpp b/gpu/gl/GrGLContext.cpp index 54deb323..5bc5b6f0 100644 --- a/gpu/gl/GrGLContext.cpp +++ b/gpu/gl/GrGLContext.cpp @@ -37,8 +37,13 @@ bool GrGLContextInfo::initialize(const GrGLInterface* interface) { if (interface->validate()) { fGLVersion = GrGLGetVersionFromString(ver); + if (GR_GL_INVALID_VER == fGLVersion) { + return false; + } - fGLSLGeneration = GrGetGLSLGeneration(interface); + if (!GrGetGLSLGeneration(interface, &fGLSLGeneration)) { + return false; + } fVendor = GrGLGetVendor(interface); @@ -51,9 +56,7 @@ bool GrGLContextInfo::initialize(const GrGLInterface* interface) { // This must occur before caps init. fInterface.reset(SkRef(interface)); - fGLCaps->init(*this, interface); - - return true; + return fGLCaps->init(*this, interface); } } return false; diff --git a/gpu/gl/GrGLCreateNullInterface.cpp b/gpu/gl/GrGLCreateNullInterface.cpp index 391aea27..18a9d726 100644 --- a/gpu/gl/GrGLCreateNullInterface.cpp +++ b/gpu/gl/GrGLCreateNullInterface.cpp @@ -327,11 +327,8 @@ const GrGLInterface* GrGLCreateNullInterface() { functions->fGetTexLevelParameteriv = noOpGLGetTexLevelParameteriv; functions->fGetUniformLocation = noOpGLGetUniformLocation; functions->fInsertEventMarker = noOpGLInsertEventMarker; - functions->fLoadIdentity = noOpGLLoadIdentity; - functions->fLoadMatrixf = noOpGLLoadMatrixf; functions->fLineWidth = noOpGLLineWidth; functions->fLinkProgram = noOpGLLinkProgram; - functions->fMatrixMode = noOpGLMatrixMode; functions->fPixelStorei = nullGLPixelStorei; functions->fPopGroupMarker = noOpGLPopGroupMarker; functions->fPushGroupMarker = noOpGLPushGroupMarker; @@ -346,8 +343,6 @@ const GrGLInterface* GrGLCreateNullInterface() { functions->fStencilMaskSeparate = noOpGLStencilMaskSeparate; functions->fStencilOp = noOpGLStencilOp; functions->fStencilOpSeparate = noOpGLStencilOpSeparate; - functions->fTexGenfv = noOpGLTexGenfv; - functions->fTexGeni = noOpGLTexGeni; functions->fTexImage2D = noOpGLTexImage2D; functions->fTexParameteri = noOpGLTexParameteri; functions->fTexParameteriv = noOpGLTexParameteriv; @@ -393,6 +388,8 @@ const GrGLInterface* GrGLCreateNullInterface() { functions->fBlitFramebuffer = noOpGLBlitFramebuffer; functions->fResolveMultisampleFramebuffer = noOpGLResolveMultisampleFramebuffer; functions->fMapBuffer = nullGLMapBuffer; + functions->fMatrixLoadf = noOpGLMatrixLoadf; + functions->fMatrixLoadIdentity = noOpGLMatrixLoadIdentity; functions->fUnmapBuffer = nullGLUnmapBuffer; functions->fBindFragDataLocationIndexed = noOpGLBindFragDataLocationIndexed; diff --git a/gpu/gl/GrGLExtensions.cpp b/gpu/gl/GrGLExtensions.cpp index 6d1b04d2..53013df6 100644 --- a/gpu/gl/GrGLExtensions.cpp +++ b/gpu/gl/GrGLExtensions.cpp @@ -54,10 +54,11 @@ bool GrGLExtensions::init(GrGLStandard standard, // glGetStringi and indexed extensions were added in version 3.0 of desktop GL and ES. const GrGLubyte* verString = getString(GR_GL_VERSION); - if (NULL == verString) { + GrGLVersion version = GrGLGetVersionFromString((const char*) verString); + if (GR_GL_INVALID_VER == version) { return false; } - GrGLVersion version = GrGLGetVersionFromString((const char*) verString); + bool indexed = version >= GR_GL_VER(3, 0); if (indexed) { diff --git a/gpu/gl/GrGLInterface.cpp b/gpu/gl/GrGLInterface.cpp index bfffdfb1..7efa067d 100644 --- a/gpu/gl/GrGLInterface.cpp +++ b/gpu/gl/GrGLInterface.cpp @@ -227,12 +227,8 @@ bool GrGLInterface::validate() const { } GrGLVersion glVer = GrGLGetVersion(this); - - bool isCoreProfile = false; - if (kGL_GrGLStandard == fStandard && glVer >= GR_GL_VER(3,2)) { - GrGLint profileMask; - GR_GL_GetIntegerv(this, GR_GL_CONTEXT_PROFILE_MASK, &profileMask); - isCoreProfile = SkToBool(profileMask & GR_GL_CONTEXT_CORE_PROFILE_BIT); + if (GR_GL_INVALID_VER == glVer) { + RETURN_FALSE_INTERFACE } // Now check that baseline ES/Desktop fns not covered above are present @@ -290,12 +286,9 @@ bool GrGLInterface::validate() const { RETURN_FALSE_INTERFACE } } - if (!isCoreProfile) { - if (NULL == fFunctions.fLoadIdentity || - NULL == fFunctions.fLoadMatrixf || - NULL == fFunctions.fMatrixMode || - NULL == fFunctions.fTexGenfv || - NULL == fFunctions.fTexGeni) { + if (fExtensions.has("GL_EXT_direct_state_access")) { + if (NULL == fFunctions.fMatrixLoadf || + NULL == fFunctions.fMatrixLoadIdentity) { RETURN_FALSE_INTERFACE } } diff --git a/gpu/gl/GrGLNoOpInterface.cpp b/gpu/gl/GrGLNoOpInterface.cpp index de38f6aa..2b84b280 100644 --- a/gpu/gl/GrGLNoOpInterface.cpp +++ b/gpu/gl/GrGLNoOpInterface.cpp @@ -164,13 +164,10 @@ GrGLvoid GR_GL_FUNCTION_TYPE noOpGLLineWidth(GrGLfloat width) { GrGLvoid GR_GL_FUNCTION_TYPE noOpGLLinkProgram(GrGLuint program) { } -GrGLvoid GR_GL_FUNCTION_TYPE noOpGLLoadIdentity() { +GrGLvoid GR_GL_FUNCTION_TYPE noOpGLMatrixLoadf(GrGLenum, const GrGLfloat*) { } -GrGLvoid GR_GL_FUNCTION_TYPE noOpGLLoadMatrixf(const GrGLfloat*) { -} - -GrGLvoid GR_GL_FUNCTION_TYPE noOpGLMatrixMode(GrGLenum) { +GrGLvoid GR_GL_FUNCTION_TYPE noOpGLMatrixLoadIdentity(GrGLenum) { } GrGLvoid GR_GL_FUNCTION_TYPE noOpGLQueryCounter(GrGLuint id, GrGLenum target) { @@ -219,15 +216,6 @@ GrGLvoid GR_GL_FUNCTION_TYPE noOpGLStencilOpSeparate(GrGLenum face, GrGLenum zpass) { } -GrGLvoid GR_GL_FUNCTION_TYPE noOpGLTexGenf(GrGLenum, GrGLenum, float) { -} - -GrGLvoid GR_GL_FUNCTION_TYPE noOpGLTexGenfv(GrGLenum, GrGLenum, const float*) { -} - -GrGLvoid GR_GL_FUNCTION_TYPE noOpGLTexGeni(GrGLenum, GrGLenum, GrGLint) { -} - GrGLvoid GR_GL_FUNCTION_TYPE noOpGLTexImage2D(GrGLenum target, GrGLint level, GrGLint internalformat, diff --git a/gpu/gl/GrGLNoOpInterface.h b/gpu/gl/GrGLNoOpInterface.h index b5b681fe..2efc1138 100644 --- a/gpu/gl/GrGLNoOpInterface.h +++ b/gpu/gl/GrGLNoOpInterface.h @@ -96,16 +96,14 @@ GrGLvoid GR_GL_FUNCTION_TYPE noOpGLFlush(); GrGLvoid GR_GL_FUNCTION_TYPE noOpGLFrontFace(GrGLenum mode); -GrGLvoid GR_GL_FUNCTION_TYPE noOpGLLoadIdentity(); +GrGLvoid GR_GL_FUNCTION_TYPE noOpGLMatrixLoadf(GrGLenum, const GrGLfloat*); -GrGLvoid GR_GL_FUNCTION_TYPE noOpGLLoadMatrixf(const GrGLfloat*); +GrGLvoid GR_GL_FUNCTION_TYPE noOpGLMatrixLoadIdentity(GrGLenum); GrGLvoid GR_GL_FUNCTION_TYPE noOpGLLineWidth(GrGLfloat width); GrGLvoid GR_GL_FUNCTION_TYPE noOpGLLinkProgram(GrGLuint program); -GrGLvoid GR_GL_FUNCTION_TYPE noOpGLMatrixMode(GrGLenum); - GrGLvoid GR_GL_FUNCTION_TYPE noOpGLQueryCounter(GrGLuint id, GrGLenum target); @@ -165,12 +163,6 @@ GrGLvoid GR_GL_FUNCTION_TYPE noOpGLTexStorage2D(GrGLenum target, GrGLsizei width, GrGLsizei height); -GrGLvoid GR_GL_FUNCTION_TYPE noOpGLTexGenf(GrGLenum, GrGLenum, GrGLfloat); - -GrGLvoid GR_GL_FUNCTION_TYPE noOpGLTexGenfv(GrGLenum, GrGLenum, const GrGLfloat*); - -GrGLvoid GR_GL_FUNCTION_TYPE noOpGLTexGeni(GrGLenum, GrGLenum, GrGLint); - GrGLvoid GR_GL_FUNCTION_TYPE noOpGLDiscardFramebuffer(GrGLenum target, GrGLsizei numAttachments, const GrGLenum* attachments); diff --git a/gpu/gl/GrGLProgram.cpp b/gpu/gl/GrGLProgram.cpp index 6e9878a9..9b997c85 100644 --- a/gpu/gl/GrGLProgram.cpp +++ b/gpu/gl/GrGLProgram.cpp @@ -229,10 +229,11 @@ void GrGLProgram::setData(GrDrawState::BlendOptFlags blendOpts, fCoverageEffects->setData(fGpu, fUniformManager, coverageStages); - // TexGen state applies to the the fixed function vertex shader. For custom shaders, it's - // ignored, so we don't need to change the texgen settings in that case. + // PathTexGen state applies to the the fixed function vertex shader. For + // custom shaders, it's ignored, so we don't need to change the texgen + // settings in that case. if (!fHasVertexShader) { - fGpu->flushTexGenSettings(fNumTexCoordSets); + fGpu->flushPathTexGenSettings(fNumTexCoordSets); } } diff --git a/gpu/gl/GrGLProgramDesc.cpp b/gpu/gl/GrGLProgramDesc.cpp index b6029fe4..4039eaf9 100644 --- a/gpu/gl/GrGLProgramDesc.cpp +++ b/gpu/gl/GrGLProgramDesc.cpp @@ -37,7 +37,7 @@ inline GrGLEffect::EffectKey get_key_and_update_stats(const GrEffectStage& stage } } void GrGLProgramDesc::Build(const GrDrawState& drawState, - bool isPoints, + GrGpu::DrawType drawType, GrDrawState::BlendOptFlags blendOpts, GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff, @@ -113,7 +113,10 @@ void GrGLProgramDesc::Build(const GrDrawState& drawState, int currEffectKey = 0; bool readsDst = false; bool readFragPosition = false; - bool hasVertexCode = false; + // We use vertexshader-less shader programs only when drawing paths. + bool hasVertexCode = !(GrGpu::kDrawPath_DrawType == drawType || + GrGpu::kDrawPaths_DrawType == drawType); + if (!skipColor) { for (int s = firstEffectiveColorStage; s < drawState.numColorStages(); ++s) { effectKeys[currEffectKey++] = @@ -132,7 +135,7 @@ void GrGLProgramDesc::Build(const GrDrawState& drawState, } header->fHasVertexCode = hasVertexCode || requiresLocalCoordAttrib; - header->fEmitsPointSize = isPoints; + header->fEmitsPointSize = GrGpu::kDrawPoints_DrawType == drawType; // Currently the experimental GS will only work with triangle prims (and it doesn't do anything // other than pass through values from the VS to the FS anyway). diff --git a/gpu/gl/GrGLProgramDesc.h b/gpu/gl/GrGLProgramDesc.h index 9116fdf6..9165f4eb 100644 --- a/gpu/gl/GrGLProgramDesc.h +++ b/gpu/gl/GrGLProgramDesc.h @@ -11,6 +11,7 @@ #include "GrGLEffect.h" #include "GrDrawState.h" #include "GrGLShaderBuilder.h" +#include "GrGpu.h" class GrGpuGL; @@ -64,7 +65,7 @@ public: * be treated as color stages in the output. */ static void Build(const GrDrawState&, - bool isPoints, + GrGpu::DrawType drawType, GrDrawState::BlendOptFlags, GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff, diff --git a/gpu/gl/GrGLProgramEffects.cpp b/gpu/gl/GrGLProgramEffects.cpp index 3bcf759b..1695a8e3 100644 --- a/gpu/gl/GrGLProgramEffects.cpp +++ b/gpu/gl/GrGLProgramEffects.cpp @@ -469,7 +469,7 @@ void GrGLVertexProgramEffectsBuilder::emitEffect(const GrEffectStage& stage, //////////////////////////////////////////////////////////////////////////////// -void GrGLTexGenProgramEffects::emitEffect(GrGLFragmentOnlyShaderBuilder* builder, +void GrGLPathTexGenProgramEffects::emitEffect(GrGLFragmentOnlyShaderBuilder* builder, const GrEffectStage& stage, EffectKey key, const char* outColor, @@ -481,7 +481,7 @@ void GrGLTexGenProgramEffects::emitEffect(GrGLFragmentOnlyShaderBuilder* builder SkSTArray<4, TextureSampler> samplers(effect->numTextures()); SkASSERT(0 == stage.getVertexAttribIndexCount()); - this->setupTexGen(builder, effect, key, &coords); + this->setupPathTexGen(builder, effect, key, &coords); this->emitSamplers(builder, effect, &samplers); GrGLEffect* glEffect = effect->getFactory().createGLInstance(drawEffect); @@ -498,7 +498,7 @@ void GrGLTexGenProgramEffects::emitEffect(GrGLFragmentOnlyShaderBuilder* builder builder->fsCodeAppend("\t}\n"); } -void GrGLTexGenProgramEffects::setupTexGen(GrGLFragmentOnlyShaderBuilder* builder, +void GrGLPathTexGenProgramEffects::setupPathTexGen(GrGLFragmentOnlyShaderBuilder* builder, const GrEffectRef& effect, EffectKey effectKey, TransformedCoordsArray* outCoords) { @@ -516,7 +516,7 @@ void GrGLTexGenProgramEffects::setupTexGen(GrGLFragmentOnlyShaderBuilder* builde } } -void GrGLTexGenProgramEffects::setData(GrGpuGL* gpu, +void GrGLPathTexGenProgramEffects::setData(GrGpuGL* gpu, const GrGLUniformManager& uniformManager, const GrEffectStage* effectStages[]) { int numEffects = fGLEffects.count(); @@ -525,12 +525,12 @@ void GrGLTexGenProgramEffects::setData(GrGpuGL* gpu, for (int e = 0; e < numEffects; ++e) { GrDrawEffect drawEffect(*effectStages[e], false); fGLEffects[e]->setData(uniformManager, drawEffect); - this->setTexGenState(gpu, drawEffect, e); + this->setPathTexGenState(gpu, drawEffect, e); this->bindTextures(gpu, *drawEffect.effect(), e); } } -void GrGLTexGenProgramEffects::setTexGenState(GrGpuGL* gpu, +void GrGLPathTexGenProgramEffects::setPathTexGenState(GrGpuGL* gpu, const GrDrawEffect& drawEffect, int effectIdx) { EffectKey totalKey = fTransforms[effectIdx].fTransformKey; @@ -542,7 +542,9 @@ void GrGLTexGenProgramEffects::setTexGenState(GrGpuGL* gpu, SkASSERT(get_transform_matrix(drawEffect, t).isIdentity()); GrGLfloat identity[] = {1, 0, 0, 0, 1, 0}; - gpu->enableTexGen(texCoordIndex++, GrGpuGL::kST_TexGenComponents, identity); + gpu->enablePathTexGen(texCoordIndex++, + GrGpuGL::kST_PathTexGenComponents, + identity); break; } case kTrans_MatrixType: { @@ -550,17 +552,23 @@ void GrGLTexGenProgramEffects::setTexGenState(GrGpuGL* gpu, get_transform_translation(drawEffect, t, &tx, &ty); GrGLfloat translate[] = {1, 0, tx, 0, 1, ty}; - gpu->enableTexGen(texCoordIndex++, GrGpuGL::kST_TexGenComponents, translate); + gpu->enablePathTexGen(texCoordIndex++, + GrGpuGL::kST_PathTexGenComponents, + translate); break; } case kNoPersp_MatrixType: { const SkMatrix& transform = get_transform_matrix(drawEffect, t); - gpu->enableTexGen(texCoordIndex++, GrGpuGL::kST_TexGenComponents, transform); + gpu->enablePathTexGen(texCoordIndex++, + GrGpuGL::kST_PathTexGenComponents, + transform); break; } case kGeneral_MatrixType: { const SkMatrix& transform = get_transform_matrix(drawEffect, t); - gpu->enableTexGen(texCoordIndex++, GrGpuGL::kSTR_TexGenComponents, transform); + gpu->enablePathTexGen(texCoordIndex++, + GrGpuGL::kSTR_PathTexGenComponents, + transform); break; } default: @@ -569,18 +577,18 @@ void GrGLTexGenProgramEffects::setTexGenState(GrGpuGL* gpu, } } -GrGLTexGenProgramEffectsBuilder::GrGLTexGenProgramEffectsBuilder( +GrGLPathTexGenProgramEffectsBuilder::GrGLPathTexGenProgramEffectsBuilder( GrGLFragmentOnlyShaderBuilder* builder, int reserveCount) : fBuilder(builder) - , fProgramEffects(SkNEW_ARGS(GrGLTexGenProgramEffects, (reserveCount))) { + , fProgramEffects(SkNEW_ARGS(GrGLPathTexGenProgramEffects, (reserveCount))) { } -void GrGLTexGenProgramEffectsBuilder::emitEffect(const GrEffectStage& stage, - GrGLProgramEffects::EffectKey key, - const char* outColor, - const char* inColor, - int stageIndex) { +void GrGLPathTexGenProgramEffectsBuilder::emitEffect(const GrEffectStage& stage, + GrGLProgramEffects::EffectKey key, + const char* outColor, + const char* inColor, + int stageIndex) { SkASSERT(NULL != fProgramEffects.get()); fProgramEffects->emitEffect(fBuilder, stage, key, outColor, inColor, stageIndex); } diff --git a/gpu/gl/GrGLProgramEffects.h b/gpu/gl/GrGLProgramEffects.h index 3320891b..0f38cdbe 100644 --- a/gpu/gl/GrGLProgramEffects.h +++ b/gpu/gl/GrGLProgramEffects.h @@ -237,19 +237,19 @@ private: //////////////////////////////////////////////////////////////////////////////// /** - * This is a GrGLProgramEffects implementation that does coord transforms with the the built-in GL - * TexGen functionality. + * This is a GrGLProgramEffects implementation that does coord transforms with + * the the NV_path_rendering PathTexGen functionality. */ -class GrGLTexGenProgramEffects : public GrGLProgramEffects { +class GrGLPathTexGenProgramEffects : public GrGLProgramEffects { public: virtual void setData(GrGpuGL*, const GrGLUniformManager&, const GrEffectStage* effectStages[]) SK_OVERRIDE; private: - friend class GrGLTexGenProgramEffectsBuilder; + friend class GrGLPathTexGenProgramEffectsBuilder; - GrGLTexGenProgramEffects(int reserveCount) + GrGLPathTexGenProgramEffects(int reserveCount) : INHERITED(reserveCount) , fTransforms(reserveCount) { } @@ -273,15 +273,15 @@ private: * types are appended to the TransformedCoordsArray* object, which is in turn passed to the * effect's emitCode() function. */ - void setupTexGen(GrGLFragmentOnlyShaderBuilder*, - const GrEffectRef&, - EffectKey, - TransformedCoordsArray*); + void setupPathTexGen(GrGLFragmentOnlyShaderBuilder*, + const GrEffectRef&, + EffectKey, + TransformedCoordsArray*); /** - * Helper for setData(). Sets the TexGen state for each transform in an effect. + * Helper for setData(). Sets the PathTexGen state for each transform in an effect. */ - void setTexGenState(GrGpuGL*, const GrDrawEffect&, int effectIdx); + void setPathTexGenState(GrGpuGL*, const GrDrawEffect&, int effectIdx); struct Transforms { Transforms(EffectKey transformKey, int texCoordIndex) @@ -296,12 +296,12 @@ private: }; /** - * This class is used to construct a GrGLTexGenProgramEffects* object. + * This class is used to construct a GrGLPathTexGenProgramEffects* object. */ -class GrGLTexGenProgramEffectsBuilder : public GrGLProgramEffectsBuilder { +class GrGLPathTexGenProgramEffectsBuilder : public GrGLProgramEffectsBuilder { public: - GrGLTexGenProgramEffectsBuilder(GrGLFragmentOnlyShaderBuilder*, int reserveCount); - virtual ~GrGLTexGenProgramEffectsBuilder() { } + GrGLPathTexGenProgramEffectsBuilder(GrGLFragmentOnlyShaderBuilder*, int reserveCount); + virtual ~GrGLPathTexGenProgramEffectsBuilder() { } virtual void emitEffect(const GrEffectStage&, GrGLProgramEffects::EffectKey, @@ -317,7 +317,7 @@ public: private: GrGLFragmentOnlyShaderBuilder* fBuilder; - SkAutoTDelete<GrGLTexGenProgramEffects> fProgramEffects; + SkAutoTDelete<GrGLPathTexGenProgramEffects> fProgramEffects; typedef GrGLProgramEffectsBuilder INHERITED; }; diff --git a/gpu/gl/GrGLSL.cpp b/gpu/gl/GrGLSL.cpp index 1ff0850a..7587fe8d 100644 --- a/gpu/gl/GrGLSL.cpp +++ b/gpu/gl/GrGLSL.cpp @@ -9,27 +9,33 @@ #include "GrGLShaderVar.h" #include "SkString.h" -GrGLSLGeneration GrGetGLSLGeneration(const GrGLInterface* gl) { +bool GrGetGLSLGeneration(const GrGLInterface* gl, GrGLSLGeneration* generation) { + SkASSERT(NULL != generation); GrGLSLVersion ver = GrGLGetGLSLVersion(gl); + if (GR_GLSL_INVALID_VER == ver) { + return false; + } switch (gl->fStandard) { case kGL_GrGLStandard: SkASSERT(ver >= GR_GLSL_VER(1,10)); if (ver >= GR_GLSL_VER(1,50)) { - return k150_GrGLSLGeneration; + *generation = k150_GrGLSLGeneration; } else if (ver >= GR_GLSL_VER(1,40)) { - return k140_GrGLSLGeneration; + *generation = k140_GrGLSLGeneration; } else if (ver >= GR_GLSL_VER(1,30)) { - return k130_GrGLSLGeneration; + *generation = k130_GrGLSLGeneration; } else { - return k110_GrGLSLGeneration; + *generation = k110_GrGLSLGeneration; } + return true; case kGLES_GrGLStandard: // version 1.00 of ES GLSL based on ver 1.20 of desktop GLSL SkASSERT(ver >= GR_GL_VER(1,00)); - return k110_GrGLSLGeneration; + *generation = k110_GrGLSLGeneration; + return true; default: GrCrash("Unknown GL Standard"); - return k110_GrGLSLGeneration; // suppress warning + return false; } } diff --git a/gpu/gl/GrGLSL.h b/gpu/gl/GrGLSL.h index 5c0a170e..8234be9c 100644 --- a/gpu/gl/GrGLSL.h +++ b/gpu/gl/GrGLSL.h @@ -40,7 +40,7 @@ enum GrGLSLGeneration { /** * Gets the most recent GLSL Generation compatible with the OpenGL context. */ -GrGLSLGeneration GrGetGLSLGeneration(const GrGLInterface* gl); +bool GrGetGLSLGeneration(const GrGLInterface* gl, GrGLSLGeneration* generation); /** * Returns a string to include at the beginning of a shader to declare the GLSL diff --git a/gpu/gl/GrGLShaderBuilder.cpp b/gpu/gl/GrGLShaderBuilder.cpp index f20d9368..b72e23f9 100644 --- a/gpu/gl/GrGLShaderBuilder.cpp +++ b/gpu/gl/GrGLShaderBuilder.cpp @@ -970,7 +970,6 @@ GrGLFragmentOnlyShaderBuilder::GrGLFragmentOnlyShaderBuilder(GrGpuGL* gpu, , fNumTexCoordSets(0) { SkASSERT(!desc.getHeader().fHasVertexCode); - SkASSERT(gpu->glCaps().fixedFunctionSupport()); SkASSERT(gpu->glCaps().pathRenderingSupport()); SkASSERT(GrGLProgramDesc::kAttribute_ColorInput != desc.getHeader().fColorInput); SkASSERT(GrGLProgramDesc::kAttribute_ColorInput != desc.getHeader().fCoverageInput); @@ -989,11 +988,12 @@ GrGLProgramEffects* GrGLFragmentOnlyShaderBuilder::createAndEmitEffects( int effectCnt, GrGLSLExpr4* inOutFSColor) { - GrGLTexGenProgramEffectsBuilder texGenEffectsBuilder(this, effectCnt); - this->INHERITED::createAndEmitEffects(&texGenEffectsBuilder, + GrGLPathTexGenProgramEffectsBuilder pathTexGenEffectsBuilder(this, + effectCnt); + this->INHERITED::createAndEmitEffects(&pathTexGenEffectsBuilder, effectStages, effectKeys, effectCnt, inOutFSColor); - return texGenEffectsBuilder.finish(); + return pathTexGenEffectsBuilder.finish(); } diff --git a/gpu/gl/GrGLUtil.cpp b/gpu/gl/GrGLUtil.cpp index a479523b..ddfcfbf0 100644 --- a/gpu/gl/GrGLUtil.cpp +++ b/gpu/gl/GrGLUtil.cpp @@ -140,7 +140,7 @@ bool GrGLIsChromiumFromRendererString(const char* rendererString) { GrGLVersion GrGLGetVersionFromString(const char* versionString) { if (NULL == versionString) { SkDEBUGFAIL("NULL GL version string."); - return 0; + return GR_GL_INVALID_VER; } int major, minor; @@ -152,7 +152,7 @@ GrGLVersion GrGLGetVersionFromString(const char* versionString) { if (get_gl_version_for_mesa(mesaMajor, &major, &minor)) { return GR_GL_VER(major, minor); } else { - return 0; + return GR_GL_INVALID_VER; } } @@ -173,13 +173,13 @@ GrGLVersion GrGLGetVersionFromString(const char* versionString) { return GR_GL_VER(major, minor); } - return 0; + return GR_GL_INVALID_VER; } GrGLSLVersion GrGLGetGLSLVersionFromString(const char* versionString) { if (NULL == versionString) { SkDEBUGFAIL("NULL GLSL version string."); - return 0; + return GR_GLSL_INVALID_VER; } int major, minor; @@ -202,7 +202,7 @@ GrGLSLVersion GrGLGetGLSLVersionFromString(const char* versionString) { } #endif - return 0; + return GR_GLSL_INVALID_VER; } GrGLVendor GrGLGetVendorFromString(const char* vendorString) { diff --git a/gpu/gl/GrGLUtil.h b/gpu/gl/GrGLUtil.h index b99487a1..73fcec11 100644 --- a/gpu/gl/GrGLUtil.h +++ b/gpu/gl/GrGLUtil.h @@ -18,6 +18,14 @@ class SkMatrix; typedef uint32_t GrGLVersion; typedef uint32_t GrGLSLVersion; +#define GR_GL_VER(major, minor) ((static_cast<int>(major) << 16) | \ + static_cast<int>(minor)) +#define GR_GLSL_VER(major, minor) ((static_cast<int>(major) << 16) | \ + static_cast<int>(minor)) + +#define GR_GL_INVALID_VER GR_GL_VER(0, 0) +#define GR_GLSL_INVALID_VER GR_GL_VER(0, 0) + /** * The Vendor and Renderer enum values are lazily updated as required. */ @@ -37,11 +45,6 @@ enum GrGLRenderer { kOther_GrGLRenderer }; -#define GR_GL_VER(major, minor) ((static_cast<int>(major) << 16) | \ - static_cast<int>(minor)) -#define GR_GLSL_VER(major, minor) ((static_cast<int>(major) << 16) | \ - static_cast<int>(minor)) - //////////////////////////////////////////////////////////////////////////////// /** diff --git a/gpu/gl/GrGpuGL.cpp b/gpu/gl/GrGpuGL.cpp index a2a6ac3b..4b39a163 100644 --- a/gpu/gl/GrGpuGL.cpp +++ b/gpu/gl/GrGpuGL.cpp @@ -120,7 +120,7 @@ GrGpuGL::GrGpuGL(const GrGLContext& ctx, GrContext* context) fCaps.reset(SkRef(ctx.caps())); fHWBoundTextures.reset(this->glCaps().maxFragmentTextureUnits()); - fHWTexGenSettings.reset(this->glCaps().maxFixedFunctionTextureCoords()); + fHWPathTexGenSettings.reset(this->glCaps().maxFixedFunctionTextureCoords()); GrGLClearErr(fGLContext.interface()); if (gPrintStartupSpew) { @@ -300,30 +300,20 @@ void GrGpuGL::onResetContext(uint32_t resetBits) { fHWBoundRenderTarget = NULL; } - if (resetBits & (kFixedFunction_GrGLBackendState | kPathRendering_GrGLBackendState)) { - if (this->glCaps().fixedFunctionSupport()) { + if (resetBits & kPathRendering_GrGLBackendState) { + if (this->caps()->pathRenderingSupport()) { fHWProjectionMatrixState.invalidate(); // we don't use the model view matrix. - GL_CALL(MatrixMode(GR_GL_MODELVIEW)); - GL_CALL(LoadIdentity()); + GL_CALL(MatrixLoadIdentity(GR_GL_MODELVIEW)); for (int i = 0; i < this->glCaps().maxFixedFunctionTextureCoords(); ++i) { - GL_CALL(ActiveTexture(GR_GL_TEXTURE0 + i)); - GL_CALL(Disable(GR_GL_TEXTURE_GEN_S)); - GL_CALL(Disable(GR_GL_TEXTURE_GEN_T)); - GL_CALL(Disable(GR_GL_TEXTURE_GEN_Q)); - GL_CALL(Disable(GR_GL_TEXTURE_GEN_R)); - if (this->caps()->pathRenderingSupport()) { - GL_CALL(PathTexGen(GR_GL_TEXTURE0 + i, GR_GL_NONE, 0, NULL)); - } - fHWTexGenSettings[i].fMode = GR_GL_NONE; - fHWTexGenSettings[i].fNumComponents = 0; + GL_CALL(PathTexGen(GR_GL_TEXTURE0 + i, GR_GL_NONE, 0, NULL)); + fHWPathTexGenSettings[i].fMode = GR_GL_NONE; + fHWPathTexGenSettings[i].fNumComponents = 0; } - fHWActiveTexGenSets = 0; - } - if (this->caps()->pathRenderingSupport()) { - fHWPathStencilSettings.invalidate(); + fHWActivePathTexGenSets = 0; } + fHWPathStencilSettings.invalidate(); } // we assume these values @@ -2230,7 +2220,7 @@ void GrGpuGL::setProjectionMatrix(const SkMatrix& matrix, const SkISize& renderTargetSize, GrSurfaceOrigin renderTargetOrigin) { - SkASSERT(this->glCaps().fixedFunctionSupport()); + SkASSERT(this->glCaps().pathRenderingSupport()); if (renderTargetOrigin == fHWProjectionMatrixState.fRenderTargetOrigin && renderTargetSize == fHWProjectionMatrixState.fRenderTargetSize && @@ -2244,113 +2234,84 @@ void GrGpuGL::setProjectionMatrix(const SkMatrix& matrix, GrGLfloat glMatrix[4 * 4]; fHWProjectionMatrixState.getGLMatrix<4>(glMatrix); - GL_CALL(MatrixMode(GR_GL_PROJECTION)); - GL_CALL(LoadMatrixf(glMatrix)); + GL_CALL(MatrixLoadf(GR_GL_PROJECTION, glMatrix)); } -void GrGpuGL::enableTexGen(int unitIdx, - TexGenComponents components, - const GrGLfloat* coefficients) { - SkASSERT(this->glCaps().fixedFunctionSupport()); - SkASSERT(components >= kS_TexGenComponents && components <= kSTR_TexGenComponents); +void GrGpuGL::enablePathTexGen(int unitIdx, + PathTexGenComponents components, + const GrGLfloat* coefficients) { + SkASSERT(this->glCaps().pathRenderingSupport()); + SkASSERT(components >= kS_PathTexGenComponents && + components <= kSTR_PathTexGenComponents); SkASSERT(this->glCaps().maxFixedFunctionTextureCoords() >= unitIdx); - if (GR_GL_OBJECT_LINEAR == fHWTexGenSettings[unitIdx].fMode && - components == fHWTexGenSettings[unitIdx].fNumComponents && - !memcmp(coefficients, fHWTexGenSettings[unitIdx].fCoefficients, + if (GR_GL_OBJECT_LINEAR == fHWPathTexGenSettings[unitIdx].fMode && + components == fHWPathTexGenSettings[unitIdx].fNumComponents && + !memcmp(coefficients, fHWPathTexGenSettings[unitIdx].fCoefficients, 3 * components * sizeof(GrGLfloat))) { return; } this->setTextureUnit(unitIdx); - if (GR_GL_OBJECT_LINEAR != fHWTexGenSettings[unitIdx].fMode) { - for (int i = 0; i < 4; i++) { - GL_CALL(TexGeni(GR_GL_S + i, GR_GL_TEXTURE_GEN_MODE, GR_GL_OBJECT_LINEAR)); - } - fHWTexGenSettings[unitIdx].fMode = GR_GL_OBJECT_LINEAR; - } - - for (int i = fHWTexGenSettings[unitIdx].fNumComponents; i < components; i++) { - GL_CALL(Enable(GR_GL_TEXTURE_GEN_S + i)); - } - for (int i = components; i < fHWTexGenSettings[unitIdx].fNumComponents; i++) { - GL_CALL(Disable(GR_GL_TEXTURE_GEN_S + i)); - } - fHWTexGenSettings[unitIdx].fNumComponents = components; - - for (int i = 0; i < components; i++) { - GrGLfloat plane[] = {coefficients[0 + 3 * i], - coefficients[1 + 3 * i], - 0, - coefficients[2 + 3 * i]}; - GL_CALL(TexGenfv(GR_GL_S + i, GR_GL_OBJECT_PLANE, plane)); - } + fHWPathTexGenSettings[unitIdx].fNumComponents = components; + GL_CALL(PathTexGen(GR_GL_TEXTURE0 + unitIdx, + GR_GL_OBJECT_LINEAR, + components, + coefficients)); - if (this->caps()->pathRenderingSupport()) { - GL_CALL(PathTexGen(GR_GL_TEXTURE0 + unitIdx, - GR_GL_OBJECT_LINEAR, - components, - coefficients)); - } - - memcpy(fHWTexGenSettings[unitIdx].fCoefficients, coefficients, + memcpy(fHWPathTexGenSettings[unitIdx].fCoefficients, coefficients, 3 * components * sizeof(GrGLfloat)); } -void GrGpuGL::enableTexGen(int unitIdx, TexGenComponents components, const SkMatrix& matrix) { +void GrGpuGL::enablePathTexGen(int unitIdx, PathTexGenComponents components, + const SkMatrix& matrix) { GrGLfloat coefficients[3 * 3]; - SkASSERT(this->glCaps().fixedFunctionSupport()); - SkASSERT(components >= kS_TexGenComponents && components <= kSTR_TexGenComponents); + SkASSERT(this->glCaps().pathRenderingSupport()); + SkASSERT(components >= kS_PathTexGenComponents && + components <= kSTR_PathTexGenComponents); coefficients[0] = SkScalarToFloat(matrix[SkMatrix::kMScaleX]); coefficients[1] = SkScalarToFloat(matrix[SkMatrix::kMSkewX]); coefficients[2] = SkScalarToFloat(matrix[SkMatrix::kMTransX]); - if (components >= kST_TexGenComponents) { + if (components >= kST_PathTexGenComponents) { coefficients[3] = SkScalarToFloat(matrix[SkMatrix::kMSkewY]); coefficients[4] = SkScalarToFloat(matrix[SkMatrix::kMScaleY]); coefficients[5] = SkScalarToFloat(matrix[SkMatrix::kMTransY]); } - if (components >= kSTR_TexGenComponents) { + if (components >= kSTR_PathTexGenComponents) { coefficients[6] = SkScalarToFloat(matrix[SkMatrix::kMPersp0]); coefficients[7] = SkScalarToFloat(matrix[SkMatrix::kMPersp1]); coefficients[8] = SkScalarToFloat(matrix[SkMatrix::kMPersp2]); } - enableTexGen(unitIdx, components, coefficients); + enablePathTexGen(unitIdx, components, coefficients); } -void GrGpuGL::flushTexGenSettings(int numUsedTexCoordSets) { - SkASSERT(this->glCaps().fixedFunctionSupport()); +void GrGpuGL::flushPathTexGenSettings(int numUsedTexCoordSets) { + SkASSERT(this->glCaps().pathRenderingSupport()); SkASSERT(this->glCaps().maxFixedFunctionTextureCoords() >= numUsedTexCoordSets); - // Only write the inactive tex gens, since active tex gens were written - // when they were enabled. + // Only write the inactive path tex gens, since active path tex gens were + // written when they were enabled. SkDEBUGCODE( for (int i = 0; i < numUsedTexCoordSets; i++) { - SkASSERT(0 != fHWTexGenSettings[i].fNumComponents); + SkASSERT(0 != fHWPathTexGenSettings[i].fNumComponents); } ); - for (int i = numUsedTexCoordSets; i < fHWActiveTexGenSets; i++) { - SkASSERT(0 != fHWTexGenSettings[i].fNumComponents); + for (int i = numUsedTexCoordSets; i < fHWActivePathTexGenSets; i++) { + SkASSERT(0 != fHWPathTexGenSettings[i].fNumComponents); this->setTextureUnit(i); - for (int j = 0; j < fHWTexGenSettings[i].fNumComponents; j++) { - GL_CALL(Disable(GR_GL_TEXTURE_GEN_S + j)); - } - - if (this->caps()->pathRenderingSupport()) { - GL_CALL(PathTexGen(GR_GL_TEXTURE0 + i, GR_GL_NONE, 0, NULL)); - } - - fHWTexGenSettings[i].fNumComponents = 0; + GL_CALL(PathTexGen(GR_GL_TEXTURE0 + i, GR_GL_NONE, 0, NULL)); + fHWPathTexGenSettings[i].fNumComponents = 0; } - fHWActiveTexGenSets = numUsedTexCoordSets; + fHWActivePathTexGenSets = numUsedTexCoordSets; } void GrGpuGL::flushMiscFixedFunctionState() { diff --git a/gpu/gl/GrGpuGL.h b/gpu/gl/GrGpuGL.h index d75c3660..f548af5f 100644 --- a/gpu/gl/GrGpuGL.h +++ b/gpu/gl/GrGpuGL.h @@ -42,22 +42,22 @@ public: virtual void discard(GrRenderTarget*) SK_OVERRIDE; - // Used by GrGLProgram and GrGLTexGenProgramEffects to configure OpenGL state. + // Used by GrGLProgram and GrGLPathTexGenProgramEffects to configure OpenGL + // state. void bindTexture(int unitIdx, const GrTextureParams& params, GrGLTexture* texture); void setProjectionMatrix(const SkMatrix& matrix, const SkISize& renderTargetSize, GrSurfaceOrigin renderTargetOrigin); - enum TexGenComponents { - kS_TexGenComponents = 1, - kST_TexGenComponents = 2, - kSTR_TexGenComponents = 3 + enum PathTexGenComponents { + kS_PathTexGenComponents = 1, + kST_PathTexGenComponents = 2, + kSTR_PathTexGenComponents = 3 }; - void enableTexGen(int unitIdx, TexGenComponents, const GrGLfloat* coefficients); - void enableTexGen(int unitIdx, TexGenComponents, const SkMatrix& matrix); - void flushTexGenSettings(int numUsedTexCoordSets); + void enablePathTexGen(int unitIdx, PathTexGenComponents, const GrGLfloat* coefficients); + void enablePathTexGen(int unitIdx, PathTexGenComponents, const SkMatrix& matrix); + void flushPathTexGenSettings(int numUsedTexCoordSets); bool shouldUseFixedFunctionTexturing() const { - return this->glCaps().fixedFunctionSupport() && - this->glCaps().pathRenderingSupport(); + return this->glCaps().pathRenderingSupport(); } bool programUnitTest(int maxStages); @@ -446,13 +446,13 @@ private: GrRenderTarget* fHWBoundRenderTarget; SkTArray<GrTexture*, true> fHWBoundTextures; - struct TexGenData { + struct PathTexGenData { GrGLenum fMode; GrGLint fNumComponents; GrGLfloat fCoefficients[3 * 3]; }; - int fHWActiveTexGenSets; - SkTArray<TexGenData, true> fHWTexGenSettings; + int fHWActivePathTexGenSets; + SkTArray<PathTexGenData, true> fHWPathTexGenSettings; ///@} // we record what stencil format worked last time to hopefully exit early diff --git a/gpu/gl/GrGpuGL_program.cpp b/gpu/gl/GrGpuGL_program.cpp index 10f10393..0a7bb0e3 100644 --- a/gpu/gl/GrGpuGL_program.cpp +++ b/gpu/gl/GrGpuGL_program.cpp @@ -233,7 +233,7 @@ bool GrGpuGL::flushGraphicsState(DrawType type, const GrDeviceCoordTexture* dstC SkSTArray<8, const GrEffectStage*, true> coverageStages; GrGLProgramDesc desc; GrGLProgramDesc::Build(this->getDrawState(), - kDrawPoints_DrawType == type, + type, blendOpts, srcCoeff, dstCoeff, @@ -343,27 +343,7 @@ void GrGpuGL::setupGeometry(const DrawInfo& info, size_t* indexOffsetInBytes) { GrGLAttribArrayState* attribState = fHWGeometryState.bindArrayAndBuffersToDraw(this, vbuf, ibuf); - if (!fCurrentProgram->hasVertexShader()) { - int posIdx = this->getDrawState().positionAttributeIndex(); - const GrVertexAttrib* vertexAttrib = this->getDrawState().getVertexAttribs() + posIdx; - GrVertexAttribType attribType = vertexAttrib->fType; - SkASSERT(!GrGLAttribTypeToLayout(attribType).fNormalized); - SkASSERT(GrGLAttribTypeToLayout(attribType).fCount == 2); - - // Attrib at location 0 is defined to be bound to vertex in fixed-function pipe. Asserts - // above should make sure position attribute goes to location 0 when below code is executed. - - attribState->set(this, - 0, - vbuf, - GrGLAttribTypeToLayout(attribType).fCount, - GrGLAttribTypeToLayout(attribType).fType, - GrGLAttribTypeToLayout(attribType).fNormalized, - stride, - reinterpret_cast<GrGLvoid*>( - vertexOffsetInBytes + vertexAttrib->fOffset)); - attribState->disableUnusedArrays(this, 1); - } else { + if (fCurrentProgram->hasVertexShader()) { int vertexAttribCount = this->getDrawState().getVertexAttribCount(); uint32_t usedAttribArraysMask = 0; const GrVertexAttrib* vertexAttrib = this->getDrawState().getVertexAttribs(); diff --git a/gpu/gl/android/GrGLCreateNativeInterface_android.cpp b/gpu/gl/android/GrGLCreateNativeInterface_android.cpp index aa5b2243..b50063fb 100644 --- a/gpu/gl/android/GrGLCreateNativeInterface_android.cpp +++ b/gpu/gl/android/GrGLCreateNativeInterface_android.cpp @@ -4,8 +4,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "gl/GrGLExtensions.h" #include "gl/GrGLInterface.h" +#include "gl/GrGLAssembleInterface.h" +#include "gl/GrGLExtensions.h" #include "gl/GrGLUtil.h" #ifndef GL_GLEXT_PROTOTYPES @@ -218,236 +219,37 @@ static GrGLInterface* create_es_interface(GrGLVersion version, return interface; } -static GrGLInterface* create_desktop_interface(GrGLVersion version, - const GrGLExtensions& extensions) { - // Currently this assumes a 4.4 context or later. Supporting lower GL versions would require - // getting suffixed versions of pointers for supported extensions. - if (version < GR_GL_VER(4,4)) { - return NULL; - } - - GrGLInterface* interface = SkNEW(GrGLInterface); - interface->fStandard = kGL_GrGLStandard; - GrGLInterface::Functions* functions = &interface->fFunctions; - - functions->fActiveTexture = (GrGLActiveTextureProc) eglGetProcAddress("glActiveTexture"); - functions->fAttachShader = (GrGLAttachShaderProc) eglGetProcAddress("glAttachShader"); - functions->fBeginQuery = (GrGLBeginQueryProc) eglGetProcAddress("glBeginQuery"); - functions->fBindAttribLocation = (GrGLBindAttribLocationProc) eglGetProcAddress("glBindAttribLocation"); - functions->fBindBuffer = (GrGLBindBufferProc) eglGetProcAddress("glBindBuffer"); - functions->fBindFragDataLocation = (GrGLBindFragDataLocationProc) eglGetProcAddress("glBindFragDataLocation"); - functions->fBindFragDataLocationIndexed = (GrGLBindFragDataLocationIndexedProc) eglGetProcAddress("glBindFragDataLocationIndexed"); - functions->fBindFramebuffer = (GrGLBindFramebufferProc) eglGetProcAddress("glBindFramebuffer"); - functions->fBindRenderbuffer = (GrGLBindRenderbufferProc) eglGetProcAddress("glBindRenderbuffer"); - functions->fBindTexture = (GrGLBindTextureProc) eglGetProcAddress("glBindTexture"); - functions->fBindVertexArray = (GrGLBindVertexArrayProc) eglGetProcAddress("glBindVertexArray"); - functions->fBlendColor = (GrGLBlendColorProc) eglGetProcAddress("glBlendColor"); - functions->fBlendFunc = (GrGLBlendFuncProc) eglGetProcAddress("glBlendFunc"); - functions->fBlitFramebuffer = (GrGLBlitFramebufferProc) eglGetProcAddress("glBlitFramebuffer"); - functions->fBufferData = (GrGLBufferDataProc) eglGetProcAddress("glBufferData"); - functions->fBufferSubData = (GrGLBufferSubDataProc) eglGetProcAddress("glBufferSubData"); - functions->fCheckFramebufferStatus = (GrGLCheckFramebufferStatusProc) eglGetProcAddress("glCheckFramebufferStatus"); - functions->fClear = (GrGLClearProc) eglGetProcAddress("glClear"); - functions->fClearColor = (GrGLClearColorProc) eglGetProcAddress("glClearColor"); - functions->fClearStencil = (GrGLClearStencilProc) eglGetProcAddress("glClearStencil"); - functions->fColorMask = (GrGLColorMaskProc) eglGetProcAddress("glColorMask"); - functions->fCompileShader = (GrGLCompileShaderProc) eglGetProcAddress("glCompileShader"); - functions->fCompressedTexImage2D = (GrGLCompressedTexImage2DProc) eglGetProcAddress("glCompressedTexImage2D"); - functions->fCopyTexSubImage2D = (GrGLCopyTexSubImage2DProc) eglGetProcAddress("glCopyTexSubImage2D"); - functions->fCreateProgram = (GrGLCreateProgramProc) eglGetProcAddress("glCreateProgram"); - functions->fCreateShader = (GrGLCreateShaderProc) eglGetProcAddress("glCreateShader"); - functions->fCullFace = (GrGLCullFaceProc) eglGetProcAddress("glCullFace"); - functions->fDeleteBuffers = (GrGLDeleteBuffersProc) eglGetProcAddress("glDeleteBuffers"); - functions->fDeleteFramebuffers = (GrGLDeleteFramebuffersProc) eglGetProcAddress("glDeleteFramebuffers"); - functions->fDeleteProgram = (GrGLDeleteProgramProc) eglGetProcAddress("glDeleteProgram"); - functions->fDeleteQueries = (GrGLDeleteQueriesProc) eglGetProcAddress("glDeleteQueries"); - functions->fDeleteRenderbuffers = (GrGLDeleteRenderbuffersProc) eglGetProcAddress("glDeleteRenderbuffers"); - functions->fDeleteShader = (GrGLDeleteShaderProc) eglGetProcAddress("glDeleteShader"); - functions->fDeleteTextures = (GrGLDeleteTexturesProc) eglGetProcAddress("glDeleteTextures"); - functions->fDeleteVertexArrays = (GrGLDeleteVertexArraysProc) eglGetProcAddress("glDeleteVertexArrays"); - functions->fDepthMask = (GrGLDepthMaskProc) eglGetProcAddress("glDepthMask"); - functions->fDisable = (GrGLDisableProc) eglGetProcAddress("glDisable"); - functions->fDisableVertexAttribArray = (GrGLDisableVertexAttribArrayProc) eglGetProcAddress("glDisableVertexAttribArray"); - functions->fDrawArrays = (GrGLDrawArraysProc) eglGetProcAddress("glDrawArrays"); - functions->fDrawBuffer = (GrGLDrawBufferProc) eglGetProcAddress("glDrawBuffer"); - functions->fDrawBuffers = (GrGLDrawBuffersProc) eglGetProcAddress("glDrawBuffers"); - functions->fDrawElements = (GrGLDrawElementsProc) eglGetProcAddress("glDrawElements"); - functions->fEnable = (GrGLEnableProc) eglGetProcAddress("glEnable"); - functions->fEnableVertexAttribArray = (GrGLEnableVertexAttribArrayProc) eglGetProcAddress("glEnableVertexAttribArray"); - functions->fEndQuery = (GrGLEndQueryProc) eglGetProcAddress("glEndQuery"); - functions->fFinish = (GrGLFinishProc) eglGetProcAddress("glFinish"); - functions->fFlush = (GrGLFlushProc) eglGetProcAddress("glFlush"); - functions->fFramebufferRenderbuffer = (GrGLFramebufferRenderbufferProc) eglGetProcAddress("glFramebufferRenderbuffer"); - functions->fFramebufferTexture2D = (GrGLFramebufferTexture2DProc) eglGetProcAddress("glFramebufferTexture2D"); - functions->fFrontFace = (GrGLFrontFaceProc) eglGetProcAddress("glFrontFace"); - functions->fGenBuffers = (GrGLGenBuffersProc) eglGetProcAddress("glGenBuffers"); - functions->fGenFramebuffers = (GrGLGenFramebuffersProc) eglGetProcAddress("glGenFramebuffers"); - functions->fGenerateMipmap = (GrGLGenerateMipmapProc) eglGetProcAddress("glGenerateMipmap"); - functions->fGenQueries = (GrGLGenQueriesProc) eglGetProcAddress("glGenQueries"); - functions->fGenRenderbuffers = (GrGLGenRenderbuffersProc) eglGetProcAddress("glGenRenderbuffers"); - functions->fGenTextures = (GrGLGenTexturesProc) eglGetProcAddress("glGenTextures"); - functions->fGenVertexArrays = (GrGLGenVertexArraysProc) eglGetProcAddress("glGenVertexArrays"); - functions->fGetBufferParameteriv = (GrGLGetBufferParameterivProc) eglGetProcAddress("glGetBufferParameteriv"); - functions->fGetError = (GrGLGetErrorProc) eglGetProcAddress("glGetError"); - functions->fGetFramebufferAttachmentParameteriv = (GrGLGetFramebufferAttachmentParameterivProc) eglGetProcAddress("glGetFramebufferAttachmentParameteriv"); - functions->fGetIntegerv = (GrGLGetIntegervProc) eglGetProcAddress("glGetIntegerv"); - functions->fGetQueryObjecti64v = (GrGLGetQueryObjecti64vProc) eglGetProcAddress("glGetQueryObjecti64v"); - functions->fGetQueryObjectiv = (GrGLGetQueryObjectivProc) eglGetProcAddress("glGetQueryObjectiv"); - functions->fGetQueryObjectui64v = (GrGLGetQueryObjectui64vProc) eglGetProcAddress("glGetQueryObjectui64v"); - functions->fGetQueryObjectuiv = (GrGLGetQueryObjectuivProc) eglGetProcAddress("glGetQueryObjectuiv"); - functions->fGetQueryiv = (GrGLGetQueryivProc) eglGetProcAddress("glGetQueryiv"); - functions->fGetProgramInfoLog = (GrGLGetProgramInfoLogProc) eglGetProcAddress("glGetProgramInfoLog"); - functions->fGetProgramiv = (GrGLGetProgramivProc) eglGetProcAddress("glGetProgramiv"); - functions->fGetRenderbufferParameteriv = (GrGLGetRenderbufferParameterivProc) eglGetProcAddress("glGetRenderbufferParameteriv"); - functions->fGetShaderInfoLog = (GrGLGetShaderInfoLogProc) eglGetProcAddress("glGetShaderInfoLog"); - functions->fGetShaderiv = (GrGLGetShaderivProc) eglGetProcAddress("glGetShaderiv"); - functions->fGetString = (GrGLGetStringProc) eglGetProcAddress("glGetString"); - functions->fGetStringi = (GrGLGetStringiProc) eglGetProcAddress("glGetStringi"); - functions->fGetTexLevelParameteriv = (GrGLGetTexLevelParameterivProc) eglGetProcAddress("glGetTexLevelParameteriv"); - functions->fGetUniformLocation = (GrGLGetUniformLocationProc) eglGetProcAddress("glGetUniformLocation"); - functions->fLineWidth = (GrGLLineWidthProc) eglGetProcAddress("glLineWidth"); - functions->fLinkProgram = (GrGLLinkProgramProc) eglGetProcAddress("glLinkProgram"); - functions->fLoadIdentity = (GrGLLoadIdentityProc) eglGetProcAddress("glLoadIdentity"); - functions->fLoadMatrixf = (GrGLLoadMatrixfProc) eglGetProcAddress("glLoadMatrixf"); - functions->fMapBuffer = (GrGLMapBufferProc) eglGetProcAddress("glMapBuffer"); - functions->fMatrixMode = (GrGLMatrixModeProc) eglGetProcAddress("glMatrixMode"); - functions->fPixelStorei = (GrGLPixelStoreiProc) eglGetProcAddress("glPixelStorei"); - functions->fQueryCounter = (GrGLQueryCounterProc) eglGetProcAddress("glQueryCounter"); - functions->fReadBuffer = (GrGLReadBufferProc) eglGetProcAddress("glReadBuffer"); - functions->fReadPixels = (GrGLReadPixelsProc) eglGetProcAddress("glReadPixels"); - functions->fRenderbufferStorage = (GrGLRenderbufferStorageProc) eglGetProcAddress("glRenderbufferStorage"); - functions->fRenderbufferStorageMultisample = (GrGLRenderbufferStorageMultisampleProc) eglGetProcAddress("glRenderbufferStorageMultisample"); - functions->fScissor = (GrGLScissorProc) eglGetProcAddress("glScissor"); - functions->fShaderSource = (GrGLShaderSourceProc) eglGetProcAddress("glShaderSource"); - functions->fStencilFunc = (GrGLStencilFuncProc) eglGetProcAddress("glStencilFunc"); - functions->fStencilFuncSeparate = (GrGLStencilFuncSeparateProc) eglGetProcAddress("glStencilFuncSeparate"); - functions->fStencilMask = (GrGLStencilMaskProc) eglGetProcAddress("glStencilMask"); - functions->fStencilMaskSeparate = (GrGLStencilMaskSeparateProc) eglGetProcAddress("glStencilMaskSeparate"); - functions->fStencilOp = (GrGLStencilOpProc) eglGetProcAddress("glStencilOp"); - functions->fStencilOpSeparate = (GrGLStencilOpSeparateProc) eglGetProcAddress("glStencilOpSeparate"); - functions->fTexGenfv = (GrGLTexGenfvProc) eglGetProcAddress("glTexGenfv"); - functions->fTexGeni = (GrGLTexGeniProc) eglGetProcAddress("glTexGeni"); - functions->fTexImage2D = (GrGLTexImage2DProc) eglGetProcAddress("glTexImage2D"); - functions->fTexParameteri = (GrGLTexParameteriProc) eglGetProcAddress("glTexParameteri"); - functions->fTexParameteriv = (GrGLTexParameterivProc) eglGetProcAddress("glTexParameteriv"); - functions->fTexSubImage2D = (GrGLTexSubImage2DProc) eglGetProcAddress("glTexSubImage2D"); - functions->fTexStorage2D = (GrGLTexStorage2DProc) eglGetProcAddress("glTexStorage2D"); - functions->fUniform1f = (GrGLUniform1fProc) eglGetProcAddress("glUniform1f"); - functions->fUniform1i = (GrGLUniform1iProc) eglGetProcAddress("glUniform1i"); - functions->fUniform1fv = (GrGLUniform1fvProc) eglGetProcAddress("glUniform1fv"); - functions->fUniform1iv = (GrGLUniform1ivProc) eglGetProcAddress("glUniform1iv"); - functions->fUniform2f = (GrGLUniform2fProc) eglGetProcAddress("glUniform2f"); - functions->fUniform2i = (GrGLUniform2iProc) eglGetProcAddress("glUniform2i"); - functions->fUniform2fv = (GrGLUniform2fvProc) eglGetProcAddress("glUniform2fv"); - functions->fUniform2iv = (GrGLUniform2ivProc) eglGetProcAddress("glUniform2iv"); - functions->fUniform3f = (GrGLUniform3fProc) eglGetProcAddress("glUniform3f"); - functions->fUniform3i = (GrGLUniform3iProc) eglGetProcAddress("glUniform3i"); - functions->fUniform3fv = (GrGLUniform3fvProc) eglGetProcAddress("glUniform3fv"); - functions->fUniform3iv = (GrGLUniform3ivProc) eglGetProcAddress("glUniform3iv"); - functions->fUniform4f = (GrGLUniform4fProc) eglGetProcAddress("glUniform4f"); - functions->fUniform4i = (GrGLUniform4iProc) eglGetProcAddress("glUniform4i"); - functions->fUniform4fv = (GrGLUniform4fvProc) eglGetProcAddress("glUniform4fv"); - functions->fUniform4iv = (GrGLUniform4ivProc) eglGetProcAddress("glUniform4iv"); - functions->fUniformMatrix2fv = (GrGLUniformMatrix2fvProc) eglGetProcAddress("glUniformMatrix2fv"); - functions->fUniformMatrix3fv = (GrGLUniformMatrix3fvProc) eglGetProcAddress("glUniformMatrix3fv"); - functions->fUniformMatrix4fv = (GrGLUniformMatrix4fvProc) eglGetProcAddress("glUniformMatrix4fv"); - functions->fUnmapBuffer = (GrGLUnmapBufferProc) eglGetProcAddress("glUnmapBuffer"); - functions->fUseProgram = (GrGLUseProgramProc) eglGetProcAddress("glUseProgram"); - functions->fVertexAttrib4fv = (GrGLVertexAttrib4fvProc) eglGetProcAddress("glVertexAttrib4fv"); - functions->fVertexAttribPointer = (GrGLVertexAttribPointerProc) eglGetProcAddress("glVertexAttribPointer"); - functions->fViewport = (GrGLViewportProc) eglGetProcAddress("glViewport"); - - if (extensions.has("GL_NV_path_rendering")) { - functions->fPathCommands = (GrGLPathCommandsProc) eglGetProcAddress("glPathCommandsNV"); - functions->fPathCoords = (GrGLPathCoordsProc) eglGetProcAddress("glPathCoordsNV"); - functions->fPathSubCommands = (GrGLPathSubCommandsProc) eglGetProcAddress("glPathSubCommandsNV"); - functions->fPathSubCoords = (GrGLPathSubCoordsProc) eglGetProcAddress("glPathSubCoordsNV"); - functions->fPathString = (GrGLPathStringProc) eglGetProcAddress("glPathStringNV"); - functions->fPathGlyphs = (GrGLPathGlyphsProc) eglGetProcAddress("glPathGlyphsNV"); - functions->fPathGlyphRange = (GrGLPathGlyphRangeProc) eglGetProcAddress("glPathGlyphRangeNV"); - functions->fWeightPaths = (GrGLWeightPathsProc) eglGetProcAddress("glWeightPathsNV"); - functions->fCopyPath = (GrGLCopyPathProc) eglGetProcAddress("glCopyPathNV"); - functions->fInterpolatePaths = (GrGLInterpolatePathsProc) eglGetProcAddress("glInterpolatePathsNV"); - functions->fTransformPath = (GrGLTransformPathProc) eglGetProcAddress("glTransformPathNV"); - functions->fPathParameteriv = (GrGLPathParameterivProc) eglGetProcAddress("glPathParameterivNV"); - functions->fPathParameteri = (GrGLPathParameteriProc) eglGetProcAddress("glPathParameteriNV"); - functions->fPathParameterfv = (GrGLPathParameterfvProc) eglGetProcAddress("glPathParameterfvNV"); - functions->fPathParameterf = (GrGLPathParameterfProc) eglGetProcAddress("glPathParameterfNV"); - functions->fPathDashArray = (GrGLPathDashArrayProc) eglGetProcAddress("glPathDashArrayNV"); - functions->fGenPaths = (GrGLGenPathsProc) eglGetProcAddress("glGenPathsNV"); - functions->fDeletePaths = (GrGLDeletePathsProc) eglGetProcAddress("glDeletePathsNV"); - functions->fIsPath = (GrGLIsPathProc) eglGetProcAddress("glIsPathNV"); - functions->fPathStencilFunc = (GrGLPathStencilFuncProc) eglGetProcAddress("glPathStencilFuncNV"); - functions->fPathStencilDepthOffset = (GrGLPathStencilDepthOffsetProc) eglGetProcAddress("glPathStencilDepthOffsetNV"); - functions->fStencilFillPath = (GrGLStencilFillPathProc) eglGetProcAddress("glStencilFillPathNV"); - functions->fStencilStrokePath = (GrGLStencilStrokePathProc) eglGetProcAddress("glStencilStrokePathNV"); - functions->fStencilFillPathInstanced = (GrGLStencilFillPathInstancedProc) eglGetProcAddress("glStencilFillPathInstancedNV"); - functions->fStencilStrokePathInstanced = (GrGLStencilStrokePathInstancedProc) eglGetProcAddress("glStencilStrokePathInstancedNV"); - functions->fPathCoverDepthFunc = (GrGLPathCoverDepthFuncProc) eglGetProcAddress("glPathCoverDepthFuncNV"); - functions->fPathColorGen = (GrGLPathColorGenProc) eglGetProcAddress("glPathColorGenNV"); - functions->fPathTexGen = (GrGLPathTexGenProc) eglGetProcAddress("glPathTexGenNV"); - functions->fPathFogGen = (GrGLPathFogGenProc) eglGetProcAddress("glPathFogGenNV"); - functions->fCoverFillPath = (GrGLCoverFillPathProc) eglGetProcAddress("glCoverFillPathNV"); - functions->fCoverStrokePath = (GrGLCoverStrokePathProc) eglGetProcAddress("glCoverStrokePathNV"); - functions->fCoverFillPathInstanced = (GrGLCoverFillPathInstancedProc) eglGetProcAddress("glCoverFillPathInstancedNV"); - functions->fCoverStrokePathInstanced = (GrGLCoverStrokePathInstancedProc) eglGetProcAddress("glCoverStrokePathInstancedNV"); - functions->fGetPathParameteriv = (GrGLGetPathParameterivProc) eglGetProcAddress("glGetPathParameterivNV"); - functions->fGetPathParameterfv = (GrGLGetPathParameterfvProc) eglGetProcAddress("glGetPathParameterfvNV"); - functions->fGetPathCommands = (GrGLGetPathCommandsProc) eglGetProcAddress("glGetPathCommandsNV"); - functions->fGetPathCoords = (GrGLGetPathCoordsProc) eglGetProcAddress("glGetPathCoordsNV"); - functions->fGetPathDashArray = (GrGLGetPathDashArrayProc) eglGetProcAddress("glGetPathDashArrayNV"); - functions->fGetPathMetrics = (GrGLGetPathMetricsProc) eglGetProcAddress("glGetPathMetricsNV"); - functions->fGetPathMetricRange = (GrGLGetPathMetricRangeProc) eglGetProcAddress("glGetPathMetricRangeNV"); - functions->fGetPathSpacing = (GrGLGetPathSpacingProc) eglGetProcAddress("glGetPathSpacingNV"); - functions->fGetPathColorGeniv = (GrGLGetPathColorGenivProc) eglGetProcAddress("glGetPathColorGenivNV"); - functions->fGetPathColorGenfv = (GrGLGetPathColorGenfvProc) eglGetProcAddress("glGetPathColorGenfvNV"); - functions->fGetPathTexGeniv = (GrGLGetPathTexGenivProc) eglGetProcAddress("glGetPathTexGenivNV"); - functions->fGetPathTexGenfv = (GrGLGetPathTexGenfvProc) eglGetProcAddress("glGetPathTexGenfvNV"); - functions->fIsPointInFillPath = (GrGLIsPointInFillPathProc) eglGetProcAddress("glIsPointInFillPathNV"); - functions->fIsPointInStrokePath = (GrGLIsPointInStrokePathProc) eglGetProcAddress("glIsPointInStrokePathNV"); - functions->fGetPathLength = (GrGLGetPathLengthProc) eglGetProcAddress("glGetPathLengthNV"); - functions->fPointAlongPath = (GrGLPointAlongPathProc) eglGetProcAddress("glPointAlongPathNV"); - } - - if (extensions.has("GL_EXT_debug_marker")) { - functions->fInsertEventMarker = (GrGLInsertEventMarkerProc) eglGetProcAddress("glInsertEventMarkerEXT"); - functions->fPushGroupMarker = (GrGLInsertEventMarkerProc) eglGetProcAddress("glPushGroupMarkerEXT"); - functions->fPopGroupMarker = (GrGLPopGroupMarkerProc) eglGetProcAddress("glPopGroupMarkerEXT"); - } - - functions->fInvalidateBufferData = (GrGLInvalidateBufferDataProc) eglGetProcAddress("glInvalidateBufferData"); - functions->fInvalidateBufferSubData = (GrGLInvalidateBufferSubDataProc) eglGetProcAddress("glInvalidateBufferSubData"); - functions->fInvalidateFramebuffer = (GrGLInvalidateFramebufferProc) eglGetProcAddress("glInvalidateFramebuffer"); - functions->fInvalidateSubFramebuffer = (GrGLInvalidateSubFramebufferProc) eglGetProcAddress("glInvalidateSubFramebuffer"); - functions->fInvalidateTexImage = (GrGLInvalidateTexImageProc) eglGetProcAddress("glInvalidateTexImage"); - functions->fInvalidateTexSubImage = (GrGLInvalidateTexSubImageProc) eglGetProcAddress("glInvalidateTexSubImage"); +static GrGLFuncPtr android_get_gl_proc(void* ctx, const char name[]) { + SkASSERT(NULL == ctx); + return eglGetProcAddress(name); +} - return interface; +static const GrGLInterface* create_desktop_interface() { + return GrGLAssembleGLInterface(NULL, android_get_gl_proc); } const GrGLInterface* GrGLCreateNativeInterface() { - GrGLGetStringiProc getStringi = (GrGLGetStringiProc) eglGetProcAddress("glGetStringi"); - const char* verStr = reinterpret_cast<const char*>(glGetString(GR_GL_VERSION)); - GrGLVersion version = GrGLGetVersionFromString(verStr); GrGLStandard standard = GrGLGetStandardInUseFromString(verStr); - GrGLExtensions extensions; - if (!extensions.init(standard, glGetString, getStringi, glGetIntegerv)) { - return NULL; - } - - GrGLInterface* interface = NULL; if (kGLES_GrGLStandard == standard) { - interface = create_es_interface(version, &extensions); - } else if (kGL_GrGLStandard == standard) { - interface = create_desktop_interface(version, extensions); - } + GrGLVersion version = GrGLGetVersionFromString(verStr); + GrGLExtensions extensions; + GrGLGetStringiProc getStringi = (GrGLGetStringiProc) eglGetProcAddress("glGetStringi"); + if (!extensions.init(standard, glGetString, getStringi, glGetIntegerv)) { + return NULL; + } + GrGLInterface* interface = create_es_interface(version, &extensions); - if (NULL != interface) { - interface->fExtensions.swap(&extensions); + if (NULL != interface) { + interface->fExtensions.swap(&extensions); + } + + return interface; + } else if (kGL_GrGLStandard == standard) { + return create_desktop_interface(); } - return interface; + return NULL; } diff --git a/gpu/gl/debug/GrGLCreateDebugInterface.cpp b/gpu/gl/debug/GrGLCreateDebugInterface.cpp index cbfbb266..0a8333b8 100644 --- a/gpu/gl/debug/GrGLCreateDebugInterface.cpp +++ b/gpu/gl/debug/GrGLCreateDebugInterface.cpp @@ -848,11 +848,8 @@ const GrGLInterface* GrGLCreateDebugInterface() { functions->fGetTexLevelParameteriv = noOpGLGetTexLevelParameteriv; functions->fGetUniformLocation = noOpGLGetUniformLocation; functions->fGenVertexArrays = debugGLGenVertexArrays; - functions->fLoadIdentity = noOpGLLoadIdentity; - functions->fLoadMatrixf = noOpGLLoadMatrixf; functions->fLineWidth = noOpGLLineWidth; functions->fLinkProgram = noOpGLLinkProgram; - functions->fMatrixMode = noOpGLMatrixMode; functions->fPixelStorei = debugGLPixelStorei; functions->fQueryCounter = noOpGLQueryCounter; functions->fReadBuffer = noOpGLReadBuffer; @@ -865,8 +862,6 @@ const GrGLInterface* GrGLCreateDebugInterface() { functions->fStencilMaskSeparate = noOpGLStencilMaskSeparate; functions->fStencilOp = noOpGLStencilOp; functions->fStencilOpSeparate = noOpGLStencilOpSeparate; - functions->fTexGenfv = noOpGLTexGenfv; - functions->fTexGeni = noOpGLTexGeni; functions->fTexImage2D = noOpGLTexImage2D; functions->fTexParameteri = noOpGLTexParameteri; functions->fTexParameteriv = noOpGLTexParameteriv; @@ -915,6 +910,8 @@ const GrGLInterface* GrGLCreateDebugInterface() { functions->fResolveMultisampleFramebuffer = noOpGLResolveMultisampleFramebuffer; functions->fMapBuffer = debugGLMapBuffer; + functions->fMatrixLoadf = noOpGLMatrixLoadf; + functions->fMatrixLoadIdentity = noOpGLMatrixLoadIdentity; functions->fUnmapBuffer = debugGLUnmapBuffer; functions->fBindFragDataLocationIndexed = noOpGLBindFragDataLocationIndexed; diff --git a/gpu/gl/mac/GrGLCreateNativeInterface_mac.cpp b/gpu/gl/mac/GrGLCreateNativeInterface_mac.cpp index 04898d11..ab3f0ad2 100644 --- a/gpu/gl/mac/GrGLCreateNativeInterface_mac.cpp +++ b/gpu/gl/mac/GrGLCreateNativeInterface_mac.cpp @@ -8,12 +8,10 @@ #include "gl/GrGLInterface.h" -#include "../GrGLUtil.h" +#include "gl/GrGLAssembleInterface.h" #include <dlfcn.h> -// We get the proc addresss of all GL functions dynamically because we sometimes link against -// alternative GL implementations (e.g. MESA) in addition to the native GL implementation. class GLLoader { public: GLLoader() { @@ -21,236 +19,40 @@ public: "/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib", RTLD_LAZY); } + ~GLLoader() { if (NULL != fLibrary) { dlclose(fLibrary); } } - void* handle() { + + void* handle() const { return NULL == fLibrary ? RTLD_DEFAULT : fLibrary; } + private: void* fLibrary; }; -static void* GetProcAddress(const char* name) { - static GLLoader gLoader; - return dlsym(gLoader.handle(), name); -} - -#define GET_PROC(name) (interface->fFunctions.f ## name = ((GrGL ## name ## Proc) GetProcAddress("gl" #name))) -#define GET_PROC_SUFFIX(name, suffix) (interface->fFunctions.f ## name = ((GrGL ## name ## Proc) GetProcAddress("gl" #name #suffix))) - -const GrGLInterface* GrGLCreateNativeInterface() { - - GrGLGetStringProc glGetString = (GrGLGetStringProc) GetProcAddress("glGetString"); - GrGLGetStringiProc glGetStringi = (GrGLGetStringiProc) GetProcAddress("glGetStringi"); - GrGLGetIntegervProc glGetIntegerv = (GrGLGetIntegervProc) GetProcAddress("glGetIntegerv"); - - const char* verStr = (const char*) glGetString(GR_GL_VERSION); - GrGLVersion ver = GrGLGetVersionFromString(verStr); - GrGLExtensions extensions; - if (!extensions.init(kGL_GrGLStandard, glGetString, glGetStringi, glGetIntegerv)) { - return NULL; - } - - GrGLInterface* interface = SkNEW(GrGLInterface); - interface->fStandard = kGL_GrGLStandard; - - GET_PROC(ActiveTexture); - GET_PROC(AttachShader); - GET_PROC(BeginQuery); - GET_PROC(BindAttribLocation); - GET_PROC(BindBuffer); - if (ver >= GR_GL_VER(3,0)) { - GET_PROC(BindFragDataLocation); - } - GET_PROC(BindTexture); - GET_PROC(BlendFunc); - - if (ver >= GR_GL_VER(1,4) || - extensions.has("GL_ARB_imaging") || - extensions.has("GL_EXT_blend_color")) { - GET_PROC(BlendColor); - } - - GET_PROC(BufferData); - GET_PROC(BufferSubData); - GET_PROC(Clear); - GET_PROC(ClearColor); - GET_PROC(ClearStencil); - GET_PROC(ColorMask); - GET_PROC(CompileShader); - GET_PROC(CompressedTexImage2D); - GET_PROC(CopyTexSubImage2D); - GET_PROC(CreateProgram); - GET_PROC(CreateShader); - GET_PROC(CullFace); - GET_PROC(DeleteBuffers); - GET_PROC(DeleteProgram); - GET_PROC(DeleteQueries); - GET_PROC(DeleteShader); - GET_PROC(DeleteTextures); - GET_PROC(DepthMask); - GET_PROC(Disable); - GET_PROC(DisableVertexAttribArray); - GET_PROC(DrawArrays); - GET_PROC(DrawBuffer); - GET_PROC(DrawBuffers); - GET_PROC(DrawElements); - GET_PROC(Enable); - GET_PROC(EnableVertexAttribArray); - GET_PROC(EndQuery); - GET_PROC(Finish); - GET_PROC(Flush); - GET_PROC(FrontFace); - GET_PROC(GenBuffers); - GET_PROC(GenerateMipmap); - GET_PROC(GenQueries); - GET_PROC(GetBufferParameteriv); - GET_PROC(GetError); - GET_PROC(GetIntegerv); - GET_PROC(GetProgramInfoLog); - GET_PROC(GetProgramiv); - GET_PROC(GetQueryiv); - GET_PROC(GetQueryObjectiv); - GET_PROC(GetQueryObjectuiv); - GET_PROC(GetShaderInfoLog); - GET_PROC(GetShaderiv); - GET_PROC(GetString); - GET_PROC(GetStringi); - GET_PROC(GetTexLevelParameteriv); - GET_PROC(GenTextures); - GET_PROC(GetUniformLocation); - GET_PROC(LineWidth); - GET_PROC(LinkProgram); - GET_PROC(LoadIdentity); - GET_PROC(LoadMatrixf); - GET_PROC(MapBuffer); - GET_PROC(MatrixMode); - GET_PROC(PixelStorei); - GET_PROC(ReadBuffer); - GET_PROC(ReadPixels); - GET_PROC(Scissor); - GET_PROC(ShaderSource); - GET_PROC(StencilFunc); - GET_PROC(StencilFuncSeparate); - GET_PROC(StencilMask); - GET_PROC(StencilMaskSeparate); - GET_PROC(StencilOp); - GET_PROC(StencilOpSeparate); - GET_PROC(TexGenfv); - GET_PROC(TexGeni); - GET_PROC(TexImage2D); - GET_PROC(TexParameteri); - GET_PROC(TexParameteriv); - if (ver >= GR_GL_VER(4,2) || extensions.has("GL_ARB_texture_storage")) { - GET_PROC(TexStorage2D); - } else if (extensions.has("GL_EXT_texture_storage")) { - GET_PROC_SUFFIX(TexStorage2D, EXT); - } - GET_PROC(TexSubImage2D); - GET_PROC(Uniform1f); - GET_PROC(Uniform1i); - GET_PROC(Uniform1fv); - GET_PROC(Uniform1iv); - GET_PROC(Uniform2f); - GET_PROC(Uniform2i); - GET_PROC(Uniform2fv); - GET_PROC(Uniform2iv); - GET_PROC(Uniform3f); - GET_PROC(Uniform3i); - GET_PROC(Uniform3fv); - GET_PROC(Uniform3iv); - GET_PROC(Uniform4f); - GET_PROC(Uniform4i); - GET_PROC(Uniform4fv); - GET_PROC(Uniform4iv); - GET_PROC(Uniform4fv); - GET_PROC(UniformMatrix2fv); - GET_PROC(UniformMatrix3fv); - GET_PROC(UniformMatrix4fv); - GET_PROC(UnmapBuffer); - GET_PROC(UseProgram); - GET_PROC(VertexAttrib4fv); - GET_PROC(VertexAttribPointer); - GET_PROC(Viewport); - - if (ver >= GR_GL_VER(3,0) || extensions.has("GL_ARB_vertex_array_object")) { - // no ARB suffix for GL_ARB_vertex_array_object - GET_PROC(BindVertexArray); - GET_PROC(DeleteVertexArrays); - GET_PROC(GenVertexArrays); - } - - if (ver >= GR_GL_VER(3,3) || extensions.has("GL_ARB_timer_query")) { - // ARB extension doesn't use the ARB suffix on the function name - GET_PROC(QueryCounter); - GET_PROC(GetQueryObjecti64v); - GET_PROC(GetQueryObjectui64v); - } else if (extensions.has("GL_EXT_timer_query")) { - GET_PROC_SUFFIX(GetQueryObjecti64v, EXT); - GET_PROC_SUFFIX(GetQueryObjectui64v, EXT); - } +class GLProcGetter { +public: + GLProcGetter() {} - if (ver >= GR_GL_VER(3,0) || extensions.has("GL_ARB_framebuffer_object")) { - // ARB extension doesn't use the ARB suffix on the function names - GET_PROC(GenFramebuffers); - GET_PROC(GetFramebufferAttachmentParameteriv); - GET_PROC(GetRenderbufferParameteriv); - GET_PROC(BindFramebuffer); - GET_PROC(FramebufferTexture2D); - GET_PROC(CheckFramebufferStatus); - GET_PROC(DeleteFramebuffers); - GET_PROC(RenderbufferStorage); - GET_PROC(GenRenderbuffers); - GET_PROC(DeleteRenderbuffers); - GET_PROC(FramebufferRenderbuffer); - GET_PROC(BindRenderbuffer); - GET_PROC(RenderbufferStorageMultisample); - GET_PROC(BlitFramebuffer); - } else { - if (extensions.has("GL_EXT_framebuffer_object")) { - GET_PROC_SUFFIX(GenFramebuffers, EXT); - GET_PROC_SUFFIX(GetFramebufferAttachmentParameteriv, EXT); - GET_PROC_SUFFIX(GetRenderbufferParameteriv, EXT); - GET_PROC_SUFFIX(BindFramebuffer, EXT); - GET_PROC_SUFFIX(FramebufferTexture2D, EXT); - GET_PROC_SUFFIX(CheckFramebufferStatus, EXT); - GET_PROC_SUFFIX(DeleteFramebuffers, EXT); - GET_PROC_SUFFIX(RenderbufferStorage, EXT); - GET_PROC_SUFFIX(GenRenderbuffers, EXT); - GET_PROC_SUFFIX(DeleteRenderbuffers, EXT); - GET_PROC_SUFFIX(FramebufferRenderbuffer, EXT); - GET_PROC_SUFFIX(BindRenderbuffer, EXT); - } - if (extensions.has("GL_EXT_framebuffer_multisample")) { - GET_PROC_SUFFIX(RenderbufferStorageMultisample, EXT); - } - if (extensions.has("GL_EXT_framebuffer_blit")) { - GET_PROC_SUFFIX(BlitFramebuffer, EXT); - } - } - if (ver >= GR_GL_VER(3,3) || extensions.has("GL_ARB_blend_func_extended")) { - // ARB extension doesn't use the ARB suffix on the function name - GET_PROC(BindFragDataLocationIndexed); + GrGLFuncPtr getProc(const char name[]) const { + return (GrGLFuncPtr) dlsym(fLoader.handle(), name); } - if (extensions.has("GL_EXT_debug_marker")) { - GET_PROC_SUFFIX(InsertEventMarker, EXT); - GET_PROC_SUFFIX(PushGroupMarker, EXT); - GET_PROC_SUFFIX(PopGroupMarker, EXT); - } +private: + GLLoader fLoader; +}; - if (ver >= GR_GL_VER(4,3) || extensions.has("GL_ARB_invalidate_subdata")) { - GET_PROC(InvalidateBufferData); - GET_PROC(InvalidateBufferSubData); - GET_PROC(InvalidateFramebuffer); - GET_PROC(InvalidateSubFramebuffer); - GET_PROC(InvalidateTexImage); - GET_PROC(InvalidateTexSubImage); - } +static GrGLFuncPtr mac_get_gl_proc(void* ctx, const char name[]) { + SkASSERT(NULL != ctx); + const GLProcGetter* getter = (const GLProcGetter*) ctx; + return getter->getProc(name); +} - interface->fExtensions.swap(&extensions); - return interface; +const GrGLInterface* GrGLCreateNativeInterface() { + GLProcGetter getter; + return GrGLAssembleGLInterface(&getter, mac_get_gl_proc); } diff --git a/gpu/gl/mesa/GrGLCreateMesaInterface.cpp b/gpu/gl/mesa/GrGLCreateMesaInterface.cpp index fd8be26f..a95b6fc8 100644 --- a/gpu/gl/mesa/GrGLCreateMesaInterface.cpp +++ b/gpu/gl/mesa/GrGLCreateMesaInterface.cpp @@ -6,235 +6,20 @@ * found in the LICENSE file. */ -#include "gl/GrGLExtensions.h" -#include "gl/GrGLInterface.h" +#include "gl/GrGLAssembleInterface.h" #include "../GrGLUtil.h" -#define GL_GLEXT_PROTOTYPES #include "osmesa_wrapper.h" -#define GR_GL_GET_PROC(F) interface->fFunctions.f ## F = (GrGL ## F ## Proc) \ - OSMesaGetProcAddress("gl" #F); -#define GR_GL_GET_PROC_SUFFIX(F, S) interface->fFunctions.f ## F = (GrGL ## F ## Proc) \ - OSMesaGetProcAddress("gl" #F #S); - -// We use OSMesaGetProcAddress for every gl function to avoid accidentally using -// non-Mesa gl functions. +static GrGLFuncPtr osmesa_get(void* ctx, const char name[]) { + SkASSERT(NULL == ctx); + SkASSERT(NULL != OSMesaGetCurrentContext()); + return OSMesaGetProcAddress(name); +} const GrGLInterface* GrGLCreateMesaInterface() { if (NULL == OSMesaGetCurrentContext()) { return NULL; } - - GrGLGetStringProc getString = (GrGLGetStringProc) OSMesaGetProcAddress("glGetString"); - GrGLGetStringiProc getStringi = (GrGLGetStringiProc) OSMesaGetProcAddress("glGetStringi"); - GrGLGetIntegervProc getIntegerv = - (GrGLGetIntegervProc) OSMesaGetProcAddress("glGetIntegerv"); - - GrGLExtensions extensions; - if (!extensions.init(kGL_GrGLStandard, getString, getStringi, getIntegerv)) { - return NULL; - } - - const char* versionString = (const char*) getString(GL_VERSION); - GrGLVersion glVer = GrGLGetVersionFromString(versionString); - - if (glVer < GR_GL_VER(1,5)) { - // We must have array and element_array buffer objects. - return NULL; - } - GrGLInterface* interface = SkNEW(GrGLInterface()); - - GR_GL_GET_PROC(ActiveTexture); - GR_GL_GET_PROC(BeginQuery); - GR_GL_GET_PROC(AttachShader); - GR_GL_GET_PROC(BindAttribLocation); - GR_GL_GET_PROC(BindBuffer); - GR_GL_GET_PROC(BindFragDataLocation); - GR_GL_GET_PROC(BindTexture); - GR_GL_GET_PROC(BlendFunc); - - if (glVer >= GR_GL_VER(1,4) || - extensions.has("GL_ARB_imaging") || - extensions.has("GL_EXT_blend_color")) { - GR_GL_GET_PROC(BlendColor); - } - - GR_GL_GET_PROC(BufferData); - GR_GL_GET_PROC(BufferSubData); - GR_GL_GET_PROC(Clear); - GR_GL_GET_PROC(ClearColor); - GR_GL_GET_PROC(ClearStencil); - GR_GL_GET_PROC(ColorMask); - GR_GL_GET_PROC(CompileShader); - GR_GL_GET_PROC(CompressedTexImage2D); - GR_GL_GET_PROC(CopyTexSubImage2D); - GR_GL_GET_PROC(CreateProgram); - GR_GL_GET_PROC(CreateShader); - GR_GL_GET_PROC(CullFace); - GR_GL_GET_PROC(DeleteBuffers); - GR_GL_GET_PROC(DeleteProgram); - GR_GL_GET_PROC(DeleteQueries); - GR_GL_GET_PROC(DeleteShader); - GR_GL_GET_PROC(DeleteTextures); - GR_GL_GET_PROC(DepthMask); - GR_GL_GET_PROC(Disable); - GR_GL_GET_PROC(DisableVertexAttribArray); - GR_GL_GET_PROC(DrawArrays); - GR_GL_GET_PROC(DrawBuffer); - GR_GL_GET_PROC(DrawBuffers); - GR_GL_GET_PROC(DrawElements); - GR_GL_GET_PROC(Enable); - GR_GL_GET_PROC(EnableVertexAttribArray); - GR_GL_GET_PROC(EndQuery); - GR_GL_GET_PROC(Finish); - GR_GL_GET_PROC(Flush); - GR_GL_GET_PROC(FrontFace); - GR_GL_GET_PROC(GenBuffers); - GR_GL_GET_PROC(GenerateMipmap); - GR_GL_GET_PROC(GenQueries); - GR_GL_GET_PROC(GetBufferParameteriv); - GR_GL_GET_PROC(GetError); - GR_GL_GET_PROC(GetIntegerv); - GR_GL_GET_PROC(GetProgramInfoLog); - GR_GL_GET_PROC(GetProgramiv); - if (glVer >= GR_GL_VER(3,3) || extensions.has("GL_ARB_timer_query")) { - GR_GL_GET_PROC(GetQueryObjecti64v); - GR_GL_GET_PROC(GetQueryObjectui64v) - GR_GL_GET_PROC(QueryCounter); - } else if (extensions.has("GL_EXT_timer_query")) { - GR_GL_GET_PROC_SUFFIX(GetQueryObjecti64v, EXT); - GR_GL_GET_PROC_SUFFIX(GetQueryObjectui64v, EXT); - } - GR_GL_GET_PROC(GetQueryObjectiv); - GR_GL_GET_PROC(GetQueryObjectuiv); - GR_GL_GET_PROC(GetQueryiv); - GR_GL_GET_PROC(GetShaderInfoLog); - GR_GL_GET_PROC(GetShaderiv); - GR_GL_GET_PROC(GetString); - GR_GL_GET_PROC(GetStringi); - GR_GL_GET_PROC(GetTexLevelParameteriv); - GR_GL_GET_PROC(GenTextures); - GR_GL_GET_PROC(GetUniformLocation); - GR_GL_GET_PROC(LineWidth); - GR_GL_GET_PROC(LinkProgram); - GR_GL_GET_PROC(LoadIdentity); - GR_GL_GET_PROC(LoadMatrixf); - GR_GL_GET_PROC(MatrixMode); - GR_GL_GET_PROC(MapBuffer); - GR_GL_GET_PROC(PixelStorei); - GR_GL_GET_PROC(ReadBuffer); - GR_GL_GET_PROC(ReadPixels); - GR_GL_GET_PROC(Scissor); - GR_GL_GET_PROC(ShaderSource); - GR_GL_GET_PROC(StencilFunc); - GR_GL_GET_PROC(StencilFuncSeparate); - GR_GL_GET_PROC(StencilMask); - GR_GL_GET_PROC(StencilMaskSeparate); - GR_GL_GET_PROC(StencilOp); - GR_GL_GET_PROC(StencilOpSeparate); - GR_GL_GET_PROC(TexGenfv); - GR_GL_GET_PROC(TexGeni); - GR_GL_GET_PROC(TexImage2D) - GR_GL_GET_PROC(TexParameteri); - GR_GL_GET_PROC(TexParameteriv); - GR_GL_GET_PROC(TexStorage2D); - if (NULL == interface->fFunctions.fTexStorage2D) { - GR_GL_GET_PROC_SUFFIX(TexStorage2D, EXT); - } - GR_GL_GET_PROC(TexSubImage2D); - GR_GL_GET_PROC(Uniform1f); - GR_GL_GET_PROC(Uniform1i); - GR_GL_GET_PROC(Uniform1fv); - GR_GL_GET_PROC(Uniform1iv); - GR_GL_GET_PROC(Uniform2f); - GR_GL_GET_PROC(Uniform2i); - GR_GL_GET_PROC(Uniform2fv); - GR_GL_GET_PROC(Uniform2iv); - GR_GL_GET_PROC(Uniform3f); - GR_GL_GET_PROC(Uniform3i); - GR_GL_GET_PROC(Uniform3fv); - GR_GL_GET_PROC(Uniform3iv); - GR_GL_GET_PROC(Uniform4f); - GR_GL_GET_PROC(Uniform4i); - GR_GL_GET_PROC(Uniform4fv); - GR_GL_GET_PROC(Uniform4iv); - GR_GL_GET_PROC(UniformMatrix2fv); - GR_GL_GET_PROC(UniformMatrix3fv); - GR_GL_GET_PROC(UniformMatrix4fv); - GR_GL_GET_PROC(UnmapBuffer); - GR_GL_GET_PROC(UseProgram); - GR_GL_GET_PROC(VertexAttrib4fv); - GR_GL_GET_PROC(VertexAttribPointer); - GR_GL_GET_PROC(Viewport); - - if (glVer >= GR_GL_VER(3,0) || extensions.has("GL_ARB_vertex_array_object")) { - // no ARB suffix for GL_ARB_vertex_array_object - GR_GL_GET_PROC(BindVertexArray); - GR_GL_GET_PROC(DeleteVertexArrays); - GR_GL_GET_PROC(GenVertexArrays); - } - - // First look for GL3.0 FBO or GL_ARB_framebuffer_object (same since - // GL_ARB_framebuffer_object doesn't use ARB suffix.) - if (glVer >= GR_GL_VER(3,0) || extensions.has("GL_ARB_framebuffer_object")) { - GR_GL_GET_PROC(GenFramebuffers); - GR_GL_GET_PROC(GetFramebufferAttachmentParameteriv); - GR_GL_GET_PROC(GetRenderbufferParameteriv); - GR_GL_GET_PROC(BindFramebuffer); - GR_GL_GET_PROC(FramebufferTexture2D); - GR_GL_GET_PROC(CheckFramebufferStatus); - GR_GL_GET_PROC(DeleteFramebuffers); - GR_GL_GET_PROC(RenderbufferStorage); - GR_GL_GET_PROC(GenRenderbuffers); - GR_GL_GET_PROC(DeleteRenderbuffers); - GR_GL_GET_PROC(FramebufferRenderbuffer); - GR_GL_GET_PROC(BindRenderbuffer); - GR_GL_GET_PROC(RenderbufferStorageMultisample); - GR_GL_GET_PROC(BlitFramebuffer); - } else if (extensions.has("GL_EXT_framebuffer_object")) { - GR_GL_GET_PROC_SUFFIX(GenFramebuffers, EXT); - GR_GL_GET_PROC_SUFFIX(GetFramebufferAttachmentParameteriv, EXT); - GR_GL_GET_PROC_SUFFIX(GetRenderbufferParameteriv, EXT); - GR_GL_GET_PROC_SUFFIX(BindFramebuffer, EXT); - GR_GL_GET_PROC_SUFFIX(FramebufferTexture2D, EXT); - GR_GL_GET_PROC_SUFFIX(CheckFramebufferStatus, EXT); - GR_GL_GET_PROC_SUFFIX(DeleteFramebuffers, EXT); - GR_GL_GET_PROC_SUFFIX(RenderbufferStorage, EXT); - GR_GL_GET_PROC_SUFFIX(GenRenderbuffers, EXT); - GR_GL_GET_PROC_SUFFIX(DeleteRenderbuffers, EXT); - GR_GL_GET_PROC_SUFFIX(FramebufferRenderbuffer, EXT); - GR_GL_GET_PROC_SUFFIX(BindRenderbuffer, EXT); - if (extensions.has("GL_EXT_framebuffer_multisample")) { - GR_GL_GET_PROC_SUFFIX(RenderbufferStorageMultisample, EXT); - } - if (extensions.has("GL_EXT_framebuffer_blit")) { - GR_GL_GET_PROC_SUFFIX(BlitFramebuffer, EXT); - } - } else { - // we must have FBOs - delete interface; - return NULL; - } - GR_GL_GET_PROC(BindFragDataLocationIndexed); - - if (extensions.has("GL_EXT_debug_marker")) { - GR_GL_GET_PROC_SUFFIX(InsertEventMarker, EXT); - GR_GL_GET_PROC_SUFFIX(PopGroupMarker, EXT); - GR_GL_GET_PROC_SUFFIX(PushGroupMarker, EXT); - } - - if (glVer >= GR_GL_VER(4,3) || extensions.has("GL_ARB_invalidate_subdata")) { - GR_GL_GET_PROC(InvalidateBufferData); - GR_GL_GET_PROC(InvalidateBufferSubData); - GR_GL_GET_PROC(InvalidateFramebuffer); - GR_GL_GET_PROC(InvalidateSubFramebuffer); - GR_GL_GET_PROC(InvalidateTexImage); - GR_GL_GET_PROC(InvalidateTexSubImage); - } - - interface->fStandard = kGL_GrGLStandard; - interface->fExtensions.swap(&extensions); - - return interface; + return GrGLAssembleGLInterface(NULL, osmesa_get); } diff --git a/gpu/gl/unix/GrGLCreateNativeInterface_unix.cpp b/gpu/gl/unix/GrGLCreateNativeInterface_unix.cpp index 93807637..ddbfe5de 100644 --- a/gpu/gl/unix/GrGLCreateNativeInterface_unix.cpp +++ b/gpu/gl/unix/GrGLCreateNativeInterface_unix.cpp @@ -1,6 +1,5 @@ - /* - * Copyright 2011 Google Inc. + * Copyright 2014 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. @@ -8,287 +7,19 @@ #include "gl/GrGLInterface.h" -#include "../GrGLUtil.h" +#include "gl/GrGLAssembleInterface.h" #include <GL/glx.h> -#include <GL/gl.h> -#include <GL/glext.h> -#include <GL/glu.h> -#define GR_GL_GET_PROC(F) interface->fFunctions.f ## F = (GrGL ## F ## Proc) \ - glXGetProcAddress(reinterpret_cast<const GLubyte*>("gl" #F)); -#define GR_GL_GET_PROC_SUFFIX(F, S) interface->fFunctions.f ## F = (GrGL ## F ## Proc) \ - glXGetProcAddress(reinterpret_cast<const GLubyte*>("gl" #F #S)); +static GrGLFuncPtr glx_get(void* ctx, const char name[]) { + SkASSERT(NULL == ctx); + SkASSERT(NULL != glXGetCurrentContext()); + return glXGetProcAddress(reinterpret_cast<const GLubyte*>(name)); +} const GrGLInterface* GrGLCreateNativeInterface() { if (NULL == glXGetCurrentContext()) { return NULL; } - - const char* versionString = (const char*) glGetString(GL_VERSION); - GrGLVersion glVer = GrGLGetVersionFromString(versionString); - - // This may or may not succeed depending on the gl version. - GrGLGetStringiProc glGetStringi = - (GrGLGetStringiProc) glXGetProcAddress(reinterpret_cast<const GLubyte*>("glGetStringi")); - - GrGLExtensions extensions; - if (!extensions.init(kGL_GrGLStandard, glGetString, glGetStringi, glGetIntegerv)) { - return NULL; - } - - if (glVer < GR_GL_VER(1,5)) { - // We must have array and element_array buffer objects. - return NULL; - } - - GrGLInterface* interface = SkNEW(GrGLInterface()); - GrGLInterface::Functions* functions = &interface->fFunctions; - - functions->fActiveTexture = glActiveTexture; - GR_GL_GET_PROC(AttachShader); - GR_GL_GET_PROC(BindAttribLocation); - GR_GL_GET_PROC(BindBuffer); - GR_GL_GET_PROC(BindFragDataLocation); - GR_GL_GET_PROC(BeginQuery); - functions->fBindTexture = glBindTexture; - functions->fBlendFunc = glBlendFunc; - - if (glVer >= GR_GL_VER(1,4) || - extensions.has("GL_ARB_imaging") || - extensions.has("GL_EXT_blend_color")) { - GR_GL_GET_PROC(BlendColor); - } - - GR_GL_GET_PROC(BufferData); - GR_GL_GET_PROC(BufferSubData); - functions->fClear = glClear; - functions->fClearColor = glClearColor; - functions->fClearStencil = glClearStencil; - functions->fColorMask = glColorMask; - GR_GL_GET_PROC(CompileShader); - functions->fCompressedTexImage2D = glCompressedTexImage2D; - functions->fCopyTexSubImage2D = glCopyTexSubImage2D; - GR_GL_GET_PROC(CreateProgram); - GR_GL_GET_PROC(CreateShader); - functions->fCullFace = glCullFace; - GR_GL_GET_PROC(DeleteBuffers); - GR_GL_GET_PROC(DeleteProgram); - GR_GL_GET_PROC(DeleteQueries); - GR_GL_GET_PROC(DeleteShader); - functions->fDeleteTextures = glDeleteTextures; - functions->fDepthMask = glDepthMask; - functions->fDisable = glDisable; - GR_GL_GET_PROC(DisableVertexAttribArray); - functions->fDrawArrays = glDrawArrays; - functions->fDrawBuffer = glDrawBuffer; - GR_GL_GET_PROC(DrawBuffers); - functions->fDrawElements = glDrawElements; - functions->fEnable = glEnable; - GR_GL_GET_PROC(EnableVertexAttribArray); - GR_GL_GET_PROC(EndQuery); - functions->fFinish = glFinish; - functions->fFlush = glFlush; - functions->fFrontFace = glFrontFace; - GR_GL_GET_PROC(GenBuffers); - GR_GL_GET_PROC(GenerateMipmap); - GR_GL_GET_PROC(GetBufferParameteriv); - functions->fGetError = glGetError; - functions->fGetIntegerv = glGetIntegerv; - GR_GL_GET_PROC(GetQueryObjectiv); - GR_GL_GET_PROC(GetQueryObjectuiv); - if (glVer >= GR_GL_VER(3,3) || extensions.has("GL_ARB_timer_query")) { - GR_GL_GET_PROC(GetQueryObjecti64v); - GR_GL_GET_PROC(GetQueryObjectui64v); - GR_GL_GET_PROC(QueryCounter); - } else if (extensions.has("GL_EXT_timer_query")) { - GR_GL_GET_PROC_SUFFIX(GetQueryObjecti64v, EXT); - GR_GL_GET_PROC_SUFFIX(GetQueryObjectui64v, EXT); - } - GR_GL_GET_PROC(GetQueryiv); - GR_GL_GET_PROC(GetProgramInfoLog); - GR_GL_GET_PROC(GetProgramiv); - GR_GL_GET_PROC(GetShaderInfoLog); - GR_GL_GET_PROC(GetShaderiv); - functions->fGetString = glGetString; - GR_GL_GET_PROC(GetStringi); - functions->fGetTexLevelParameteriv = glGetTexLevelParameteriv; - GR_GL_GET_PROC(GenQueries); - functions->fGenTextures = glGenTextures; - GR_GL_GET_PROC(GetUniformLocation); - functions->fLineWidth = glLineWidth; - GR_GL_GET_PROC(LinkProgram); - GR_GL_GET_PROC(MapBuffer); - functions->fPixelStorei = glPixelStorei; - functions->fReadBuffer = glReadBuffer; - functions->fReadPixels = glReadPixels; - functions->fScissor = glScissor; - GR_GL_GET_PROC(ShaderSource); - functions->fStencilFunc = glStencilFunc; - GR_GL_GET_PROC(StencilFuncSeparate); - functions->fStencilMask = glStencilMask; - GR_GL_GET_PROC(StencilMaskSeparate); - functions->fStencilOp = glStencilOp; - GR_GL_GET_PROC(StencilOpSeparate); - functions->fTexImage2D = glTexImage2D; - functions->fTexGenfv = glTexGenfv; - functions->fTexGeni = glTexGeni; - functions->fTexParameteri = glTexParameteri; - functions->fTexParameteriv = glTexParameteriv; - if (glVer >= GR_GL_VER(4,2) || extensions.has("GL_ARB_texture_storage")) { - GR_GL_GET_PROC(TexStorage2D); - } else if (extensions.has("GL_EXT_texture_storage")) { - GR_GL_GET_PROC_SUFFIX(TexStorage2D, EXT); - } - functions->fTexSubImage2D = glTexSubImage2D; - GR_GL_GET_PROC(Uniform1f); - GR_GL_GET_PROC(Uniform1i); - GR_GL_GET_PROC(Uniform1fv); - GR_GL_GET_PROC(Uniform1iv); - GR_GL_GET_PROC(Uniform2f); - GR_GL_GET_PROC(Uniform2i); - GR_GL_GET_PROC(Uniform2fv); - GR_GL_GET_PROC(Uniform2iv); - GR_GL_GET_PROC(Uniform3f); - GR_GL_GET_PROC(Uniform3i); - GR_GL_GET_PROC(Uniform3fv); - GR_GL_GET_PROC(Uniform3iv); - GR_GL_GET_PROC(Uniform4f); - GR_GL_GET_PROC(Uniform4i); - GR_GL_GET_PROC(Uniform4fv); - GR_GL_GET_PROC(Uniform4iv); - GR_GL_GET_PROC(UniformMatrix2fv); - GR_GL_GET_PROC(UniformMatrix3fv); - GR_GL_GET_PROC(UniformMatrix4fv); - GR_GL_GET_PROC(UnmapBuffer); - GR_GL_GET_PROC(UseProgram); - GR_GL_GET_PROC(VertexAttrib4fv); - GR_GL_GET_PROC(VertexAttribPointer); - functions->fViewport = glViewport; - GR_GL_GET_PROC(BindFragDataLocationIndexed); - - if (glVer >= GR_GL_VER(3,0) || extensions.has("GL_ARB_vertex_array_object")) { - // no ARB suffix for GL_ARB_vertex_array_object - GR_GL_GET_PROC(BindVertexArray); - GR_GL_GET_PROC(GenVertexArrays); - GR_GL_GET_PROC(DeleteVertexArrays); - } - - // First look for GL3.0 FBO or GL_ARB_framebuffer_object (same since - // GL_ARB_framebuffer_object doesn't use ARB suffix.) - if (glVer >= GR_GL_VER(3,0) || extensions.has("GL_ARB_framebuffer_object")) { - GR_GL_GET_PROC(GenFramebuffers); - GR_GL_GET_PROC(GetFramebufferAttachmentParameteriv); - GR_GL_GET_PROC(GetRenderbufferParameteriv); - GR_GL_GET_PROC(BindFramebuffer); - GR_GL_GET_PROC(FramebufferTexture2D); - GR_GL_GET_PROC(CheckFramebufferStatus); - GR_GL_GET_PROC(DeleteFramebuffers); - GR_GL_GET_PROC(RenderbufferStorage); - GR_GL_GET_PROC(GenRenderbuffers); - GR_GL_GET_PROC(DeleteRenderbuffers); - GR_GL_GET_PROC(FramebufferRenderbuffer); - GR_GL_GET_PROC(BindRenderbuffer); - GR_GL_GET_PROC(RenderbufferStorageMultisample); - GR_GL_GET_PROC(BlitFramebuffer); - } else if (extensions.has("GL_EXT_framebuffer_object")) { - GR_GL_GET_PROC_SUFFIX(GenFramebuffers, EXT); - GR_GL_GET_PROC_SUFFIX(GetFramebufferAttachmentParameteriv, EXT); - GR_GL_GET_PROC_SUFFIX(GetRenderbufferParameteriv, EXT); - GR_GL_GET_PROC_SUFFIX(BindFramebuffer, EXT); - GR_GL_GET_PROC_SUFFIX(FramebufferTexture2D, EXT); - GR_GL_GET_PROC_SUFFIX(CheckFramebufferStatus, EXT); - GR_GL_GET_PROC_SUFFIX(DeleteFramebuffers, EXT); - GR_GL_GET_PROC_SUFFIX(RenderbufferStorage, EXT); - GR_GL_GET_PROC_SUFFIX(GenRenderbuffers, EXT); - GR_GL_GET_PROC_SUFFIX(DeleteRenderbuffers, EXT); - GR_GL_GET_PROC_SUFFIX(FramebufferRenderbuffer, EXT); - GR_GL_GET_PROC_SUFFIX(BindRenderbuffer, EXT); - if (extensions.has("GL_EXT_framebuffer_multisample")) { - GR_GL_GET_PROC_SUFFIX(RenderbufferStorageMultisample, EXT); - } - if (extensions.has("GL_EXT_framebuffer_blit")) { - GR_GL_GET_PROC_SUFFIX(BlitFramebuffer, EXT); - } - } else { - // we must have FBOs - delete interface; - return NULL; - } - - GR_GL_GET_PROC(LoadIdentity); - GR_GL_GET_PROC(LoadMatrixf); - GR_GL_GET_PROC(MatrixMode); - - if (extensions.has("GL_NV_path_rendering")) { - GR_GL_GET_PROC_SUFFIX(PathCommands, NV); - GR_GL_GET_PROC_SUFFIX(PathCoords, NV); - GR_GL_GET_PROC_SUFFIX(PathSubCommands, NV); - GR_GL_GET_PROC_SUFFIX(PathSubCoords, NV); - GR_GL_GET_PROC_SUFFIX(PathString, NV); - GR_GL_GET_PROC_SUFFIX(PathGlyphs, NV); - GR_GL_GET_PROC_SUFFIX(PathGlyphRange, NV); - GR_GL_GET_PROC_SUFFIX(WeightPaths, NV); - GR_GL_GET_PROC_SUFFIX(CopyPath, NV); - GR_GL_GET_PROC_SUFFIX(InterpolatePaths, NV); - GR_GL_GET_PROC_SUFFIX(TransformPath, NV); - GR_GL_GET_PROC_SUFFIX(PathParameteriv, NV); - GR_GL_GET_PROC_SUFFIX(PathParameteri, NV); - GR_GL_GET_PROC_SUFFIX(PathParameterfv, NV); - GR_GL_GET_PROC_SUFFIX(PathParameterf, NV); - GR_GL_GET_PROC_SUFFIX(PathDashArray, NV); - GR_GL_GET_PROC_SUFFIX(GenPaths, NV); - GR_GL_GET_PROC_SUFFIX(DeletePaths, NV); - GR_GL_GET_PROC_SUFFIX(IsPath, NV); - GR_GL_GET_PROC_SUFFIX(PathStencilFunc, NV); - GR_GL_GET_PROC_SUFFIX(PathStencilDepthOffset, NV); - GR_GL_GET_PROC_SUFFIX(StencilFillPath, NV); - GR_GL_GET_PROC_SUFFIX(StencilStrokePath, NV); - GR_GL_GET_PROC_SUFFIX(StencilFillPathInstanced, NV); - GR_GL_GET_PROC_SUFFIX(StencilStrokePathInstanced, NV); - GR_GL_GET_PROC_SUFFIX(PathCoverDepthFunc, NV); - GR_GL_GET_PROC_SUFFIX(PathColorGen, NV); - GR_GL_GET_PROC_SUFFIX(PathTexGen, NV); - GR_GL_GET_PROC_SUFFIX(PathFogGen, NV); - GR_GL_GET_PROC_SUFFIX(CoverFillPath, NV); - GR_GL_GET_PROC_SUFFIX(CoverStrokePath, NV); - GR_GL_GET_PROC_SUFFIX(CoverFillPathInstanced, NV); - GR_GL_GET_PROC_SUFFIX(CoverStrokePathInstanced, NV); - GR_GL_GET_PROC_SUFFIX(GetPathParameteriv, NV); - GR_GL_GET_PROC_SUFFIX(GetPathParameterfv, NV); - GR_GL_GET_PROC_SUFFIX(GetPathCommands, NV); - GR_GL_GET_PROC_SUFFIX(GetPathCoords, NV); - GR_GL_GET_PROC_SUFFIX(GetPathDashArray, NV); - GR_GL_GET_PROC_SUFFIX(GetPathMetrics, NV); - GR_GL_GET_PROC_SUFFIX(GetPathMetricRange, NV); - GR_GL_GET_PROC_SUFFIX(GetPathSpacing, NV); - GR_GL_GET_PROC_SUFFIX(GetPathColorGeniv, NV); - GR_GL_GET_PROC_SUFFIX(GetPathColorGenfv, NV); - GR_GL_GET_PROC_SUFFIX(GetPathTexGeniv, NV); - GR_GL_GET_PROC_SUFFIX(GetPathTexGenfv, NV); - GR_GL_GET_PROC_SUFFIX(IsPointInFillPath, NV); - GR_GL_GET_PROC_SUFFIX(IsPointInStrokePath, NV); - GR_GL_GET_PROC_SUFFIX(GetPathLength, NV); - GR_GL_GET_PROC_SUFFIX(PointAlongPath, NV); - } - - if (extensions.has("GL_EXT_debug_marker")) { - GR_GL_GET_PROC_SUFFIX(InsertEventMarker, EXT); - GR_GL_GET_PROC_SUFFIX(PushGroupMarker, EXT); - GR_GL_GET_PROC_SUFFIX(PopGroupMarker, EXT); - } - - if (glVer >= GR_GL_VER(4,3) || extensions.has("GL_ARB_invalidate_subdata")) { - GR_GL_GET_PROC(InvalidateBufferData); - GR_GL_GET_PROC(InvalidateBufferSubData); - GR_GL_GET_PROC(InvalidateFramebuffer); - GR_GL_GET_PROC(InvalidateSubFramebuffer); - GR_GL_GET_PROC(InvalidateTexImage); - GR_GL_GET_PROC(InvalidateTexSubImage); - } - - interface->fStandard = kGL_GrGLStandard; - interface->fExtensions.swap(&extensions); - - return interface; + return GrGLAssembleGLInterface(NULL, glx_get); } diff --git a/gpu/gl/win/GrGLCreateNativeInterface_win.cpp b/gpu/gl/win/GrGLCreateNativeInterface_win.cpp index 9a237825..6adaf196 100644 --- a/gpu/gl/win/GrGLCreateNativeInterface_win.cpp +++ b/gpu/gl/win/GrGLCreateNativeInterface_win.cpp @@ -7,20 +7,10 @@ */ #include "gl/GrGLInterface.h" -#include "gl/GrGLUtil.h" +#include "gl/GrGLAssembleInterface.h" #define WIN32_LEAN_AND_MEAN #include <windows.h> -/* - * Windows makes the GL funcs all be __stdcall instead of __cdecl :( - * This implementation will only work if GR_GL_FUNCTION_TYPE is __stdcall. - * Otherwise, a springboard would be needed that hides the calling convention. - */ - -#define SET_PROC(F) interface->fFunctions.f ## F = (GrGL ## F ## Proc) GetProcAddress(alu.get(), "gl" #F); -#define WGL_SET_PROC(F) interface->fFunctions.f ## F = (GrGL ## F ## Proc) wglGetProcAddress("gl" #F); -#define WGL_SET_PROC_SUFFIX(F, S) interface->fFunctions.f ## F = (GrGL ## F ## Proc) wglGetProcAddress("gl" #F #S); - class AutoLibraryUnload { public: AutoLibraryUnload(const char* moduleName) { @@ -37,288 +27,48 @@ private: HMODULE fModule; }; -const GrGLInterface* GrGLCreateNativeInterface() { - AutoLibraryUnload alu("opengl32.dll"); - if (NULL == alu.get()) { - return NULL; - } - - if (NULL != wglGetCurrentContext()) { - - // These should always be present and don't require wglGetProcAddress - GrGLGetStringProc glGetString = - (GrGLGetStringProc) GetProcAddress(alu.get(), "glGetString"); - GrGLGetIntegervProc glGetIntegerv = - (GrGLGetIntegervProc) GetProcAddress(alu.get(), "glGetIntegerv"); - if (NULL == glGetString || NULL == glGetIntegerv) { - return NULL; - } - - // This may or may not succeed depending on the gl version. - GrGLGetStringiProc glGetStringi = (GrGLGetStringiProc) wglGetProcAddress("glGetStringi"); - - GrGLExtensions extensions; - if (!extensions.init(kGL_GrGLStandard, glGetString, glGetStringi, glGetIntegerv)) { - return NULL; - } - const char* versionString = (const char*) glGetString(GR_GL_VERSION); - GrGLVersion glVer = GrGLGetVersionFromString(versionString); - - if (glVer < GR_GL_VER(1,5)) { - // We must have array and element_array buffer objects. - return NULL; - } - GrGLInterface* interface = SkNEW(GrGLInterface); - - // Functions that are part of GL 1.1 will return NULL in - // wglGetProcAddress - SET_PROC(BindTexture) - SET_PROC(BlendFunc) - - if (glVer >= GR_GL_VER(1,4) || - extensions.has("GL_ARB_imaging") || - extensions.has("GL_EXT_blend_color")) { - WGL_SET_PROC(BlendColor); - } - - SET_PROC(Clear) - SET_PROC(ClearColor) - SET_PROC(ClearStencil) - SET_PROC(ColorMask) - SET_PROC(CopyTexSubImage2D) - SET_PROC(CullFace) - SET_PROC(DeleteTextures) - SET_PROC(DepthMask) - SET_PROC(Disable) - SET_PROC(DrawArrays) - SET_PROC(DrawElements) - SET_PROC(DrawBuffer) - SET_PROC(Enable) - SET_PROC(FrontFace) - SET_PROC(Finish) - SET_PROC(Flush) - SET_PROC(GenTextures) - SET_PROC(GetError) - SET_PROC(GetIntegerv) - SET_PROC(GetString) - SET_PROC(GetTexLevelParameteriv) - SET_PROC(LineWidth) - SET_PROC(LoadIdentity) - SET_PROC(LoadMatrixf) - SET_PROC(MatrixMode) - SET_PROC(PixelStorei) - SET_PROC(ReadBuffer) - SET_PROC(ReadPixels) - SET_PROC(Scissor) - SET_PROC(StencilFunc) - SET_PROC(StencilMask) - SET_PROC(StencilOp) - SET_PROC(TexGenfv) - SET_PROC(TexGeni) - SET_PROC(TexImage2D) - SET_PROC(TexParameteri) - SET_PROC(TexParameteriv) - if (glVer >= GR_GL_VER(4,2) || extensions.has("GL_ARB_texture_storage")) { - WGL_SET_PROC(TexStorage2D); - } else if (extensions.has("GL_EXT_texture_storage")) { - WGL_SET_PROC_SUFFIX(TexStorage2D, EXT); - } - SET_PROC(TexSubImage2D) - SET_PROC(Viewport) - - WGL_SET_PROC(ActiveTexture); - WGL_SET_PROC(AttachShader); - WGL_SET_PROC(BeginQuery); - WGL_SET_PROC(BindAttribLocation); - WGL_SET_PROC(BindBuffer); - WGL_SET_PROC(BindFragDataLocation); - WGL_SET_PROC(BufferData); - WGL_SET_PROC(BufferSubData); - WGL_SET_PROC(CompileShader); - WGL_SET_PROC(CompressedTexImage2D); - WGL_SET_PROC(CreateProgram); - WGL_SET_PROC(CreateShader); - WGL_SET_PROC(DeleteBuffers); - WGL_SET_PROC(DeleteQueries); - WGL_SET_PROC(DeleteProgram); - WGL_SET_PROC(DeleteShader); - WGL_SET_PROC(DisableVertexAttribArray); - WGL_SET_PROC(DrawBuffers); - WGL_SET_PROC(EnableVertexAttribArray); - WGL_SET_PROC(EndQuery); - WGL_SET_PROC(GenBuffers); - WGL_SET_PROC(GenerateMipmap); - WGL_SET_PROC(GenQueries); - WGL_SET_PROC(GetBufferParameteriv); - WGL_SET_PROC(GetQueryiv); - WGL_SET_PROC(GetQueryObjectiv); - WGL_SET_PROC(GetQueryObjectuiv); - if (glVer > GR_GL_VER(3,3) || extensions.has("GL_ARB_timer_query")) { - WGL_SET_PROC(GetQueryObjecti64v); - WGL_SET_PROC(GetQueryObjectui64v); - WGL_SET_PROC(QueryCounter); - } else if (extensions.has("GL_EXT_timer_query")) { - WGL_SET_PROC_SUFFIX(GetQueryObjecti64v, EXT); - WGL_SET_PROC_SUFFIX(GetQueryObjectui64v, EXT); - } - WGL_SET_PROC(GetProgramInfoLog); - WGL_SET_PROC(GetProgramiv); - WGL_SET_PROC(GetShaderInfoLog); - WGL_SET_PROC(GetShaderiv); - WGL_SET_PROC(GetStringi) - WGL_SET_PROC(GetUniformLocation); - WGL_SET_PROC(LinkProgram); - WGL_SET_PROC(ShaderSource); - WGL_SET_PROC(StencilFuncSeparate); - WGL_SET_PROC(StencilMaskSeparate); - WGL_SET_PROC(StencilOpSeparate); - WGL_SET_PROC(Uniform1f); - WGL_SET_PROC(Uniform1i); - WGL_SET_PROC(Uniform1fv); - WGL_SET_PROC(Uniform1iv); - WGL_SET_PROC(Uniform2f); - WGL_SET_PROC(Uniform2i); - WGL_SET_PROC(Uniform2fv); - WGL_SET_PROC(Uniform2iv); - WGL_SET_PROC(Uniform3f); - WGL_SET_PROC(Uniform3i); - WGL_SET_PROC(Uniform3fv); - WGL_SET_PROC(Uniform3iv); - WGL_SET_PROC(Uniform4f); - WGL_SET_PROC(Uniform4i); - WGL_SET_PROC(Uniform4fv); - WGL_SET_PROC(Uniform4iv); - WGL_SET_PROC(UniformMatrix2fv); - WGL_SET_PROC(UniformMatrix3fv); - WGL_SET_PROC(UniformMatrix4fv); - WGL_SET_PROC(UseProgram); - WGL_SET_PROC(VertexAttrib4fv); - WGL_SET_PROC(VertexAttribPointer); - WGL_SET_PROC(BindFragDataLocationIndexed); +class GLProcGetter { +public: + GLProcGetter() : fGLLib("opengl32.dll") {} - if (glVer >= GR_GL_VER(3,0) || extensions.has("GL_ARB_vertex_array_object")) { - // no ARB suffix for GL_ARB_vertex_array_object - WGL_SET_PROC(BindVertexArray); - WGL_SET_PROC(DeleteVertexArrays); - WGL_SET_PROC(GenVertexArrays); - } + bool isInitialized() const { return NULL != fGLLib.get(); } - // First look for GL3.0 FBO or GL_ARB_framebuffer_object (same since - // GL_ARB_framebuffer_object doesn't use ARB suffix.) - if (glVer >= GR_GL_VER(3,0) || extensions.has("GL_ARB_framebuffer_object")) { - WGL_SET_PROC(GenFramebuffers); - WGL_SET_PROC(GetFramebufferAttachmentParameteriv); - WGL_SET_PROC(GetRenderbufferParameteriv); - WGL_SET_PROC(BindFramebuffer); - WGL_SET_PROC(FramebufferTexture2D); - WGL_SET_PROC(CheckFramebufferStatus); - WGL_SET_PROC(DeleteFramebuffers); - WGL_SET_PROC(RenderbufferStorage); - WGL_SET_PROC(GenRenderbuffers); - WGL_SET_PROC(DeleteRenderbuffers); - WGL_SET_PROC(FramebufferRenderbuffer); - WGL_SET_PROC(BindRenderbuffer); - WGL_SET_PROC(RenderbufferStorageMultisample); - WGL_SET_PROC(BlitFramebuffer); - } else if (extensions.has("GL_EXT_framebuffer_object")) { - WGL_SET_PROC_SUFFIX(GenFramebuffers, EXT); - WGL_SET_PROC_SUFFIX(GetFramebufferAttachmentParameteriv, EXT); - WGL_SET_PROC_SUFFIX(GetRenderbufferParameteriv, EXT); - WGL_SET_PROC_SUFFIX(BindFramebuffer, EXT); - WGL_SET_PROC_SUFFIX(FramebufferTexture2D, EXT); - WGL_SET_PROC_SUFFIX(CheckFramebufferStatus, EXT); - WGL_SET_PROC_SUFFIX(DeleteFramebuffers, EXT); - WGL_SET_PROC_SUFFIX(RenderbufferStorage, EXT); - WGL_SET_PROC_SUFFIX(GenRenderbuffers, EXT); - WGL_SET_PROC_SUFFIX(DeleteRenderbuffers, EXT); - WGL_SET_PROC_SUFFIX(FramebufferRenderbuffer, EXT); - WGL_SET_PROC_SUFFIX(BindRenderbuffer, EXT); - if (extensions.has("GL_EXT_framebuffer_multisample")) { - WGL_SET_PROC_SUFFIX(RenderbufferStorageMultisample, EXT); - } - if (extensions.has("GL_EXT_framebuffer_blit")) { - WGL_SET_PROC_SUFFIX(BlitFramebuffer, EXT); - } - } else { - // we must have FBOs - delete interface; - return NULL; + GrGLFuncPtr getProc(const char name[]) const { + GrGLFuncPtr proc; + if (NULL != (proc = (GrGLFuncPtr) GetProcAddress(fGLLib.get(), name))) { + return proc; } - WGL_SET_PROC(MapBuffer); - WGL_SET_PROC(UnmapBuffer); - - if (extensions.has("GL_NV_path_rendering")) { - WGL_SET_PROC_SUFFIX(PathCommands, NV); - WGL_SET_PROC_SUFFIX(PathCoords, NV); - WGL_SET_PROC_SUFFIX(PathSubCommands, NV); - WGL_SET_PROC_SUFFIX(PathSubCoords, NV); - WGL_SET_PROC_SUFFIX(PathString, NV); - WGL_SET_PROC_SUFFIX(PathGlyphs, NV); - WGL_SET_PROC_SUFFIX(PathGlyphRange, NV); - WGL_SET_PROC_SUFFIX(WeightPaths, NV); - WGL_SET_PROC_SUFFIX(CopyPath, NV); - WGL_SET_PROC_SUFFIX(InterpolatePaths, NV); - WGL_SET_PROC_SUFFIX(TransformPath, NV); - WGL_SET_PROC_SUFFIX(PathParameteriv, NV); - WGL_SET_PROC_SUFFIX(PathParameteri, NV); - WGL_SET_PROC_SUFFIX(PathParameterfv, NV); - WGL_SET_PROC_SUFFIX(PathParameterf, NV); - WGL_SET_PROC_SUFFIX(PathDashArray, NV); - WGL_SET_PROC_SUFFIX(GenPaths, NV); - WGL_SET_PROC_SUFFIX(DeletePaths, NV); - WGL_SET_PROC_SUFFIX(IsPath, NV); - WGL_SET_PROC_SUFFIX(PathStencilFunc, NV); - WGL_SET_PROC_SUFFIX(PathStencilDepthOffset, NV); - WGL_SET_PROC_SUFFIX(StencilFillPath, NV); - WGL_SET_PROC_SUFFIX(StencilStrokePath, NV); - WGL_SET_PROC_SUFFIX(StencilFillPathInstanced, NV); - WGL_SET_PROC_SUFFIX(StencilStrokePathInstanced, NV); - WGL_SET_PROC_SUFFIX(PathCoverDepthFunc, NV); - WGL_SET_PROC_SUFFIX(PathColorGen, NV); - WGL_SET_PROC_SUFFIX(PathTexGen, NV); - WGL_SET_PROC_SUFFIX(PathFogGen, NV); - WGL_SET_PROC_SUFFIX(CoverFillPath, NV); - WGL_SET_PROC_SUFFIX(CoverStrokePath, NV); - WGL_SET_PROC_SUFFIX(CoverFillPathInstanced, NV); - WGL_SET_PROC_SUFFIX(CoverStrokePathInstanced, NV); - WGL_SET_PROC_SUFFIX(GetPathParameteriv, NV); - WGL_SET_PROC_SUFFIX(GetPathParameterfv, NV); - WGL_SET_PROC_SUFFIX(GetPathCommands, NV); - WGL_SET_PROC_SUFFIX(GetPathCoords, NV); - WGL_SET_PROC_SUFFIX(GetPathDashArray, NV); - WGL_SET_PROC_SUFFIX(GetPathMetrics, NV); - WGL_SET_PROC_SUFFIX(GetPathMetricRange, NV); - WGL_SET_PROC_SUFFIX(GetPathSpacing, NV); - WGL_SET_PROC_SUFFIX(GetPathColorGeniv, NV); - WGL_SET_PROC_SUFFIX(GetPathColorGenfv, NV); - WGL_SET_PROC_SUFFIX(GetPathTexGeniv, NV); - WGL_SET_PROC_SUFFIX(GetPathTexGenfv, NV); - WGL_SET_PROC_SUFFIX(IsPointInFillPath, NV); - WGL_SET_PROC_SUFFIX(IsPointInStrokePath, NV); - WGL_SET_PROC_SUFFIX(GetPathLength, NV); - WGL_SET_PROC_SUFFIX(PointAlongPath, NV); + if (NULL != (proc = (GrGLFuncPtr) wglGetProcAddress(name))) { + return proc; } + return NULL; + } - if (extensions.has("GL_EXT_debug_marker")) { - WGL_SET_PROC_SUFFIX(InsertEventMarker, EXT); - WGL_SET_PROC_SUFFIX(PushGroupMarker, EXT); - WGL_SET_PROC_SUFFIX(PopGroupMarker, EXT); - } +private: + AutoLibraryUnload fGLLib; +}; - if (glVer >= GR_GL_VER(4,3) || extensions.has("GL_ARB_invalidate_subdata")) { - WGL_SET_PROC(InvalidateBufferData); - WGL_SET_PROC(InvalidateBufferSubData); - WGL_SET_PROC(InvalidateFramebuffer); - WGL_SET_PROC(InvalidateSubFramebuffer); - WGL_SET_PROC(InvalidateTexImage); - WGL_SET_PROC(InvalidateTexSubImage); - } +static GrGLFuncPtr win_get_gl_proc(void* ctx, const char name[]) { + SkASSERT(NULL != ctx); + SkASSERT(NULL != wglGetCurrentContext()); + const GLProcGetter* getter = (const GLProcGetter*) ctx; + return getter->getProc(name); +} - interface->fStandard = kGL_GrGLStandard; - interface->fExtensions.swap(&extensions); +/* + * Windows makes the GL funcs all be __stdcall instead of __cdecl :( + * This implementation will only work if GR_GL_FUNCTION_TYPE is __stdcall. + * Otherwise, a springboard would be needed that hides the calling convention. + */ +const GrGLInterface* GrGLCreateNativeInterface() { + if (NULL == wglGetCurrentContext()) { + return NULL; + } - return interface; - } else { + GLProcGetter getter; + if (!getter.isInitialized()) { return NULL; } + + return GrGLAssembleGLInterface(&getter, win_get_gl_proc); } diff --git a/image/SkImagePriv.cpp b/image/SkImagePriv.cpp index dada230d..538c6bb8 100644 --- a/image/SkImagePriv.cpp +++ b/image/SkImagePriv.cpp @@ -68,60 +68,3 @@ SkImage* SkNewImageFromBitmap(const SkBitmap& bm, bool canSharePixelRef) { } return image; } - -static bool needs_layer(const SkPaint& paint) { - return 0xFF != paint.getAlpha() || - paint.getColorFilter() || - paint.getImageFilter() || - SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode); -} - -void SkImagePrivDrawPicture(SkCanvas* canvas, SkPicture* picture, - SkScalar x, SkScalar y, const SkPaint* paint) { - int saveCount = canvas->getSaveCount(); - - if (paint && needs_layer(*paint)) { - SkRect bounds; - bounds.set(x, y, - x + SkIntToScalar(picture->width()), - y + SkIntToScalar(picture->height())); - canvas->saveLayer(&bounds, paint); - canvas->translate(x, y); - } else if (x || y) { - canvas->save(); - canvas->translate(x, y); - } - - canvas->drawPicture(*picture); - canvas->restoreToCount(saveCount); -} - -void SkImagePrivDrawPicture(SkCanvas* canvas, SkPicture* picture, - const SkRect* src, const SkRect& dst, const SkPaint* paint) { - int saveCount = canvas->getSaveCount(); - - SkMatrix matrix; - SkRect tmpSrc; - - if (NULL != src) { - tmpSrc = *src; - } else { - tmpSrc.set(0, 0, - SkIntToScalar(picture->width()), - SkIntToScalar(picture->height())); - } - - matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit); - if (paint && needs_layer(*paint)) { - canvas->saveLayer(&dst, paint); - } else { - canvas->save(); - } - canvas->concat(matrix); - if (!paint || !needs_layer(*paint)) { - canvas->clipRect(tmpSrc); - } - - canvas->drawPicture(*picture); - canvas->restoreToCount(saveCount); -} diff --git a/image/SkSurface_Gpu.cpp b/image/SkSurface_Gpu.cpp index 2f32d2fc..6f018bf2 100644 --- a/image/SkSurface_Gpu.cpp +++ b/image/SkSurface_Gpu.cpp @@ -110,13 +110,11 @@ SkSurface* SkSurface::NewRenderTarget(GrContext* ctx, const SkImageInfo& info, i return NULL; } - SkBitmap::Config config = SkImageInfoToBitmapConfig(info); - GrTextureDesc desc; desc.fFlags = kRenderTarget_GrTextureFlagBit | kCheckAllocation_GrTextureFlagBit; - desc.fWidth = info.fWidth; - desc.fHeight = info.fHeight; - desc.fConfig = SkBitmapConfig2GrPixelConfig(config); + desc.fWidth = info.width(); + desc.fHeight = info.height(); + desc.fConfig = SkImageInfo2GrPixelConfig(info); desc.fSampleCnt = sampleCount; SkAutoTUnref<GrTexture> tex(ctx->createUncachedTexture(desc, NULL, 0)); @@ -132,13 +130,11 @@ SkSurface* SkSurface::NewScratchRenderTarget(GrContext* ctx, const SkImageInfo& return NULL; } - SkBitmap::Config config = SkImageInfoToBitmapConfig(info); - GrTextureDesc desc; desc.fFlags = kRenderTarget_GrTextureFlagBit | kCheckAllocation_GrTextureFlagBit; - desc.fWidth = info.fWidth; - desc.fHeight = info.fHeight; - desc.fConfig = SkBitmapConfig2GrPixelConfig(config); + desc.fWidth = info.width(); + desc.fHeight = info.height(); + desc.fConfig = SkImageInfo2GrPixelConfig(info); desc.fSampleCnt = sampleCount; SkAutoTUnref<GrTexture> tex(ctx->lockAndRefScratchTexture(desc, GrContext::kExact_ScratchTexMatch)); diff --git a/images/SkImageDecoder_libwebp.cpp b/images/SkImageDecoder_libwebp.cpp index 49d5bd1c..02990258 100644 --- a/images/SkImageDecoder_libwebp.cpp +++ b/images/SkImageDecoder_libwebp.cpp @@ -298,8 +298,20 @@ bool SkWEBPImageDecoder::setDecodeConfig(SkBitmap* decodedBitmap, return false; } - return decodedBitmap->setConfig(config, width, height, 0, - fHasAlpha ? kPremul_SkAlphaType : kOpaque_SkAlphaType); + SkImageInfo info; + info.fWidth = width; + info.fHeight = height; + info.fColorType = SkBitmapConfigToColorType(config); + if (SkToBool(fHasAlpha)) { + if (this->getRequireUnpremultipliedColors()) { + info.fAlphaType = kUnpremul_SkAlphaType; + } else { + info.fAlphaType = kPremul_SkAlphaType; + } + } else { + info.fAlphaType = kOpaque_SkAlphaType; + } + return decodedBitmap->setConfig(info); } bool SkWEBPImageDecoder::onBuildTileIndex(SkStreamRewindable* stream, diff --git a/opts/SkBitmapProcState_opts_SSE2.cpp b/opts/SkBitmapProcState_opts_SSE2.cpp index 0b079977..54a2f2da 100644 --- a/opts/SkBitmapProcState_opts_SSE2.cpp +++ b/opts/SkBitmapProcState_opts_SSE2.cpp @@ -9,6 +9,7 @@ #include <emmintrin.h> #include "SkBitmapProcState_opts_SSE2.h" +#include "SkColorPriv.h" #include "SkPaint.h" #include "SkUtils.h" @@ -639,8 +640,8 @@ void ClampX_ClampY_nofilter_affine_SSE2(const SkBitmapProcState& s, * It combines S32_opaque_D32_filter_DX_SSE2 and SkPixel32ToPixel16 */ void S32_D16_filter_DX_SSE2(const SkBitmapProcState& s, - const uint32_t* xy, - int count, uint16_t* colors) { + const uint32_t* xy, + int count, uint16_t* colors) { SkASSERT(count > 0 && colors != NULL); SkASSERT(s.fFilterLevel != SkPaint::kNone_FilterLevel); SkASSERT(s.fBitmap->config() == SkBitmap::kARGB_8888_Config); @@ -744,23 +745,6 @@ void S32_D16_filter_DX_SSE2(const SkBitmapProcState& s, // Extract low int and store. dstColor = _mm_cvtsi128_si32(sum); - //*colors++ = SkPixel32ToPixel16(dstColor); - // below is much faster than the above. It's tested for Android benchmark--Softweg - __m128i _m_temp1 = _mm_set1_epi32(dstColor); - __m128i _m_temp2 = _mm_srli_epi32(_m_temp1, 3); - - unsigned int r32 = _mm_cvtsi128_si32(_m_temp2); - unsigned r = (r32 & ((1<<5) -1)) << 11; - - _m_temp2 = _mm_srli_epi32(_m_temp2, 7); - unsigned int g32 = _mm_cvtsi128_si32(_m_temp2); - unsigned g = (g32 & ((1<<6) -1)) << 5; - - _m_temp2 = _mm_srli_epi32(_m_temp2, 9); - unsigned int b32 = _mm_cvtsi128_si32(_m_temp2); - unsigned b = (b32 & ((1<<5) -1)); - - *colors++ = r | g | b; - + *colors++ = SkPixel32ToPixel16(dstColor); } while (--count > 0); } diff --git a/opts/SkBlitRow_opts_arm.cpp b/opts/SkBlitRow_opts_arm.cpp index c334e495..34b85647 100644 --- a/opts/SkBlitRow_opts_arm.cpp +++ b/opts/SkBlitRow_opts_arm.cpp @@ -12,8 +12,6 @@ #include "SkUtils.h" #include "SkUtilsArm.h" -#include "SkCachePreload_arm.h" - // Define USE_NEON_CODE to indicate that we need to build NEON routines #define USE_NEON_CODE (!SK_ARM_NEON_IS_NONE) diff --git a/opts/SkBlitRow_opts_arm_neon.cpp b/opts/SkBlitRow_opts_arm_neon.cpp index 950e4f71..f6fd0638 100644 --- a/opts/SkBlitRow_opts_arm_neon.cpp +++ b/opts/SkBlitRow_opts_arm_neon.cpp @@ -14,7 +14,6 @@ #include "SkMathPriv.h" #include "SkUtils.h" -#include "SkCachePreload_arm.h" #include "SkColor_opts_neon.h" #include <arm_neon.h> @@ -1384,84 +1383,88 @@ void Color32_arm_neon(SkPMColor* dst, const SkPMColor* src, int count, unsigned colorA = SkGetPackedA32(color); if (255 == colorA) { sk_memset32(dst, color, count); - } else { - unsigned scale = 256 - SkAlpha255To256(colorA); + return; + } - if (count >= 8) { - // at the end of this assembly, count will have been decremented - // to a negative value. That is, if count mod 8 = x, it will be - // -8 +x coming out. - asm volatile ( - PLD128(src, 0) - - "vdup.32 q0, %[color] \n\t" - - PLD128(src, 128) - - // scale numerical interval [0-255], so load as 8 bits - "vdup.8 d2, %[scale] \n\t" - - PLD128(src, 256) - - "subs %[count], %[count], #8 \n\t" - - PLD128(src, 384) - - "Loop_Color32: \n\t" - - // load src color, 8 pixels, 4 64 bit registers - // (and increment src). - "vld1.32 {d4-d7}, [%[src]]! \n\t" - - PLD128(src, 384) - - // multiply long by scale, 64 bits at a time, - // destination into a 128 bit register. - "vmull.u8 q4, d4, d2 \n\t" - "vmull.u8 q5, d5, d2 \n\t" - "vmull.u8 q6, d6, d2 \n\t" - "vmull.u8 q7, d7, d2 \n\t" - - // shift the 128 bit registers, containing the 16 - // bit scaled values back to 8 bits, narrowing the - // results to 64 bit registers. - "vshrn.i16 d8, q4, #8 \n\t" - "vshrn.i16 d9, q5, #8 \n\t" - "vshrn.i16 d10, q6, #8 \n\t" - "vshrn.i16 d11, q7, #8 \n\t" - - // adding back the color, using 128 bit registers. - "vadd.i8 q6, q4, q0 \n\t" - "vadd.i8 q7, q5, q0 \n\t" - - // store back the 8 calculated pixels (2 128 bit - // registers), and increment dst. - "vst1.32 {d12-d15}, [%[dst]]! \n\t" - - "subs %[count], %[count], #8 \n\t" - "bge Loop_Color32 \n\t" - : [src] "+r" (src), [dst] "+r" (dst), [count] "+r" (count) - : [color] "r" (color), [scale] "r" (scale) - : "cc", "memory", - "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", - "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15" - ); - // At this point, if we went through the inline assembly, count is - // a negative value: - // if the value is -8, there is no pixel left to process. - // if the value is -7, there is one pixel left to process - // ... - // And'ing it with 7 will give us the number of pixels - // left to process. - count = count & 0x7; - } + unsigned scale = 256 - SkAlpha255To256(colorA); - while (count > 0) { - *dst = color + SkAlphaMulQ(*src, scale); - src += 1; - dst += 1; - count--; - } + if (count >= 8) { + uint32x4_t vcolor; + uint8x8_t vscale; + + vcolor = vdupq_n_u32(color); + + // scale numerical interval [0-255], so load as 8 bits + vscale = vdup_n_u8(scale); + + do { + // load src color, 8 pixels, 4 64 bit registers + // (and increment src). + uint32x2x4_t vsrc; +#if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 6)) + asm ( + "vld1.32 %h[vsrc], [%[src]]!" + : [vsrc] "=w" (vsrc), [src] "+r" (src) + : : + ); +#else // (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 6)) + vsrc.val[0] = vld1_u32(src); + vsrc.val[1] = vld1_u32(src+2); + vsrc.val[2] = vld1_u32(src+4); + vsrc.val[3] = vld1_u32(src+6); + src += 8; +#endif + + // multiply long by scale, 64 bits at a time, + // destination into a 128 bit register. + uint16x8x4_t vtmp; + vtmp.val[0] = vmull_u8(vreinterpret_u8_u32(vsrc.val[0]), vscale); + vtmp.val[1] = vmull_u8(vreinterpret_u8_u32(vsrc.val[1]), vscale); + vtmp.val[2] = vmull_u8(vreinterpret_u8_u32(vsrc.val[2]), vscale); + vtmp.val[3] = vmull_u8(vreinterpret_u8_u32(vsrc.val[3]), vscale); + + // shift the 128 bit registers, containing the 16 + // bit scaled values back to 8 bits, narrowing the + // results to 64 bit registers. + uint8x16x2_t vres; + vres.val[0] = vcombine_u8( + vshrn_n_u16(vtmp.val[0], 8), + vshrn_n_u16(vtmp.val[1], 8)); + vres.val[1] = vcombine_u8( + vshrn_n_u16(vtmp.val[2], 8), + vshrn_n_u16(vtmp.val[3], 8)); + + // adding back the color, using 128 bit registers. + uint32x4x2_t vdst; + vdst.val[0] = vreinterpretq_u32_u8(vres.val[0] + + vreinterpretq_u8_u32(vcolor)); + vdst.val[1] = vreinterpretq_u32_u8(vres.val[1] + + vreinterpretq_u8_u32(vcolor)); + + // store back the 8 calculated pixels (2 128 bit + // registers), and increment dst. +#if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 6)) + asm ( + "vst1.32 %h[vdst], [%[dst]]!" + : [dst] "+r" (dst) + : [vdst] "w" (vdst) + : "memory" + ); +#else // (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 6)) + vst1q_u32(dst, vdst.val[0]); + vst1q_u32(dst+4, vdst.val[1]); + dst += 8; +#endif + count -= 8; + + } while (count >= 8); + } + + while (count > 0) { + *dst = color + SkAlphaMulQ(*src, scale); + src += 1; + dst += 1; + count--; } } diff --git a/opts/SkCachePreload_arm.h b/opts/SkCachePreload_arm.h deleted file mode 100644 index cff8c2a9..00000000 --- a/opts/SkCachePreload_arm.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2012 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ -#ifndef SkCachePreload_arm_DEFINED -#define SkCachePreload_arm_DEFINED - -// This file defines macros for preload instructions for ARM. These macros -// are designed to be embedded inside GNU inline assembly. -// For the use of these macros, __ARM_USE_PLD needs to be enabled. The cache -// line size also needs to be known (and needs to be contained inside -// __ARM_CACHE_LINE_SIZE). -#if defined(__ARM_USE_PLD) - -#define PLD(x, n) "pld [%["#x"], #("#n")]\n\t" - -#if __ARM_CACHE_LINE_SIZE == 32 - #define PLD64(x, n) PLD(x, n) PLD(x, (n) + 32) -#elif __ARM_CACHE_LINE_SIZE == 64 - #define PLD64(x, n) PLD(x, n) -#else - #error "unknown __ARM_CACHE_LINE_SIZE." -#endif -#else - // PLD is disabled, all macros become empty. - #define PLD(x, n) - #define PLD64(x, n) -#endif - -#define PLD128(x, n) PLD64(x, n) PLD64(x, (n) + 64) - -#endif // SkCachePreload_arm_DEFINED diff --git a/opts/SkColor_opts_SSE2.h b/opts/SkColor_opts_SSE2.h index 960c48a0..b06fe1a7 100644 --- a/opts/SkColor_opts_SSE2.h +++ b/opts/SkColor_opts_SSE2.h @@ -10,6 +10,21 @@ #include <emmintrin.h> +// Because no _mm_mul_epi32() in SSE2, we emulate it here. +// Multiplies 4 32-bit integers from a by 4 32-bit intergers from b. +// The 4 multiplication results should be represented within 32-bit +// integers, otherwise they would be overflow. +static inline __m128i Multiply32_SSE2(const __m128i& a, const __m128i& b) { + // Calculate results of a0 * b0 and a2 * b2. + __m128i r1 = _mm_mul_epu32(a, b); + // Calculate results of a1 * b1 and a3 * b3. + __m128i r2 = _mm_mul_epu32(_mm_srli_si128(a, 4), _mm_srli_si128(b, 4)); + // Shuffle results to [63..0] and interleave the results. + __m128i r = _mm_unpacklo_epi32(_mm_shuffle_epi32(r1, _MM_SHUFFLE(0,0,2,0)), + _mm_shuffle_epi32(r2, _MM_SHUFFLE(0,0,2,0))); + return r; +} + static inline __m128i SkAlpha255To256_SSE2(const __m128i& alpha) { return _mm_add_epi32(alpha, _mm_set1_epi32(1)); } diff --git a/opts/SkMath_opts_SSE2.h b/opts/SkMath_opts_SSE2.h new file mode 100644 index 00000000..2cc21afa --- /dev/null +++ b/opts/SkMath_opts_SSE2.h @@ -0,0 +1,51 @@ +/* + * Copyright 2014 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkMath_opts_SSE2_DEFINED +#define SkMath_opts_SSE2_DEFINED + +#include <emmintrin.h> + +// Because no _mm_div_epi32() in SSE2, we use float division to emulate. +// When using this function, make sure a and b don't exceed float's precision. +static inline __m128i shim_mm_div_epi32(const __m128i& a, const __m128i& b) { + __m128 x = _mm_cvtepi32_ps(a); + __m128 y = _mm_cvtepi32_ps(b); + return _mm_cvttps_epi32(_mm_div_ps(x, y)); +} + +// Portable version of SkSqrtBits is in SkMath.cpp. +static inline __m128i SkSqrtBits_SSE2(const __m128i& x, int count) { + __m128i root = _mm_setzero_si128(); + __m128i remHi = _mm_setzero_si128(); + __m128i remLo = x; + __m128i one128 = _mm_set1_epi32(1); + + do { + root = _mm_slli_epi32(root, 1); + + remHi = _mm_or_si128(_mm_slli_epi32(remHi, 2), + _mm_srli_epi32(remLo, 30)); + remLo = _mm_slli_epi32(remLo, 2); + + __m128i testDiv = _mm_slli_epi32(root, 1); + testDiv = _mm_add_epi32(testDiv, _mm_set1_epi32(1)); + + __m128i cmp = _mm_cmplt_epi32(remHi, testDiv); + __m128i remHi1 = _mm_and_si128(cmp, remHi); + __m128i root1 = _mm_and_si128(cmp, root); + __m128i remHi2 = _mm_andnot_si128(cmp, _mm_sub_epi32(remHi, testDiv)); + __m128i root2 = _mm_andnot_si128(cmp, _mm_add_epi32(root, one128)); + + remHi = _mm_or_si128(remHi1, remHi2); + root = _mm_or_si128(root1, root2); + } while (--count >= 0); + + return root; +} + +#endif // SkMath_opts_SSE2_DEFINED diff --git a/opts/SkXfermode_opts_SSE2.cpp b/opts/SkXfermode_opts_SSE2.cpp index d1a2632f..4e4532b7 100644 --- a/opts/SkXfermode_opts_SSE2.cpp +++ b/opts/SkXfermode_opts_SSE2.cpp @@ -1,6 +1,7 @@ #include "SkColorPriv.h" #include "SkColor_opts_SSE2.h" #include "SkMathPriv.h" +#include "SkMath_opts_SSE2.h" #include "SkXfermode.h" #include "SkXfermode_opts_SSE2.h" #include "SkXfermode_proccoeff.h" @@ -26,6 +27,17 @@ static inline __m128i saturated_add_SSE2(const __m128i& a, const __m128i& b) { return sum; } +static inline __m128i clamp_signed_byte_SSE2(const __m128i& n) { + __m128i cmp1 = _mm_cmplt_epi32(n, _mm_setzero_si128()); + __m128i cmp2 = _mm_cmpgt_epi32(n, _mm_set1_epi32(255)); + __m128i ret = _mm_and_si128(cmp2, _mm_set1_epi32(255)); + + __m128i cmp = _mm_or_si128(cmp1, cmp2); + ret = _mm_or_si128(_mm_and_si128(cmp, ret), _mm_andnot_si128(cmp, n)); + + return ret; +} + static inline __m128i clamp_div255round_SSE2(const __m128i& prod) { // test if > 0 __m128i cmp1 = _mm_cmpgt_epi32(prod, _mm_setzero_si128()); @@ -171,6 +183,11 @@ static __m128i modulate_modeproc_SSE2(const __m128i& src, const __m128i& dst) { return SkPackARGB32_SSE2(a, r, g, b); } +static inline __m128i SkMin32_SSE2(const __m128i& a, const __m128i& b) { + __m128i cmp = _mm_cmplt_epi32(a, b); + return _mm_or_si128(_mm_and_si128(cmp, a), _mm_andnot_si128(cmp, b)); +} + static inline __m128i srcover_byte_SSE2(const __m128i& a, const __m128i& b) { // a + b - SkAlphaMulAlpha(a, b); return _mm_sub_epi32(_mm_add_epi32(a, b), SkAlphaMulAlpha_SSE2(a, b)); @@ -229,6 +246,388 @@ static __m128i screen_modeproc_SSE2(const __m128i& src, const __m128i& dst) { return SkPackARGB32_SSE2(a, r, g, b); } +// Portable version overlay_byte() is in SkXfermode.cpp. +static inline __m128i overlay_byte_SSE2(const __m128i& sc, const __m128i& dc, + const __m128i& sa, const __m128i& da) { + __m128i ida = _mm_sub_epi32(_mm_set1_epi32(255), da); + __m128i tmp1 = _mm_mullo_epi16(sc, ida); + __m128i isa = _mm_sub_epi32(_mm_set1_epi32(255), sa); + __m128i tmp2 = _mm_mullo_epi16(dc, isa); + __m128i tmp = _mm_add_epi32(tmp1, tmp2); + + __m128i cmp = _mm_cmpgt_epi32(_mm_slli_epi32(dc, 1), da); + __m128i rc1 = _mm_slli_epi32(sc, 1); // 2 * sc + rc1 = Multiply32_SSE2(rc1, dc); // *dc + + __m128i rc2 = _mm_mullo_epi16(sa, da); // sa * da + __m128i tmp3 = _mm_slli_epi32(_mm_sub_epi32(da, dc), 1); // 2 * (da - dc) + tmp3 = Multiply32_SSE2(tmp3, _mm_sub_epi32(sa, sc)); // * (sa - sc) + rc2 = _mm_sub_epi32(rc2, tmp3); + + __m128i rc = _mm_or_si128(_mm_andnot_si128(cmp, rc1), + _mm_and_si128(cmp, rc2)); + return clamp_div255round_SSE2(_mm_add_epi32(rc, tmp)); +} + +static __m128i overlay_modeproc_SSE2(const __m128i& src, const __m128i& dst) { + __m128i sa = SkGetPackedA32_SSE2(src); + __m128i da = SkGetPackedA32_SSE2(dst); + + __m128i a = srcover_byte_SSE2(sa, da); + __m128i r = overlay_byte_SSE2(SkGetPackedR32_SSE2(src), + SkGetPackedR32_SSE2(dst), sa, da); + __m128i g = overlay_byte_SSE2(SkGetPackedG32_SSE2(src), + SkGetPackedG32_SSE2(dst), sa, da); + __m128i b = overlay_byte_SSE2(SkGetPackedB32_SSE2(src), + SkGetPackedB32_SSE2(dst), sa, da); + return SkPackARGB32_SSE2(a, r, g, b); +} + +static inline __m128i darken_byte_SSE2(const __m128i& sc, const __m128i& dc, + const __m128i& sa, const __m128i& da) { + __m128i sd = _mm_mullo_epi16(sc, da); + __m128i ds = _mm_mullo_epi16(dc, sa); + + __m128i cmp = _mm_cmplt_epi32(sd, ds); + + __m128i tmp = _mm_add_epi32(sc, dc); + __m128i ret1 = _mm_sub_epi32(tmp, SkDiv255Round_SSE2(ds)); + __m128i ret2 = _mm_sub_epi32(tmp, SkDiv255Round_SSE2(sd)); + __m128i ret = _mm_or_si128(_mm_and_si128(cmp, ret1), + _mm_andnot_si128(cmp, ret2)); + return ret; +} + +static __m128i darken_modeproc_SSE2(const __m128i& src, const __m128i& dst) { + __m128i sa = SkGetPackedA32_SSE2(src); + __m128i da = SkGetPackedA32_SSE2(dst); + + __m128i a = srcover_byte_SSE2(sa, da); + __m128i r = darken_byte_SSE2(SkGetPackedR32_SSE2(src), + SkGetPackedR32_SSE2(dst), sa, da); + __m128i g = darken_byte_SSE2(SkGetPackedG32_SSE2(src), + SkGetPackedG32_SSE2(dst), sa, da); + __m128i b = darken_byte_SSE2(SkGetPackedB32_SSE2(src), + SkGetPackedB32_SSE2(dst), sa, da); + return SkPackARGB32_SSE2(a, r, g, b); +} + +static inline __m128i lighten_byte_SSE2(const __m128i& sc, const __m128i& dc, + const __m128i& sa, const __m128i& da) { + __m128i sd = _mm_mullo_epi16(sc, da); + __m128i ds = _mm_mullo_epi16(dc, sa); + + __m128i cmp = _mm_cmpgt_epi32(sd, ds); + + __m128i tmp = _mm_add_epi32(sc, dc); + __m128i ret1 = _mm_sub_epi32(tmp, SkDiv255Round_SSE2(ds)); + __m128i ret2 = _mm_sub_epi32(tmp, SkDiv255Round_SSE2(sd)); + __m128i ret = _mm_or_si128(_mm_and_si128(cmp, ret1), + _mm_andnot_si128(cmp, ret2)); + return ret; +} + +static __m128i lighten_modeproc_SSE2(const __m128i& src, const __m128i& dst) { + __m128i sa = SkGetPackedA32_SSE2(src); + __m128i da = SkGetPackedA32_SSE2(dst); + + __m128i a = srcover_byte_SSE2(sa, da); + __m128i r = lighten_byte_SSE2(SkGetPackedR32_SSE2(src), + SkGetPackedR32_SSE2(dst), sa, da); + __m128i g = lighten_byte_SSE2(SkGetPackedG32_SSE2(src), + SkGetPackedG32_SSE2(dst), sa, da); + __m128i b = lighten_byte_SSE2(SkGetPackedB32_SSE2(src), + SkGetPackedB32_SSE2(dst), sa, da); + return SkPackARGB32_SSE2(a, r, g, b); +} + +static inline __m128i colordodge_byte_SSE2(const __m128i& sc, const __m128i& dc, + const __m128i& sa, const __m128i& da) { + __m128i diff = _mm_sub_epi32(sa, sc); + __m128i ida = _mm_sub_epi32(_mm_set1_epi32(255), da); + __m128i isa = _mm_sub_epi32(_mm_set1_epi32(255), sa); + + // if (0 == dc) + __m128i cmp1 = _mm_cmpeq_epi32(dc, _mm_setzero_si128()); + __m128i rc1 = _mm_and_si128(cmp1, SkAlphaMulAlpha_SSE2(sc, ida)); + + // else if (0 == diff) + __m128i cmp2 = _mm_cmpeq_epi32(diff, _mm_setzero_si128()); + __m128i cmp = _mm_andnot_si128(cmp1, cmp2); + __m128i tmp1 = _mm_mullo_epi16(sa, da); + __m128i tmp2 = _mm_mullo_epi16(sc, ida); + __m128i tmp3 = _mm_mullo_epi16(dc, isa); + __m128i rc2 = _mm_add_epi32(tmp1, tmp2); + rc2 = _mm_add_epi32(rc2, tmp3); + rc2 = clamp_div255round_SSE2(rc2); + rc2 = _mm_and_si128(cmp, rc2); + + // else + __m128i cmp3 = _mm_or_si128(cmp1, cmp2); + __m128i value = _mm_mullo_epi16(dc, sa); + diff = shim_mm_div_epi32(value, diff); + + __m128i tmp4 = SkMin32_SSE2(da, diff); + tmp4 = Multiply32_SSE2(sa, tmp4); + __m128i rc3 = _mm_add_epi32(tmp4, tmp2); + rc3 = _mm_add_epi32(rc3, tmp3); + rc3 = clamp_div255round_SSE2(rc3); + rc3 = _mm_andnot_si128(cmp3, rc3); + + __m128i rc = _mm_or_si128(rc1, rc2); + rc = _mm_or_si128(rc, rc3); + + return rc; +} + +static __m128i colordodge_modeproc_SSE2(const __m128i& src, + const __m128i& dst) { + __m128i sa = SkGetPackedA32_SSE2(src); + __m128i da = SkGetPackedA32_SSE2(dst); + + __m128i a = srcover_byte_SSE2(sa, da); + __m128i r = colordodge_byte_SSE2(SkGetPackedR32_SSE2(src), + SkGetPackedR32_SSE2(dst), sa, da); + __m128i g = colordodge_byte_SSE2(SkGetPackedG32_SSE2(src), + SkGetPackedG32_SSE2(dst), sa, da); + __m128i b = colordodge_byte_SSE2(SkGetPackedB32_SSE2(src), + SkGetPackedB32_SSE2(dst), sa, da); + return SkPackARGB32_SSE2(a, r, g, b); +} + +static inline __m128i colorburn_byte_SSE2(const __m128i& sc, const __m128i& dc, + const __m128i& sa, const __m128i& da) { + __m128i ida = _mm_sub_epi32(_mm_set1_epi32(255), da); + __m128i isa = _mm_sub_epi32(_mm_set1_epi32(255), sa); + + // if (dc == da) + __m128i cmp1 = _mm_cmpeq_epi32(dc, da); + __m128i tmp1 = _mm_mullo_epi16(sa, da); + __m128i tmp2 = _mm_mullo_epi16(sc, ida); + __m128i tmp3 = _mm_mullo_epi16(dc, isa); + __m128i rc1 = _mm_add_epi32(tmp1, tmp2); + rc1 = _mm_add_epi32(rc1, tmp3); + rc1 = clamp_div255round_SSE2(rc1); + rc1 = _mm_and_si128(cmp1, rc1); + + // else if (0 == sc) + __m128i cmp2 = _mm_cmpeq_epi32(sc, _mm_setzero_si128()); + __m128i rc2 = SkAlphaMulAlpha_SSE2(dc, isa); + __m128i cmp = _mm_andnot_si128(cmp1, cmp2); + rc2 = _mm_and_si128(cmp, rc2); + + // else + __m128i cmp3 = _mm_or_si128(cmp1, cmp2); + __m128i tmp4 = _mm_sub_epi32(da, dc); + tmp4 = Multiply32_SSE2(tmp4, sa); + tmp4 = shim_mm_div_epi32(tmp4, sc); + + __m128i tmp5 = _mm_sub_epi32(da, SkMin32_SSE2(da, tmp4)); + tmp5 = Multiply32_SSE2(sa, tmp5); + __m128i rc3 = _mm_add_epi32(tmp5, tmp2); + rc3 = _mm_add_epi32(rc3, tmp3); + rc3 = clamp_div255round_SSE2(rc3); + rc3 = _mm_andnot_si128(cmp3, rc3); + + __m128i rc = _mm_or_si128(rc1, rc2); + rc = _mm_or_si128(rc, rc3); + + return rc; +} + +static __m128i colorburn_modeproc_SSE2(const __m128i& src, const __m128i& dst) { + __m128i sa = SkGetPackedA32_SSE2(src); + __m128i da = SkGetPackedA32_SSE2(dst); + + __m128i a = srcover_byte_SSE2(sa, da); + __m128i r = colorburn_byte_SSE2(SkGetPackedR32_SSE2(src), + SkGetPackedR32_SSE2(dst), sa, da); + __m128i g = colorburn_byte_SSE2(SkGetPackedG32_SSE2(src), + SkGetPackedG32_SSE2(dst), sa, da); + __m128i b = colorburn_byte_SSE2(SkGetPackedB32_SSE2(src), + SkGetPackedB32_SSE2(dst), sa, da); + return SkPackARGB32_SSE2(a, r, g, b); +} + +static inline __m128i hardlight_byte_SSE2(const __m128i& sc, const __m128i& dc, + const __m128i& sa, const __m128i& da) { + // if (2 * sc <= sa) + __m128i tmp1 = _mm_slli_epi32(sc, 1); + __m128i cmp1 = _mm_cmpgt_epi32(tmp1, sa); + __m128i rc1 = _mm_mullo_epi16(sc, dc); // sc * dc; + rc1 = _mm_slli_epi32(rc1, 1); // 2 * sc * dc + rc1 = _mm_andnot_si128(cmp1, rc1); + + // else + tmp1 = _mm_mullo_epi16(sa, da); + __m128i tmp2 = Multiply32_SSE2(_mm_sub_epi32(da, dc), + _mm_sub_epi32(sa, sc)); + tmp2 = _mm_slli_epi32(tmp2, 1); + __m128i rc2 = _mm_sub_epi32(tmp1, tmp2); + rc2 = _mm_and_si128(cmp1, rc2); + + __m128i rc = _mm_or_si128(rc1, rc2); + + __m128i ida = _mm_sub_epi32(_mm_set1_epi32(255), da); + tmp1 = _mm_mullo_epi16(sc, ida); + __m128i isa = _mm_sub_epi32(_mm_set1_epi32(255), sa); + tmp2 = _mm_mullo_epi16(dc, isa); + rc = _mm_add_epi32(rc, tmp1); + rc = _mm_add_epi32(rc, tmp2); + return clamp_div255round_SSE2(rc); +} + +static __m128i hardlight_modeproc_SSE2(const __m128i& src, const __m128i& dst) { + __m128i sa = SkGetPackedA32_SSE2(src); + __m128i da = SkGetPackedA32_SSE2(dst); + + __m128i a = srcover_byte_SSE2(sa, da); + __m128i r = hardlight_byte_SSE2(SkGetPackedR32_SSE2(src), + SkGetPackedR32_SSE2(dst), sa, da); + __m128i g = hardlight_byte_SSE2(SkGetPackedG32_SSE2(src), + SkGetPackedG32_SSE2(dst), sa, da); + __m128i b = hardlight_byte_SSE2(SkGetPackedB32_SSE2(src), + SkGetPackedB32_SSE2(dst), sa, da); + return SkPackARGB32_SSE2(a, r, g, b); +} + +static __m128i sqrt_unit_byte_SSE2(const __m128i& n) { + return SkSqrtBits_SSE2(n, 15+4); +} + +static inline __m128i softlight_byte_SSE2(const __m128i& sc, const __m128i& dc, + const __m128i& sa, const __m128i& da) { + __m128i tmp1, tmp2, tmp3; + + // int m = da ? dc * 256 / da : 0; + __m128i cmp = _mm_cmpeq_epi32(da, _mm_setzero_si128()); + __m128i m = _mm_slli_epi32(dc, 8); + __m128 x = _mm_cvtepi32_ps(m); + __m128 y = _mm_cvtepi32_ps(da); + m = _mm_cvttps_epi32(_mm_div_ps(x, y)); + m = _mm_andnot_si128(cmp, m); + + // if (2 * sc <= sa) + tmp1 = _mm_slli_epi32(sc, 1); // 2 * sc + __m128i cmp1 = _mm_cmpgt_epi32(tmp1, sa); + tmp1 = _mm_sub_epi32(tmp1, sa); // 2 * sc - sa + tmp2 = _mm_sub_epi32(_mm_set1_epi32(256), m); // 256 - m + tmp1 = Multiply32_SSE2(tmp1, tmp2); + tmp1 = _mm_srai_epi32(tmp1, 8); + tmp1 = _mm_add_epi32(sa, tmp1); + tmp1 = Multiply32_SSE2(dc, tmp1); + __m128i rc1 = _mm_andnot_si128(cmp1, tmp1); + + // else if (4 * dc <= da) + tmp2 = _mm_slli_epi32(dc, 2); // dc * 4 + __m128i cmp2 = _mm_cmpgt_epi32(tmp2, da); + __m128i i = _mm_slli_epi32(m, 2); // 4 * m + __m128i j = _mm_add_epi32(i, _mm_set1_epi32(256)); // 4 * m + 256 + __m128i k = Multiply32_SSE2(i, j); // 4 * m * (4 * m + 256) + __m128i t = _mm_sub_epi32(m, _mm_set1_epi32(256)); // m - 256 + i = Multiply32_SSE2(k, t); // 4 * m * (4 * m + 256) * (m - 256) + i = _mm_srai_epi32(i, 16); // >> 16 + j = Multiply32_SSE2(_mm_set1_epi32(7), m); // 7 * m + tmp2 = _mm_add_epi32(i, j); + i = Multiply32_SSE2(dc, sa); // dc * sa + j = _mm_slli_epi32(sc, 1); // 2 * sc + j = _mm_sub_epi32(j, sa); // 2 * sc - sa + j = Multiply32_SSE2(da, j); // da * (2 * sc - sa) + tmp2 = Multiply32_SSE2(j, tmp2); // * tmp + tmp2 = _mm_srai_epi32(tmp2, 8); // >> 8 + tmp2 = _mm_add_epi32(i, tmp2); + cmp = _mm_andnot_si128(cmp2, cmp1); + __m128i rc2 = _mm_and_si128(cmp, tmp2); + __m128i rc = _mm_or_si128(rc1, rc2); + + // else + tmp3 = sqrt_unit_byte_SSE2(m); + tmp3 = _mm_sub_epi32(tmp3, m); + tmp3 = Multiply32_SSE2(j, tmp3); // j = da * (2 * sc - sa) + tmp3 = _mm_srai_epi32(tmp3, 8); + tmp3 = _mm_add_epi32(i, tmp3); // i = dc * sa + cmp = _mm_and_si128(cmp1, cmp2); + __m128i rc3 = _mm_and_si128(cmp, tmp3); + rc = _mm_or_si128(rc, rc3); + + tmp1 = _mm_sub_epi32(_mm_set1_epi32(255), da); // 255 - da + tmp1 = _mm_mullo_epi16(sc, tmp1); + tmp2 = _mm_sub_epi32(_mm_set1_epi32(255), sa); // 255 - sa + tmp2 = _mm_mullo_epi16(dc, tmp2); + rc = _mm_add_epi32(rc, tmp1); + rc = _mm_add_epi32(rc, tmp2); + return clamp_div255round_SSE2(rc); +} + +static __m128i softlight_modeproc_SSE2(const __m128i& src, const __m128i& dst) { + __m128i sa = SkGetPackedA32_SSE2(src); + __m128i da = SkGetPackedA32_SSE2(dst); + + __m128i a = srcover_byte_SSE2(sa, da); + __m128i r = softlight_byte_SSE2(SkGetPackedR32_SSE2(src), + SkGetPackedR32_SSE2(dst), sa, da); + __m128i g = softlight_byte_SSE2(SkGetPackedG32_SSE2(src), + SkGetPackedG32_SSE2(dst), sa, da); + __m128i b = softlight_byte_SSE2(SkGetPackedB32_SSE2(src), + SkGetPackedB32_SSE2(dst), sa, da); + return SkPackARGB32_SSE2(a, r, g, b); +} + +static inline __m128i difference_byte_SSE2(const __m128i& sc, const __m128i& dc, + const __m128i& sa, const __m128i& da) { + __m128i tmp1 = _mm_mullo_epi16(sc, da); + __m128i tmp2 = _mm_mullo_epi16(dc, sa); + __m128i tmp = SkMin32_SSE2(tmp1, tmp2); + + __m128i ret1 = _mm_add_epi32(sc, dc); + __m128i ret2 = _mm_slli_epi32(SkDiv255Round_SSE2(tmp), 1); + __m128i ret = _mm_sub_epi32(ret1, ret2); + + ret = clamp_signed_byte_SSE2(ret); + return ret; +} + +static __m128i difference_modeproc_SSE2(const __m128i& src, + const __m128i& dst) { + __m128i sa = SkGetPackedA32_SSE2(src); + __m128i da = SkGetPackedA32_SSE2(dst); + + __m128i a = srcover_byte_SSE2(sa, da); + __m128i r = difference_byte_SSE2(SkGetPackedR32_SSE2(src), + SkGetPackedR32_SSE2(dst), sa, da); + __m128i g = difference_byte_SSE2(SkGetPackedG32_SSE2(src), + SkGetPackedG32_SSE2(dst), sa, da); + __m128i b = difference_byte_SSE2(SkGetPackedB32_SSE2(src), + SkGetPackedB32_SSE2(dst), sa, da); + return SkPackARGB32_SSE2(a, r, g, b); +} + +static inline __m128i exclusion_byte_SSE2(const __m128i& sc, const __m128i& dc, + const __m128i&, __m128i&) { + __m128i tmp1 = _mm_mullo_epi16(_mm_set1_epi32(255), sc); // 255 * sc + __m128i tmp2 = _mm_mullo_epi16(_mm_set1_epi32(255), dc); // 255 * dc + tmp1 = _mm_add_epi32(tmp1, tmp2); + tmp2 = _mm_mullo_epi16(sc, dc); // sc * dc + tmp2 = _mm_slli_epi32(tmp2, 1); // 2 * sc * dc + + __m128i r = _mm_sub_epi32(tmp1, tmp2); + return clamp_div255round_SSE2(r); +} + +static __m128i exclusion_modeproc_SSE2(const __m128i& src, const __m128i& dst) { + __m128i sa = SkGetPackedA32_SSE2(src); + __m128i da = SkGetPackedA32_SSE2(dst); + + __m128i a = srcover_byte_SSE2(sa, da); + __m128i r = exclusion_byte_SSE2(SkGetPackedR32_SSE2(src), + SkGetPackedR32_SSE2(dst), sa, da); + __m128i g = exclusion_byte_SSE2(SkGetPackedG32_SSE2(src), + SkGetPackedG32_SSE2(dst), sa, da); + __m128i b = exclusion_byte_SSE2(SkGetPackedB32_SSE2(src), + SkGetPackedB32_SSE2(dst), sa, da); + return SkPackARGB32_SSE2(a, r, g, b); +} + //////////////////////////////////////////////////////////////////////////////// typedef __m128i (*SkXfermodeProcSIMD)(const __m128i& src, const __m128i& dst); @@ -384,15 +783,15 @@ SkXfermodeProcSIMD gSSE2XfermodeProcs[] = { modulate_modeproc_SSE2, screen_modeproc_SSE2, - NULL, // kOverlay_Mode - NULL, // kDarken_Mode - NULL, // kLighten_Mode - NULL, // kColorDodge_Mode - NULL, // kColorBurn_Mode - NULL, // kHardLight_Mode - NULL, // kSoftLight_Mode - NULL, // kDifference_Mode - NULL, // kExclusion_Mode + overlay_modeproc_SSE2, + darken_modeproc_SSE2, + lighten_modeproc_SSE2, + colordodge_modeproc_SSE2, + colorburn_modeproc_SSE2, + hardlight_modeproc_SSE2, + softlight_modeproc_SSE2, + difference_modeproc_SSE2, + exclusion_modeproc_SSE2, multiply_modeproc_SSE2, NULL, // kHue_Mode diff --git a/opts/opts_check_SSE2.cpp b/opts/opts_check_SSE2.cpp index e7677220..6c684c27 100644 --- a/opts/opts_check_SSE2.cpp +++ b/opts/opts_check_SSE2.cpp @@ -91,6 +91,16 @@ static inline bool hasSSE2() { static inline bool hasSSSE3() { return true; } +#elif defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) +/* For the Android framework we should always know at compile time if the device + * we are building for supports SSSE3. The one exception to this rule is on the + * emulator where we are compiled without the -msse3 option (so we have no SSSE3 + * procs) but can be run on a host machine that supports SSSE3 instructions. So + * for that particular case we disable our SSSE3 options. + */ +static inline bool hasSSSE3() { + return false; +} #else static inline bool hasSSSE3() { @@ -123,46 +133,54 @@ void SkBitmapProcState::platformConvolutionProcs(SkConvolutionProcs* procs) { } void SkBitmapProcState::platformProcs() { - if (cachedHasSSSE3()) { - if (fSampleProc32 == S32_opaque_D32_filter_DX) { + /* Every optimization in the function requires at least SSE2 */ + if (!cachedHasSSE2()) { + return; + } + + /* Check fSampleProc32 */ + if (fSampleProc32 == S32_opaque_D32_filter_DX) { + if (cachedHasSSSE3()) { fSampleProc32 = S32_opaque_D32_filter_DX_SSSE3; - } else if (fSampleProc32 == S32_alpha_D32_filter_DX) { - fSampleProc32 = S32_alpha_D32_filter_DX_SSSE3; + } else { + fSampleProc32 = S32_opaque_D32_filter_DX_SSE2; } - - if (fSampleProc32 == S32_opaque_D32_filter_DXDY) { + } else if (fSampleProc32 == S32_opaque_D32_filter_DXDY) { + if (cachedHasSSSE3()) { fSampleProc32 = S32_opaque_D32_filter_DXDY_SSSE3; - } else if (fSampleProc32 == S32_alpha_D32_filter_DXDY) { - fSampleProc32 = S32_alpha_D32_filter_DXDY_SSSE3; } - } else if (cachedHasSSE2()) { - if (fSampleProc32 == S32_opaque_D32_filter_DX) { - fSampleProc32 = S32_opaque_D32_filter_DX_SSE2; - } else if (fSampleProc32 == S32_alpha_D32_filter_DX) { + } else if (fSampleProc32 == S32_alpha_D32_filter_DX) { + if (cachedHasSSSE3()) { + fSampleProc32 = S32_alpha_D32_filter_DX_SSSE3; + } else { fSampleProc32 = S32_alpha_D32_filter_DX_SSE2; } - - if (fSampleProc16 == S32_D16_filter_DX) { - fSampleProc16 = S32_D16_filter_DX_SSE2; + } else if (fSampleProc32 == S32_alpha_D32_filter_DXDY) { + if (cachedHasSSSE3()) { + fSampleProc32 = S32_alpha_D32_filter_DXDY_SSSE3; } } - if (cachedHasSSSE3() || cachedHasSSE2()) { - if (fMatrixProc == ClampX_ClampY_filter_scale) { - fMatrixProc = ClampX_ClampY_filter_scale_SSE2; - } else if (fMatrixProc == ClampX_ClampY_nofilter_scale) { - fMatrixProc = ClampX_ClampY_nofilter_scale_SSE2; - } + /* Check fSampleProc16 */ + if (fSampleProc16 == S32_D16_filter_DX) { + fSampleProc16 = S32_D16_filter_DX_SSE2; + } - if (fMatrixProc == ClampX_ClampY_filter_affine) { - fMatrixProc = ClampX_ClampY_filter_affine_SSE2; - } else if (fMatrixProc == ClampX_ClampY_nofilter_affine) { - fMatrixProc = ClampX_ClampY_nofilter_affine_SSE2; - } - if (c_hqfilter_sse) { - if (fShaderProc32 == highQualityFilter32) { - fShaderProc32 = highQualityFilter_SSE2; - } + /* Check fMatrixProc */ + if (fMatrixProc == ClampX_ClampY_filter_scale) { + fMatrixProc = ClampX_ClampY_filter_scale_SSE2; + } else if (fMatrixProc == ClampX_ClampY_nofilter_scale) { + fMatrixProc = ClampX_ClampY_nofilter_scale_SSE2; + } else if (fMatrixProc == ClampX_ClampY_filter_affine) { + fMatrixProc = ClampX_ClampY_filter_affine_SSE2; + } else if (fMatrixProc == ClampX_ClampY_nofilter_affine) { + fMatrixProc = ClampX_ClampY_nofilter_affine_SSE2; + } + + /* Check fShaderProc32 */ + if (c_hqfilter_sse) { + if (fShaderProc32 == highQualityFilter32) { + fShaderProc32 = highQualityFilter_SSE2; } } } diff --git a/pathops/SkDCubicIntersection.cpp b/pathops/SkDCubicIntersection.cpp index dc1063c3..dd51195d 100644 --- a/pathops/SkDCubicIntersection.cpp +++ b/pathops/SkDCubicIntersection.cpp @@ -494,7 +494,18 @@ int SkIntersections::intersect(const SkDCubic& c1, const SkDCubic& c2) { cubicNearEnd(c1, false, c2, c2Bounds); } if (!(exactEndBits & 8)) { + if (selfIntersect && fUsed) { + return fUsed; + } cubicNearEnd(c1, true, c2, c2Bounds); + if (selfIntersect && fUsed && ((approximately_less_than_zero(fT[0][0]) + && approximately_less_than_zero(fT[1][0])) + || (approximately_greater_than_one(fT[0][0]) + && approximately_greater_than_one(fT[1][0])))) { + SkASSERT(fUsed == 1); + fUsed = 0; + return fUsed; + } } if (!selfIntersect) { SkDRect c1Bounds; diff --git a/pathops/SkDCubicLineIntersection.cpp b/pathops/SkDCubicLineIntersection.cpp index abbc4e32..be38ddbf 100644 --- a/pathops/SkDCubicLineIntersection.cpp +++ b/pathops/SkDCubicLineIntersection.cpp @@ -302,10 +302,17 @@ public: } double cT = *cubicT = SkPinT(*cubicT); double lT = *lineT = SkPinT(*lineT); + SkDPoint lPt = fLine.ptAtT(lT); + SkDPoint cPt = fCubic.ptAtT(cT); + if (!lPt.moreRoughlyEqual(cPt)) { + return false; + } + // FIXME: if points are roughly equal but not approximately equal, need to do + // a binary search like quad/quad intersection to find more precise t values if (lT == 0 || lT == 1 || (ptSet == kPointUninitialized && cT != 0 && cT != 1)) { - *pt = fLine.ptAtT(lT); + *pt = lPt; } else if (ptSet == kPointUninitialized) { - *pt = fCubic.ptAtT(cT); + *pt = cPt; } SkPoint gridPt = pt->asSkPoint(); if (gridPt == fLine[0].asSkPoint()) { diff --git a/pathops/SkDLineIntersection.cpp b/pathops/SkDLineIntersection.cpp index f1adce21..89695395 100644 --- a/pathops/SkDLineIntersection.cpp +++ b/pathops/SkDLineIntersection.cpp @@ -292,7 +292,7 @@ int SkIntersections::vertical(const SkDLine& line, double x) { int SkIntersections::vertical(const SkDLine& line, double top, double bottom, double x, bool flipped) { - fMax = 2; + fMax = 3; // cleanup parallel lines will bring this back line // see if end points intersect the opposite line double t; SkDPoint topPt = { x, top }; @@ -344,6 +344,7 @@ int SkIntersections::vertical(const SkDLine& line, double top, double bottom, } } cleanUpParallelLines(result == 2); + SkASSERT(fUsed <= 2); return fUsed; } diff --git a/pathops/SkDQuadLineIntersection.cpp b/pathops/SkDQuadLineIntersection.cpp index 45daa10d..1b9d8ccd 100644 --- a/pathops/SkDQuadLineIntersection.cpp +++ b/pathops/SkDQuadLineIntersection.cpp @@ -98,7 +98,7 @@ public: , fLine(l) , fIntersections(i) , fAllowNear(true) { - i->setMax(2); + i->setMax(3); // allow short partial coincidence plus discrete intersection } void allowNear(bool allow) { @@ -331,6 +331,9 @@ protected: *pt = fLine[1]; *lineT = 1; } + if (fIntersections->used() > 0 && approximately_equal((*fIntersections)[1][0], *lineT)) { + return false; + } if (gridPt == fQuad[0].asSkPoint()) { *pt = fQuad[0]; *quadT = 0; diff --git a/pathops/SkIntersections.h b/pathops/SkIntersections.h index 119ca781..eced4dd1 100644 --- a/pathops/SkIntersections.h +++ b/pathops/SkIntersections.h @@ -164,7 +164,7 @@ public: quad.set(a); SkDLine line; line.set(b); - fMax = 2; + fMax = 3; // 2; permit small coincident segment + non-coincident intersection return intersect(quad, line); } diff --git a/pathops/SkOpAngle.cpp b/pathops/SkOpAngle.cpp index 62cf4b0e..094b22c7 100644 --- a/pathops/SkOpAngle.cpp +++ b/pathops/SkOpAngle.cpp @@ -321,9 +321,11 @@ recomputeSector: fUnorderable = true; return false; } + int saveEnd = fEnd; fEnd = checkEnd - step; setSpans(); setSector(); + fEnd = saveEnd; return !fUnorderable; } @@ -658,6 +660,9 @@ void SkOpAngle::insert(SkOpAngle* angle) { } SkOpAngle* next = fNext; if (next->fNext == this) { + if (angle->overlap(*this)) { + return; + } if (singleton || angle->after(this)) { this->fNext = angle; angle->fNext = next; @@ -671,6 +676,9 @@ void SkOpAngle::insert(SkOpAngle* angle) { SkOpAngle* last = this; do { SkASSERT(last->fNext == next); + if (angle->overlap(*last) || angle->overlap(*next)) { + return; + } if (angle->after(last)) { last->fNext = angle; angle->fNext = next; @@ -701,6 +709,33 @@ SkOpSpan* SkOpAngle::lastMarked() const { return fLastMarked; } +bool SkOpAngle::loopContains(const SkOpAngle& test) const { + if (!fNext) { + return false; + } + const SkOpAngle* first = this; + const SkOpAngle* loop = this; + const SkOpSegment* tSegment = test.fSegment; + double tStart = tSegment->span(test.fStart).fT; + double tEnd = tSegment->span(test.fEnd).fT; + do { + const SkOpSegment* lSegment = loop->fSegment; + // FIXME : use precisely_equal ? or compare points exactly ? + if (lSegment != tSegment) { + continue; + } + double lStart = lSegment->span(loop->fStart).fT; + if (lStart != tEnd) { + continue; + } + double lEnd = lSegment->span(loop->fEnd).fT; + if (lEnd == tStart) { + return true; + } + } while ((loop = loop->fNext) != first); + return false; +} + int SkOpAngle::loopCount() const { int count = 0; const SkOpAngle* first = this; @@ -813,6 +848,23 @@ unorderable: return true; } +bool SkOpAngle::overlap(const SkOpAngle& other) const { + int min = SkTMin(fStart, fEnd); + const SkOpSpan& span = fSegment->span(min); + const SkOpSegment* oSeg = other.fSegment; + int oMin = SkTMin(other.fStart, other.fEnd); + const SkOpSpan& oSpan = oSeg->span(oMin); + if (!span.fSmall && !oSpan.fSmall) { + return false; + } + if (fSegment->span(fStart).fPt != oSeg->span(other.fStart).fPt) { + return false; + } + // see if small span is contained by opposite span + return span.fSmall ? oSeg->containsPt(fSegment->span(fEnd).fPt, other.fEnd, other.fStart) + : fSegment->containsPt(oSeg->span(other.fEnd).fPt, fEnd, fStart); +} + // OPTIMIZE: if this shows up in a profile, add a previous pointer // as is, this should be rarely called SkOpAngle* SkOpAngle::previous() const { diff --git a/pathops/SkOpAngle.h b/pathops/SkOpAngle.h index 01150e6f..e5669133 100644 --- a/pathops/SkOpAngle.h +++ b/pathops/SkOpAngle.h @@ -24,6 +24,7 @@ public: kBinaryOpp, }; + int end() const { return fEnd; } @@ -37,6 +38,7 @@ public: void insert(SkOpAngle* ); bool isHorizontal() const; SkOpSpan* lastMarked() const; + bool loopContains(const SkOpAngle& ) const; int loopCount() const; void markStops(); bool merge(SkOpAngle* ); @@ -104,6 +106,7 @@ private: double midT() const; bool oppositePlanes(const SkOpAngle& rh) const; bool orderable(const SkOpAngle& rh) const; // false == this < rh ; true == this > rh + bool overlap(const SkOpAngle& test) const; void setCurveHullSweep(); void setSector(); void setSpans(); diff --git a/pathops/SkOpContour.cpp b/pathops/SkOpContour.cpp index db805a21..e3137b75 100644 --- a/pathops/SkOpContour.cpp +++ b/pathops/SkOpContour.cpp @@ -211,9 +211,12 @@ void SkOpContour::joinCoincidence(const SkTArray<SkCoincidence, true>& coinciden } bool swapStart = startT > endT; bool swapOther = oStartT > oEndT; + const SkPoint* startPt = &coincidence.fPts[0]; + const SkPoint* endPt = &coincidence.fPts[1]; if (swapStart) { - SkTSwap<double>(startT, endT); - SkTSwap<double>(oStartT, oEndT); + SkTSwap(startT, endT); + SkTSwap(oStartT, oEndT); + SkTSwap(startPt, endPt); } bool cancel = swapOther != swapStart; int step = swapStart ? -1 : 1; @@ -222,17 +225,18 @@ void SkOpContour::joinCoincidence(const SkTArray<SkCoincidence, true>& coinciden if (partial ? startT != 0 || oMatchStart != 0 : (startT == 0) != (oMatchStart == 0)) { bool added = false; if (oMatchStart != 0) { - added = thisOne.joinCoincidence(&other, oMatchStart, oStep, cancel); + const SkPoint& oMatchStartPt = cancel ? *endPt : *startPt; + added = thisOne.joinCoincidence(&other, oMatchStart, oMatchStartPt, oStep, cancel); } if (!cancel && startT != 0 && !added) { - (void) other.joinCoincidence(&thisOne, startT, step, cancel); + (void) other.joinCoincidence(&thisOne, startT, *startPt, step, cancel); } } double oMatchEnd = cancel ? oStartT : oEndT; if (partial ? endT != 1 || oMatchEnd != 1 : (endT == 1) != (oMatchEnd == 1)) { bool added = false; if (cancel && endT != 1 && !added) { - (void) other.joinCoincidence(&thisOne, endT, -step, cancel); + (void) other.joinCoincidence(&thisOne, endT, *endPt, -step, cancel); } } } @@ -329,7 +333,7 @@ void SkOpContour::topSortableSegment(const SkPoint& topLeft, SkPoint* bestXY, continue; } fDone = false; - SkPoint testXY = testSegment->activeLeftTop(true, NULL); + SkPoint testXY = testSegment->activeLeftTop(NULL); if (*topStart) { if (testXY.fY < topLeft.fY) { continue; diff --git a/pathops/SkOpContour.h b/pathops/SkOpContour.h index 5b92a4b0..7fad7a40 100644 --- a/pathops/SkOpContour.h +++ b/pathops/SkOpContour.h @@ -10,6 +10,10 @@ #include "SkOpSegment.h" #include "SkTArray.h" +#if defined(SK_DEBUG) || !FORCE_RELEASE +#include "SkThread.h" +#endif + class SkIntersections; class SkOpContour; class SkPathWriter; @@ -26,7 +30,7 @@ public: SkOpContour() { reset(); #if defined(SK_DEBUG) || !FORCE_RELEASE - fID = ++SkPathOpsDebug::gContourID; + fID = sk_atomic_inc(&SkPathOpsDebug::gContourID); #endif } diff --git a/pathops/SkOpEdgeBuilder.cpp b/pathops/SkOpEdgeBuilder.cpp index ae72e293..31a446b3 100644 --- a/pathops/SkOpEdgeBuilder.cpp +++ b/pathops/SkOpEdgeBuilder.cpp @@ -13,10 +13,6 @@ void SkOpEdgeBuilder::init() { fOperand = false; fXorMask[0] = fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_PathOpsMask : kWinding_PathOpsMask; -#ifdef SK_DEBUG - SkPathOpsDebug::gContourID = 0; - SkPathOpsDebug::gSegmentID = 0; -#endif fUnparseable = false; fSecondHalf = preFetch(); } diff --git a/pathops/SkOpSegment.cpp b/pathops/SkOpSegment.cpp index 67f9fb2f..0e48b3f9 100644 --- a/pathops/SkOpSegment.cpp +++ b/pathops/SkOpSegment.cpp @@ -70,16 +70,12 @@ const SkOpAngle* SkOpSegment::activeAngleInner(int index, int* start, int* end, int next = nextExactSpan(index, 1); if (next > 0) { const SkOpSpan& upSpan = fTs[index]; - if (upSpan.fUnsortableStart) { - *sortable = false; - return NULL; - } if (upSpan.fWindValue || upSpan.fOppValue) { if (*end < 0) { *start = index; *end = next; } - if (!upSpan.fDone && !upSpan.fUnsortableEnd) { + if (!upSpan.fDone) { if (upSpan.fWindSum != SK_MinS32) { return spanToAngle(index, next); } @@ -93,10 +89,6 @@ const SkOpAngle* SkOpSegment::activeAngleInner(int index, int* start, int* end, // edge leading into junction if (prev >= 0) { const SkOpSpan& downSpan = fTs[prev]; - if (downSpan.fUnsortableEnd) { - *sortable = false; - return NULL; - } if (downSpan.fWindValue || downSpan.fOppValue) { if (*end < 0) { *start = index; @@ -123,19 +115,15 @@ const SkOpAngle* SkOpSegment::activeAngleOther(int index, int* start, int* end, return other->activeAngleInner(oIndex, start, end, done, sortable); } -SkPoint SkOpSegment::activeLeftTop(bool onlySortable, int* firstT) const { +SkPoint SkOpSegment::activeLeftTop(int* firstT) const { SkASSERT(!done()); SkPoint topPt = {SK_ScalarMax, SK_ScalarMax}; int count = fTs.count(); // see if either end is not done since we want smaller Y of the pair bool lastDone = true; - bool lastUnsortable = false; double lastT = -1; for (int index = 0; index < count; ++index) { const SkOpSpan& span = fTs[index]; - if (onlySortable && (span.fUnsortableStart || lastUnsortable)) { - goto next; - } if (span.fDone && lastDone) { goto next; } @@ -164,7 +152,6 @@ SkPoint SkOpSegment::activeLeftTop(bool onlySortable, int* firstT) const { } next: lastDone = span.fDone; - lastUnsortable = span.fUnsortableEnd; } return topPt; } @@ -345,16 +332,19 @@ void SkOpSegment::addCoinOutsides(const SkPoint& startPt, const SkPoint& endPt, do { workPt = &fTs[++tIndex].fPt; } while (nextPt == *workPt); + const SkPoint* oWorkPt; do { - workPt = &other->fTs[++oIndex].fPt; - } while (nextPt == *workPt); + oWorkPt = &other->fTs[++oIndex].fPt; + } while (nextPt == *oWorkPt); nextPt = *workPt; double tStart = fTs[tIndex].fT; double oStart = other->fTs[oIndex].fT; if (tStart == 1 && oStart == 1 && fOperand == other->fOperand) { break; } - addTPair(tStart, other, oStart, false, nextPt); + if (*workPt == *oWorkPt) { + addTPair(tStart, other, oStart, false, nextPt); + } } while (endPt != nextPt); } @@ -618,8 +608,6 @@ int SkOpSegment::addT(SkOpSegment* other, const SkPoint& pt, double newT) { span->fLoop = false; span->fSmall = false; span->fTiny = false; - span->fUnsortableStart = false; - span->fUnsortableEnd = false; int less = -1; // find range of spans with nearly the same point as this one while (&span[less + 1] - fTs.begin() > 0 && AlmostEqualUlps(span[less].fPt, pt)) { @@ -834,18 +822,27 @@ bool SkOpSegment::alignSpan(int index, double thisT, const SkPoint& thisPt) { aligned = true; } double oT = oSpan->fT; - if (oT == 0 || oT == 1) { + if (oT == 0) { return aligned; } int oStart = other->nextSpan(oIndex, -1) + 1; - int oEnd = other->nextSpan(oIndex, 1); oSpan = &other->fTs[oStart]; + int otherIndex = oStart; + if (oT == 1) { + if (aligned) { + while (oSpan->fPt == thisPt && oSpan->fT != 1) { + oSpan->fTiny = true; + ++oSpan; + } + } + return aligned; + } oT = oSpan->fT; + int oEnd = other->nextSpan(oIndex, 1); bool oAligned = false; if (oSpan->fPt != thisPt) { oAligned |= other->alignSpan(oStart, oT, thisPt); } - int otherIndex = oStart; while (++otherIndex < oEnd) { SkOpSpan* oNextSpan = &other->fTs[otherIndex]; if (oNextSpan->fT != oT || oNextSpan->fPt != thisPt) { @@ -1352,14 +1349,17 @@ void SkOpSegment::ComputeOneSumReverse(const SkOpAngle* baseAngle, SkOpAngle* ne nextAngle->setLastMarked(last); } -void SkOpSegment::constructLine(SkPoint shortLine[2]) { - addLine(shortLine, false, false); - addT(NULL, shortLine[0], 0); - addT(NULL, shortLine[1], 1); - addStartSpan(1); - addEndSpan(1); - SkOpAngle& angle = fAngles.push_back(); - angle.set(this, 0, 1); +bool SkOpSegment::containsPt(const SkPoint& pt, int index, int endIndex) const { + int step = index < endIndex ? 1 : -1; + do { + const SkOpSpan& span = this->span(index); + if (span.fPt == pt) { + const SkOpSpan& endSpan = this->span(endIndex); + return span.fT == endSpan.fT && pt != endSpan.fPt; + } + index += step; + } while (index != endIndex); + return false; } int SkOpSegment::crossedSpanY(const SkPoint& basePt, SkScalar* bestY, double* hitT, @@ -1923,7 +1923,7 @@ nextSmallCheck: missing.fPt)) { continue; } - int otherTIndex = missingOther->findT(missing.fOtherT, missing.fSegment); + int otherTIndex = missingOther->findT(missing.fOtherT, missing.fPt, missing.fSegment); const SkOpSpan& otherSpan = missingOther->span(otherTIndex); if (otherSpan.fSmall) { const SkOpSpan* nextSpan = &otherSpan; @@ -1955,7 +1955,9 @@ nextSmallCheck: void SkOpSegment::checkSmallCoincidence(const SkOpSpan& span, SkTArray<MissingSpan, true>* checkMultiple) { SkASSERT(span.fSmall); - SkASSERT(span.fWindValue); + if (0 && !span.fWindValue) { + return; + } SkASSERT(&span < fTs.end() - 1); const SkOpSpan* next = &span + 1; SkASSERT(!next->fSmall || checkMultiple); @@ -2271,11 +2273,13 @@ SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpan*>* chase, int* nextStart bool sortable = calcWinding != SK_NaN32; if (!sortable) { *unsortable = true; + markDoneBinary(SkMin32(startIndex, endIndex)); return NULL; } SkOpAngle* angle = spanToAngle(end, startIndex); if (angle->unorderable()) { *unsortable = true; + markDoneBinary(SkMin32(startIndex, endIndex)); return NULL; } #if DEBUG_SORT @@ -2283,6 +2287,11 @@ SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpan*>* chase, int* nextStart angle->debugLoop(); #endif int sumMiWinding = updateWinding(endIndex, startIndex); + if (sumMiWinding == SK_MinS32) { + *unsortable = true; + markDoneBinary(SkMin32(startIndex, endIndex)); + return NULL; + } int sumSuWinding = updateOppWinding(endIndex, startIndex); if (operand()) { SkTSwap<int>(sumMiWinding, sumSuWinding); @@ -2302,6 +2311,7 @@ SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpan*>* chase, int* nextStart if (!foundAngle || (foundDone && activeCount & 1)) { if (nextSegment->isTiny(nextAngle)) { *unsortable = true; + markDoneBinary(SkMin32(startIndex, endIndex)); return NULL; } foundAngle = nextAngle; @@ -2393,6 +2403,7 @@ SkOpSegment* SkOpSegment::findNextWinding(SkTDArray<SkOpSpan*>* chase, int* next bool sortable = calcWinding != SK_NaN32; if (!sortable) { *unsortable = true; + markDoneUnary(SkMin32(startIndex, endIndex)); return NULL; } SkOpAngle* angle = spanToAngle(end, startIndex); @@ -2415,6 +2426,7 @@ SkOpSegment* SkOpSegment::findNextWinding(SkTDArray<SkOpSpan*>* chase, int* next if (!foundAngle || (foundDone && activeCount & 1)) { if (nextSegment->isTiny(nextAngle)) { *unsortable = true; + markDoneUnary(SkMin32(startIndex, endIndex)); return NULL; } foundAngle = nextAngle; @@ -2433,7 +2445,6 @@ SkOpSegment* SkOpSegment::findNextWinding(SkTDArray<SkOpSpan*>* chase, int* next SkOpSpan* last = nextAngle->lastMarked(); if (last) { SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last)); - // assert here that span isn't already in array *chase->append() = last; #if DEBUG_WINDING SkDebugf("%s chase.append id=%d windSum=%d small=%d\n", __FUNCTION__, @@ -2584,7 +2595,7 @@ int SkOpSegment::findExactT(double t, const SkOpSegment* match) const { return -1; } -int SkOpSegment::findT(double t, const SkOpSegment* match) const { +int SkOpSegment::findT(double t, const SkPoint& pt, const SkOpSegment* match) const { int count = this->count(); for (int index = 0; index < count; ++index) { const SkOpSpan& span = fTs[index]; @@ -2592,18 +2603,28 @@ int SkOpSegment::findT(double t, const SkOpSegment* match) const { return index; } } + // Usually, the pair of ts are an exact match. It's possible that the t values have + // been adjusted to make multiple intersections align. In this rare case, look for a + // matching point / match pair instead. + for (int index = 0; index < count; ++index) { + const SkOpSpan& span = fTs[index]; + if (span.fPt == pt && span.fOther == match) { + return index; + } + } SkASSERT(0); return -1; } -SkOpSegment* SkOpSegment::findTop(int* tIndexPtr, int* endIndexPtr, bool* unsortable) { +SkOpSegment* SkOpSegment::findTop(int* tIndexPtr, int* endIndexPtr, bool* unsortable, + bool firstPass) { // iterate through T intersections and return topmost // topmost tangent from y-min to first pt is closer to horizontal SkASSERT(!done()); int firstT = -1; - /* SkPoint topPt = */ activeLeftTop(true, &firstT); + /* SkPoint topPt = */ activeLeftTop(&firstT); if (firstT < 0) { - *unsortable = true; + *unsortable = !firstPass; firstT = 0; while (fTs[firstT].fDone) { SkASSERT(firstT < fTs.count()); @@ -2655,14 +2676,24 @@ SkOpSegment* SkOpSegment::findTop(int* tIndexPtr, int* endIndexPtr, bool* unsort #endif // skip edges that have already been processed angle = firstAngle; - SkOpSegment* leftSegment; + SkOpSegment* leftSegment = NULL; + bool looped = false; do { -// SkASSERT(!angle->unsortable()); - leftSegment = angle->segment(); - *tIndexPtr = angle->end(); - *endIndexPtr = angle->start(); + *unsortable = angle->unorderable(); + if (firstPass || !*unsortable) { + leftSegment = angle->segment(); + *tIndexPtr = angle->end(); + *endIndexPtr = angle->start(); + if (!leftSegment->fTs[SkMin32(*tIndexPtr, *endIndexPtr)].fDone) { + break; + } + } angle = angle->next(); - } while (leftSegment->fTs[SkMin32(*tIndexPtr, *endIndexPtr)].fDone); + looped = true; + } while (angle != firstAngle); + if (angle == firstAngle && looped) { + return NULL; + } if (leftSegment->verb() >= SkPath::kQuad_Verb) { const int tIndex = *tIndexPtr; const int endIndex = *endIndexPtr; @@ -2670,8 +2701,9 @@ SkOpSegment* SkOpSegment::findTop(int* tIndexPtr, int* endIndexPtr, bool* unsort bool swap = !leftSegment->monotonicInY(tIndex, endIndex) && !leftSegment->serpentine(tIndex, endIndex); #if DEBUG_SWAP_TOP - SkDebugf("%s swap=%d serpentine=%d containedByEnds=%d monotonic=%d\n", __FUNCTION__, - swap, + SkDebugf("%s swap=%d inflections=%d serpentine=%d controlledbyends=%d monotonic=%d\n", + __FUNCTION__, + swap, leftSegment->debugInflections(tIndex, endIndex), leftSegment->serpentine(tIndex, endIndex), leftSegment->controlsContainedByEnds(tIndex, endIndex), leftSegment->monotonicInY(tIndex, endIndex)); @@ -2840,13 +2872,6 @@ bool SkOpSegment::isSimple(int end) const { #endif } -bool SkOpSegment::isSmall(const SkOpAngle* angle) const { - int start = angle->start(); - int end = angle->end(); - const SkOpSpan& mSpan = fTs[SkMin32(start, end)]; - return mSpan.fSmall; -} - bool SkOpSegment::isTiny(const SkOpAngle* angle) const { int start = angle->start(); int end = angle->end(); @@ -2863,8 +2888,9 @@ bool SkOpSegment::isTiny(int index) const { // if both are active, look to see if they both the connect to another coincident pair // if at least one is a line, then make the pair coincident // if neither is a line, test for coincidence -bool SkOpSegment::joinCoincidence(SkOpSegment* other, double otherT, int step, bool cancel) { - int otherTIndex = other->findT(otherT, this); +bool SkOpSegment::joinCoincidence(SkOpSegment* other, double otherT, const SkPoint& otherPt, + int step, bool cancel) { + int otherTIndex = other->findT(otherT, otherPt, this); int next = other->nextExactSpan(otherTIndex, step); int otherMin = SkMin32(otherTIndex, next); int otherWind = other->span(otherMin).fWindValue; @@ -3106,7 +3132,9 @@ SkOpSpan* SkOpSegment::markOneWinding(const char* funName, int tIndex, int windi debugShowNewWinding(funName, span, winding); #endif SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding); - SkASSERT(abs(winding) <= SkPathOpsDebug::gMaxWindSum); +#if DEBUG_LIMIT_WIND_SUM + SkASSERT(abs(winding) <= DEBUG_LIMIT_WIND_SUM); +#endif span.fWindSum = winding; return &span; } @@ -3121,10 +3149,14 @@ SkOpSpan* SkOpSegment::markOneWinding(const char* funName, int tIndex, int windi debugShowNewWinding(funName, span, winding, oppWinding); #endif SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding); - SkASSERT(abs(winding) <= SkPathOpsDebug::gMaxWindSum); +#if DEBUG_LIMIT_WIND_SUM + SkASSERT(abs(winding) <= DEBUG_LIMIT_WIND_SUM); +#endif span.fWindSum = winding; SkASSERT(span.fOppSum == SK_MinS32 || span.fOppSum == oppWinding); - SkASSERT(abs(oppWinding) <= SkPathOpsDebug::gMaxWindSum); +#if DEBUG_LIMIT_WIND_SUM + SkASSERT(abs(oppWinding) <= DEBUG_LIMIT_WIND_SUM); +#endif span.fOppSum = oppWinding; debugValidate(); return &span; @@ -3157,9 +3189,7 @@ bool SkOpSegment::clockwise(int tStart, int tEnd) const { } bool SkOpSegment::monotonicInY(int tStart, int tEnd) const { - if (fVerb == SkPath::kLine_Verb) { - return false; - } + SkASSERT(fVerb != SkPath::kLine_Verb); if (fVerb == SkPath::kQuad_Verb) { SkDQuad dst = SkDQuad::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT); return dst.monotonicInY(); @@ -3210,33 +3240,6 @@ SkOpSpan* SkOpSegment::verifyOneWindingU(const char* funName, int tIndex) { return &span; } -// note that just because a span has one end that is unsortable, that's -// not enough to mark it done. The other end may be sortable, allowing the -// span to be added. -// FIXME: if abs(start - end) > 1, mark intermediates as unsortable on both ends -void SkOpSegment::markUnsortable(int start, int end) { - SkOpSpan* span = &fTs[start]; - if (start < end) { -#if DEBUG_UNSORTABLE - debugShowNewWinding(__FUNCTION__, *span, 0); -#endif - span->fUnsortableStart = true; - } else { - --span; -#if DEBUG_UNSORTABLE - debugShowNewWinding(__FUNCTION__, *span, 0); -#endif - span->fUnsortableEnd = true; - } - if (!span->fUnsortableStart || !span->fUnsortableEnd || span->fDone) { - debugValidate(); - return; - } - span->fDone = true; - fDoneSpans++; - debugValidate(); -} - void SkOpSegment::markWinding(int index, int winding) { // SkASSERT(!done()); SkASSERT(winding); @@ -3426,8 +3429,10 @@ void SkOpSegment::setUpWindings(int index, int endIndex, int* sumMiWinding, int* *oppMaxWinding = *sumSuWinding; *oppSumWinding = *sumSuWinding -= oppDeltaSum; } - SkASSERT(abs(*sumWinding) <= SkPathOpsDebug::gMaxWindSum); - SkASSERT(abs(*oppSumWinding) <= SkPathOpsDebug::gMaxWindSum); +#if DEBUG_LIMIT_WIND_SUM + SkASSERT(abs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM); + SkASSERT(abs(*oppSumWinding) <= DEBUG_LIMIT_WIND_SUM); +#endif } void SkOpSegment::setUpWindings(int index, int endIndex, int* sumMiWinding, @@ -3435,7 +3440,9 @@ void SkOpSegment::setUpWindings(int index, int endIndex, int* sumMiWinding, int deltaSum = spanSign(index, endIndex); *maxWinding = *sumMiWinding; *sumWinding = *sumMiWinding -= deltaSum; - SkASSERT(abs(*sumWinding) <= SkPathOpsDebug::gMaxWindSum); +#if DEBUG_LIMIT_WIND_SUM + SkASSERT(abs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM); +#endif } void SkOpSegment::sortAngles() { @@ -3494,7 +3501,10 @@ void SkOpSegment::sortAngles() { wroteAfterHeader = true; } #endif - baseAngle->insert(&other->angle(otherAngleIndex)); + SkOpAngle* oAngle = &other->angle(otherAngleIndex); + if (!oAngle->loopContains(*baseAngle)) { + baseAngle->insert(oAngle); + } } otherAngleIndex = oSpan.fToAngleIndex; if (otherAngleIndex >= 0) { @@ -3505,7 +3515,10 @@ void SkOpSegment::sortAngles() { wroteAfterHeader = true; } #endif - baseAngle->insert(&other->angle(otherAngleIndex)); + SkOpAngle* oAngle = &other->angle(otherAngleIndex); + if (!oAngle->loopContains(*baseAngle)) { + baseAngle->insert(oAngle); + } } if (++index == spanCount) { break; @@ -3673,6 +3686,9 @@ int SkOpSegment::updateOppWindingReverse(const SkOpAngle* angle) const { int SkOpSegment::updateWinding(int index, int endIndex) const { int lesser = SkMin32(index, endIndex); int winding = windSum(lesser); + if (winding == SK_MinS32) { + return winding; + } int spanWinding = spanSign(index, endIndex); if (winding && UseInnerWinding(winding - spanWinding, winding) && winding != SK_MaxS32) { diff --git a/pathops/SkOpSegment.h b/pathops/SkOpSegment.h index 54c1892d..1eaef698 100644 --- a/pathops/SkOpSegment.h +++ b/pathops/SkOpSegment.h @@ -14,13 +14,17 @@ #include "SkTArray.h" #include "SkTDArray.h" +#if defined(SK_DEBUG) || !FORCE_RELEASE +#include "SkThread.h" +#endif + class SkPathWriter; class SkOpSegment { public: SkOpSegment() { #if defined(SK_DEBUG) || !FORCE_RELEASE - fID = ++SkPathOpsDebug::gSegmentID; + fID = sk_atomic_inc(&SkPathOpsDebug::gSegmentID); #endif } @@ -48,8 +52,6 @@ public: return count > 1 && fTs[0].fT == 0 && fTs[--count].fT == 1; } - void constructLine(SkPoint shortLine[2]); - int count() const { return fTs.count(); } @@ -193,11 +195,6 @@ public: return const_cast<SkOpAngle*>(cAngle); } - // OPTIMIZATION: mark as debugging only if used solely by tests - const SkTDArray<SkOpSpan>& spans() const { - return fTs; - } - int spanSign(const SkOpAngle* angle) const { SkASSERT(angle->segment() == this); return spanSign(angle->start(), angle->end()); @@ -219,10 +216,6 @@ public: return fTs[start].fT * (1 - mid) + fTs[end].fT * mid; } - bool unsortable(int index) const { - return fTs[index].fUnsortableStart || fTs[index].fUnsortableEnd; - } - void updatePts(const SkPoint pts[]) { fPts = pts; } @@ -267,7 +260,7 @@ public: const SkOpAngle* activeAngle(int index, int* start, int* end, bool* done, bool* sortable) const; - SkPoint activeLeftTop(bool onlySortable, int* firstT) const; + SkPoint activeLeftTop(int* firstT) const; bool activeOp(int index, int endIndex, int xorMiMask, int xorSuMask, SkPathOp op); bool activeWinding(int index, int endIndex); void addCubic(const SkPoint pts[4], bool operand, bool evenOdd); @@ -297,6 +290,7 @@ public: bool checkSmall(int index) const; void checkTiny(); int computeSum(int startIndex, int endIndex, SkOpAngle::IncludeType includeType); + bool containsPt(const SkPoint& , int index, int endIndex) const; int crossedSpanY(const SkPoint& basePt, SkScalar* bestY, double* hitT, bool* hitSomething, double mid, bool opp, bool current) const; bool findCoincidentMatch(const SkOpSpan* span, const SkOpSegment* other, int oStart, int oEnd, @@ -307,16 +301,16 @@ public: bool* unsortable); SkOpSegment* findNextXor(int* nextStart, int* nextEnd, bool* unsortable); int findExactT(double t, const SkOpSegment* ) const; - int findT(double t, const SkOpSegment* ) const; - SkOpSegment* findTop(int* tIndex, int* endIndex, bool* unsortable); + int findT(double t, const SkPoint& , const SkOpSegment* ) const; + SkOpSegment* findTop(int* tIndex, int* endIndex, bool* unsortable, bool firstPass); void fixOtherTIndex(); void initWinding(int start, int end, SkOpAngle::IncludeType angleIncludeType); void initWinding(int start, int end, double tHit, int winding, SkScalar hitDx, int oppWind, SkScalar hitOppDx); bool isMissing(double startT, const SkPoint& pt) const; - bool isSmall(const SkOpAngle* angle) const; bool isTiny(const SkOpAngle* angle) const; - bool joinCoincidence(SkOpSegment* other, double otherT, int step, bool cancel); + bool joinCoincidence(SkOpSegment* other, double otherT, const SkPoint& otherPt, int step, + bool cancel); SkOpSpan* markAndChaseDoneBinary(int index, int endIndex); SkOpSpan* markAndChaseDoneUnary(int index, int endIndex); SkOpSpan* markAndChaseWinding(const SkOpAngle* angle, int winding, int oppWinding); @@ -361,6 +355,7 @@ public: #if DEBUG_SHOW_WINDING int debugShowWindingValues(int slotCount, int ofInterest) const; #endif + const SkTDArray<SkOpSpan>& debugSpans() const; void debugValidate() const; // available to testing only void dumpAngles() const; @@ -439,7 +434,6 @@ private: SkOpSpan* markOneWinding(const char* funName, int tIndex, int winding, int oppWinding); void markWinding(int index, int winding); void markWinding(int index, int winding, int oppWinding); - void markUnsortable(int start, int end); bool monotonicInY(int tStart, int tEnd) const; bool multipleEnds() const { @@ -490,6 +484,9 @@ private: #if DEBUG_ANGLE void debugCheckPointsEqualish(int tStart, int tEnd) const; #endif +#if DEBUG_SWAP_TOP + int debugInflections(int index, int endIndex) const; +#endif #if DEBUG_MARK_DONE || DEBUG_UNSORTABLE void debugShowNewWinding(const char* fun, const SkOpSpan& span, int winding); void debugShowNewWinding(const char* fun, const SkOpSpan& span, int winding, int oppWinding); diff --git a/pathops/SkOpSpan.h b/pathops/SkOpSpan.h index 2fe0b611..1ffdc0e2 100644 --- a/pathops/SkOpSpan.h +++ b/pathops/SkOpSpan.h @@ -28,8 +28,6 @@ struct SkOpSpan { bool fLoop; // set when a cubic loops back to this point bool fSmall; // if set, consecutive points are almost equal bool fTiny; // if set, consecutive points are equal but consecutive ts are not precisely equal - bool fUnsortableStart; // set when start is part of an unsortable pair - bool fUnsortableEnd; // set when end is part of an unsortable pair // available to testing only const SkOpSegment* debugToSegment(ptrdiff_t* ) const; diff --git a/pathops/SkPathOpsCommon.cpp b/pathops/SkPathOpsCommon.cpp index f3414839..0e9e1bee 100644 --- a/pathops/SkPathOpsCommon.cpp +++ b/pathops/SkPathOpsCommon.cpp @@ -206,7 +206,7 @@ void DebugShowActiveSpans(SkTArray<SkOpContour*, true>& contourList) { static SkOpSegment* findSortableTop(const SkTArray<SkOpContour*, true>& contourList, int* index, int* endIndex, SkPoint* topLeft, bool* unsortable, - bool* done, bool onlySortable) { + bool* done, bool firstPass) { SkOpSegment* result; const SkOpSegment* lastTopStart = NULL; int lastIndex = -1, lastEndIndex = -1; @@ -238,7 +238,7 @@ static SkOpSegment* findSortableTop(const SkTArray<SkOpContour*, true>& contourL return NULL; } *topLeft = bestXY; - result = topStart->findTop(index, endIndex, unsortable); + result = topStart->findTop(index, endIndex, unsortable, firstPass); if (!result) { if (lastTopStart == topStart && lastIndex == *index && lastEndIndex == *endIndex) { *done = true; @@ -249,9 +249,11 @@ static SkOpSegment* findSortableTop(const SkTArray<SkOpContour*, true>& contourL lastEndIndex = *endIndex; } } while (!result); +#if 0 if (result) { *unsortable = false; } +#endif return result; } @@ -283,18 +285,20 @@ static void skipVertical(const SkTArray<SkOpContour*, true>& contourList, if (contour->done()) { continue; } - *current = contour->nonVerticalSegment(index, endIndex); - if (*current) { + SkOpSegment* nonVertical = contour->nonVerticalSegment(index, endIndex); + if (nonVertical) { + *current = nonVertical; return; } } + return; } SkOpSegment* FindSortableTop(const SkTArray<SkOpContour*, true>& contourList, SkOpAngle::IncludeType angleIncludeType, bool* firstContour, int* indexPtr, - int* endIndexPtr, SkPoint* topLeft, bool* unsortable, bool* done) { + int* endIndexPtr, SkPoint* topLeft, bool* unsortable, bool* done, bool firstPass) { SkOpSegment* current = findSortableTop(contourList, indexPtr, endIndexPtr, topLeft, unsortable, - done, true); + done, firstPass); if (!current) { return NULL; } @@ -332,7 +336,7 @@ SkOpSegment* FindSortableTop(const SkTArray<SkOpContour*, true>& contourList, // if only remaining candidates are vertical, then they can be marked done SkASSERT(*indexPtr != *endIndexPtr && *indexPtr >= 0 && *endIndexPtr >= 0); skipVertical(contourList, ¤t, indexPtr, endIndexPtr); - + SkASSERT(current); // FIXME: if null, all remaining are vertical SkASSERT(*indexPtr != *endIndexPtr && *indexPtr >= 0 && *endIndexPtr >= 0); tryAgain = false; contourWinding = rightAngleWinding(contourList, ¤t, indexPtr, endIndexPtr, &tHit, @@ -348,6 +352,9 @@ SkOpSegment* FindSortableTop(const SkTArray<SkOpContour*, true>& contourList, } while (tryAgain); current->initWinding(*indexPtr, *endIndexPtr, tHit, contourWinding, hitDx, oppContourWinding, hitOppDx); + if (current->done()) { + return NULL; + } return current; } diff --git a/pathops/SkPathOpsCommon.h b/pathops/SkPathOpsCommon.h index 9a558cf1..6a7bb724 100644 --- a/pathops/SkPathOpsCommon.h +++ b/pathops/SkPathOpsCommon.h @@ -18,7 +18,7 @@ void Assemble(const SkPathWriter& path, SkPathWriter* simple); SkOpSegment* FindChase(SkTDArray<SkOpSpan*>* chase, int* tIndex, int* endIndex); SkOpSegment* FindSortableTop(const SkTArray<SkOpContour*, true>& , SkOpAngle::IncludeType , bool* firstContour, int* index, int* endIndex, SkPoint* topLeft, - bool* unsortable, bool* done); + bool* unsortable, bool* done, bool firstPass); SkOpSegment* FindUndone(SkTArray<SkOpContour*, true>& contourList, int* start, int* end); void MakeContourList(SkTArray<SkOpContour>& contours, SkTArray<SkOpContour*, true>& list, bool evenOdd, bool oppEvenOdd); diff --git a/pathops/SkPathOpsCubic.cpp b/pathops/SkPathOpsCubic.cpp index fda42a31..a89604f9 100644 --- a/pathops/SkPathOpsCubic.cpp +++ b/pathops/SkPathOpsCubic.cpp @@ -94,6 +94,11 @@ bool SkDCubic::monotonicInY() const { } bool SkDCubic::serpentine() const { +#if 0 // FIXME: enabling this fixes cubicOp114 but breaks cubicOp58d and cubicOp53d + double tValues[2]; + // OPTIMIZATION : another case where caching the present of cubic inflections would be useful + return findInflections(tValues) > 1; +#endif if (!controlsContainedByEnds()) { return false; } diff --git a/pathops/SkPathOpsDebug.cpp b/pathops/SkPathOpsDebug.cpp index 4e421631..1f2b0133 100644 --- a/pathops/SkPathOpsDebug.cpp +++ b/pathops/SkPathOpsDebug.cpp @@ -10,12 +10,12 @@ #if defined SK_DEBUG || !FORCE_RELEASE -int SkPathOpsDebug::gMaxWindSum = SK_MaxS32; -int SkPathOpsDebug::gMaxWindValue = SK_MaxS32; - const char* SkPathOpsDebug::kLVerbStr[] = {"", "line", "quad", "cubic"}; -int SkPathOpsDebug::gContourID; -int SkPathOpsDebug::gSegmentID; + +#if defined(SK_DEBUG) || !FORCE_RELEASE +int SkPathOpsDebug::gContourID = 0; +int SkPathOpsDebug::gSegmentID = 0; +#endif #if DEBUG_SORT || DEBUG_SWAP_TOP int SkPathOpsDebug::gSortCountDefault = SK_MaxS32; @@ -393,6 +393,17 @@ bool SkOpSegment::debugContains(const SkOpAngle* angle) const { } #endif +#if DEBUG_SWAP_TOP +int SkOpSegment::debugInflections(int tStart, int tEnd) const { + if (fVerb != SkPath::kCubic_Verb) { + return false; + } + SkDCubic dst = SkDCubic::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT); + double inflections[2]; + return dst.findInflections(inflections); +} +#endif + void SkOpSegment::debugReset() { fTs.reset(); fAngles.reset(); diff --git a/pathops/SkPathOpsDebug.h b/pathops/SkPathOpsDebug.h index 5cacee5c..39d5a6dd 100644 --- a/pathops/SkPathOpsDebug.h +++ b/pathops/SkPathOpsDebug.h @@ -52,6 +52,7 @@ #define DEBUG_CROSS 0 #define DEBUG_FLAT_QUADS 0 #define DEBUG_FLOW 0 +#define DEBUG_LIMIT_WIND_SUM 0 #define DEBUG_MARK_DONE 0 #define DEBUG_PATH_CONSTRUCTION 0 #define DEBUG_SHOW_TEST_NAME 0 @@ -85,6 +86,7 @@ #define DEBUG_CROSS 01 #define DEBUG_FLAT_QUADS 0 #define DEBUG_FLOW 1 +#define DEBUG_LIMIT_WIND_SUM 4 #define DEBUG_MARK_DONE 1 #define DEBUG_PATH_CONSTRUCTION 1 #define DEBUG_SHOW_TEST_NAME 1 @@ -96,7 +98,7 @@ #define DEBUG_SORT_SINGLE 0 #define DEBUG_SWAP_TOP 1 #define DEBUG_UNSORTABLE 1 -#define DEBUG_VALIDATE 1 +#define DEBUG_VALIDATE 0 #define DEBUG_WIND_BUMP 0 #define DEBUG_WINDING 1 #define DEBUG_WINDING_AT_T 1 @@ -134,12 +136,12 @@ class SkPathOpsDebug { public: - static int gMaxWindSum; - static int gMaxWindValue; - static const char* kLVerbStr[]; + +#if defined(SK_DEBUG) || !FORCE_RELEASE static int gContourID; static int gSegmentID; +#endif #if DEBUG_SORT || DEBUG_SWAP_TOP static int gSortCountDefault; diff --git a/pathops/SkPathOpsOp.cpp b/pathops/SkPathOpsOp.cpp index 130d4983..5af4753b 100644 --- a/pathops/SkPathOpsOp.cpp +++ b/pathops/SkPathOpsOp.cpp @@ -21,6 +21,9 @@ static SkOpSegment* findChaseOp(SkTDArray<SkOpSpan*>& chase, int* tIndex, int* e *endIndex = -1; if (const SkOpAngle* last = segment->activeAngle(*tIndex, tIndex, endIndex, &done, &sortable)) { + if (last->unorderable()) { + continue; + } *tIndex = last->start(); *endIndex = last->end(); #if TRY_ROTATE @@ -116,21 +119,31 @@ static bool bridgeOp(SkTArray<SkOpContour*, true>& contourList, const SkPathOp o bool firstContour = true; bool unsortable = false; bool topUnsortable = false; + bool firstPass = true; + SkPoint lastTopLeft; SkPoint topLeft = {SK_ScalarMin, SK_ScalarMin}; do { int index, endIndex; - bool done; + bool topDone; + lastTopLeft = topLeft; SkOpSegment* current = FindSortableTop(contourList, SkOpAngle::kBinarySingle, &firstContour, - &index, &endIndex, &topLeft, &topUnsortable, &done); + &index, &endIndex, &topLeft, &topUnsortable, &topDone, firstPass); if (!current) { - if (topUnsortable || !done) { - topUnsortable = false; + if ((!topUnsortable || firstPass) && !topDone) { SkASSERT(topLeft.fX != SK_ScalarMin && topLeft.fY != SK_ScalarMin); + if (lastTopLeft.fX == SK_ScalarMin && lastTopLeft.fY == SK_ScalarMin) { + if (firstPass) { + firstPass = false; + } else { + break; + } + } topLeft.fX = topLeft.fY = SK_ScalarMin; continue; } break; } + firstPass = !topUnsortable || lastTopLeft != topLeft; SkTDArray<SkOpSpan*> chaseArray; do { if (current->activeOp(index, endIndex, xorMask, xorOpMask, op)) { diff --git a/pathops/SkPathOpsSimplify.cpp b/pathops/SkPathOpsSimplify.cpp index 66a6c402..0917b69e 100644 --- a/pathops/SkPathOpsSimplify.cpp +++ b/pathops/SkPathOpsSimplify.cpp @@ -13,21 +13,24 @@ static bool bridgeWinding(SkTArray<SkOpContour*, true>& contourList, SkPathWrite bool firstContour = true; bool unsortable = false; bool topUnsortable = false; + bool firstPass = true; + SkPoint lastTopLeft; SkPoint topLeft = {SK_ScalarMin, SK_ScalarMin}; do { int index, endIndex; bool topDone; + lastTopLeft = topLeft; SkOpSegment* current = FindSortableTop(contourList, SkOpAngle::kUnaryWinding, &firstContour, - &index, &endIndex, &topLeft, &topUnsortable, &topDone); + &index, &endIndex, &topLeft, &topUnsortable, &topDone, firstPass); if (!current) { - if (topUnsortable || !topDone) { - topUnsortable = false; + if ((!topUnsortable || firstPass) && !topDone) { SkASSERT(topLeft.fX != SK_ScalarMin && topLeft.fY != SK_ScalarMin); topLeft.fX = topLeft.fY = SK_ScalarMin; continue; } break; } + firstPass = !topUnsortable || lastTopLeft != topLeft; SkTDArray<SkOpSpan*> chaseArray; do { if (current->activeWinding(index, endIndex)) { diff --git a/pathops/SkReduceOrder.cpp b/pathops/SkReduceOrder.cpp index ada52761..bb2038b4 100644 --- a/pathops/SkReduceOrder.cpp +++ b/pathops/SkReduceOrder.cpp @@ -161,8 +161,8 @@ static int check_linear(const SkDCubic& cubic, while (cubic[startIndex].approximatelyEqual(cubic[endIndex])) { --endIndex; if (endIndex == 0) { - SkDebugf("%s shouldn't get here if all four points are about equal\n", __FUNCTION__); - SkASSERT(0); + endIndex = 3; + break; } } if (!cubic.isLinear(startIndex, endIndex)) { diff --git a/pipe/SkGPipeRead.cpp b/pipe/SkGPipeRead.cpp index f95bb7c4..41c417f9 100644 --- a/pipe/SkGPipeRead.cpp +++ b/pipe/SkGPipeRead.cpp @@ -230,15 +230,13 @@ private: /////////////////////////////////////////////////////////////////////////////// -template <typename T> const T* skip(SkReader32* reader, int count = 1) { - SkASSERT(count >= 0); +template <typename T> const T* skip(SkReader32* reader, size_t count = 1) { size_t size = sizeof(T) * count; SkASSERT(SkAlign4(size) == size); return reinterpret_cast<const T*>(reader->skip(size)); } -template <typename T> const T* skipAlign(SkReader32* reader, int count = 1) { - SkASSERT(count >= 0); +template <typename T> const T* skipAlign(SkReader32* reader, size_t count = 1) { size_t size = SkAlign4(sizeof(T) * count); return reinterpret_cast<const T*>(reader->skip(size)); } diff --git a/pipe/SkGPipeWrite.cpp b/pipe/SkGPipeWrite.cpp index 297e613a6..82848f8a 100644 --- a/pipe/SkGPipeWrite.cpp +++ b/pipe/SkGPipeWrite.cpp @@ -59,7 +59,7 @@ static size_t writeTypeface(SkWriter32* writer, SkTypeface* typeface) { typeface->serialize(&stream); size_t size = stream.getOffset(); if (writer) { - writer->write32(size); + writer->write32(SkToU32(size)); SkAutoDataUnref data(stream.copyToData()); writer->writePad(data->data(), size); } @@ -379,7 +379,7 @@ bool SkGPipeCanvas::shuttleBitmap(const SkBitmap& bm, int32_t slot) { buffer.setNamedFactoryRecorder(fFactorySet); buffer.writeBitmap(bm); this->flattenFactoryNames(); - uint32_t size = buffer.bytesWritten(); + size_t size = buffer.bytesWritten(); if (this->needOpBytes(size)) { this->writeOp(kDef_Bitmap_DrawOp, 0, slot); void* dst = static_cast<void*>(fWriter.reserve(size)); @@ -478,7 +478,7 @@ bool SkGPipeCanvas::needOpBytes(size_t needed) { // Before we wipe out any data that has already been written, read it // out. this->doNotify(); - size_t blockSize = SkMax32(MIN_BLOCK_SIZE, needed); + size_t blockSize = SkTMax<size_t>(MIN_BLOCK_SIZE, needed); void* block = fController->requestBlock(blockSize, &fBlockSize); if (NULL == block) { // Do not notify the readers, which would call this function again. @@ -704,7 +704,7 @@ void SkGPipeCanvas::drawPoints(PointMode mode, size_t count, this->writePaint(paint); if (this->needOpBytes(4 + count * sizeof(SkPoint))) { this->writeOp(kDrawPoints_DrawOp, mode, 0); - fWriter.write32(count); + fWriter.write32(SkToU32(count)); fWriter.write(pts, count * sizeof(SkPoint)); } } @@ -855,7 +855,7 @@ void SkGPipeCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, this->writePaint(paint); if (this->needOpBytes(4 + SkAlign4(byteLength) + 2 * sizeof(SkScalar))) { this->writeOp(kDrawText_DrawOp); - fWriter.write32(byteLength); + fWriter.write32(SkToU32(byteLength)); fWriter.writePad(text, byteLength); fWriter.writeScalar(x); fWriter.writeScalar(y); @@ -871,7 +871,7 @@ void SkGPipeCanvas::onDrawPosText(const void* text, size_t byteLength, const SkP int count = paint.textToGlyphs(text, byteLength, NULL); if (this->needOpBytes(4 + SkAlign4(byteLength) + 4 + count * sizeof(SkPoint))) { this->writeOp(kDrawPosText_DrawOp); - fWriter.write32(byteLength); + fWriter.write32(SkToU32(byteLength)); fWriter.writePad(text, byteLength); fWriter.write32(count); fWriter.write(pos, count * sizeof(SkPoint)); @@ -887,7 +887,7 @@ void SkGPipeCanvas::onDrawPosTextH(const void* text, size_t byteLength, const Sk int count = paint.textToGlyphs(text, byteLength, NULL); if (this->needOpBytes(4 + SkAlign4(byteLength) + 4 + count * sizeof(SkScalar) + 4)) { this->writeOp(kDrawPosTextH_DrawOp); - fWriter.write32(byteLength); + fWriter.write32(SkToU32(byteLength)); fWriter.writePad(text, byteLength); fWriter.write32(count); fWriter.write(xpos, count * sizeof(SkScalar)); @@ -910,7 +910,7 @@ void SkGPipeCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const if (this->needOpBytes(size)) { this->writeOp(kDrawTextOnPath_DrawOp, flags, 0); - fWriter.write32(byteLength); + fWriter.write32(SkToU32(byteLength)); fWriter.writePad(text, byteLength); fWriter.writePath(path); @@ -989,7 +989,7 @@ void SkGPipeCanvas::drawData(const void* ptr, size_t size) { if (this->needOpBytes(4 + SkAlign4(size))) { this->writeOp(kDrawData_DrawOp, 0, data); if (0 == data) { - fWriter.write32(size); + fWriter.write32(SkToU32(size)); } fWriter.writePad(ptr, size); } @@ -1139,7 +1139,7 @@ void SkGPipeCanvas::writePaint(const SkPaint& paint) { size_t size = (char*)ptr - (char*)storage; if (size && this->needOpBytes(size)) { - this->writeOp(kPaintOp_DrawOp, 0, size); + this->writeOp(kPaintOp_DrawOp, 0, SkToU32(size)); fWriter.write(storage, size); for (size_t i = 0; i < size/4; i++) { // SkDebugf("[%d] %08X\n", i, storage[i]); @@ -1159,7 +1159,7 @@ void SkGPipeCanvas::writePaint(const SkPaint& paint) { paint.getAnnotation()->writeToBuffer(buffer); const size_t size = buffer.bytesWritten(); if (this->needOpBytes(size)) { - this->writeOp(kSetAnnotation_DrawOp, 0, size); + this->writeOp(kSetAnnotation_DrawOp, 0, SkToU32(size)); buffer.writeToMemory(fWriter.reserve(size)); } } diff --git a/record/SkRecord.h b/record/SkRecord.h index ddf1b3d9..b1e4ae24 100644 --- a/record/SkRecord.h +++ b/record/SkRecord.h @@ -82,20 +82,31 @@ public: // Replace the i-th command with a new command of type T. // You are expected to placement new an object of type T onto this pointer. - // References to the old command remain valid for the life of the SkRecord, but - // you must destroy the old command. (It's okay to destroy it first before calling replace.) + // References to the original command are invalidated. template <typename T> T* replace(unsigned i) { SkASSERT(i < this->count()); + + Destroyer destroyer; + this->mutate(i, destroyer); + fTypes[i] = T::kType; return fRecords[i].set(this->alloc<T>()); } - // A mutator that can be used with replace to destroy canvas commands. - struct Destroyer { - template <typename T> - void operator()(T* record) { record->~T(); } - }; + // Replace the i-th command with a new command of type T. + // You are expected to placement new an object of type T onto this pointer. + // You must show proof that you've already adopted the existing command. + template <typename T, typename Existing> + T* replace(unsigned i, const SkRecords::Adopted<Existing>& proofOfAdoption) { + SkASSERT(i < this->count()); + + SkASSERT(Existing::kType == fTypes[i]); + SkASSERT(proofOfAdoption == fRecords[i].ptr<Existing>()); + + fTypes[i] = T::kType; + return fRecords[i].set(this->alloc<T>()); + } private: // Implementation notes! @@ -134,6 +145,11 @@ private: // // The cost to append a T into this structure is 1 + sizeof(void*) + sizeof(T). + // A mutator that can be used with replace to destroy canvas commands. + struct Destroyer { + template <typename T> + void operator()(T* record) { record->~T(); } + }; // Logically the same as SkRecords::Type, but packed into 8 bits. struct Type8 { @@ -157,6 +173,10 @@ private: return ptr; } + // Get the data in fAlloc, assuming it's of type T. + template <typename T> + T* ptr() const { return (T*)fPtr; } + // Visit this record with functor F (see public API above) assuming the record we're // pointing to has this type. template <typename F> @@ -176,9 +196,6 @@ private: } private: - template <typename T> - T* ptr() const { return (T*)fPtr; } - void* fPtr; }; diff --git a/record/SkRecordDraw.cpp b/record/SkRecordDraw.cpp index 21b2c7a8..4878b3f4 100644 --- a/record/SkRecordDraw.cpp +++ b/record/SkRecordDraw.cpp @@ -12,7 +12,7 @@ namespace { // This is an SkRecord visitor that will draw that SkRecord to an SkCanvas. class Draw : SkNoncopyable { public: - explicit Draw(SkCanvas* canvas) : fCanvas(canvas), fIndex(0), fClipEmpty(false) {} + explicit Draw(SkCanvas* canvas) : fCanvas(canvas), fIndex(0) {} unsigned index() const { return fIndex; } void next() { ++fIndex; } @@ -20,65 +20,36 @@ public: template <typename T> void operator()(const T& r) { if (!this->skip(r)) { this->draw(r); - this->updateClip<T>(); } } private: - // Return true if we can skip this command, false if not. - // Update fIndex here directly to skip more than just this one command. - template <typename T> bool skip(const T&) { - // We can skip most commands if the clip is empty. Exceptions are specialized below. - return fClipEmpty; - } - // No base case, so we'll be compile-time checked that we implemented all possibilities below. template <typename T> void draw(const T&); - // Update fClipEmpty if necessary. - template <typename T> void updateClip() { - // Most commands don't change the clip. Exceptions are specialized below. + // skip() should return true if we can skip this command, false if not. + // It may update fIndex directly to skip more than just this one command. + + // Mostly we just blindly call fCanvas and let it handle quick rejects itself. + template <typename T> bool skip(const T&) { return false; } + + // We add our own quick rejects for commands added by optimizations. + bool skip(const SkRecords::PairedPushCull& r) { + if (fCanvas->quickReject(r.base->rect)) { + fIndex += r.skip; + return true; + } + return false; + } + bool skip(const SkRecords::BoundedDrawPosTextH& r) { + return fCanvas->quickRejectY(r.minY, r.maxY); } SkCanvas* fCanvas; unsigned fIndex; - bool fClipEmpty; }; -// TODO(mtklein): do this specialization with template traits instead of macros - -// These commands may change the clip. -#define UPDATE_CLIP(T) template <> void Draw::updateClip<SkRecords::T>() \ - { fClipEmpty = fCanvas->isClipEmpty(); } -UPDATE_CLIP(Restore); -UPDATE_CLIP(SaveLayer); -UPDATE_CLIP(ClipPath); -UPDATE_CLIP(ClipRRect); -UPDATE_CLIP(ClipRect); -UPDATE_CLIP(ClipRegion); -#undef UPDATE_CLIP - -// These commands must always run. -#define SKIP(T) template <> bool Draw::skip(const SkRecords::T&) { return false; } -SKIP(Restore); -SKIP(Save); -SKIP(SaveLayer); -SKIP(Clear); -SKIP(PushCull); -SKIP(PopCull); -#undef SKIP - -// We can skip these commands if they're intersecting with a clip that's already empty. -#define SKIP(T) template <> bool Draw::skip(const SkRecords::T& r) \ - { return fClipEmpty && SkRegion::kIntersect_Op == r.op; } -SKIP(ClipPath); -SKIP(ClipRRect); -SKIP(ClipRect); -SKIP(ClipRegion); -#undef SKIP - -// NoOps can always be skipped and draw nothing. -template <> bool Draw::skip(const SkRecords::NoOp&) { return true; } +// NoOps draw nothing. template <> void Draw::draw(const SkRecords::NoOp&) {} #define DRAW(T, call) template <> void Draw::draw(const SkRecords::T& r) { fCanvas->call; } @@ -116,25 +87,8 @@ DRAW(DrawVertices, drawVertices(r.vmode, r.vertexCount, r.vertices, r.texs, r.co r.xmode.get(), r.indices, r.indexCount, r.paint)); #undef DRAW -// Added by SkRecordAnnotateCullingPairs. -template <> bool Draw::skip(const SkRecords::PairedPushCull& r) { - if (fCanvas->quickReject(r.base->rect)) { - fIndex += r.skip; - return true; - } - return false; -} - -// Added by SkRecordBoundDrawPosTextH -template <> bool Draw::skip(const SkRecords::BoundedDrawPosTextH& r) { - return fClipEmpty || fCanvas->quickRejectY(r.minY, r.maxY); -} - -// These draw by proxying to the commands they wrap. (All the optimization is for skip().) -#define DRAW(T) template <> void Draw::draw(const SkRecords::T& r) { this->draw(*r.base); } -DRAW(PairedPushCull); -DRAW(BoundedDrawPosTextH); -#undef DRAW +template <> void Draw::draw(const SkRecords::PairedPushCull& r) { this->draw(*r.base); } +template <> void Draw::draw(const SkRecords::BoundedDrawPosTextH& r) { this->draw(*r.base); } } // namespace diff --git a/record/SkRecordOpts.cpp b/record/SkRecordOpts.cpp index 3cf135fb..5b537de0 100644 --- a/record/SkRecordOpts.cpp +++ b/record/SkRecordOpts.cpp @@ -7,6 +7,7 @@ #include "SkRecordOpts.h" +#include "SkRecordTraits.h" #include "SkRecords.h" #include "SkTDArray.h" @@ -18,10 +19,6 @@ void SkRecordOptimize(SkRecord* record) { SkRecordBoundDrawPosTextH(record); } -// Streamline replacing one command with another. -#define REPLACE(record, index, T, ...) \ - SkNEW_PLACEMENT_ARGS(record->replace<SkRecords::T>(index), SkRecords::T, (__VA_ARGS__)) - namespace { // Convenience base class to share some common implementation code. @@ -44,9 +41,28 @@ public: explicit SaveRestoreNooper(SkRecord* record) : Common(record), fSave(kInactive), fChanged(false) {} - // Most drawing commands reset to inactive state without nooping anything. + // Drawing commands reset state to inactive without nooping. + template <typename T> + SK_WHEN(SkRecords::IsDraw<T>, void) operator()(T*) { fSave = kInactive; } + + // Most non-drawing commands can be ignored. template <typename T> - void operator()(T*) { fSave = kInactive; } + SK_WHEN(!SkRecords::IsDraw<T>, void) operator()(T*) {} + + void operator()(SkRecords::Save* r) { + fSave = SkCanvas::kMatrixClip_SaveFlag == r->flags ? this->index() : kInactive; + } + + void operator()(SkRecords::Restore* r) { + if (fSave != kInactive) { + // Remove everything between the save and restore, inclusive on both sides. + fChanged = true; + for (unsigned i = fSave; i <= this->index(); i++) { + fRecord->replace<SkRecords::NoOp>(i); + } + fSave = kInactive; + } + } bool changed() const { return fChanged; } @@ -56,41 +72,6 @@ private: bool fChanged; }; -// If the command doesn't draw anything, that doesn't reset the state back to inactive. -// TODO(mtklein): do this with some sort of template-based trait mechanism instead of macros -#define DOESNT_DRAW(T) template <> void SaveRestoreNooper::operator()(SkRecords::T*) {} -DOESNT_DRAW(NoOp) -DOESNT_DRAW(Concat) -DOESNT_DRAW(SetMatrix) -DOESNT_DRAW(ClipRect) -DOESNT_DRAW(ClipRRect) -DOESNT_DRAW(ClipPath) -DOESNT_DRAW(ClipRegion) -DOESNT_DRAW(PairedPushCull) -DOESNT_DRAW(PushCull) -DOESNT_DRAW(PopCull) -#undef DOESNT_DRAW - -template <> -void SaveRestoreNooper::operator()(SkRecords::Save* r) { - fSave = SkCanvas::kMatrixClip_SaveFlag == r->flags ? this->index() : kInactive; -} - -template <> -void SaveRestoreNooper::operator()(SkRecords::Restore* r) { - if (fSave != kInactive) { - // Remove everything between the save and restore, inclusive on both sides. - fChanged = true; - SkRecord::Destroyer destroyer; - for (unsigned i = fSave; i <= this->index(); i++) { - fRecord->mutate(i, destroyer); - REPLACE(fRecord, i, NoOp); - } - fSave = kInactive; - } -} - - // Tries to replace PushCull with PairedPushCull, which lets us skip to the paired PopCull // when the canvas can quickReject the cull rect. class CullAnnotator : public Common { @@ -98,8 +79,24 @@ public: explicit CullAnnotator(SkRecord* record) : Common(record) {} // Do nothing to most ops. - template <typename T> - void operator()(T*) {} + template <typename T> void operator()(T*) {} + + void operator()(SkRecords::PushCull* push) { + Pair pair = { this->index(), push }; + fPushStack.push(pair); + } + + void operator()(SkRecords::PopCull* pop) { + Pair push = fPushStack.top(); + fPushStack.pop(); + + SkASSERT(this->index() > push.index); + unsigned skip = this->index() - push.index; + + SkRecords::Adopted<SkRecords::PushCull> adopted(push.command); + SkNEW_PLACEMENT_ARGS(fRecord->replace<SkRecords::PairedPushCull>(push.index, adopted), + SkRecords::PairedPushCull, (&adopted, skip)); + } private: struct Pair { @@ -110,66 +107,46 @@ private: SkTDArray<Pair> fPushStack; }; -template <> -void CullAnnotator::operator()(SkRecords::PushCull* push) { - Pair pair = { this->index(), push }; - fPushStack.push(pair); -} - -template <> -void CullAnnotator::operator()(SkRecords::PopCull* pop) { - Pair push = fPushStack.top(); - fPushStack.pop(); - - SkASSERT(this->index() > push.index); - unsigned skip = this->index() - push.index; - - // PairedPushCull adopts push.command. - REPLACE(fRecord, push.index, PairedPushCull, push.command, skip); -} - // Replaces DrawPosText with DrawPosTextH when all Y coordinates are equal. class StrengthReducer : public Common { public: explicit StrengthReducer(SkRecord* record) : Common(record) {} // Do nothing to most ops. - template <typename T> - void operator()(T*) {} -}; + template <typename T> void operator()(T*) {} -template <> -void StrengthReducer::operator()(SkRecords::DrawPosText* r) { - const unsigned points = r->paint.countText(r->text, r->byteLength); - if (points == 0) { - // No point (ha!). - return; - } - - const SkScalar firstY = r->pos[0].fY; - for (unsigned i = 1; i < points; i++) { - if (r->pos[i].fY != firstY) { - // Needs the full strength of DrawPosText. + void operator()(SkRecords::DrawPosText* r) { + const unsigned points = r->paint.countText(r->text, r->byteLength); + if (points == 0) { + // No point (ha!). return; } - } - // All ys are the same. We can replace DrawPosText with DrawPosTextH. - - // r->pos is points SkPoints, [(x,y),(x,y),(x,y),(x,y), ... ]. - // We're going to squint and look at that as 2*points SkScalars, [x,y,x,y,x,y,x,y, ...]. - // Then we'll rearrange things so all the xs are in order up front, clobbering the ys. - SK_COMPILE_ASSERT(sizeof(SkPoint) == 2 * sizeof(SkScalar), SquintingIsNotSafe); - SkScalar* scalars = &r->pos[0].fX; - for (unsigned i = 0; i < 2*points; i += 2) { - scalars[i/2] = scalars[i]; - } - SkRecord::Destroyer destroyer; - fRecord->mutate(this->index(), destroyer); - REPLACE(fRecord, this->index(), - DrawPosTextH, (char*)r->text, r->byteLength, scalars, firstY, r->paint); -} + const SkScalar firstY = r->pos[0].fY; + for (unsigned i = 1; i < points; i++) { + if (r->pos[i].fY != firstY) { + // Needs the full strength of DrawPosText. + return; + } + } + // All ys are the same. We can replace DrawPosText with DrawPosTextH. + + // r->pos is points SkPoints, [(x,y),(x,y),(x,y),(x,y), ... ]. + // We're going to squint and look at that as 2*points SkScalars, [x,y,x,y,x,y,x,y, ...]. + // Then we'll rearrange things so all the xs are in order up front, clobbering the ys. + SK_COMPILE_ASSERT(sizeof(SkPoint) == 2 * sizeof(SkScalar), SquintingIsNotSafe); + SkScalar* scalars = &r->pos[0].fX; + for (unsigned i = 0; i < 2*points; i += 2) { + scalars[i/2] = scalars[i]; + } + // Extend lifetime of r to the end of the method so we can copy its parts. + SkRecords::Adopted<SkRecords::DrawPosText> adopted(r); + SkNEW_PLACEMENT_ARGS(fRecord->replace<SkRecords::DrawPosTextH>(this->index(), adopted), + SkRecords::DrawPosTextH, + (r->text, r->byteLength, scalars, firstY, r->paint)); + } +}; // Tries to replace DrawPosTextH with BoundedDrawPosTextH, which knows conservative upper and lower // bounds to use with SkCanvas::quickRejectY. @@ -178,35 +155,37 @@ public: explicit TextBounder(SkRecord* record) : Common(record) {} // Do nothing to most ops. - template <typename T> - void operator()(T*) {} -}; + template <typename T> void operator()(T*) {} -template <> -void TextBounder::operator()(SkRecords::DrawPosTextH* r) { - // If we're drawing vertical text, none of the checks we're about to do make any sense. - // We'll need to call SkPaint::computeFastBounds() later, so bail if that's not possible. - if (r->paint.isVerticalText() || !r->paint.canComputeFastBounds()) { - return; + void operator()(SkRecords::DrawPosTextH* r) { + // If we're drawing vertical text, none of the checks we're about to do make any sense. + // We'll need to call SkPaint::computeFastBounds() later, so bail if that's not possible. + if (r->paint.isVerticalText() || !r->paint.canComputeFastBounds()) { + return; + } + + // Rather than checking the top and bottom font metrics, we guess. Actually looking up the + // top and bottom metrics is slow, and this overapproximation should be good enough. + const SkScalar buffer = r->paint.getTextSize() * 1.5f; + SkDEBUGCODE(SkPaint::FontMetrics metrics;) + SkDEBUGCODE(r->paint.getFontMetrics(&metrics);) + SkASSERT(-buffer <= metrics.fTop); + SkASSERT(+buffer >= metrics.fBottom); + + // Let the paint adjust the text bounds. We don't care about left and right here, so we use + // 0 and 1 respectively just so the bounds rectangle isn't empty. + SkRect bounds; + bounds.set(0, r->y - buffer, SK_Scalar1, r->y + buffer); + SkRect adjusted = r->paint.computeFastBounds(bounds, &bounds); + + SkRecords::Adopted<SkRecords::DrawPosTextH> adopted(r); + SkNEW_PLACEMENT_ARGS( + fRecord->replace<SkRecords::BoundedDrawPosTextH>(this->index(), adopted), + SkRecords::BoundedDrawPosTextH, + (&adopted, adjusted.fTop, adjusted.fBottom)); } +}; - // Rather than checking the top and bottom font metrics, we guess. Actually looking up the - // top and bottom metrics is slow, and this overapproximation should be good enough. - const SkScalar buffer = r->paint.getTextSize() * 1.5f; - SkDEBUGCODE(SkPaint::FontMetrics metrics;) - SkDEBUGCODE(r->paint.getFontMetrics(&metrics);) - SkASSERT(-buffer <= metrics.fTop); - SkASSERT(+buffer >= metrics.fBottom); - - // Let the paint adjust the text bounds. We don't care about left and right here, so we use - // 0 and 1 respectively just so the bounds rectangle isn't empty. - SkRect bounds; - bounds.set(0, r->y - buffer, SK_Scalar1, r->y + buffer); - SkRect adjusted = r->paint.computeFastBounds(bounds, &bounds); - - // BoundedDrawPosTextH adopts r. - REPLACE(fRecord, this->index(), BoundedDrawPosTextH, r, adjusted.fTop, adjusted.fBottom); -} template <typename Pass> static void run_pass(Pass& pass, SkRecord* record) { @@ -242,5 +221,3 @@ void SkRecordBoundDrawPosTextH(SkRecord* record) { TextBounder bounder(record); run_pass(bounder, record); } - -#undef REPLACE diff --git a/record/SkRecordOpts.h b/record/SkRecordOpts.h index c9cbccf9..6db7abca 100644 --- a/record/SkRecordOpts.h +++ b/record/SkRecordOpts.h @@ -15,15 +15,15 @@ void SkRecordOptimize(SkRecord*); // Turns logical no-op Save-[non-drawing command]*-Restore patterns into actual no-ops. -void SkRecordNoopSaveRestores(SkRecord*); // TODO(mtklein): add unit tests +void SkRecordNoopSaveRestores(SkRecord*); // Annotates PushCull commands with the relative offset of their paired PopCull. void SkRecordAnnotateCullingPairs(SkRecord*); // Convert DrawPosText to DrawPosTextH when all the Y coordinates are equal. -void SkRecordReduceDrawPosTextStrength(SkRecord*); // TODO(mtklein): add unit tests +void SkRecordReduceDrawPosTextStrength(SkRecord*); // Calculate min and max Y bounds for DrawPosTextH commands, for use with SkCanvas::quickRejectY. -void SkRecordBoundDrawPosTextH(SkRecord*); // TODO(mtklein): add unit tests +void SkRecordBoundDrawPosTextH(SkRecord*); #endif//SkRecordOpts_DEFINED diff --git a/record/SkRecordTraits.h b/record/SkRecordTraits.h new file mode 100644 index 00000000..570a717e --- /dev/null +++ b/record/SkRecordTraits.h @@ -0,0 +1,31 @@ +#include "SkRecords.h" +#include "SkTLogic.h" + +// Type traits that are useful for working with SkRecords. + +namespace SkRecords { + +namespace { + +// Abstracts away whether the T is optional or not. +template <typename T> const T* as_ptr(const SkRecords::Optional<T>& x) { return x; } +template <typename T> const T* as_ptr(const T& x) { return &x; } + +} // namespace + +// Gets the paint from any command that may have one. +template <typename Command> const SkPaint* GetPaint(const Command& x) { return as_ptr(x.paint); } + +// Have a paint? You are a draw command! +template <typename Command> struct IsDraw { + SK_CREATE_MEMBER_DETECTOR(paint); + static const bool value = HasMember_paint<Command>::value; +}; + +// Have a clip op? You are a clip command. +template <typename Command> struct IsClip { + SK_CREATE_MEMBER_DETECTOR(op); + static const bool value = HasMember_op<Command>::value; +}; + +} // namespace SkRecords diff --git a/record/SkRecorder.cpp b/record/SkRecorder.cpp index 345597c5..fe4f35f5 100644 --- a/record/SkRecorder.cpp +++ b/record/SkRecorder.cpp @@ -12,6 +12,10 @@ SkRecorder::SkRecorder(SkRecorder::Mode mode, SkRecord* record, int width, int height) : SkCanvas(width, height), fMode(mode), fRecord(record) {} +void SkRecorder::forgetRecord() { + fRecord = NULL; +} + // To make appending to fRecord a little less verbose. #define APPEND(T, ...) \ SkNEW_PLACEMENT_ARGS(fRecord->append<SkRecords::T>(), SkRecords::T, (__VA_ARGS__)) diff --git a/record/SkRecorder.h b/record/SkRecorder.h index dc3de294..e6bddd75 100644 --- a/record/SkRecorder.h +++ b/record/SkRecorder.h @@ -28,6 +28,9 @@ public: // Does not take ownership of the SkRecord. SkRecorder(Mode mode, SkRecord*, int width, int height); + // Make SkRecorder forget entirely about its SkRecord*; all calls to SkRecorder will fail. + void forgetRecord(); + void clear(SkColor) SK_OVERRIDE; void drawPaint(const SkPaint& paint) SK_OVERRIDE; void drawPoints(PointMode mode, diff --git a/record/SkRecording.cpp b/record/SkRecording.cpp index 6af19593..57743622 100644 --- a/record/SkRecording.cpp +++ b/record/SkRecording.cpp @@ -16,38 +16,29 @@ namespace EXPERIMENTAL { SkPlayback::SkPlayback(const SkRecord* record) : fRecord(record) {} -SkPlayback::~SkPlayback() { - SkDELETE(fRecord); -} +SkPlayback::~SkPlayback() {} void SkPlayback::draw(SkCanvas* canvas) const { - SkASSERT(fRecord != NULL); + SkASSERT(fRecord.get() != NULL); SkRecordDraw(*fRecord, canvas); } -/*static*/ SkRecording* SkRecording::Create(int width, int height) { - return SkNEW_ARGS(SkRecording, (width, height)); -} +SkRecording::SkRecording(int width, int height) + : fRecord(SkNEW(SkRecord)) + , fRecorder(SkNEW_ARGS(SkRecorder, (SkRecorder::kReadWrite_Mode, fRecord.get(), width, height))) + {} -SkRecording::SkRecording(int width, int height) { - SkRecord* record = SkNEW(SkRecord); - fRecorder = SkNEW_ARGS(SkRecorder, (SkRecorder::kReadWrite_Mode, record, width, height)); - fRecord = record; +SkPlayback* SkRecording::releasePlayback() { + SkASSERT(fRecorder->unique()); + fRecorder->forgetRecord(); + SkRecordOptimize(fRecord.get()); + return SkNEW_ARGS(SkPlayback, (fRecord.detach())); } -/*static*/ const SkPlayback* SkRecording::Delete(SkRecording* recording) { - SkRecord* record = recording->fRecord; - SkRecordOptimize(record); - SkDELETE(recording); - return SkNEW_ARGS(SkPlayback, (record)); -} - -SkRecording::~SkRecording() { - SkDELETE(fRecorder); -} +SkRecording::~SkRecording() {} SkCanvas* SkRecording::canvas() { - return fRecorder; + return fRecord.get() ? fRecorder.get() : NULL; } } // namespace EXPERIMENTAL diff --git a/record/SkRecords.h b/record/SkRecords.h index 8b96e8d9..bfa15496 100644 --- a/record/SkRecords.h +++ b/record/SkRecords.h @@ -133,7 +133,12 @@ template <typename T> class Adopted : SkNoncopyable { public: Adopted(T* ptr) : fPtr(ptr) { SkASSERT(fPtr); } - ~Adopted() { fPtr->~T(); } + Adopted(Adopted* source) { + // Transfer ownership from source to this. + fPtr = source->fPtr; + source->fPtr = NULL; + } + ~Adopted() { if (fPtr) fPtr->~T(); } ACT_AS_PTR(fPtr); private: @@ -142,9 +147,10 @@ private: // PODArray doesn't own the pointer's memory, and we assume the data is POD. template <typename T> -class PODArray : SkNoncopyable { +class PODArray { public: PODArray(T* ptr) : fPtr(ptr) {} + // Default copy and assign. ACT_AS_PTR(fPtr); private: diff --git a/sfnt/SkOTUtils.cpp b/sfnt/SkOTUtils.cpp index 004a8883..e76d1da0 100644 --- a/sfnt/SkOTUtils.cpp +++ b/sfnt/SkOTUtils.cpp @@ -103,7 +103,7 @@ SkData* SkOTUtils::RenameFont(SkStream* fontData, const char* fontName, int font for (; currentEntry < endEntry; ++currentEntry) { uint32_t oldOffset = SkEndian_SwapBE32(currentEntry->offset); if (oldOffset > oldNameTableOffset) { - currentEntry->offset = SkEndian_SwapBE32(oldOffset - oldNameTablePhysicalSize); + currentEntry->offset = SkEndian_SwapBE32(SkToU32(oldOffset - oldNameTablePhysicalSize)); } if (SkOTTableHead::TAG == currentEntry->tag) { headTableEntry = currentEntry; @@ -112,8 +112,8 @@ SkData* SkOTUtils::RenameFont(SkStream* fontData, const char* fontName, int font // Make the table directory entry point to the new 'name' table. SkSFNTHeader::TableDirectoryEntry* nameTableEntry = reinterpret_cast<SkSFNTHeader::TableDirectoryEntry*>(data + sizeof(SkSFNTHeader)) + tableIndex; - nameTableEntry->logicalLength = SkEndian_SwapBE32(nameTableLogicalSize); - nameTableEntry->offset = SkEndian_SwapBE32(originalDataSize); + nameTableEntry->logicalLength = SkEndian_SwapBE32(SkToU32(nameTableLogicalSize)); + nameTableEntry->offset = SkEndian_SwapBE32(SkToU32(originalDataSize)); // Write the new 'name' table after the original font data. SkOTTableName* nameTable = reinterpret_cast<SkOTTableName*>(data + originalDataSize); diff --git a/utils/SkTLogic.h b/utils/SkTLogic.h index bf9ee1ab..62952ad1 100644 --- a/utils/SkTLogic.h +++ b/utils/SkTLogic.h @@ -58,4 +58,35 @@ struct SkTMux { typename SkTIf<b, B, Neither>::type>::type type; }; +/** SkTEnableIf_c::type = (condition) ? T : [does not exist]; */ +template <bool condition, class T = void> struct SkTEnableIf_c { }; +template <class T> struct SkTEnableIf_c<true, T> { + typedef T type; +}; + +/** SkTEnableIf::type = (Condition::value) ? T : [does not exist]; */ +template <class Condition, class T = void> struct SkTEnableIf + : public SkTEnableIf_c<static_cast<bool>(Condition::value), T> { }; + +/** Use as a return type to enable a function only when cond_type::value is true, + * like C++14's std::enable_if_t. E.g. (N.B. this is a dumb example.) + * SK_WHEN(SkTrue, int) f(void* ptr) { return 1; } + * SK_WHEN(!SkTrue, int) f(void* ptr) { return 2; } + */ +#define SK_WHEN(cond_prefix, T) typename SkTEnableIf_c<cond_prefix::value, T>::type + +// See http://en.wikibooks.org/wiki/More_C++_Idioms/Member_Detector +#define SK_CREATE_MEMBER_DETECTOR(member) \ +template <typename T> \ +class HasMember_##member { \ + struct Fallback { int member; }; \ + struct Derived : T, Fallback {}; \ + template <typename U, U> struct Check; \ + template <typename U> static uint8_t func(Check<int Fallback::*, &U::member>*); \ + template <typename U> static uint16_t func(...); \ +public: \ + typedef HasMember_##member type; \ + static const bool value = sizeof(func<Derived>(NULL)) == sizeof(uint16_t); \ +} + #endif |