/* * 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_Recorder_DEFINED #define skgpu_graphite_Recorder_DEFINED #include "include/core/SkRefCnt.h" #include "include/core/SkSize.h" #include "include/gpu/graphite/GraphiteTypes.h" #include "include/gpu/graphite/Recording.h" #include "include/private/base/SingleOwner.h" #include class SkCanvas; struct SkImageInfo; class SkPixmap; namespace skgpu { class TokenTracker; } namespace sktext::gpu { class StrikeCache; class TextBlobRedrawCoordinator; } namespace skgpu::graphite { class AtlasManager; class BackendTexture; class Caps; class Context; class Device; class DrawBufferManager; class GlobalCache; class ImageProvider; class RecorderPriv; class ResourceProvider; class RuntimeEffectDictionary; class SharedContext; class Task; class TaskGraph; class TextureDataBlock; class TextureInfo; class UniformDataBlock; class UploadBufferManager; template class PipelineDataCache; using UniformDataCache = PipelineDataCache; using TextureDataCache = PipelineDataCache; struct SK_API RecorderOptions final { RecorderOptions(); RecorderOptions(const RecorderOptions&); ~RecorderOptions(); sk_sp fImageProvider; }; class SK_API Recorder final { public: Recorder(const Recorder&) = delete; Recorder(Recorder&&) = delete; Recorder& operator=(const Recorder&) = delete; Recorder& operator=(Recorder&&) = delete; ~Recorder(); std::unique_ptr snap(); ImageProvider* clientImageProvider() { return fClientImageProvider.get(); } const ImageProvider* clientImageProvider() const { return fClientImageProvider.get(); } /** * Creates a new backend gpu texture matching the dimensions and TextureInfo. If an invalid * TextureInfo or a TextureInfo Skia can't support is passed in, this will return an invalid * BackendTexture. Thus the client should check isValid on the returned BackendTexture to know * if it succeeded or not. * * If this does return a valid BackendTexture, the caller is required to use * Recorder::deleteBackendTexture or Context::deleteBackendTexture to delete the texture. It is * safe to use the Context that created this Recorder or any other Recorder created from the * same Context to call deleteBackendTexture. */ BackendTexture createBackendTexture(SkISize dimensions, const TextureInfo&); /** * If possible, updates a backend texture with the provided pixmap data. The client * should check the return value to see if the update was successful. The client is required * to insert a Recording into the Context and call `submit` to send the upload work to the gpu. * The backend texture must be compatible with the provided pixmap(s). Compatible, in this case, * means that the backend format is compatible with the base pixmap's colortype. The src data * can be deleted when this call returns. * If the backend texture is mip mapped, the data for all the mipmap levels must be provided. * In the mipmapped case all the colortypes of the provided pixmaps must be the same. * Additionally, all the miplevels must be sized correctly (please see * SkMipmap::ComputeLevelSize and ComputeLevelCount). * Note: the pixmap's alphatypes and colorspaces are ignored. * For the Vulkan backend after a successful update the layout of the created VkImage will be: * VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL */ bool updateBackendTexture(const BackendTexture&, const SkPixmap srcData[], int numLevels); /** * Called to delete the passed in BackendTexture. This should only be called if the * BackendTexture was created by calling Recorder::createBackendTexture on a Recorder that is * associated with the same Context. If the BackendTexture is not valid or does not match the * BackendApi of the Recorder then nothing happens. * * Otherwise this will delete/release the backend object that is wrapped in the BackendTexture. * The BackendTexture will be reset to an invalid state and should not be used again. */ void deleteBackendTexture(BackendTexture&); // Returns a canvas that will record to a proxy surface, which must be instantiated on replay. // This can only be called once per Recording; subsequent calls will return null until a // Recording is snapped. Additionally, the returned SkCanvas is only valid until the next // Recording snap, at which point it is deleted. SkCanvas* makeDeferredCanvas(const SkImageInfo&, const TextureInfo&); // Provides access to functions that aren't part of the public API. RecorderPriv priv(); const RecorderPriv priv() const; // NOLINT(readability-const-return-type) #if GR_TEST_UTILS bool deviceIsRegistered(Device*); #endif private: friend class Context; // For ctor friend class Device; // For registering and deregistering Devices; friend class RecorderPriv; // for ctor and hidden methods Recorder(sk_sp, const RecorderOptions&); SingleOwner* singleOwner() const { return &fSingleOwner; } BackendApi backend() const; // We keep track of all Devices that are connected to a Recorder. This allows the client to // safely delete an SkSurface or a Recorder in any order. If the client deletes the Recorder // we need to notify all Devices that the Recorder is no longer valid. If we delete the // SkSurface/Device first we will flush all the Device's into the Recorder before deregistering // it from the Recorder. // // We do not need to take a ref on the Device since the Device will flush and deregister itself // in its dtor. There is no other need for the Recorder to know about the Device after this // point. // // Note: We could probably get by with only registering Devices directly connected to // SkSurfaces. All other one off Devices will be created in a controlled scope where the // Recorder should still be valid by the time they need to flush their work when the Device is // deleted. We would have to make sure we safely handle cases where a client calls saveLayer // then either deletes the SkSurface or Recorder before calling restore. For simplicity we just // register every device for now, but if we see extra overhead in pushing back the extra // pointers, we can look into only registering SkSurface Devices. void registerDevice(Device*); void deregisterDevice(const Device*); sk_sp fSharedContext; std::unique_ptr fResourceProvider; std::unique_ptr fRuntimeEffectDict; std::unique_ptr fGraph; std::unique_ptr fUniformDataCache; std::unique_ptr fTextureDataCache; std::unique_ptr fDrawBufferManager; std::unique_ptr fUploadBufferManager; std::vector fTrackedDevices; uint32_t fRecorderID; // Needed for MessageBox handling for text std::unique_ptr fAtlasManager; std::unique_ptr fTokenTracker; std::unique_ptr fStrikeCache; std::unique_ptr fTextBlobCache; sk_sp fClientImageProvider; // In debug builds we guard against improper thread handling // This guard is passed to the ResourceCache. // TODO: Should we also pass this to Device, DrawContext, and similar classes? mutable SingleOwner fSingleOwner; sk_sp fTargetProxyDevice; std::unique_ptr fTargetProxyCanvas; std::unique_ptr fTargetProxyData; #if GRAPHITE_TEST_UTILS // For testing use only -- the Context used to create this Recorder Context* fContext = nullptr; #endif }; } // namespace skgpu::graphite #endif // skgpu_graphite_Recorder_DEFINED