Index: src/core/SkLiteDL.cpp |
diff --git a/src/core/SkLiteDL.cpp b/src/core/SkLiteDL.cpp |
index 77b1704d7052b6f5cdae4a314e48381dd2a9a1b4..f13255b4946a3fbb2b8907f10114fd64961b464a 100644 |
--- a/src/core/SkLiteDL.cpp |
+++ b/src/core/SkLiteDL.cpp |
@@ -15,25 +15,24 @@ |
#include "SkSpinlock.h" |
#include "SkTextBlob.h" |
-// TODO: make sure DrawPosText and DrawPosTextH positions are aligned |
-// (move the text after the positions). |
- |
// A stand-in for an optional SkRect which was not set, e.g. bounds for a saveLayer(). |
static const SkRect kUnset = {SK_ScalarInfinity, 0,0,0}; |
static const SkRect* maybe_unset(const SkRect& r) { |
return r.left() == SK_ScalarInfinity ? nullptr : &r; |
} |
-// memcpy_v(dst, src,bytes, src,bytes, ...) copies an arbitrary number of srcs into dst. |
-static void memcpy_v(void* dst) {} |
+// copy_v(dst, src,n, src,n, ...) copies an arbitrary number of typed srcs into dst. |
+static void copy_v(void* dst) {} |
-template <typename... Rest> |
-static void memcpy_v(void* dst, const void* src, size_t bytes, Rest&&... rest) { |
- sk_careful_memcpy(dst, src, bytes); |
- memcpy_v(SkTAddOffset<void>(dst, bytes), std::forward<Rest>(rest)...); |
+template <typename S, typename... Rest> |
+static void copy_v(void* dst, const S* src, int n, Rest&&... rest) { |
+ SkASSERTF(((uintptr_t)dst & (alignof(S)-1)) == 0, |
+ "Expected %p to be aligned for at least %zu bytes.", dst, alignof(S)); |
+ sk_careful_memcpy(dst, src, n*sizeof(S)); |
+ copy_v(SkTAddOffset<void>(dst, n*sizeof(S)), std::forward<Rest>(rest)...); |
} |
-// Helper for getting back at arrays which have been memcpy_v'd together after an Op. |
+// Helper for getting back at arrays which have been copy_v'd together after an Op. |
template <typename D, typename T> |
static D* pod(T* op, size_t offset = 0) { |
return SkTAddOffset<D>(op+1, offset); |
@@ -53,11 +52,18 @@ static void optimize_for(GrContext* ctx, SkPaint* paint, sk_sp<const SkImage>* i |
} |
} |
+// Pre-cache lazy non-threadsafe fields on SkPath and/or SkMatrix. |
+static void make_threadsafe(SkPath* path, SkMatrix* matrix) { |
+ if (path) { path->updateBoundsCache(); } |
+ if (matrix) { (void)matrix->getType(); } |
+} |
+ |
namespace { |
struct Op { |
virtual ~Op() {} |
virtual void draw(SkCanvas*) = 0; |
virtual void optimizeFor(GrContext*) {} |
+ virtual void makeThreadsafe() {} |
size_t skip; |
}; |
@@ -86,11 +92,13 @@ namespace { |
Concat(const SkMatrix& matrix) : matrix(matrix) {} |
SkMatrix matrix; |
void draw(SkCanvas* c) override { c->concat(matrix); } |
+ void makeThreadsafe() override { make_threadsafe(nullptr, &matrix); } |
}; |
struct SetMatrix final : Op { |
SetMatrix(const SkMatrix& matrix) : matrix(matrix) {} |
SkMatrix matrix; |
void draw(SkCanvas* c) override { c->setMatrix(matrix); } |
+ void makeThreadsafe() override { make_threadsafe(nullptr, &matrix); } |
}; |
struct TranslateZ final : Op { |
TranslateZ(SkScalar dz) : dz(dz) {} |
@@ -108,6 +116,7 @@ namespace { |
SkRegion::Op op; |
bool aa; |
void draw(SkCanvas* c) override { c->clipPath(path, op, aa); } |
+ void makeThreadsafe() override { make_threadsafe(&path, nullptr); } |
}; |
struct ClipRect final : Op { |
ClipRect(const SkRect& rect, SkRegion::Op op, bool aa) : rect(rect), op(op), aa(aa) {} |
@@ -142,6 +151,7 @@ namespace { |
SkPaint paint; |
void draw(SkCanvas* c) override { c->drawPath(path, paint); } |
void optimizeFor(GrContext* ctx) override { optimize_for(ctx, &paint); } |
+ void makeThreadsafe() override { make_threadsafe(&path, nullptr); } |
}; |
struct DrawRect final : Op { |
DrawRect(const SkRect& rect, const SkPaint& paint) : rect(rect), paint(paint) {} |
@@ -183,21 +193,33 @@ namespace { |
DrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) : drawable(sk_ref_sp(drawable)) { |
if (matrix) { this->matrix = *matrix; } |
} |
- sk_sp<SkDrawable> drawable; |
- SkMatrix matrix = SkMatrix::I(); |
- void draw(SkCanvas* c) override { c->drawDrawable(drawable.get(), &matrix); } |
+ sk_sp<SkDrawable> drawable; |
+ sk_sp<const SkPicture> snapped; |
+ SkMatrix matrix = SkMatrix::I(); |
+ void draw(SkCanvas* c) override { |
+ snapped ? c->drawPicture(snapped.get(), &matrix, nullptr) |
+ : c->drawDrawable(drawable.get(), &matrix); |
+ } |
+ void makeThreadsafe() override { |
+ snapped.reset(drawable->newPictureSnapshot()); |
+ make_threadsafe(nullptr, &matrix); |
+ } |
}; |
struct DrawPicture final : Op { |
DrawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) |
: picture(sk_ref_sp(picture)) { |
if (matrix) { this->matrix = *matrix; } |
- if (paint) { this->paint = *paint; } |
+ if (paint) { this->paint = *paint; has_paint = true; } |
} |
sk_sp<const SkPicture> picture; |
SkMatrix matrix = SkMatrix::I(); |
SkPaint paint; |
- void draw(SkCanvas* c) override { c->drawPicture(picture.get(), &matrix, &paint); } |
+ bool has_paint = false; // TODO: why is a default paint not the same? |
+ void draw(SkCanvas* c) override { |
+ c->drawPicture(picture.get(), &matrix, has_paint ? &paint : nullptr); |
+ } |
void optimizeFor(GrContext* ctx) override { optimize_for(ctx, &paint); } |
+ void makeThreadsafe() override { make_threadsafe(nullptr, &matrix); } |
}; |
struct DrawShadowedPicture final : Op { |
DrawShadowedPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) |
@@ -214,6 +236,7 @@ namespace { |
#endif |
} |
void optimizeFor(GrContext* ctx) override { optimize_for(ctx, &paint); } |
+ void makeThreadsafe() override { make_threadsafe(nullptr, &matrix); } |
}; |
struct DrawImage final : Op { |
@@ -284,23 +307,29 @@ namespace { |
void optimizeFor(GrContext* ctx) override { optimize_for(ctx, &paint); } |
}; |
struct DrawPosText final : Op { |
- DrawPosText(size_t bytes, const SkPaint& paint) |
- : bytes(bytes), paint(paint) {} |
+ DrawPosText(size_t bytes, const SkPaint& paint, int n) |
+ : bytes(bytes), paint(paint), n(n) {} |
size_t bytes; |
SkPaint paint; |
+ int n; |
void draw(SkCanvas* c) override { |
- c->drawPosText(pod<void>(this), bytes, pod<SkPoint>(this, bytes), paint); |
+ auto points = pod<SkPoint>(this); |
+ auto text = pod<void>(this, n*sizeof(SkPoint)); |
+ c->drawPosText(text, bytes, points, paint); |
} |
void optimizeFor(GrContext* ctx) override { optimize_for(ctx, &paint); } |
}; |
struct DrawPosTextH final : Op { |
- DrawPosTextH(size_t bytes, SkScalar y, const SkPaint& paint) |
- : bytes(bytes), y(y), paint(paint) {} |
+ DrawPosTextH(size_t bytes, SkScalar y, const SkPaint& paint, int n) |
+ : bytes(bytes), y(y), paint(paint), n(n) {} |
size_t bytes; |
SkScalar y; |
SkPaint paint; |
+ int n; |
void draw(SkCanvas* c) override { |
- c->drawPosTextH(pod<void>(this), bytes, pod<SkScalar>(this, bytes), y, paint); |
+ auto xs = pod<SkScalar>(this); |
+ auto text = pod<void>(this, n*sizeof(SkScalar)); |
+ c->drawPosTextH(text, bytes, xs, y, paint); |
} |
void optimizeFor(GrContext* ctx) override { optimize_for(ctx, &paint); } |
}; |
@@ -318,6 +347,7 @@ namespace { |
c->drawTextOnPath(pod<void>(this), bytes, path, &matrix, paint); |
} |
void optimizeFor(GrContext* ctx) override { optimize_for(ctx, &paint); } |
+ void makeThreadsafe() override { make_threadsafe(&path, &matrix); } |
}; |
struct DrawTextRSXform final : Op { |
DrawTextRSXform(size_t bytes, const SkRect* cull, const SkPaint& paint) |
@@ -343,6 +373,27 @@ namespace { |
void optimizeFor(GrContext* ctx) override { optimize_for(ctx, &paint); } |
}; |
+ struct DrawPatch final : Op { |
+ DrawPatch(const SkPoint cubics[12], const SkColor colors[4], const SkPoint texs[4], |
+ SkXfermode* xfermode, const SkPaint& paint) |
+ : xfermode(sk_ref_sp(xfermode)), paint(paint) { |
+ copy_v(this->cubics, cubics, 12); |
+ if (colors) { copy_v(this->colors, colors, 4); has_colors = true; } |
+ if (texs ) { copy_v(this->texs , texs , 4); has_texs = true; } |
+ } |
+ SkPoint cubics[12]; |
+ SkColor colors[4]; |
+ SkPoint texs[4]; |
+ sk_sp<SkXfermode> xfermode; |
+ SkPaint paint; |
+ bool has_colors = false; |
+ bool has_texs = false; |
+ void draw(SkCanvas* c) override { |
+ c->drawPatch(cubics, has_colors ? colors : nullptr, has_texs ? texs : nullptr, |
+ xfermode.get(), paint); |
+ } |
+ void optimizeFor(GrContext* ctx) override { optimize_for(ctx, &paint); } |
+ }; |
struct DrawPoints final : Op { |
DrawPoints(SkCanvas::PointMode mode, size_t count, const SkPaint& paint) |
: mode(mode), count(count), paint(paint) {} |
@@ -352,6 +403,44 @@ namespace { |
void draw(SkCanvas* c) override { c->drawPoints(mode, count, pod<SkPoint>(this), paint); } |
void optimizeFor(GrContext* ctx) override { optimize_for(ctx, &paint); } |
}; |
+ struct DrawVertices final : Op { |
+ DrawVertices(SkCanvas::VertexMode mode, int count, SkXfermode* xfermode, int nindices, |
+ const SkPaint& paint, bool has_texs, bool has_colors, bool has_indices) |
+ : mode(mode), count(count), xfermode(sk_ref_sp(xfermode)), nindices(nindices) |
+ , paint(paint), has_texs(has_texs), has_colors(has_colors), has_indices(has_indices) {} |
+ SkCanvas::VertexMode mode; |
+ int count; |
+ sk_sp<SkXfermode> xfermode; |
+ int nindices; |
+ SkPaint paint; |
+ bool has_texs; |
+ bool has_colors; |
+ bool has_indices; |
+ void draw(SkCanvas* c) override { |
+ SkPoint* vertices = pod<SkPoint>(this, 0); |
+ size_t offset = count*sizeof(SkPoint); |
+ |
+ SkPoint* texs = nullptr; |
+ if (has_texs) { |
+ texs = pod<SkPoint>(this, offset); |
+ offset += count*sizeof(SkPoint); |
+ } |
+ |
+ SkColor* colors = nullptr; |
+ if (has_colors) { |
+ colors = pod<SkColor>(this, offset); |
+ offset += count*sizeof(SkColor); |
+ } |
+ |
+ uint16_t* indices = nullptr; |
+ if (has_indices) { |
+ indices = pod<uint16_t>(this, offset); |
+ } |
+ c->drawVertices(mode, count, vertices, texs, colors, xfermode.get(), |
+ indices, nindices, paint); |
+ } |
+ void optimizeFor(GrContext* ctx) override { optimize_for(ctx, &paint); } |
+ }; |
struct DrawAtlas final : Op { |
DrawAtlas(const SkImage* atlas, int count, SkXfermode::Mode xfermode, |
const SkRect* cull, const SkPaint* paint, bool has_colors) |
@@ -442,7 +531,7 @@ void SkLiteDL::drawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPa |
void SkLiteDL::drawAnnotation(const SkRect& rect, const char* key, SkData* value) { |
size_t bytes = strlen(key)+1; |
void* pod = push<DrawAnnotation>(&fBytes, bytes, rect, value); |
- memcpy_v(pod, key,bytes); |
+ copy_v(pod, key,bytes); |
} |
void SkLiteDL::drawDrawable(SkDrawable* drawable, const SkMatrix* matrix) { |
push<DrawDrawable>(&fBytes, 0, drawable, matrix); |
@@ -484,46 +573,64 @@ void SkLiteDL::drawImageLattice(const SkImage* image, const SkCanvas::Lattice& l |
int xs = lattice.fXCount, ys = lattice.fYCount; |
size_t bytes = (xs + ys) * sizeof(int); |
void* pod = push<DrawImageLattice>(&fBytes, bytes, sk_ref_sp(image), xs, ys, dst, paint); |
- memcpy_v(pod, lattice.fXDivs,xs*sizeof(int), |
- lattice.fYDivs,ys*sizeof(int)); |
+ copy_v(pod, lattice.fXDivs, xs, |
+ lattice.fYDivs, ys); |
} |
void SkLiteDL::drawText(const void* text, size_t bytes, |
SkScalar x, SkScalar y, const SkPaint& paint) { |
void* pod = push<DrawText>(&fBytes, bytes, bytes, x, y, paint); |
- memcpy_v(pod, text,bytes); |
+ copy_v(pod, (const char*)text,bytes); |
} |
void SkLiteDL::drawPosText(const void* text, size_t bytes, |
const SkPoint pos[], const SkPaint& paint) { |
int n = paint.countText(text, bytes); |
- void* pod = push<DrawPosText>(&fBytes, bytes+n*sizeof(SkPoint), bytes, paint); |
- memcpy_v(pod, text,bytes, pos,n*sizeof(SkPoint)); |
+ void* pod = push<DrawPosText>(&fBytes, n*sizeof(SkPoint)+bytes, bytes, paint, n); |
+ copy_v(pod, pos,n, (const char*)text,bytes); |
} |
void SkLiteDL::drawPosTextH(const void* text, size_t bytes, |
const SkScalar xs[], SkScalar y, const SkPaint& paint) { |
int n = paint.countText(text, bytes); |
- void* pod = push<DrawPosTextH>(&fBytes, bytes+n*sizeof(SkScalar), bytes, y, paint); |
- memcpy_v(pod, text,bytes, xs,n*sizeof(SkScalar)); |
+ void* pod = push<DrawPosTextH>(&fBytes, n*sizeof(SkScalar)+bytes, bytes, y, paint, n); |
+ copy_v(pod, xs,n, (const char*)text,bytes); |
} |
void SkLiteDL::drawTextOnPath(const void* text, size_t bytes, |
const SkPath& path, const SkMatrix* matrix, const SkPaint& paint) { |
void* pod = push<DrawTextOnPath>(&fBytes, bytes, bytes, path, matrix, paint); |
- memcpy_v(pod, text,bytes); |
+ copy_v(pod, (const char*)text,bytes); |
} |
void SkLiteDL::drawTextRSXform(const void* text, size_t bytes, |
const SkRSXform xforms[], const SkRect* cull, const SkPaint& paint) { |
int n = paint.countText(text, bytes); |
void* pod = push<DrawTextRSXform>(&fBytes, bytes+n*sizeof(SkRSXform), bytes, cull, paint); |
- memcpy_v(pod, text,bytes, xforms,n*sizeof(SkRSXform)); |
+ copy_v(pod, (const char*)text,bytes, xforms,n); |
} |
void SkLiteDL::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint& paint) { |
push<DrawTextBlob>(&fBytes, 0, blob, x,y, paint); |
} |
+void SkLiteDL::drawPatch(const SkPoint points[12], const SkColor colors[4], const SkPoint texs[4], |
+ SkXfermode* xfermode, const SkPaint& paint) { |
+ push<DrawPatch>(&fBytes, 0, points, colors, texs, xfermode, paint); |
+} |
void SkLiteDL::drawPoints(SkCanvas::PointMode mode, size_t count, const SkPoint points[], |
const SkPaint& paint) { |
void* pod = push<DrawPoints>(&fBytes, count*sizeof(SkPoint), mode, count, paint); |
- memcpy_v(pod, points,count*sizeof(SkPoint)); |
+ copy_v(pod, points,count); |
+} |
+void SkLiteDL::drawVertices(SkCanvas::VertexMode mode, int count, const SkPoint vertices[], |
+ const SkPoint texs[], const SkColor colors[], SkXfermode* xfermode, |
+ const uint16_t indices[], int nindices, const SkPaint& paint) { |
+ size_t bytes = count * sizeof(SkPoint); |
+ if (texs ) { bytes += count * sizeof(SkPoint); } |
+ if (colors) { bytes += count * sizeof(SkColor); } |
+ if (indices) { bytes += nindices * sizeof(uint16_t); } |
+ void* pod = push<DrawVertices>(&fBytes, bytes, mode, count, xfermode, nindices, paint, |
+ texs != nullptr, colors != nullptr, indices != nullptr); |
+ copy_v(pod, vertices, count, |
+ texs, texs ? count : 0, |
+ colors, colors ? count : 0, |
+ indices, indices ? nindices : 0); |
} |
void SkLiteDL::drawAtlas(const SkImage* atlas, const SkRSXform xforms[], const SkRect texs[], |
const SkColor colors[], int count, SkXfermode::Mode xfermode, |
@@ -534,9 +641,9 @@ void SkLiteDL::drawAtlas(const SkImage* atlas, const SkRSXform xforms[], const S |
} |
void* pod = push<DrawAtlas>(&fBytes, bytes, |
atlas, count, xfermode, cull, paint, colors != nullptr); |
- memcpy_v(pod, xforms, count*sizeof(SkRSXform), |
- texs, count*sizeof(SkRect), |
- colors, colors ? count*sizeof(SkColor) : 0); |
+ copy_v(pod, xforms, count, |
+ texs, count, |
+ colors, colors ? count : 0); |
} |
@@ -548,6 +655,10 @@ void SkLiteDL::optimizeFor(GrContext* ctx) { |
map(&fBytes, [ctx](Op* op) { op->optimizeFor(ctx); }); |
} |
+void SkLiteDL::makeThreadsafe() { |
+ map(&fBytes, [](Op* op) { op->makeThreadsafe(); }); |
+} |
+ |
SkRect SkLiteDL::onGetBounds() { |
return fBounds; |
} |