summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBo Liu <boliu@google.com>2014-05-01 10:38:38 -0700
committerBo Liu <boliu@google.com>2014-05-01 10:38:38 -0700
commit27ab20dffff01006f5d20fdb2b3f4ea503d69114 (patch)
treef8a42f1186f835772ed0c20a7f9095392e124b04
parent51512eaae8128a677f92e2689d8df720dca13d32 (diff)
parent2e8705638185600b128f867809b6cd034225451c (diff)
downloadsrc-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
-rw-r--r--animator/SkDrawBlur.cpp7
-rw-r--r--animator/SkDrawBlur.h2
-rw-r--r--animator/SkDrawGradient.cpp8
-rw-r--r--animator/SkDrawShader.cpp9
-rw-r--r--animator/SkPaintPart.h2
-rw-r--r--core/SkBBoxHierarchyRecord.cpp5
-rw-r--r--core/SkBBoxHierarchyRecord.h3
-rw-r--r--core/SkBBoxRecord.h4
-rw-r--r--core/SkBitmapDevice.cpp4
-rw-r--r--core/SkBitmapProcShader.cpp11
-rw-r--r--core/SkBitmapProcShader.h5
-rw-r--r--core/SkBlitter.cpp3
-rw-r--r--core/SkCanvas.cpp21
-rw-r--r--core/SkComposeShader.cpp4
-rw-r--r--core/SkDraw.cpp13
-rw-r--r--core/SkDrawLooper.cpp4
-rwxr-xr-xcore/SkGlyphCache.cpp11
-rw-r--r--core/SkMaskFilter.cpp4
-rw-r--r--core/SkPicture.cpp203
-rw-r--r--core/SkPicturePlayback.cpp170
-rw-r--r--core/SkPicturePlayback.h35
-rw-r--r--core/SkPictureRecord.cpp27
-rw-r--r--core/SkPictureRecord.h6
-rw-r--r--core/SkPictureShader.cpp3
-rw-r--r--core/SkPictureStateTree.cpp11
-rw-r--r--core/SkQuadTree.cpp1
-rw-r--r--core/SkReadBuffer.cpp4
-rw-r--r--core/SkRegion.cpp4
-rw-r--r--core/SkRegionPriv.h4
-rw-r--r--core/SkScalerContext.cpp5
-rw-r--r--core/SkShader.cpp60
-rw-r--r--core/SkSmallAllocator.h10
-rw-r--r--core/SkStream.cpp16
-rw-r--r--core/SkValidatingReadBuffer.cpp6
-rw-r--r--core/SkWriter32.cpp4
-rw-r--r--effects/SkBlurDrawLooper.cpp87
-rw-r--r--effects/SkBlurMask.cpp72
-rw-r--r--effects/SkBlurMask.h40
-rw-r--r--effects/SkBlurMaskFilter.cpp399
-rw-r--r--effects/SkEmbossMaskFilter.cpp9
-rw-r--r--effects/SkLayerDrawLooper.cpp44
-rw-r--r--effects/SkMatrixConvolutionImageFilter.cpp13
-rw-r--r--effects/SkTileImageFilter.cpp17
-rw-r--r--effects/gradients/SkGradientShader.cpp33
-rw-r--r--effects/gradients/SkGradientShaderPriv.h2
-rw-r--r--effects/gradients/SkLinearGradient.cpp5
-rw-r--r--effects/gradients/SkLinearGradient.h2
-rw-r--r--effects/gradients/SkRadialGradient.cpp4
-rw-r--r--effects/gradients/SkRadialGradient.h3
-rw-r--r--effects/gradients/SkSweepGradient.cpp4
-rw-r--r--effects/gradients/SkSweepGradient.h3
-rw-r--r--effects/gradients/SkTwoPointConicalGradient.cpp5
-rw-r--r--effects/gradients/SkTwoPointConicalGradient.h3
-rw-r--r--effects/gradients/SkTwoPointRadialGradient.cpp4
-rw-r--r--effects/gradients/SkTwoPointRadialGradient.h2
-rw-r--r--gpu/GrGpu.h2
-rw-r--r--gpu/SkGpuDevice.cpp9
-rw-r--r--gpu/SkGr.cpp4
-rw-r--r--gpu/effects/GrTextureStripAtlas.cpp2
-rw-r--r--gpu/gl/GrGLAssembleInterface.cpp289
-rw-r--r--gpu/gl/GrGLAssembleInterface.h18
-rw-r--r--gpu/gl/GrGLCaps.cpp16
-rw-r--r--gpu/gl/GrGLCaps.h4
-rw-r--r--gpu/gl/GrGLContext.cpp11
-rw-r--r--gpu/gl/GrGLCreateNullInterface.cpp7
-rw-r--r--gpu/gl/GrGLExtensions.cpp5
-rw-r--r--gpu/gl/GrGLInterface.cpp17
-rw-r--r--gpu/gl/GrGLNoOpInterface.cpp16
-rw-r--r--gpu/gl/GrGLNoOpInterface.h12
-rw-r--r--gpu/gl/GrGLProgram.cpp7
-rw-r--r--gpu/gl/GrGLProgramDesc.cpp9
-rw-r--r--gpu/gl/GrGLProgramDesc.h3
-rw-r--r--gpu/gl/GrGLProgramEffects.cpp42
-rw-r--r--gpu/gl/GrGLProgramEffects.h32
-rw-r--r--gpu/gl/GrGLSL.cpp20
-rw-r--r--gpu/gl/GrGLSL.h2
-rw-r--r--gpu/gl/GrGLShaderBuilder.cpp8
-rw-r--r--gpu/gl/GrGLUtil.cpp10
-rw-r--r--gpu/gl/GrGLUtil.h13
-rw-r--r--gpu/gl/GrGpuGL.cpp127
-rw-r--r--gpu/gl/GrGpuGL.h26
-rw-r--r--gpu/gl/GrGpuGL_program.cpp24
-rw-r--r--gpu/gl/android/GrGLCreateNativeInterface_android.cpp244
-rw-r--r--gpu/gl/debug/GrGLCreateDebugInterface.cpp7
-rw-r--r--gpu/gl/mac/GrGLCreateNativeInterface_mac.cpp240
-rw-r--r--gpu/gl/mesa/GrGLCreateMesaInterface.cpp229
-rw-r--r--gpu/gl/unix/GrGLCreateNativeInterface_unix.cpp285
-rw-r--r--gpu/gl/win/GrGLCreateNativeInterface_win.cpp320
-rw-r--r--image/SkImagePriv.cpp57
-rw-r--r--image/SkSurface_Gpu.cpp16
-rw-r--r--images/SkImageDecoder_libwebp.cpp16
-rw-r--r--opts/SkBitmapProcState_opts_SSE2.cpp24
-rw-r--r--opts/SkBlitRow_opts_arm.cpp2
-rw-r--r--opts/SkBlitRow_opts_arm_neon.cpp157
-rw-r--r--opts/SkCachePreload_arm.h34
-rw-r--r--opts/SkColor_opts_SSE2.h15
-rw-r--r--opts/SkMath_opts_SSE2.h51
-rw-r--r--opts/SkXfermode_opts_SSE2.cpp417
-rw-r--r--opts/opts_check_SSE2.cpp78
-rw-r--r--pathops/SkDCubicIntersection.cpp11
-rw-r--r--pathops/SkDCubicLineIntersection.cpp11
-rw-r--r--pathops/SkDLineIntersection.cpp3
-rw-r--r--pathops/SkDQuadLineIntersection.cpp5
-rw-r--r--pathops/SkIntersections.h2
-rw-r--r--pathops/SkOpAngle.cpp52
-rw-r--r--pathops/SkOpAngle.h3
-rw-r--r--pathops/SkOpContour.cpp16
-rw-r--r--pathops/SkOpContour.h6
-rw-r--r--pathops/SkOpEdgeBuilder.cpp4
-rw-r--r--pathops/SkOpSegment.cpp202
-rw-r--r--pathops/SkOpSegment.h33
-rw-r--r--pathops/SkOpSpan.h2
-rw-r--r--pathops/SkPathOpsCommon.cpp21
-rw-r--r--pathops/SkPathOpsCommon.h2
-rw-r--r--pathops/SkPathOpsCubic.cpp5
-rw-r--r--pathops/SkPathOpsDebug.cpp21
-rw-r--r--pathops/SkPathOpsDebug.h10
-rw-r--r--pathops/SkPathOpsOp.cpp21
-rw-r--r--pathops/SkPathOpsSimplify.cpp9
-rw-r--r--pathops/SkReduceOrder.cpp4
-rw-r--r--pipe/SkGPipeRead.cpp6
-rw-r--r--pipe/SkGPipeWrite.cpp22
-rw-r--r--record/SkRecord.h37
-rw-r--r--record/SkRecordDraw.cpp86
-rw-r--r--record/SkRecordOpts.cpp217
-rw-r--r--record/SkRecordOpts.h6
-rw-r--r--record/SkRecordTraits.h31
-rw-r--r--record/SkRecorder.cpp4
-rw-r--r--record/SkRecorder.h3
-rw-r--r--record/SkRecording.cpp35
-rw-r--r--record/SkRecords.h10
-rw-r--r--sfnt/SkOTUtils.cpp6
-rw-r--r--utils/SkTLogic.h31
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, &copyInfo));
+ 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>(&copyInfo.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, &copyInfo));
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, &params);
+
+ 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(&params, 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, &current, indexPtr, endIndexPtr);
-
+ SkASSERT(current); // FIXME: if null, all remaining are vertical
SkASSERT(*indexPtr != *endIndexPtr && *indexPtr >= 0 && *endIndexPtr >= 0);
tryAgain = false;
contourWinding = rightAngleWinding(contourList, &current, 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