aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/compute/sk
diff options
context:
space:
mode:
authorGravatar Allan MacKinnon <allanmac@google.com>2018-06-19 13:57:04 -0700
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-06-20 01:19:18 +0000
commit4359d529121fc1f39f882693d641c0133d138d41 (patch)
treed2c3239162e68d24d5c2cebc8a4f6659860cc2a0 /src/compute/sk
parent47c29fa64b3ffc1eec7723d40e9862b2d2a8443f (diff)
Skia Compute core files
Bug: skia: Change-Id: I4bba49cf20eff013e581800a3f114c85acd8498c Reviewed-on: https://skia-review.googlesource.com/135782 Reviewed-by: Mike Klein <mtklein@google.com> Reviewed-by: Mike Reed <reed@google.com> Commit-Queue: Mike Klein <mtklein@google.com>
Diffstat (limited to 'src/compute/sk')
-rw-r--r--src/compute/sk/SkContext_Compute.cpp95
-rw-r--r--src/compute/sk/SkContext_Compute.h71
-rw-r--r--src/compute/sk/SkDevice_Compute.cpp887
-rw-r--r--src/compute/sk/SkDevice_Compute.h265
-rw-r--r--src/compute/sk/SkImage_Compute.cpp49
-rw-r--r--src/compute/sk/SkImage_Compute.h83
-rw-r--r--src/compute/sk/SkSurface_Compute.cpp191
-rw-r--r--src/compute/sk/SkSurface_Compute.h113
8 files changed, 1754 insertions, 0 deletions
diff --git a/src/compute/sk/SkContext_Compute.cpp b/src/compute/sk/SkContext_Compute.cpp
new file mode 100644
index 0000000000..331fad6df4
--- /dev/null
+++ b/src/compute/sk/SkContext_Compute.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ */
+
+#include "SkContext_Compute.h"
+
+//
+//
+//
+
+//
+//
+//
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#define TARGET_PLATFORM_SUBSTRING "TO BE SET"
+#define TARGET_DEVICE_SUBSTRING "TO BE SET"
+
+//
+//
+//
+
+//
+//
+//
+
+SkContext_Compute::SkContext_Compute(GrGLInterface const * fInterface)
+ : fInterface(fInterface)
+{
+ //
+ // Make sure fInterface destruction occurs after compute
+ //
+ SkSafeRef(fInterface);
+
+ skc_err err;
+
+ //
+ // CREATE A NEW SPINEL CONTEXT AND ATTACH TO WINDOW
+ //
+ err = skc_context_create(&context, TARGET_PLATFORM_SUBSTRING, TARGET_DEVICE_SUBSTRING);
+ SKC_ERR_CHECK(err);
+
+ //
+ // CREATE A NEW REUSABLE INTEROP OBJECT
+ //
+ // interop = skc_interop_create(fInterface,1); TODO have this in skc.h
+
+ //
+ // CREATE A NEW REUSABLE SURFACE OBJECT
+ //
+ err = skc_surface_create(context,
+ interop,
+ &surface);
+ SKC_ERR_CHECK(err);
+}
+
+//
+//
+//
+
+SkContext_Compute::~SkContext_Compute()
+{
+ skc_err err;
+
+ // dispose of surface
+ err = skc_surface_dispose(surface);
+ SKC_ERR_CHECK(err);
+
+ // dispose of interop
+ // skc_interop_dispose(interop); TODO have this in skc.h
+
+ // dispose of context
+ err = skc_context_release(context);
+ SKC_ERR_CHECK(err);
+
+ // unref GL interface
+ SkSafeUnref(fInterface);
+}
+
+//
+//
+//
+
diff --git a/src/compute/sk/SkContext_Compute.h b/src/compute/sk/SkContext_Compute.h
new file mode 100644
index 0000000000..066e11df45
--- /dev/null
+++ b/src/compute/sk/SkContext_Compute.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ */
+
+#pragma once
+
+//
+//
+//
+
+#include "gl/GrGLInterface.h"
+
+//
+//
+//
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "skc.h"
+
+#ifdef __cplusplus
+}
+#endif
+
+//
+//
+//
+
+class SkContext_Compute : public SkRefCntBase
+{
+ public:
+
+ //
+ //
+ //
+
+ SkContext_Compute(GrGLInterface const * fInterface);
+
+ ~SkContext_Compute();
+
+ //
+ //
+ //
+
+ skc_context_t context;
+ skc_interop_t interop;
+ skc_surface_t surface;
+
+ //
+ //
+ //
+
+ private:
+
+ GrGLInterface const * fInterface;
+
+ //
+ //
+ //
+};
+
+//
+//
+//
diff --git a/src/compute/sk/SkDevice_Compute.cpp b/src/compute/sk/SkDevice_Compute.cpp
new file mode 100644
index 0000000000..f19f7dbc75
--- /dev/null
+++ b/src/compute/sk/SkDevice_Compute.cpp
@@ -0,0 +1,887 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can
+ * be found in the LICENSE file.
+ */
+
+//
+// C++
+//
+
+#include "SkDevice_Compute.h"
+#include "SkPM4f.h"
+
+//
+//
+//
+
+#if SK_SUPPORT_GPU_COMPUTE
+
+//
+// C++
+//
+
+#include "SkImageInfo.h"
+#include "SkDraw.h"
+#include "SkMatrix.h"
+#include "SkPath.h"
+
+//
+// C
+//
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "../spinel/spinel/color.h"
+#include "../compute/skc/skc.h"
+
+#ifdef __cplusplus
+}
+#endif
+
+//
+//
+//
+
+SkDevice_Compute::SkDevice_Compute(sk_sp<SkContext_Compute> compute, int w, int h)
+ : SkClipStackDevice(SkImageInfo::MakeN32Premul(w,h), SkSurfaceProps(0,kUnknown_SkPixelGeometry))
+ , fCompute(std::move(compute))
+{
+ fTopCTM = this->ctm();
+ fTransformWeakref = SKC_WEAKREF_INVALID;
+
+ fClipWeakref = SKC_WEAKREF_INVALID;
+
+ skc_err err;
+
+ //
+ // create a composition
+ //
+#define LAYER_COUNT (1<<14)
+
+ err = skc_composition_create(fCompute->context, &fComposition);
+ SKC_ERR_CHECK(err);
+
+ // Is this correct?
+ int clipRect[] = { 0, 0, w - 1, h - 1 };
+ err = skc_composition_clip_set(fComposition, clipRect);
+ SKC_ERR_CHECK(err);
+
+ //
+ // create styling
+ //
+ err = skc_styling_create(fCompute->context,
+ LAYER_COUNT,
+ 10,
+ 2 * 1024 * 1024,
+ &fStyling);
+
+ //
+ // create a path builder
+ //
+ err = skc_path_builder_create(fCompute->context, &fPB);
+ SKC_ERR_CHECK(err);
+
+ //
+ // create a raster builder
+ //
+ err = skc_raster_builder_create(fCompute->context, &fRB);
+ SKC_ERR_CHECK(err);
+
+ //
+ // create the simplest styling group that encloses all layers
+ //
+ styling_group_init();
+}
+
+
+//
+//
+//
+
+SkDevice_Compute::~SkDevice_Compute() {
+ skc_err err;
+
+ err = skc_raster_builder_release(fRB);
+ SKC_ERR_CHECK(err);
+
+ err = skc_path_builder_release(fPB);
+ SKC_ERR_CHECK(err);
+
+ err = skc_styling_dispose(fStyling);
+ SKC_ERR_CHECK(err);
+
+ err = skc_composition_dispose(fComposition);
+ SKC_ERR_CHECK(err);
+}
+
+//
+//
+//
+
+void SkDevice_Compute::flush() {
+ //
+ // seal the styling and composition objects
+ //
+ skc_err err;
+
+ err = skc_composition_seal(fComposition);
+ SKC_ERR_CHECK(err);
+
+ err = skc_styling_seal(fStyling);
+ SKC_ERR_CHECK(err);
+
+ //
+ // we're going to block here -- API mismatch
+ //
+
+ //
+ // render to surface
+ //
+ // note this implicitly seals composition and styling
+ //
+ err = skc_surface_render(fCompute->surface, fComposition, fStyling);
+ SKC_ERR_CHECK(err);
+
+ //
+ // kick off pipeline and wait here -- not needed since skc_surface_reset() blocks
+ //
+ err = skc_surface_wait(fCompute->surface);
+ SKC_ERR_CHECK(err);
+
+ //
+ // reset the surface -- implicitly waits for render to finish -- FIXME -- composition might be released too early
+ //
+ err = skc_surface_reset(fCompute->surface);
+ SKC_ERR_CHECK(err);
+
+ //
+ // reset composition and styling
+ //
+ err = skc_composition_reset(fComposition);
+ SKC_ERR_CHECK(err);
+
+ err = skc_styling_reset(fStyling);
+ SKC_ERR_CHECK(err);
+
+ //
+ //
+ //
+ styling_group_init();
+}
+
+//
+//
+//
+
+#define SKC_STYLING_CMDS(...) SK_ARRAY_COUNT(__VA_ARGS__),__VA_ARGS__
+#define SKC_GROUP_IDS(...) SK_ARRAY_COUNT(__VA_ARGS__),__VA_ARGS__
+
+void SkDevice_Compute::styling_group_init() {
+ skc_styling_group_alloc(fStyling, &fGroupID);
+ fParents.push_back(fGroupID);
+
+ // ENTER
+ skc_styling_cmd_t const styling_cmds_enter[] = {
+ SKC_STYLING_CMD_OP_COVER_ZERO_ACC,
+ SKC_STYLING_CMD_OP_COLOR_ZERO_ACC | SKC_STYLING_CMD_OP_IS_FINAL
+ };
+ skc_styling_group_enter(fStyling, fGroupID, SKC_STYLING_CMDS(styling_cmds_enter));
+
+ skc_group_id const group_id_parents[] = { fGroupID };
+ skc_styling_group_parents(fStyling, fGroupID, SKC_GROUP_IDS(group_id_parents));
+
+ // RANGE
+ skc_styling_group_range_lo(fStyling, fGroupID, 0);
+ skc_styling_group_range_hi(fStyling, fGroupID, LAYER_COUNT-1);
+
+ // LEAVE
+ skc_styling_cmd_t const styling_cmds_leave[] = {
+ SKC_STYLING_CMD_OP_SURFACE_COMPOSITE | SKC_STYLING_CMD_OP_IS_FINAL
+ };
+ skc_styling_group_leave(fStyling, fGroupID, SKC_STYLING_CMDS(styling_cmds_leave));
+
+ // START
+ fGroupLayerID = LAYER_COUNT-1;
+}
+
+//
+//
+//
+
+#define SK_SCALE_F32 (1.0f/255.0f)
+#define SK_TO_RGBA_F32(c) { SK_SCALE_F32 * SkColorGetR(c), \
+ SK_SCALE_F32 * SkColorGetG(c), \
+ SK_SCALE_F32 * SkColorGetB(c), \
+ SK_SCALE_F32 * SkColorGetA(c) }
+//
+//
+//
+
+void SkDevice_Compute::path_rasterize_and_place(const SkPaint& paint,
+ const skc_path_t path,
+ const SkMatrix* prePathMatrix) {
+ float transform[9];
+ const SkMatrix& ctm = fTopCTM;
+ SkMatrix tmp;
+
+ if (prePathMatrix) {
+ tmp.setConcat(ctm, *prePathMatrix);
+ }
+ transform[0] = tmp.get(SkMatrix::kMScaleX);
+ transform[1] = tmp.get(SkMatrix::kMSkewX );
+ transform[2] = tmp.get(SkMatrix::kMTransX);
+ transform[3] = tmp.get(SkMatrix::kMSkewY );
+ transform[4] = tmp.get(SkMatrix::kMScaleY);
+ transform[5] = tmp.get(SkMatrix::kMTransY);
+ transform[6] = tmp.get(SkMatrix::kMPersp0);
+ transform[7] = tmp.get(SkMatrix::kMPersp1);
+ transform[8] = tmp.get(SkMatrix::kMPersp2);
+
+ skc_transform_weakref_t& transform_weakref = fTransformWeakref;
+ //
+
+ // always invalid for now
+ //
+ skc_raster_clip_weakref_t clip_weakref = fClipWeakref;
+
+ // TODO Support arbitrary path clip?
+ SkRect devClip = SkRect::MakeFromIRect(this->devClipBounds());
+ const float clip[] = { devClip.fLeft, devClip.fTop, devClip.fRight, devClip.fBottom };
+
+ //
+ //
+ //
+ skc_err err;
+ skc_raster_t raster;
+
+ err = skc_raster_begin(fRB);
+ err = skc_raster_add_filled(fRB, path, &transform_weakref, transform, &clip_weakref, clip);
+ err = skc_raster_end(fRB, &raster);
+
+ //
+ // can release path handle now because it is being referenced by raster
+ //
+ err = skc_path_release(fCompute->context, path);
+
+ //
+ // style the path
+ //
+ skc_styling_cmd_t cmds[1 + 3 + 1];
+
+ cmds[0] = SKC_STYLING_CMD_OP_COVER_NONZERO;
+ cmds[SK_ARRAY_COUNT(cmds)-1] = SKC_STYLING_CMD_OP_BLEND_OVER | SKC_STYLING_CMD_OP_IS_FINAL;
+
+ {
+ SkPM4f rgba = SkColor4f::FromColor(paint.getColor()).premul();
+
+ skc_styling_layer_fill_solid_encoder(cmds+1, rgba.fVec);
+
+ skc_styling_group_layer(fStyling, fGroupID, fGroupLayerID, SKC_STYLING_CMDS(cmds));
+ }
+
+ err = skc_composition_place(fComposition, fGroupLayerID, raster, 0, 0);
+
+ //
+ // can release raster handle now because it is being referenced by composition
+ //
+ err = skc_raster_release(fCompute->context, raster);
+
+ SkASSERT(err == SKC_ERR_SUCCESS);
+
+ fGroupLayerID -= 1;
+}
+
+//
+//
+//
+
+void SkDevice_Compute::path_add(const SkPaint& paint,
+ const SkPath& path,
+ const SkMatrix* prePathMatrix) {
+ skc_err err;
+
+ err = skc_path_begin(fPB);
+
+#if 0
+ SkPath::Iter pi(path,false);
+#else
+ SkPath::RawIter pi(path); // this seems to work fine for now
+#endif
+
+ SkPoint xy0;
+
+ //
+ // build path
+ //
+ while (true)
+ {
+ SkPoint pts[4];
+ SkPath::Verb const verb = pi.next(pts);
+
+ switch (verb)
+ {
+ case SkPath::kMove_Verb:
+ xy0 = pts[0];
+ err = skc_path_move_to(fPB,
+ pts[0].x(),pts[0].y());
+ continue;
+
+ case SkPath::kLine_Verb:
+ err = skc_path_line_to(fPB,
+ pts[1].x(),pts[1].y());
+ continue;
+
+ case SkPath::kQuad_Verb:
+ err = skc_path_quad_to(fPB,
+ pts[1].x(),pts[1].y(),
+ pts[2].x(),pts[2].y());
+ continue;
+
+ case SkPath::kConic_Verb: // <--------------------- FIXME
+ err = skc_path_line_to(fPB,
+ pts[2].x(),pts[2].y());
+ continue;
+
+ case SkPath::kCubic_Verb:
+ err = skc_path_cubic_to(fPB,
+ pts[1].x(),pts[1].y(),
+ pts[2].x(),pts[2].y(),
+ pts[3].x(),pts[3].y());
+ continue;
+
+ case SkPath::kClose_Verb:
+ err = skc_path_line_to(fPB,xy0.x(),xy0.y());
+ continue;
+
+ case SkPath::kDone_Verb:
+ break;
+ }
+
+ //
+ // otherwise, kDone_Verb breaks out of while loop
+ //
+ break;
+ }
+
+ //
+ // seal the path
+ //
+ skc_path_t skc_path;
+
+ err = skc_path_end(fPB,&skc_path);
+
+ //
+ // rasterize the path and place it in a composition
+ //
+ path_rasterize_and_place(paint,skc_path,prePathMatrix);
+
+ SkASSERT(err == SKC_ERR_SUCCESS);
+}
+
+//
+//
+//
+
+void
+SkDevice_Compute::circles_add(
+ const SkPaint & paint,
+ const SkPoint points[],
+ int32_t const count,
+ SkScalar const radius)
+{
+#define CIRCLE_KAPPA 0.55228474983079339840f // moar digits!
+
+#define CIRCLE_RADIUS_X radius
+#define CIRCLE_RADIUS_Y radius
+
+#define CIRCLE_KAPPA_X (CIRCLE_RADIUS_X * CIRCLE_KAPPA)
+#define CIRCLE_KAPPA_Y (CIRCLE_RADIUS_Y * CIRCLE_KAPPA)
+
+ //
+ // use a 4 Bezier approximation
+ //
+ float const circle[] =
+ {
+ 0.0f, +CIRCLE_RADIUS_Y, // move_to
+
+ +CIRCLE_KAPPA_X, +CIRCLE_RADIUS_Y, // cubic_to
+ +CIRCLE_RADIUS_X, +CIRCLE_KAPPA_Y,
+ +CIRCLE_RADIUS_X, 0.0f,
+
+ +CIRCLE_RADIUS_X, -CIRCLE_KAPPA_Y, // cubic_to
+ +CIRCLE_KAPPA_X, -CIRCLE_RADIUS_Y,
+ 0.0f, -CIRCLE_RADIUS_Y,
+
+ -CIRCLE_KAPPA_X, -CIRCLE_RADIUS_Y, // cubic_to
+ -CIRCLE_RADIUS_X, -CIRCLE_KAPPA_Y,
+ -CIRCLE_RADIUS_X, 0.0f,
+
+ -CIRCLE_RADIUS_X, +CIRCLE_KAPPA_Y, // cubic_to
+ -CIRCLE_KAPPA_X, +CIRCLE_RADIUS_Y,
+ 0.0f, +CIRCLE_RADIUS_Y
+ };
+
+#define CXLAT(x,y,t) circle[x]+t.fX,circle[y]+t.fY
+
+ //
+ //
+ //
+
+ skc_err err;
+
+ err = skc_path_begin(fPB);
+
+ //
+ //
+ //
+ for (int32_t ii=0; ii<count; ii++)
+ {
+ SkPoint const p = points[ii];
+
+ err = skc_path_move_to(fPB,
+ CXLAT(0,1,p));
+
+ err = skc_path_cubic_to(fPB,
+ CXLAT(2,3,p),
+ CXLAT(4,5,p),
+ CXLAT(6,7,p));
+
+ err = skc_path_cubic_to(fPB,
+ CXLAT(8, 9,p),
+ CXLAT(10,11,p),
+ CXLAT(12,13,p));
+
+ err = skc_path_cubic_to(fPB,
+ CXLAT(14,15,p),
+ CXLAT(16,17,p),
+ CXLAT(18,19,p));
+
+ err = skc_path_cubic_to(fPB,
+ CXLAT(20,21,p),
+ CXLAT(22,23,p),
+ CXLAT(24,25,p));
+ }
+
+ //
+ // seal the path
+ //
+ skc_path_t skc_path;
+
+ err = skc_path_end(fPB,&skc_path);
+
+ //
+ // rasterize the path and place it in a composition
+ //
+ path_rasterize_and_place(paint,skc_path,NULL);
+
+ SkASSERT(err == SKC_ERR_SUCCESS);
+}
+
+//
+//
+//
+
+void
+SkDevice_Compute::squares_add(
+ const SkPaint & paint,
+ const SkPoint points[],
+ int32_t const count,
+ SkScalar const radius)
+{
+ float const square[] =
+ {
+ -radius,+radius, // move_to
+ +radius,+radius, // line_to
+ +radius,-radius, // line_to
+ -radius,-radius, // line_to
+ -radius,+radius // line_to
+ };
+
+#define SXLAT(x,y,t) square[x]+t.fX,square[y]+t.fY
+
+ //
+ //
+ //
+
+ skc_err err;
+
+ err = skc_path_begin(fPB);
+
+ //
+ //
+ //
+ for (int32_t ii=0; ii<count; ii++)
+ {
+ SkPoint const p = points[ii];
+
+ err = skc_path_move_to(fPB,SXLAT(0,1,p));
+ err = skc_path_line_to(fPB,SXLAT(2,3,p));
+ err = skc_path_line_to(fPB,SXLAT(4,5,p));
+ err = skc_path_line_to(fPB,SXLAT(6,7,p));
+ err = skc_path_line_to(fPB,SXLAT(8,9,p));
+ }
+
+ //
+ // seal the path
+ //
+ skc_path_t skc_path;
+
+ err = skc_path_end(fPB,&skc_path);
+
+ //
+ // rasterize the path and place it in a composition
+ //
+ path_rasterize_and_place(paint,skc_path,NULL);
+
+ SkASSERT(err == SKC_ERR_SUCCESS);
+}
+
+//
+// FIXME -- THIS IS NOT CORRECT
+//
+// Need to implement butt, round, square caps
+//
+
+void
+SkDevice_Compute::line_stroked_butt(SkPoint const xy0,
+ SkPoint const xy1,
+ SkScalar const radius)
+{
+ float const dx = xy1.fX - xy0.fX;
+ float const dy = xy1.fY - xy0.fY;
+
+ float const hypot = hypotf(dx,dy);
+
+ // FIXME -- what's practical here?
+ if (hypot == 0.0f)
+ return;
+
+ float const scale = radius / hypot;
+
+ float const rx = dy * scale;
+ float const ry = dx * scale;
+
+ skc_err err;
+
+ err = skc_path_move_to(fPB,xy0.fX-rx,xy0.fY+ry);
+ err = skc_path_line_to(fPB,xy1.fX-rx,xy1.fY+ry);
+ err = skc_path_line_to(fPB,xy1.fX+rx,xy1.fY-ry);
+ err = skc_path_line_to(fPB,xy0.fX+rx,xy0.fY-ry);
+ err = skc_path_line_to(fPB,xy0.fX-rx,xy0.fY+ry);
+
+ SkASSERT(err == SKC_ERR_SUCCESS);
+}
+
+void
+SkDevice_Compute::lines_stroked_add(
+ const SkPaint & paint,
+ const SkPoint points[],
+ int32_t const count,
+ SkScalar const radius)
+{
+ skc_err err;
+
+ err = skc_path_begin(fPB);
+
+ //
+ //
+ //
+ for (int32_t ii=0; ii<count; ii+=2)
+ line_stroked_butt(points[ii],points[ii+1],radius);
+
+ //
+ // seal the path
+ //
+ skc_path_t skc_path;
+
+ err = skc_path_end(fPB,&skc_path);
+
+ //
+ // rasterize the path and place it in a composition
+ //
+ path_rasterize_and_place(paint,skc_path,NULL);
+
+ SkASSERT(err == SKC_ERR_SUCCESS);
+}
+
+
+//
+//
+//
+
+// drawPaint is really just a short-cut for drawRect(wide_open, paint)
+// so we have to respect everything (but stroking and maskfilter) in the paint
+// - color | shader
+// - colorFilter
+// - blendmode
+// - etc.
+void SkDevice_Compute::drawPaint(const SkPaint& paint) {
+ //
+ // clear the surface -- will be postponed until render is complete
+ //
+ SkColor const c = paint.getColor();
+ float rgba[4] = SK_TO_RGBA_F32(c);
+
+ skc_surface_clear(fCompute->surface,rgba);
+}
+
+void SkDevice_Compute::drawPoints(SkCanvas::PointMode mode, size_t count, const SkPoint points[],
+ const SkPaint& paint) {
+ if (count == 0) {
+ return;
+ }
+
+ const SkScalar radius = paint.getStrokeWidth() * 0.5f;
+
+ /*
+ * drawPoints draws each element (point, line) separately. This means our bulk-adding into the
+ * same raster is not valid for most blendmodes.
+ */
+ switch (mode) {
+ case SkCanvas::kPoints_PointMode: {
+ if (paint.getStrokeCap() == SkPaint::kRound_Cap) {
+ circles_add(paint, points, (int32_t)count, radius);
+ } else {
+ squares_add(paint, points,(int32_t)count, radius);
+ }
+ } break;
+
+ case SkCanvas::kLines_PointMode: {
+ if (count <= 1) {
+ return;
+ }
+ lines_stroked_add(paint, points, (int32_t)count & ~1, radius);
+ } break;
+
+ case SkCanvas::kPolygon_PointMode: {
+ SkPoint xy0 = points[0];
+ skc_err err = skc_path_begin(fPB);
+
+ for (size_t i = 0; i < count; ++i) {
+ const SkPoint xy1 = points[i];
+ line_stroked_butt(xy0, xy1, radius);
+ xy0 = xy1;
+ }
+
+ //
+ // seal the path
+ //
+ skc_path_t skc_path;
+ err = skc_path_end(fPB, &skc_path);
+
+ //
+ // rasterize the path and place it in a composition
+ //
+ path_rasterize_and_place(paint, skc_path, nullptr);
+
+ SkASSERT(err == SKC_ERR_SUCCESS);
+ } break;
+
+ default:
+ break;
+ }
+}
+
+void SkDevice_Compute::drawRect(const SkRect& rect, const SkPaint& paint) {
+ SkPath path;
+
+ path.addRect(rect);
+ this->drawPath(path, paint, nullptr, true);
+}
+
+void SkDevice_Compute::drawOval(const SkRect& oval, const SkPaint& paint) {
+ SkPath path;
+
+ path.addOval(oval);
+ this->drawPath(path, paint, nullptr, true);
+}
+
+void SkDevice_Compute::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
+ SkPath path;
+
+ path.addRRect(rrect);
+ this->drawPath(path, paint, nullptr, true);
+}
+
+void SkDevice_Compute::drawPath(const SkPath& path, const SkPaint& paint,
+ const SkMatrix* prePathMatrix, bool pathIsMutable) {
+ if (paint.getStyle() == SkPaint::kFill_Style) {
+ path_add(paint,path,prePathMatrix);
+ } else {
+ SkPath stroked;
+
+#define SK_MAGIC_RES_SCALE 1024
+
+ paint.getFillPath(path, &stroked, nullptr, SK_MAGIC_RES_SCALE);
+ this->path_add(paint, stroked, prePathMatrix);
+ }
+}
+
+void SkDevice_Compute::drawText(const void* text,
+ size_t length,
+ SkScalar x,
+ SkScalar y,
+ const SkPaint& paint) {
+ SkPath outline;
+
+ paint.getTextPath(text,length,x,y,&outline);
+ this->drawPath(outline, paint, nullptr, true);
+}
+
+void
+SkDevice_Compute::drawPosText(const void * text,
+ size_t length,
+ const SkScalar pos[],
+ int scalarsPerPos,
+ const SkPoint & offset,
+ const SkPaint & paint)
+{
+#if 0
+ draw.drawPosText_asPaths((const char *)text,length,
+ pos,scalarsPerPos,offset,paint);
+#endif
+}
+
+SkBaseDevice* SkDevice_Compute::onCreateDevice(const CreateInfo& cinfo, const SkPaint* paint) {
+#ifdef SK_USE_COMPUTE_LAYER_GROUP
+ return this->createLayerGroup(cinfo, paint);
+#else
+ // TODO return a new SkDevice_Compute when SkDevice_ComputeLayerGroup doesn't work
+ return nullptr;
+#endif
+}
+
+void SkDevice_Compute::drawDevice(SkBaseDevice* device, int left, int top, const SkPaint& paint) {
+ // It seems that we won't support image filter until snapSpecial and drawSpecial are implemented
+ // (SkCanvas.cpp will call drawSpecial when the paint has an image filter).
+ SkASSERT(!paint.getImageFilter());
+
+#ifdef SK_USE_COMPUTE_LAYER_GROUP
+ // In case of SkDevice_ComputeLayerGroup, we close the group
+ SkDevice_ComputeLayerGroup* layerDevice = static_cast<SkDevice_ComputeLayerGroup*>(device);
+ SkASSERT(layerDevice->fRoot == this); // the layerDevice should belong to this root device
+ SkASSERT(layerDevice->fGroupID == fGroupID); // the layerDevice should be the top device
+
+ // left, top should be the same as the origin,
+ // and we can ignore them because we have no offscreen buffer.
+ SkASSERT(SkIPoint::Make(left, top) == device->getOrigin());
+
+ // close the group and pop the top device
+ skc_styling_group_range_lo(fStyling, fGroupID, fGroupLayerID + 1);
+ fGroupID = fParents.back();
+ fParents.pop_back();
+#else
+ // TODO handle the case where the device is a SkDevice_Compute rather than
+ // SkDevice_ComputeLayerGroup (in which case an offscreen buffer is created).
+#endif
+}
+
+#ifdef SK_USE_COMPUTE_LAYER_GROUP
+
+SkDevice_ComputeLayerGroup* SkDevice_Compute::createLayerGroup(const CreateInfo& cinfo,
+ const SkPaint* paint) {
+ return new SkDevice_ComputeLayerGroup(this, cinfo, paint);
+}
+
+void SkDevice_Compute::onCtmChanged() {
+ fTopCTM = this->ctm();
+ fTransformWeakref = SKC_WEAKREF_INVALID;
+}
+
+SkDevice_ComputeLayerGroup::SkDevice_ComputeLayerGroup(SkDevice_Compute* root,
+ const CreateInfo& cinfo, const SkPaint* paint)
+ : SkBaseDevice(SkImageInfo::MakeN32Premul(cinfo.fInfo.width(), cinfo.fInfo.height()),
+ SkSurfaceProps(0,kUnknown_SkPixelGeometry)) {
+ // TODO clip the group using cinfo; handle the paint's alpha and maybe color filter?
+
+ // Create a new group. We'll restore the previous group during onRestore.
+ skc_styling_group_alloc(fRoot->fStyling, &fRoot->fGroupID);
+ fRoot->fParents.push_back(fRoot->fGroupID);
+ fGroupID = fRoot->fGroupID;
+
+ // ENTER
+ skc_styling_cmd_t const styling_cmds_enter[] = {
+ SKC_STYLING_CMD_OP_COVER_ZERO_ACC,
+ SKC_STYLING_CMD_OP_COLOR_ZERO_ACC
+ };
+ skc_styling_group_enter(fRoot->fStyling, fRoot->fGroupID, SKC_STYLING_CMDS(styling_cmds_enter));
+
+ skc_styling_group_parents(fRoot->fStyling, fRoot->fGroupID, fRoot->fParents.count(),
+ fRoot->fParents.begin());
+
+ // RANGE
+ // We'll set range_lo at restore
+ skc_styling_group_range_hi(fRoot->fStyling, fRoot->fGroupID, fRoot->fGroupLayerID);
+
+ // LEAVE
+ skc_styling_cmd_t const styling_cmds_leave[] = {
+ SKC_STYLING_CMD_OP_SURFACE_COMPOSITE
+ };
+ skc_styling_group_leave(fRoot->fStyling, fRoot->fGroupID, SKC_STYLING_CMDS(styling_cmds_leave));
+}
+
+void SkDevice_ComputeLayerGroup::drawDevice(SkBaseDevice* device, int left, int top,
+ const SkPaint& paint) {
+ fRoot->drawDevice(device, left, top, paint); // the root will properly close the group
+}
+
+SkBaseDevice* SkDevice_ComputeLayerGroup::onCreateDevice(const CreateInfo& cinfo,
+ const SkPaint* paint) {
+ return fRoot->createLayerGroup(cinfo, paint);
+}
+
+void SkDevice_ComputeLayerGroup::onCtmChanged() {
+ this->sanityCheck();
+
+ // Cancels the translation as we're not using an offscreen buffer
+ const SkIPoint& origin = this->getOrigin();
+ fRoot->fTopCTM = this->ctm();
+ fRoot->fTopCTM.postTranslate(SkIntToScalar(origin.fX), SkIntToScalar(origin.fY));
+ fRoot->fTransformWeakref = SKC_WEAKREF_INVALID;
+}
+
+void SkDevice_ComputeLayerGroup::onSave() {
+ this->sanityCheck();
+ fRoot->onSave();
+}
+
+void SkDevice_ComputeLayerGroup::onRestore() {
+ this->sanityCheck();
+ fRoot->onRestore();
+}
+
+void SkDevice_ComputeLayerGroup::onClipRect(const SkRect& rect, SkClipOp op, bool aa) {
+ this->sanityCheck();
+ fRoot->fClipStack.clipRect(rect, fRoot->fTopCTM, op, aa);
+ fRoot->fClipWeakref = SKC_WEAKREF_INVALID;
+}
+
+void SkDevice_ComputeLayerGroup::onClipRRect(const SkRRect& rrect, SkClipOp op, bool aa) {
+ this->sanityCheck();
+ fRoot->fClipStack.clipRRect(rrect, fRoot->fTopCTM, op, aa);
+ fRoot->fClipWeakref = SKC_WEAKREF_INVALID;
+}
+
+void SkDevice_ComputeLayerGroup::onClipPath(const SkPath& path, SkClipOp op, bool aa) {
+ this->sanityCheck();
+ fRoot->fClipStack.clipPath(path, fRoot->fTopCTM, op, aa);
+ fRoot->fClipWeakref = SKC_WEAKREF_INVALID;
+}
+
+void SkDevice_ComputeLayerGroup::onClipRegion(const SkRegion& deviceRgn, SkClipOp op) {
+ this->sanityCheck();
+ fRoot->onClipRegion(deviceRgn, op);
+}
+
+void SkDevice_ComputeLayerGroup::onSetDeviceClipRestriction(SkIRect* mutableClipRestriction) {
+ this->sanityCheck();
+ fRoot->onSetDeviceClipRestriction(mutableClipRestriction);
+}
+
+#endif // SK_USE_COMPUTE_LAYER_GROUP
+
+#endif
diff --git a/src/compute/sk/SkDevice_Compute.h b/src/compute/sk/SkDevice_Compute.h
new file mode 100644
index 0000000000..d2d16e50b7
--- /dev/null
+++ b/src/compute/sk/SkDevice_Compute.h
@@ -0,0 +1,265 @@
+/*
+ * 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
diff --git a/src/compute/sk/SkImage_Compute.cpp b/src/compute/sk/SkImage_Compute.cpp
new file mode 100644
index 0000000000..039766f109
--- /dev/null
+++ b/src/compute/sk/SkImage_Compute.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+//
+//
+//
+
+#include "SkImage_Compute.h"
+
+//
+//
+//
+
+#if SK_SUPPORT_GPU_COMPUTE
+
+//
+// C++
+//
+
+//
+//
+//
+
+SkImage_Compute::SkImage_Compute(sk_sp<SkContext_Compute> compute,
+ GrGLuint const snap,
+ int const width,
+ int const height)
+
+ : SkImage(width,height,0), // FIXME -- who provides unique id?
+ compute(compute),
+ snap(snap)
+{
+ ;
+}
+
+SkImage_Compute::~SkImage_Compute()
+{
+ // skc_interop_snap_dispose(compute->interop,snap); TODO skc.h
+}
+
+//
+//
+//
+
+#endif
diff --git a/src/compute/sk/SkImage_Compute.h b/src/compute/sk/SkImage_Compute.h
new file mode 100644
index 0000000000..a3d9f028a3
--- /dev/null
+++ b/src/compute/sk/SkImage_Compute.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkSurface_Image_DEFINED
+#define SkSurface_Image_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
+
+//
+//
+//
+
+// #include "GrContext.h"
+// #include "SkRefCnt.h"
+#include "SkImage.h"
+#include "gl/GrGLGpu.h"
+
+//
+//
+//
+
+#include "SkContext_Compute.h"
+
+//
+//
+//
+
+class SkImage_Compute : public SkImage
+{
+ public:
+
+ SkImage_Compute(sk_sp<SkContext_Compute> compute,
+ GrGLuint const snap,
+ int const width,
+ int const height);
+
+ ~SkImage_Compute();
+
+ //
+ //
+ //
+
+ private:
+
+ //
+ //
+ //
+
+ sk_sp<SkContext_Compute> compute; // reference to compute context
+ GrGLuint snap; // fbo
+
+ //
+ //
+ //
+};
+
+//
+//
+//
+
+#endif
+
+//
+//
+//
+
+#endif
diff --git a/src/compute/sk/SkSurface_Compute.cpp b/src/compute/sk/SkSurface_Compute.cpp
new file mode 100644
index 0000000000..5dac0f0aff
--- /dev/null
+++ b/src/compute/sk/SkSurface_Compute.cpp
@@ -0,0 +1,191 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+//
+//
+//
+
+#include "SkSurface_Compute.h"
+#include "SkDevice_Compute.h"
+#include "SkImage_Compute.h"
+
+//
+//
+//
+
+#if SK_SUPPORT_GPU_COMPUTE
+
+//
+// C++
+//
+
+#include "gl/GrGLGpu.h"
+#include "SkSurface_Gpu.h"
+
+//
+//
+//
+
+SkSurface_Compute::SkSurface_Compute(sk_sp<SkContext_Compute> compute,
+ int const width, int const height)
+ : INHERITED(width,height,nullptr),
+ compute(compute)
+{
+ //
+ // resize interop
+ //
+ // skc_interop_size_set(compute->interop,width,height,NULL); TODO skc.h
+}
+
+SkSurface_Compute::~SkSurface_Compute()
+{
+ ;
+}
+
+//
+//
+//
+
+SkCanvas*
+SkSurface_Compute::onNewCanvas()
+{
+ uint32_t w = 0,h = 0;
+
+ // skc_interop_size_get(compute->interop,&w,&h); TODO skc.h
+
+ SkDevice_Compute * const device_compute = new SkDevice_Compute(compute,w,h);;
+ SkCanvas * const canvas = new SkCanvas(device_compute,SkCanvas::kConservativeRasterClip_InitFlag);
+
+ //
+ // destroy device upon surface destruction
+ //
+ device = sk_sp<SkBaseDevice>(device_compute);
+
+ //
+ // move origin from upper left to lower left
+ //
+ SkMatrix matrix;
+
+ matrix.setScaleTranslate(1.0f,-1.0f,0.0f,(SkScalar)h);
+
+ canvas->setMatrix(matrix);
+
+ return canvas;
+}
+
+//
+//
+//
+
+sk_sp<SkSurface>
+SkSurface_Compute::onNewSurface(const SkImageInfo& info)
+{
+ return sk_make_sp<SkSurface_Compute>(compute,info.width(),info.height());
+}
+
+//
+//
+//
+
+sk_sp<SkImage>
+SkSurface_Compute::onNewImageSnapshot()
+{
+ uint32_t w,h;
+
+ // skc_interop_size_get(compute->interop,&w,&h); TODO skc.h
+
+ GrGLuint snap;
+
+ // skc_interop_snap_create(compute->interop, TODO skc.h
+ // skc_surface_interop_surface_get(compute->surface),
+ // &snap);
+
+ return sk_make_sp<SkImage_Compute>(compute,snap,w,h);
+}
+
+//
+//
+//
+
+void
+SkSurface_Compute::onCopyOnWrite(ContentChangeMode mode)
+{
+ ;
+}
+
+//
+//
+//
+
+#if 0
+
+sk_sp<SkSurface>
+SkSurface_Compute::MakeComputeBackedSurface(SkWindow * const window,
+ const SkWindow::AttachmentInfo & attachmentInfo,
+ GrGLInterface const * const grInterface,
+ GrContext * const grContext,
+ sk_sp<SkContext_Compute> compute)
+{
+ GrBackendRenderTargetDesc desc;
+
+ desc.fWidth = SkScalarRoundToInt(window->width());
+ desc.fHeight = SkScalarRoundToInt(window->height());
+
+ if (0 == desc.fWidth || 0 == desc.fHeight) {
+ return nullptr;
+ }
+
+ // TODO: Query the actual framebuffer for sRGB capable. However, to
+ // preserve old (fake-linear) behavior, we don't do this. Instead, rely
+ // on the flag (currently driven via 'C' mode in SampleApp).
+ //
+ // Also, we may not have real sRGB support (ANGLE, in particular), so check for
+ // that, and fall back to L32:
+ //
+ // ... and, if we're using a 10-bit/channel FB0, it doesn't do sRGB conversion on write,
+ // so pretend that it's non-sRGB 8888:
+ desc.fConfig =
+ grContext->caps()->srgbSupport() &&
+ SkImageInfoIsGammaCorrect(window->info()) &&
+ (attachmentInfo.fColorBits != 30)
+ ? kSkiaGamma8888_GrPixelConfig : kSkia8888_GrPixelConfig;
+
+ desc.fOrigin = kBottomLeft_GrSurfaceOrigin;
+ desc.fSampleCnt = 0; // attachmentInfo.fSampleCount;
+ desc.fStencilBits = 0; // attachmentInfo.fStencilBits;
+
+ GrGLint buffer;
+
+ GR_GL_GetIntegerv(grInterface,GR_GL_FRAMEBUFFER_BINDING,&buffer);
+ desc.fRenderTargetHandle = buffer;
+
+ sk_sp<SkColorSpace> colorSpace =
+ grContext->caps()->srgbSupport() && SkImageInfoIsGammaCorrect(window->info())
+ ? SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named) : nullptr;
+
+ //
+ //
+ //
+
+ if (!grContext) {
+ return nullptr;
+ }
+
+ if (!SkSurface_Gpu::Valid(grContext,desc.fConfig,colorSpace.get())) {
+ return nullptr;
+ }
+
+ return sk_make_sp<SkSurface_Compute>(compute,desc.fWidth,desc.fHeight);
+}
+
+#endif
+
+//
+//
+//
+
+#endif
diff --git a/src/compute/sk/SkSurface_Compute.h b/src/compute/sk/SkSurface_Compute.h
new file mode 100644
index 0000000000..84836c0f29
--- /dev/null
+++ b/src/compute/sk/SkSurface_Compute.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkSurface_Compute_DEFINED
+#define SkSurface_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
+
+//
+//
+//
+
+#include "SkSurface_Base.h"
+#include "GrContext.h"
+#include "SkRefCnt.h"
+
+// Yuqian: It doesn't seem right to me for SkSurface_Compute to depend on SkWindow.
+// Maybe we should move MakeComputeBackedSurface(from SkWindow) to SkWindow.cpp.
+// #include "SkWindow.h"
+
+//
+//
+//
+
+#include "SkContext_Compute.h"
+
+//
+//
+//
+
+//
+//
+//
+
+class SkSurface_Compute : public SkSurface_Base
+{
+ public:
+
+ SkSurface_Compute(sk_sp<SkContext_Compute> compute,
+ int const width, int const height);
+
+ ~SkSurface_Compute();
+
+ //
+ //
+ //
+
+ SkCanvas* onNewCanvas() override;
+ sk_sp<SkSurface> onNewSurface(const SkImageInfo&) override;
+ sk_sp<SkImage> onNewImageSnapshot() override;
+ void onCopyOnWrite(ContentChangeMode) override;
+
+ //
+ //
+ //
+
+ // static sk_sp<SkSurface> MakeComputeBackedSurface(SkWindow * const window,
+ // const SkWindow::AttachmentInfo & attachmentInfo,
+ // GrGLInterface const * const grInterface,
+ // GrContext * const grContext,
+ // sk_sp<SkContext_Compute> compute);
+ // //
+ //
+ //
+
+ private:
+
+ typedef SkSurface_Base INHERITED;
+
+ //
+ //
+ //
+
+ sk_sp<SkBaseDevice> device;
+
+ //
+ //
+ //
+
+ sk_sp<SkContext_Compute> compute;
+
+ //
+ //
+ //
+};
+
+//
+//
+//
+
+#endif
+
+//
+//
+//
+
+#endif