1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309
|
/*
* 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 "include/private/base/SkTArray.h"
#include <chrono>
struct AHardwareBuffer;
class SkCanvas;
struct SkImageInfo;
class SkPixmap;
class SkTraceMemoryDump;
namespace skgpu {
class RefCntedCallback;
class TokenTracker;
}
namespace sktext::gpu {
class StrikeCache;
class TextBlobRedrawCoordinator;
}
namespace skgpu::graphite {
class AtlasProvider;
class BackendTexture;
class Caps;
class Context;
class Device;
class DrawBufferManager;
class GlobalCache;
class ImageProvider;
class ProxyCache;
class ProxyReadCountMap;
class RecorderPriv;
class ResourceProvider;
class RuntimeEffectDictionary;
class SharedContext;
class Task;
class TaskList;
class TextureDataBlock;
class TextureInfo;
class UniformDataBlock;
class UploadBufferManager;
class UploadList;
template<typename T> class PipelineDataCache;
using TextureDataCache = PipelineDataCache<TextureDataBlock>;
struct SK_API RecorderOptions final {
RecorderOptions();
RecorderOptions(const RecorderOptions&);
~RecorderOptions();
sk_sp<ImageProvider> fImageProvider;
static constexpr size_t kDefaultRecorderBudget = 256 * (1 << 20);
// What is the budget for GPU resources allocated and held by this Recorder.
size_t fGpuBudgetInBytes = kDefaultRecorderBudget;
};
class SK_API Recorder final {
public:
Recorder(const Recorder&) = delete;
Recorder(Recorder&&) = delete;
Recorder& operator=(const Recorder&) = delete;
Recorder& operator=(Recorder&&) = delete;
~Recorder();
BackendApi backend() const;
std::unique_ptr<Recording> snap();
ImageProvider* clientImageProvider() { return fClientImageProvider.get(); }
const ImageProvider* clientImageProvider() const { return fClientImageProvider.get(); }
/**
* Gets the maximum supported texture size.
*/
int maxTextureSize() const;
/**
* 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&);
#ifdef SK_BUILD_FOR_ANDROID
BackendTexture createBackendTexture(AHardwareBuffer*,
bool isRenderable,
bool isProtectedContent,
SkISize dimensions,
bool fromAndroidWindow = false) const;
#endif
/**
* 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. When the BackendTexture is safe to be destroyed by the
* client, Skia will call the passed in GpuFinishedProc. The BackendTexture should not be
* destroyed before that.
* 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,
GpuFinishedProc = nullptr,
GpuFinishedContext = nullptr);
/**
* If possible, updates a compressed backend texture filled with the provided raw 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. When the BackendTexture is safe to be destroyed by the client, Skia will call the
* passed in GpuFinishedProc. The BackendTexture should not be destroyed before that.
* If the backend texture is mip mapped, the data for all the mipmap levels must be provided.
* Additionally, all the miplevels must be sized correctly (please see
* SkMipMap::ComputeLevelSize and ComputeLevelCount).
* For the Vulkan backend after a successful update the layout of the created VkImage will be:
* VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
*/
bool updateCompressedBackendTexture(const BackendTexture&,
const void* data,
size_t dataSize,
GpuFinishedProc = nullptr,
GpuFinishedContext = nullptr);
/**
* 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(const BackendTexture&);
// Adds a proc that will be moved to the Recording upon snap, subsequently attached to the
// CommandBuffer when the Recording is added, and called when that CommandBuffer is submitted
// and finishes. If the Recorder or Recording is deleted before the proc is added to the
// CommandBuffer, it will be called with result Failure.
void addFinishInfo(const InsertFinishInfo&);
// 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&);
/**
* Frees GPU resources created and held by the Recorder. Can be called to reduce GPU memory
* pressure. Any resources that are still in use (e.g. being used by work submitted to the GPU)
* will not be deleted by this call. If the caller wants to make sure all resources are freed,
* then they should first make sure to submit and wait on any outstanding work.
*/
void freeGpuResources();
/**
* Purge GPU resources on the Recorder that haven't been used in the past 'msNotUsed'
* milliseconds or are otherwise marked for deletion, regardless of whether the context is under
* budget.
*/
void performDeferredCleanup(std::chrono::milliseconds msNotUsed);
/**
* Returns the number of bytes of the Recorder's gpu memory cache budget that are currently in
* use.
*/
size_t currentBudgetedBytes() const;
/**
* Returns the number of bytes of the Recorder's resource cache that are currently purgeable.
*/
size_t currentPurgeableBytes() const;
/**
* Returns the size of Recorder's gpu memory cache budget in bytes.
*/
size_t maxBudgetedBytes() const;
/**
* Sets the size of Recorders's gpu memory cache budget in bytes. If the new budget is lower
* than the current budget, the cache will try to free resources to get under the new budget.
*/
void setMaxBudgetedBytes(size_t bytes);
/**
* Enumerates all cached GPU resources owned by the Recorder and dumps their memory to
* traceMemoryDump.
*/
void dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const;
// Provides access to functions that aren't part of the public API.
RecorderPriv priv();
const RecorderPriv priv() const; // NOLINT(readability-const-return-type)
private:
friend class Context; // For ctor
friend class Device; // For registering and deregistering Devices;
friend class RecorderPriv; // for ctor and hidden methods
// If Context is non-null, the Recorder will use the Context's resource provider
// instead of creating its own.
Recorder(sk_sp<SharedContext>, const RecorderOptions&, const Context*);
SingleOwner* singleOwner() const { return &fSingleOwner; }
// 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 take a ref on the Device so that ~Device() does not have to deregister the recorder
// (which can happen on any thread if the Device outlives the Surface via an Image view).
// Recorder::flushTrackedDevices() cleans up uniquely held and immutable Devices on the recorder
// thread so this extra ref is not significantly increasing the Device lifetime.
//
// 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(sk_sp<Device>);
void deregisterDevice(const Device*);
sk_sp<SharedContext> fSharedContext;
ResourceProvider* fResourceProvider; // May point to the Context's resource provider
std::unique_ptr<ResourceProvider> fOwnedResourceProvider; // May be null
std::unique_ptr<RuntimeEffectDictionary> fRuntimeEffectDict;
// NOTE: These are stored by pointer to allow them to be forward declared.
std::unique_ptr<TaskList> fRootTaskList;
// Aggregated one-time uploads that preceed all tasks in the root task list.
std::unique_ptr<UploadList> fRootUploads;
std::unique_ptr<TextureDataCache> fTextureDataCache;
std::unique_ptr<DrawBufferManager> fDrawBufferManager;
std::unique_ptr<UploadBufferManager> fUploadBufferManager;
std::unique_ptr<ProxyReadCountMap> fProxyReadCounts;
// Iterating over tracked devices in flushTrackedDevices() needs to be re-entrant and support
// additions to fTrackedDevices if registerDevice() is triggered by a temporary device during
// flushing. Removals are handled by setting elements to null; final clean up is handled at the
// end of the initial call to flushTrackedDevices().
skia_private::TArray<sk_sp<Device>> fTrackedDevices;
int fFlushingDevicesIndex = -1;
uint32_t fUniqueID; // Needed for MessageBox handling for text
uint32_t fNextRecordingID = 1;
std::unique_ptr<AtlasProvider> fAtlasProvider;
std::unique_ptr<TokenTracker> fTokenTracker;
std::unique_ptr<sktext::gpu::StrikeCache> fStrikeCache;
std::unique_ptr<sktext::gpu::TextBlobRedrawCoordinator> fTextBlobCache;
sk_sp<ImageProvider> 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<Device> fTargetProxyDevice;
std::unique_ptr<SkCanvas> fTargetProxyCanvas;
std::unique_ptr<Recording::LazyProxyData> fTargetProxyData;
skia_private::TArray<sk_sp<RefCntedCallback>> fFinishedProcs;
#if defined(GPU_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
|