diff --git a/experimental/graphite/src/Device.cpp b/experimental/graphite/src/Device.cpp index 6d1d0d46a3..abe9098a1f 100644 --- a/experimental/graphite/src/Device.cpp +++ b/experimental/graphite/src/Device.cpp @@ -246,6 +246,12 @@ bool Device::readPixels(Context* context, return true; } +bool Device::onWritePixels(const SkPixmap& pm, int x, int y) { + this->flushPendingWorkToRecorder(); + + return fDC->writePixels(fRecorder, pm, {x, y}); +} + SkIRect Device::onDevClipBounds() const { auto target = fDC->target(); return SkIRect::MakeSize(target->dimensions()); @@ -469,6 +475,11 @@ void Device::flushPendingWorkToRecorder() { // TODO: we may need to further split this function up since device->device drawList and // DrawPass stealing will need to share some of the same logic w/o becoming a Task. + auto uploadTask = fDC->snapUploadTask(fRecorder); + if (uploadTask) { + fRecorder->priv().add(std::move(uploadTask)); + } + // TODO: iterate the clip stack and issue a depth-only draw for every clip element that has // a non-empty usage bounds, using that bounds as the scissor. auto drawTask = fDC->snapRenderPassTask(fRecorder, fColorDepthBoundsManager.get()); diff --git a/experimental/graphite/src/Device.h b/experimental/graphite/src/Device.h index 0ae6f1a0be..19111cf9d4 100644 --- a/experimental/graphite/src/Device.h +++ b/experimental/graphite/src/Device.h @@ -93,7 +93,7 @@ private: void onClipRegion(const SkRegion& deviceRgn, SkClipOp) override {} void onReplaceClip(const SkIRect& rect) override {} - bool onWritePixels(const SkPixmap&, int x, int y) override { return false; } + bool onWritePixels(const SkPixmap&, int x, int y) override; // TODO: This will likely be implemented with the same primitive building block that drawRect // and drawRRect will rely on. diff --git a/experimental/graphite/src/DrawContext.cpp b/experimental/graphite/src/DrawContext.cpp index 8094efb420..46b8110737 100644 --- a/experimental/graphite/src/DrawContext.cpp +++ b/experimental/graphite/src/DrawContext.cpp @@ -7,6 +7,7 @@ #include "experimental/graphite/src/DrawContext.h" +#include "include/core/SkPixmap.h" #include "include/private/SkColorData.h" #include "experimental/graphite/include/Context.h" @@ -47,7 +48,8 @@ sk_sp DrawContext::Make(sk_sp target, DrawContext::DrawContext(sk_sp target, const SkImageInfo& ii) : fTarget(std::move(target)) , fImageInfo(ii) - , fPendingDraws(std::make_unique()) { + , fPendingDraws(std::make_unique()) + , fPendingUploads(std::make_unique()) { // TBD - Will probably want DrawLists (and its internal commands) to come from an arena // that the DC manages. } @@ -97,6 +99,52 @@ void DrawContext::clear(const SkColor4f& clearColor) { fDrawPasses.clear(); } +// +// TODO: The other draw-recording APIs in DrawContext are relatively simple, just storing state +// from the caller's decision making. If possible we should consider moving the more complex logic +// somewhere above DrawContext and have this be much simpler. +bool DrawContext::writePixels(Recorder* recorder, const SkPixmap& src, SkIPoint dstPoint) { + // TODO: add mipmap support for createBackendTexture + + // Our caller should have clipped to the bounds of the surface already. + SkASSERT(SkIRect::MakeSize(fTarget->dimensions()).contains( + SkIRect::MakePtSize(dstPoint, src.dimensions()))); + + if (!recorder) { + return false; + } + + if (src.colorType() == kUnknown_SkColorType) { + return false; + } + + // TODO: check for readOnly or framebufferOnly target and return false if so + + const Caps* caps = recorder->priv().caps(); + + // TODO: canvas2DFastPath? + // TODO: check that surface supports writePixels + // TODO: handle writePixels as draw if needed (e.g., canvas2DFastPath || !supportsWritePixels) + + // TODO: check for flips and conversions and either handle here or pass info to appendUpload + + // for now, until conversions are supported + if (!caps->areColorTypeAndTextureInfoCompatible(src.colorType(), + fTarget->textureInfo())) { + return false; + } + + std::vector levels; + levels.push_back({src.addr(), src.rowBytes()}); + + SkIRect dstRect = SkIRect::MakePtSize(dstPoint, src.dimensions()); + return fPendingUploads->appendUpload(recorder, + fTarget, + src.colorType(), + levels, + dstRect); +} + void DrawContext::snapDrawPass(Recorder* recorder, const BoundsManager* occlusionCuller) { if (fPendingDraws->drawCount() == 0) { return; @@ -147,6 +195,10 @@ sk_sp DrawContext::snapRenderPassTask(Recorder* recorder, } sk_sp DrawContext::snapUploadTask(Recorder* recorder) { + if (!fPendingUploads) { + return nullptr; + } + sk_sp uploadTask = UploadTask::Make(fPendingUploads.get()); fPendingUploads = std::make_unique(); diff --git a/experimental/graphite/src/DrawContext.h b/experimental/graphite/src/DrawContext.h index b16c905e9f..31ca03cde0 100644 --- a/experimental/graphite/src/DrawContext.h +++ b/experimental/graphite/src/DrawContext.h @@ -18,6 +18,8 @@ #include +class SkPixmap; + namespace skgpu { class BoundsManager; @@ -71,6 +73,10 @@ public: DrawOrder order, const PaintParams* paint); + bool writePixels(Recorder* recorder, + const SkPixmap& src, + SkIPoint dstPt); + // Ends the current DrawList being accumulated by the SDC, converting it into an optimized and // immutable DrawPass. The DrawPass will be ordered after any other snapped DrawPasses or // appended DrawPasses from a child SDC. A new DrawList is started to record subsequent drawing diff --git a/experimental/graphite/src/Surface_Graphite.cpp b/experimental/graphite/src/Surface_Graphite.cpp index c6e1d91ae8..d0c33ced90 100644 --- a/experimental/graphite/src/Surface_Graphite.cpp +++ b/experimental/graphite/src/Surface_Graphite.cpp @@ -34,7 +34,10 @@ sk_sp Surface::onNewImageSnapshot(const SkIRect* subset) { return sk_sp(new Image_Graphite(ii)); } -void Surface::onWritePixels(const SkPixmap&, int x, int y) {} +void Surface::onWritePixels(const SkPixmap& pixmap, int x, int y) { + fDevice->writePixels(pixmap, x, y); +} + bool Surface::onCopyOnWrite(ContentChangeMode) { return true; } bool Surface::onReadPixels(Context* context, diff --git a/experimental/graphite/src/UploadTask.cpp b/experimental/graphite/src/UploadTask.cpp index 07e1de1c03..5e2629f9d0 100644 --- a/experimental/graphite/src/UploadTask.cpp +++ b/experimental/graphite/src/UploadTask.cpp @@ -139,7 +139,7 @@ bool UploadList::appendUpload(Recorder* recorder, copyData[currentMipLevel].fBufferRowBytes = trimRowBytes; copyData[currentMipLevel].fRect = { dstRect.left(), dstRect.top(), // TODO: can we recompute this for mips? - currentWidth, currentHeight + dstRect.left() + currentWidth, dstRect.top() + currentHeight }; copyData[currentMipLevel].fMipLevel = currentMipLevel; diff --git a/gm/graphitestart.cpp b/gm/graphitestart.cpp index 6f0d661323..b14bc1abc9 100644 --- a/gm/graphitestart.cpp +++ b/gm/graphitestart.cpp @@ -10,6 +10,7 @@ #include "include/core/SkImage.h" #include "include/core/SkPaint.h" #include "include/effects/SkGradientShader.h" +#include "tools/Resources.h" namespace { @@ -61,6 +62,7 @@ class GraphiteStartGM : public GM { public: GraphiteStartGM() { this->setBGColor(0xFFCCCCCC); + GetResourceAsBitmap("images/color_wheel.gif", &fBitmap); } protected: @@ -69,7 +71,7 @@ protected: } SkISize onISize() override { - return SkISize::Make(256, 256); + return SkISize::Make(256, 384); } void onDraw(SkCanvas* canvas) override { @@ -102,7 +104,13 @@ protected: p.setShader(create_blend_shader(SkBlendMode::kDstOver)); canvas->drawRect({129, 129, 255, 255}, p); } +#ifdef SK_GRAPHITE_ENABLED + // TODO: failing serialize test on Linux, not sure what's going on + canvas->writePixels(fBitmap, 0, 256); +#endif } + + SkBitmap fBitmap; }; //////////////////////////////////////////////////////////////////////////////