/* * Copyright 2021 Google LLC * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "experimental/graphite/src/DrawContext.h" #include "include/private/SkColorData.h" #include "experimental/graphite/src/CommandBuffer.h" #include "experimental/graphite/src/DrawList.h" #include "experimental/graphite/src/DrawPass.h" #include "experimental/graphite/src/RenderPassTask.h" #include "experimental/graphite/src/TextureProxy.h" #include "experimental/graphite/src/geom/BoundsManager.h" #include "experimental/graphite/src/geom/Shape.h" namespace skgpu { sk_sp DrawContext::Make(sk_sp target, sk_sp colorSpace, SkColorType colorType, SkAlphaType alphaType) { if (!target) { return nullptr; } // TODO: validate that the color type and alpha type are compatible with the target's info SkImageInfo imageInfo = SkImageInfo::Make(target->dimensions(), colorType, alphaType, std::move(colorSpace)); return sk_sp(new DrawContext(std::move(target), imageInfo)); } DrawContext::DrawContext(sk_sp target, const SkImageInfo& ii) : fTarget(std::move(target)) , fImageInfo(ii) , fPendingDraws(std::make_unique()) { // TBD - Will probably want DrawLists (and its internal commands) to come from an arena // that the DC manages. } DrawContext::~DrawContext() { // If the DC is destroyed and there are pending commands, they won't be drawn. fPendingDraws.reset(); fDrawPasses.clear(); } void DrawContext::stencilAndFillPath(const Transform& localToDevice, const Shape& shape, const Clip& clip, DrawOrder order, const PaintParams* paint) { SkASSERT(SkIRect::MakeSize(fTarget->dimensions()).contains(clip.scissor())); fPendingDraws->stencilAndFillPath(localToDevice, shape, clip, order,paint); } void DrawContext::fillConvexPath(const Transform& localToDevice, const Shape& shape, const Clip& clip, DrawOrder order, const PaintParams* paint) { SkASSERT(SkIRect::MakeSize(fTarget->dimensions()).contains(clip.scissor())); fPendingDraws->fillConvexPath(localToDevice, shape, clip, order, paint); } void DrawContext::strokePath(const Transform& localToDevice, const Shape& shape, const StrokeParams& stroke, const Clip& clip, DrawOrder order, const PaintParams* paint) { SkASSERT(SkIRect::MakeSize(fTarget->dimensions()).contains(clip.scissor())); fPendingDraws->strokePath(localToDevice, shape, stroke, clip, order, paint); } void DrawContext::clear(const SkColor4f& clearColor) { fPendingLoadOp = LoadOp::kClear; SkPMColor4f pmColor = clearColor.premul(); fPendingClearColor = pmColor.array(); // a fullscreen clear will overwrite anything that came before, so start a new DrawList // and clear any drawpasses that haven't been snapped yet fPendingDraws = std::make_unique(); fDrawPasses.clear(); } void DrawContext::snapDrawPass(Recorder* recorder, const BoundsManager* occlusionCuller) { if (fPendingDraws->drawCount() == 0) { return; } auto pass = DrawPass::Make(recorder, std::move(fPendingDraws), fTarget, std::make_pair(fPendingLoadOp, fPendingStoreOp), fPendingClearColor, occlusionCuller); fDrawPasses.push_back(std::move(pass)); fPendingDraws = std::make_unique(); fPendingLoadOp = LoadOp::kLoad; fPendingStoreOp = StoreOp::kStore; } sk_sp DrawContext::snapRenderPassTask(Recorder* recorder, const BoundsManager* occlusionCuller) { this->snapDrawPass(recorder, occlusionCuller); if (fDrawPasses.empty()) { return nullptr; } // TODO: At this point we would determine all the targets used by the drawPasses, // build up the union of them and store them in the RenderPassDesc. However, for // the moment we should have only one drawPass. SkASSERT(fDrawPasses.size() == 1); RenderPassDesc desc; desc.fColorAttachment.fTextureProxy = sk_ref_sp(fDrawPasses[0]->target()); std::tie(desc.fColorAttachment.fLoadOp, desc.fColorAttachment.fStoreOp) = fDrawPasses[0]->ops(); desc.fClearColor = fDrawPasses[0]->clearColor(); return RenderPassTask::Make(std::move(fDrawPasses), desc); } } // namespace skgpu