/* * Copyright 2016 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 SkDevice_Compute_DEFINED #define SkDevice_Compute_DEFINED // // for now make sure it's defined // #if !defined(SK_SUPPORT_GPU_COMPUTE) #define SK_SUPPORT_GPU_COMPUTE 1 #endif // // // #if SK_SUPPORT_GPU_COMPUTE // TODO Check whether we can use SkDevice_ComputeLayerGroup at compile time // by checking whether there is only one top device. #define SK_USE_COMPUTE_LAYER_GROUP // // C // #ifdef __cplusplus extern "C" { #endif #include #ifdef __cplusplus } #endif #include "../compute/skc/skc.h" // // C++ // #include "SkDevice.h" #include "SkClipStackDevice.h" #include "SkContext_Compute.h" #include "SkTArray.h" // // // #ifdef SK_USE_COMPUTE_LAYER_GROUP class SkDevice_ComputeLayerGroup; #endif class SkDevice_Compute : public SkClipStackDevice { public: SkDevice_Compute(sk_sp, int w, int h); ~SkDevice_Compute() override; void drawPaint(const SkPaint& paint) override; void drawPoints(SkCanvas::PointMode, size_t, const SkPoint[], const SkPaint&) override; void drawRect(const SkRect&, const SkPaint&) override; void drawOval(const SkRect&, const SkPaint&) override; void drawRRect(const SkRRect&, const SkPaint&) override; void drawPath(const SkPath&, const SkPaint&, const SkMatrix*, bool) override; void drawText(const void*, size_t, SkScalar, SkScalar, const SkPaint&) override; void drawPosText(const void*, size_t, const SkScalar[], int, const SkPoint&, const SkPaint&) override; void onRestore() override { this->SkClipStackDevice::onRestore(); fClipWeakref = SKC_WEAKREF_INVALID; } void onClipRect(const SkRect& rect, SkClipOp op, bool aa) override { this->SkClipStackDevice::onClipRect(rect, op, aa); fClipWeakref = SKC_WEAKREF_INVALID; } void onClipRRect(const SkRRect& rrect, SkClipOp op, bool aa) override { this->SkClipStackDevice::onClipRRect(rrect, op, aa); fClipWeakref = SKC_WEAKREF_INVALID; } void onClipPath(const SkPath& path, SkClipOp op, bool aa) override { this->SkClipStackDevice::onClipPath(path, op, aa); fClipWeakref = SKC_WEAKREF_INVALID; } void onClipRegion(const SkRegion& deviceRgn, SkClipOp op) override { this->SkClipStackDevice::onClipRegion(deviceRgn, op); fClipWeakref = SKC_WEAKREF_INVALID; } void onSetDeviceClipRestriction(SkIRect* clipRestriction) override { this->SkClipStackDevice::onSetDeviceClipRestriction(clipRestriction); fClipWeakref = SKC_WEAKREF_INVALID; } ClipType onGetClipType() const override { // TODO Support non-rect clip return kRect_ClipType; } void drawBitmap(const SkBitmap&, const SkMatrix&, const SkPaint&) override {} void drawSprite(const SkBitmap&, int, int, const SkPaint&) override {} void drawBitmapRect(const SkBitmap&, const SkRect*, const SkRect&, const SkPaint&, SkCanvas::SrcRectConstraint) override {} void drawDevice(SkBaseDevice*, int, int, const SkPaint&) override; void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) override {} void flush() override; SkBaseDevice* onCreateDevice(const CreateInfo&, const SkPaint*) override; void onCtmChanged() override; friend class SkDevice_ComputeLayerGroup; private: void styling_group_init(); void path_add(const SkPaint&, const SkPath&, const SkMatrix* prePathMatrix = nullptr); void circles_add(const SkPaint&, const SkPoint points[], int32_t count, SkScalar radius); void squares_add(const SkPaint&, const SkPoint points[], int32_t count, SkScalar radius); void line_stroked_butt(SkPoint xy0, SkPoint xy1, SkScalar radius); void lines_stroked_add(const SkPaint&, const SkPoint points[], int32_t count, SkScalar radius); void path_rasterize_and_place(const SkPaint&, const skc_path_t path, const SkMatrix* prePathMatrix = nullptr); sk_sp fCompute; skc_composition_t fComposition; skc_styling_t fStyling; skc_path_builder_t fPB; skc_raster_builder_t fRB; skc_group_id fGroupID; skc_group_id fGroupLayerID; // When SK_USE_COMPUTE_LAYER_GROUP is set, fTopCTM is the global CTM for the top device. // When SK_USE_COMPUTE_LAYER_GROUP is not set, fTopCTM is equal to this->ctm(). SkMatrix fTopCTM; skc_transform_weakref_t fTransformWeakref; skc_raster_clip_weakref_t fClipWeakref; #ifdef SK_USE_COMPUTE_LAYER_GROUP SkTArray fParents; SkDevice_ComputeLayerGroup* createLayerGroup(const CreateInfo&, const SkPaint*); #endif }; #ifdef SK_USE_COMPUTE_LAYER_GROUP // A group of skc layers that correspond to a saveLayer in the top level (root) SkDevice_Compute. class SkDevice_ComputeLayerGroup : public SkBaseDevice { public: SkDevice_ComputeLayerGroup(SkDevice_Compute* root, const CreateInfo&, const SkPaint*); ~SkDevice_ComputeLayerGroup() override; void drawPaint(const SkPaint& paint) override { this->sanityCheck(); fRoot->drawPaint(paint); } void drawPoints(SkCanvas::PointMode pm, size_t s, const SkPoint pts[], const SkPaint& p) override { this->sanityCheck(); fRoot->drawPoints(pm, s, pts, p); } void drawRect(const SkRect& r, const SkPaint& p) override { this->sanityCheck(); fRoot->drawRect(r, p); } void drawOval(const SkRect& r, const SkPaint& p) override { this->sanityCheck(); fRoot->drawOval(r, p); } void drawRRect(const SkRRect& rr, const SkPaint& p) override { this->sanityCheck(); fRoot->drawRRect(rr, p); } void drawPath(const SkPath& path, const SkPaint& p, const SkMatrix* m, bool b) override { this->sanityCheck(); fRoot->drawPath(path, p, m, b); } void drawText(const void* t, size_t l, SkScalar x, SkScalar y, const SkPaint& p) override { this->sanityCheck(); fRoot->drawText(t, l, x, y, p); } void drawPosText(const void* t, size_t l, const SkScalar p[], int s, const SkPoint& o, const SkPaint& paint) override { this->sanityCheck(); fRoot->drawPosText(t, l, p, s, o, paint); } void onSave() override; void onRestore() override; void onClipRect(const SkRect& rect, SkClipOp, bool aa) override; void onClipRRect(const SkRRect& rrect, SkClipOp, bool aa) override; void onClipPath(const SkPath& path, SkClipOp, bool aa) override; void onClipRegion(const SkRegion& deviceRgn, SkClipOp) override; void onSetDeviceClipRestriction(SkIRect* mutableClipRestriction) override; bool onClipIsAA() const override { return fRoot->onClipIsAA(); } void onAsRgnClip(SkRegion* rgn) const override { return fRoot->onAsRgnClip(rgn); } ClipType onGetClipType() const override { return fRoot->onGetClipType(); } void onCtmChanged() override; void drawBitmap(const SkBitmap&, const SkMatrix&, const SkPaint&) override {} void drawSprite(const SkBitmap&, int, int, const SkPaint&) override {} void drawBitmapRect(const SkBitmap&, const SkRect*, const SkRect&, const SkPaint&, SkCanvas::SrcRectConstraint) override {} void drawDevice(SkBaseDevice*, int, int, const SkPaint&) override; void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) override {} void flush() override; SkBaseDevice* onCreateDevice(const CreateInfo&, const SkPaint*) override; friend class SkDevice_Compute; private: SkDevice_Compute* fRoot; // Save a copy of the current group id for sanity check. // If the sanity check fails, we're probably in the Android world where // multiple top-level devices can co-exist. In that case, we can no longer use the group syntax // and we have to create a new root-level SkDevice_Compute with an offscreen surface. // According to reed@, we should be able to tell whether this sanity check will fail // at the compile time (e.g., Chrome and Flutter never do this; Android sometimes does this). skc_group_id fGroupID; void sanityCheck() { #ifdef SK_DEBUG // We should only change the top level device's CTM. // Otherwise we can't use SkDevice_ComputeLayerGroup. SkASSERT(fGroupID == fRoot->fGroupID); // The root SkDevice_Compute must have an origin (0, 0) as saveLayer won't // ever create another SkDevice_Compute SkASSERT(fRoot->getOrigin() == SkIPoint::Make(0, 0)); #endif } }; #endif // SK_USE_COMPUTE_LAYER_GROUP #endif // SK_SUPPORT_GPU_COMPUTE #endif // SkDevice_Compute_DEFINED