1 /* 2 * Copyright 2021 Google LLC 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #ifndef skgpu_graphite_Device_DEFINED 9 #define skgpu_graphite_Device_DEFINED 10 11 #include "include/core/SkImage.h" 12 #include "include/gpu/GpuTypes.h" 13 #include "src/base/SkEnumBitMask.h" 14 #include "src/core/SkDevice.h" 15 #include "src/gpu/graphite/ClipStack_graphite.h" 16 #include "src/gpu/graphite/DrawOrder.h" 17 #include "src/gpu/graphite/geom/Rect.h" 18 #include "src/gpu/graphite/geom/Transform_graphite.h" 19 #include "src/text/gpu/SubRunContainer.h" 20 #include "src/text/gpu/SubRunControl.h" 21 22 enum class SkBackingFit; 23 class SkStrokeRec; 24 25 namespace skgpu::graphite { 26 27 class PathAtlas; 28 class BoundsManager; 29 class Clip; 30 class Context; 31 class DrawContext; 32 enum class DstReadRequirement; 33 class Geometry; 34 class Image; 35 enum class LoadOp : uint8_t; 36 class PaintParams; 37 class Recorder; 38 class Renderer; 39 class Shape; 40 class StrokeStyle; 41 class Task; 42 class TextureProxy; 43 class TextureProxyView; 44 45 class Device final : public SkDevice { 46 public: 47 ~Device() override; 48 49 // If 'registerWithRecorder' is false, it is meant to be a short-lived Device that is managed 50 // by the caller within a limited scope (such that it is guaranteed to go out of scope before 51 // the Recorder can be snapped). 52 static sk_sp<Device> Make(Recorder* recorder, 53 sk_sp<TextureProxy>, 54 SkISize deviceSize, 55 const SkColorInfo&, 56 const SkSurfaceProps&, 57 LoadOp initialLoadOp, 58 bool registerWithRecorder=true); 59 // Convenience factory to create the underlying TextureProxy based on the configuration provided 60 static sk_sp<Device> Make(Recorder*, 61 const SkImageInfo&, 62 Budgeted, 63 Mipmapped, 64 SkBackingFit, 65 const SkSurfaceProps&, 66 LoadOp initialLoadOp, 67 std::string_view label, 68 bool registerWithRecorder=true); 69 asGraphiteDevice()70 Device* asGraphiteDevice() override { return this; } 71 recorder()72 Recorder* recorder() const override { return fRecorder; } 73 // This call is triggered from the Recorder on its registered Devices. It is typically called 74 // when the Recorder is abandoned or deleted. abandonRecorder()75 void abandonRecorder() { fRecorder = nullptr; } 76 77 // Ensures clip elements are drawn that will clip previous draw calls, snaps all pending work 78 // from the DrawContext as a RenderPassTask and records it in the Device's recorder. 79 void flushPendingWorkToRecorder(); 80 81 const Transform& localToDeviceTransform(); 82 83 // Flushes any pending work to the recorder and then deregisters and abandons the recorder. 84 void setImmutable() override; 85 86 SkStrikeDeviceInfo strikeDeviceInfo() const override; 87 88 TextureProxy* target(); 89 // May be null if target is not sampleable. 90 TextureProxyView readSurfaceView() const; 91 // Can succeed if target is readable but not sampleable. Assumes 'subset' is contained in bounds 92 sk_sp<Image> makeImageCopy(const SkIRect& subset, Budgeted, Mipmapped, SkBackingFit); 93 94 // True if this Device represents an internal renderable surface that will go out of scope 95 // before the next Recorder snap. 96 // NOTE: Currently, there are two different notions of "scratch" that are being merged together. 97 // 1. Devices whose targets are not instantiated (Device::Make). 98 // 2. Devices that are not registered with the Recorder (Surface::MakeScratch). 99 // 100 // This function reflects notion #1, since the long-term plan will be that all Devices that are 101 // not instantiated will also not be registered with the Recorder. For the time being, due to 102 // shared atlas management, layer-backing Devices need to be registered with the Recorder but 103 // are otherwise the canonical scratch device. 104 // 105 // Existing uses of Surface::MakeScratch() will migrate to using un-instantiated Devices with 106 // the requirement that if the Device's target is being returned in a client-owned object 107 // (e.g. SkImages::MakeWithFilter), that it should then be explicitly instantiated. Once scratch 108 // tasks are fully organized in a graph and not automatically appended to the root task list, 109 // this explicit instantiation will be responsible for moving the scratch tasks to the root list 110 bool isScratchDevice() const; 111 112 // Only used for scratch devices. 113 sk_sp<Task> lastDrawTask() const; 114 useDrawCoverageMaskForMaskFilters()115 bool useDrawCoverageMaskForMaskFilters() const override { return true; } 116 117 // Clipping pushClipStack()118 void pushClipStack() override { fClip.save(); } popClipStack()119 void popClipStack() override { fClip.restore(); } 120 isClipWideOpen()121 bool isClipWideOpen() const override { 122 return fClip.clipState() == ClipStack::ClipState::kWideOpen; 123 } isClipEmpty()124 bool isClipEmpty() const override { 125 return fClip.clipState() == ClipStack::ClipState::kEmpty; 126 } isClipRect()127 bool isClipRect() const override { 128 return fClip.clipState() == ClipStack::ClipState::kDeviceRect || 129 fClip.clipState() == ClipStack::ClipState::kWideOpen; 130 } 131 132 bool isClipAntiAliased() const override; 133 SkIRect devClipBounds() const override; 134 void android_utils_clipAsRgn(SkRegion*) const override; 135 136 void clipRect(const SkRect& rect, SkClipOp, bool aa) override; 137 void clipRRect(const SkRRect& rrect, SkClipOp, bool aa) override; 138 void clipPath(const SkPath& path, SkClipOp, bool aa) override; 139 140 void clipRegion(const SkRegion& globalRgn, SkClipOp) override; 141 void replaceClip(const SkIRect& rect) override; 142 143 // Drawing 144 void drawPaint(const SkPaint& paint) override; 145 void drawRect(const SkRect& r, const SkPaint& paint) override; 146 void drawOval(const SkRect& oval, const SkPaint& paint) override; 147 void drawRRect(const SkRRect& rr, const SkPaint& paint) override; 148 void drawArc(const SkArc& arc, const SkPaint& paint) override; 149 void drawPoints(SkCanvas::PointMode mode, size_t count, 150 const SkPoint[], const SkPaint& paint) override; 151 void drawPath(const SkPath& path, const SkPaint& paint, bool pathIsMutable = false) override; 152 153 // No need to specialize drawDRRect, drawRegion, drawPatch as the default impls all 154 // route to drawPath, drawRect, or drawVertices as desired. 155 156 void drawEdgeAAQuad(const SkRect& rect, const SkPoint clip[4], 157 SkCanvas::QuadAAFlags aaFlags, const SkColor4f& color, 158 SkBlendMode mode) override; 159 160 void drawEdgeAAImageSet(const SkCanvas::ImageSetEntry[], int count, 161 const SkPoint dstClips[], const SkMatrix preViewMatrices[], 162 const SkSamplingOptions&, const SkPaint&, 163 SkCanvas::SrcRectConstraint) override; 164 165 void drawImageRect(const SkImage*, const SkRect* src, const SkRect& dst, 166 const SkSamplingOptions&, const SkPaint&, 167 SkCanvas::SrcRectConstraint) override; 168 169 void drawVertices(const SkVertices*, sk_sp<SkBlender>, const SkPaint&, bool) override; 170 bool drawAsTiledImageRect(SkCanvas*, 171 const SkImage*, 172 const SkRect* src, 173 const SkRect& dst, 174 const SkSamplingOptions&, 175 const SkPaint&, 176 SkCanvas::SrcRectConstraint) override; 177 // TODO: Implement these using per-edge AA quads and an inlined image shader program. drawImageLattice(const SkImage *,const SkCanvas::Lattice &,const SkRect & dst,SkFilterMode,const SkPaint &)178 void drawImageLattice(const SkImage*, const SkCanvas::Lattice&, 179 const SkRect& dst, SkFilterMode, const SkPaint&) override {} drawAtlas(const SkRSXform[],const SkRect[],const SkColor[],int count,sk_sp<SkBlender>,const SkPaint &)180 void drawAtlas(const SkRSXform[], const SkRect[], const SkColor[], int count, sk_sp<SkBlender>, 181 const SkPaint&) override {} 182 drawDrawable(SkCanvas *,SkDrawable *,const SkMatrix *)183 void drawDrawable(SkCanvas*, SkDrawable*, const SkMatrix*) override {} drawMesh(const SkMesh &,sk_sp<SkBlender>,const SkPaint &)184 void drawMesh(const SkMesh&, sk_sp<SkBlender>, const SkPaint&) override {} 185 186 // Special images and layers 187 sk_sp<SkSurface> makeSurface(const SkImageInfo&, const SkSurfaceProps&) override; 188 189 sk_sp<SkDevice> createDevice(const CreateInfo&, const SkPaint*) override; 190 191 sk_sp<SkSpecialImage> snapSpecial(const SkIRect& subset, bool forceCopy = false) override; 192 193 void drawSpecial(SkSpecialImage*, const SkMatrix& localToDevice, 194 const SkSamplingOptions&, const SkPaint&, 195 SkCanvas::SrcRectConstraint) override; 196 void drawCoverageMask(const SkSpecialImage*, const SkMatrix& localToDevice, 197 const SkSamplingOptions&, const SkPaint&) override; 198 199 bool drawBlurredRRect(const SkRRect&, const SkPaint&, float deviceSigma) override; 200 201 private: 202 class IntersectionTreeSet; 203 204 Device(Recorder*, sk_sp<DrawContext>); 205 206 sk_sp<SkSpecialImage> makeSpecial(const SkBitmap&) override; 207 sk_sp<SkSpecialImage> makeSpecial(const SkImage*) override; 208 209 bool onReadPixels(const SkPixmap&, int x, int y) override; 210 211 bool onWritePixels(const SkPixmap&, int x, int y) override; 212 213 void onDrawGlyphRunList(SkCanvas*, const sktext::GlyphRunList&, const SkPaint&) override; 214 215 void onClipShader(sk_sp<SkShader> shader) override; 216 217 sk_sp<skif::Backend> createImageFilteringBackend(const SkSurfaceProps& surfaceProps, 218 SkColorType colorType) const override; 219 220 // DrawFlags alters the effects used by drawGeometry. 221 // 222 // There is no kIgnoreMaskFilter flag because the Device always ignores the mask filter -- the 223 // mask filter should be handled by the SkCanvas, either with an auto mask filter layer or 224 // being converted to an analytic blur draw. 225 enum class DrawFlags : unsigned { 226 kNone = 0b000, 227 228 // Any SkPathEffect on the SkPaint passed into drawGeometry() is ignored. 229 // - drawPaint, drawImageLattice, drawImageRect, drawEdgeAAImageSet, drawVertices, drawAtlas 230 // - drawGeometry after it's applied the path effect. 231 kIgnorePathEffect = 0b001, 232 }; 233 SK_DECL_BITMASK_OPS_FRIENDS(DrawFlags) 234 235 // Handles applying path effects, mask filters, stroke-and-fill styles, and hairlines. 236 // Ignores geometric style on the paint in favor of explicitly provided SkStrokeRec and flags. 237 // All overridden SkDevice::draw() functions should bottom-out with calls to drawGeometry(). 238 void drawGeometry(const Transform&, 239 const Geometry&, 240 const SkPaint&, 241 const SkStrokeRec&, 242 SkEnumBitMask<DrawFlags> = DrawFlags::kNone, 243 sk_sp<SkBlender> primitiveBlender = nullptr, 244 bool skipColorXform = false); 245 246 // Like drawGeometry() but is Shape-only, depth-only, fill-only, and lets the ClipStack define 247 // the transform, clip, and DrawOrder (although Device still tracks stencil buffer usage). 248 void drawClipShape(const Transform&, const Shape&, const Clip&, DrawOrder); 249 250 sktext::gpu::AtlasDrawDelegate atlasDelegate(); 251 // Handles primitive processing for atlas-based text 252 void drawAtlasSubRun(const sktext::gpu::AtlasSubRun*, 253 SkPoint drawOrigin, 254 const SkPaint& paint, 255 sk_sp<SkRefCnt> subRunStorage, 256 sktext::gpu::RendererData); 257 258 sk_sp<sktext::gpu::Slug> convertGlyphRunListToSlug(const sktext::GlyphRunList& glyphRunList, 259 const SkPaint& paint) override; 260 261 void drawSlug(SkCanvas*, const sktext::gpu::Slug* slug, const SkPaint& paint) override; 262 263 // Returns the Renderer to draw the shape in the given style. If SkStrokeRec is a 264 // stroke-and-fill, this returns the Renderer used for the fill portion and it can be assumed 265 // that Renderer::TessellatedStrokes() will be used for the stroke portion. 266 // 267 // Depending on the preferred anti-aliasing quality and platform capabilities (such as compute 268 // shader support), an atlas handler for path rendering may be returned alongside the chosen 269 // Renderer. In that case, all fill, stroke, and stroke-and-fill styles should be rendered with 270 // a single recorded CoverageMask draw and the shape data should be added to the provided atlas 271 // handler to be scheduled for a coverage mask render. 272 // 273 // TODO: Renderers may have fallbacks (e.g. pre-chop large paths, or convert stroke to fill). 274 // Are those handled inside ChooseRenderer() where it can modify the shape, stroke? or does it 275 // return a retry error code? or does drawGeometry() handle all the fallbacks, knowing that 276 // a particular shape type needs to be pre-chopped? 277 // TODO: Move this into a RendererSelector object provided by the Context. 278 std::pair<const Renderer*, PathAtlas*> chooseRenderer(const Transform& localToDevice, 279 const Geometry&, 280 const SkStrokeRec&, 281 bool requireMSAA) const; 282 283 bool needsFlushBeforeDraw(int numNewRenderSteps, DstReadRequirement) const; 284 285 // Flush internal work, such as pending clip draws and atlas uploads, into the Device's DrawTask 286 void internalFlush(); 287 288 Recorder* fRecorder; 289 sk_sp<DrawContext> fDC; 290 // Scratch devices hold on to their last snapped DrawTask so that they can be directly 291 // referenced when the device image is drawn into some other surface. 292 // NOTE: For now, this task is still added to the root task list when the Device is flushed, but 293 // in the long-term, these scratch draw tasks will only be executed if they are referenced by 294 // some other task chain that makes it to the root list. 295 sk_sp<Task> fLastTask; 296 297 ClipStack fClip; 298 299 // Tracks accumulated intersections for ordering dependent use of the color and depth attachment 300 // (i.e. depth-based clipping, and transparent blending) 301 std::unique_ptr<BoundsManager> fColorDepthBoundsManager; 302 // Tracks disjoint stencil indices for all recordered draws 303 std::unique_ptr<IntersectionTreeSet> fDisjointStencilSet; 304 305 // Lazily updated Transform constructed from localToDevice()'s SkM44 306 Transform fCachedLocalToDevice; 307 308 // The max depth value sent to the DrawContext, incremented so each draw has a unique value. 309 PaintersDepth fCurrentDepth; 310 311 // The DrawContext's target supports MSAA 312 bool fMSAASupported = false; 313 314 // TODO(b/330864257): Clean up once flushPendingWorkToRecorder() doesn't have to be re-entrant 315 bool fIsFlushing = false; 316 317 const sktext::gpu::SubRunControl fSubRunControl; 318 319 #if defined(SK_DEBUG) 320 // When not 0, this Device is an unregistered scratch device that is intended to go out of 321 // scope before the Recorder is snapped. Assuming controlling code is valid, that means the 322 // Device's recorder's next recording ID should still be the the recording ID at the time the 323 // Device was created. If not, it means the Device lived too long and may not be flushing tasks 324 // in the expected order. 325 uint32_t fScopedRecordingID = 0; 326 #endif 327 328 friend class ClipStack; // for recordDraw 329 }; 330 331 SK_MAKE_BITMASK_OPS(Device::DrawFlags) 332 333 } // namespace skgpu::graphite 334 335 #endif // skgpu_graphite_Device_DEFINED 336