/*
* 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 <context.h>
#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<SkContext_Compute>, 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<SkContext_Compute> 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<skc_group_id> 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