diff options
author | Allan MacKinnon <allanmac@google.com> | 2018-06-19 13:57:04 -0700 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2018-06-20 01:19:18 +0000 |
commit | 4359d529121fc1f39f882693d641c0133d138d41 (patch) | |
tree | d2c3239162e68d24d5c2cebc8a4f6659860cc2a0 /src/compute/sk | |
parent | 47c29fa64b3ffc1eec7723d40e9862b2d2a8443f (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.cpp | 95 | ||||
-rw-r--r-- | src/compute/sk/SkContext_Compute.h | 71 | ||||
-rw-r--r-- | src/compute/sk/SkDevice_Compute.cpp | 887 | ||||
-rw-r--r-- | src/compute/sk/SkDevice_Compute.h | 265 | ||||
-rw-r--r-- | src/compute/sk/SkImage_Compute.cpp | 49 | ||||
-rw-r--r-- | src/compute/sk/SkImage_Compute.h | 83 | ||||
-rw-r--r-- | src/compute/sk/SkSurface_Compute.cpp | 191 | ||||
-rw-r--r-- | src/compute/sk/SkSurface_Compute.h | 113 |
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 |