/* * Copyright 2021 Google LLC * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef skgpu_graphite_DrawContext_DEFINED #define skgpu_graphite_DrawContext_DEFINED #include "include/core/SkColor.h" #include "include/core/SkImageInfo.h" #include "include/core/SkRefCnt.h" #include "include/core/SkSurfaceProps.h" #include "src/gpu/graphite/DrawListBase.h" #include "src/gpu/graphite/PaintParams.h" #include "src/gpu/graphite/StorageContext.h" #include "src/gpu/graphite/TextureProxy.h" #include "src/gpu/graphite/TextureProxyView.h" #include "src/gpu/graphite/task/UploadTask.h" #include #include #include struct SkIRect; struct SkISize; namespace skgpu::graphite { class Caps; class Clip; class ComputePathAtlas; class ConditionalUploadContext; class DrawOrder; class DrawTask; class Geometry; class PaintParams; class PathAtlas; class Recorder; class Renderer; class StrokeStyle; class Task; class Transform; /** * DrawContext records draw commands into a specific Surface, via a general task graph * representing GPU work and their inter-dependencies. */ class DrawContext final : public SkRefCnt { public: // allowUnpremul=true should only be used if the target is only going to be rendered // into with src-blending with calls to drawPaint or pixel-aligned drawRect calls to // avoid anti-aliasing. static sk_sp Make(const Caps* caps, sk_sp target, SkISize deviceSize, const SkColorInfo&, const SkSurfaceProps&, bool allowUnpremul); ~DrawContext() override; const SkImageInfo& imageInfo() const { return fImageInfo; } const SkColorInfo& colorInfo() const { return fImageInfo.colorInfo(); } const TextureProxyView& target() const { return fTarget; } bool isTexturable() const { return fIsTexturable; } const SkSurfaceProps& surfaceProps() const { return fSurfaceProps; } int pendingRenderSteps() const { return fPendingDraws->renderStepCount(); } bool modifiesTarget() const { return fPendingDraws->modifiesTarget(); } bool readsTexture(const TextureProxy*) const; void clear(const SkColor4f& clearColor); void discard(); std::pair recordDraw( const Renderer* renderer, const Transform& localToDevice, const Geometry& geometry, const Clip& clip, DrawOrder ordering, UniquePaintParamsID paintID, SkEnumBitMask dstUsage, PipelineDataGatherer* gatherer, const StrokeStyle* stroke, Layer* lastInsertion=nullptr); bool recordUpload(Recorder* recorder, const UploadSource& source, std::unique_ptr = nullptr); // Add a Task that will be executed *before* any of the pending draws and uploads are // executed as part of the next flush(). void recordDependency(sk_sp); // Returns the transient path atlas that uses compute to accumulate coverage masks for atlas // draws recorded to this SDC. The atlas gets created lazily upon request. Returns nullptr // if compute path generation is not supported. PathAtlas* getComputePathAtlas(Recorder*); // Moves all accumulated pending recorded operations (draws and uploads), and any other // dependent tasks into the DrawTask currently being built. void flush(Recorder*); // Returns the current DrawTask to the caller, so all pending draws and uploads (if flush() // was not immediately called prior to this) and subsequently recorded draws and uploads will // go into a new DrawTask. sk_sp snapDrawTask(); // Returns the dst read strategy to use when/if a paint requires a dst read DstReadStrategy dstReadStrategy() const { return fDstReadStrategy; } StorageContext* storageContext() { return &fStorageContext; } private: DrawContext(const Caps*, sk_sp, const SkImageInfo&, const SkSurfaceProps&); void resetForClearOrDiscard(); // May not be texturable, but preserves the read swizzle if it were to be read back to CPU or // copied to a texturable proxy. TextureProxyView fTarget; SkImageInfo fImageInfo; const SkSurfaceProps fSurfaceProps; bool fIsTexturable; // Cache at creation so we don't require constant Caps access // Does *not* reflect whether a dst read is needed by the DrawLists - simply specifies the // strategies to use should any encountered paint require it. const DstReadStrategy fDstReadStrategy; const bool fSupportsHardwareAdvancedBlend; const bool fAdvancedBlendsRequireBarrier; // The in-progress DrawTask that will be snapped and returned when some external requirement // must depend on the contents of this DrawContext's target. As higher-level Skia operations // are recorded, it can be necessary to flush pending draws and uploads into the task list. // This provides a place to reset scratch textures or buffers as their previous state will have // been consumed by the flushed tasks rendering to this DrawContext's target. sk_sp fCurrentDrawTask; // Stores the most immediately recorded draws and uploads into the DrawContext's target. These // are collected outside of the DrawTask so that encoder switches can be minimized when // flushing. std::unique_ptr fPendingDraws; std::unique_ptr fPendingUploads; // Accumulates atlas coverage masks generated by compute dispatches that are required by one or // more entries in `fPendingDraws`. When pending draws are snapped into a new DrawPass, a // compute dispatch group gets recorded which schedules the accumulated masks to get drawn into // an atlas texture. The accumulated masks are then cleared which frees up the atlas for // future draws. // // TODO: Currently every PathAtlas contains a single texture. If multiple snapped draw // passes resulted in multiple ComputePathAtlas dispatch groups, the later dispatches would // overwrite the atlas texture since all compute tasks are scheduled before render tasks. This // is currently not an issue since there is only one DrawPass per flush but we may want to // either support one atlas texture per DrawPass or record the dispatches once per // RenderPassTask rather than DrawPass. std::unique_ptr fComputePathAtlas; StorageContext fStorageContext; }; } // namespace skgpu::graphite #endif // skgpu_graphite_DrawContext_DEFINED