/* * 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_GraphiteTypes_DEFINED #define skgpu_graphite_GraphiteTypes_DEFINED #include "include/core/SkPoint.h" #include "include/core/SkRect.h" #include "include/core/SkTypes.h" #include "include/gpu/GpuTypes.h" #include #include class SkSurface; namespace skgpu { class MutableTextureState; } namespace skgpu::graphite { class BackendSemaphore; class Recording; class Task; using GpuFinishedContext = void*; using GpuFinishedProc = void (*)(GpuFinishedContext finishedContext, CallbackResult); using GpuFinishedWithStatsProc = void (*)(GpuFinishedContext finishedContext, CallbackResult, const GpuStats&); // NOTE: This can be converted to just an `enum class InsertStatus {}` once clients are migrated // off of assuming `Context::insertRecording()` returns a boolean. class InsertStatus { public: // Do not refer to V directly; use these constants as if InsertStatus were a class enum, e.g. // InsertStatus::kSuccess. enum V { // Everything successfully added to underlying CommandBuffer kSuccess, // Recording or InsertRecordingInfo invalid, no CB changes kInvalidRecording, // Promise image instantiation failed, no CB changes kPromiseImageInstantiationFailed, // Internal failure, CB partially modified, state unrecoverable or unknown (e.g. dependent // texture uploads for future Recordings may or may not get executed) kAddCommandsFailed, // Internal failure, shader pipeline compilation failed (driver issue, or disk corruption), // state unrecoverable. kAsyncShaderCompilesFailed, // The inserted Recording is out of order from what the Context expects (when // `[Context|Recorder]Options::fRequireOrderedRecordings` is true), which can either // represent a client synchronization error or an internal failure when a prior dependent // Recording failed for some reason, no CB changes but state likely unrecoverable. kOutOfOrderRecording, }; InsertStatus() = default; /*implicit*/ InsertStatus(V v) : fValue(v) {} InsertStatus(V v, std::string message) : fValue(v), fMessage(std::move(message)) {} InsertStatus(V v, int numPendingCommands, int numPendingPasses) : fValue(v) , fNumPendingCommands(numPendingCommands) , fNumPendingPasses(numPendingPasses) {} operator InsertStatus::V() const { return fValue; } const std::string& message() const { return fMessage; } /** * Returns the number of pending commands in the CommandBuffer waiting to be submitted * to the GPU (including low-level GPU draw commands across all draw passes, compute * dispatches, buffer/texture copies, buffer clears, and CPU synchronizations) after * inserting the Recording. Note that this counts low-level GPU draw commands rather than * high-level Skia draw commands (e.g. SkCanvas::draw* calls), and counts all pending * commands currently in the CommandBuffer, not just the commands in the newly inserted * Recording. * * This count is approximate only and does not include commands generated directly by * the backends (e.g. backend-specific layout transitions, barriers, blits, or * pipeline binds). */ int numPendingCommands() const { return fNumPendingCommands; } /** * Returns the number of pending passes (render passes and compute passes) in the * CommandBuffer waiting to be submitted to the GPU after inserting the Recording. Note * that this counts all pending passes currently in the CommandBuffer, not just those * in the newly inserted Recording. * * This count is approximate only and does not include passes generated directly by * the backends. */ int numPendingPasses() const { return fNumPendingPasses; } // Assist migration from old bool return value of insertRecording; kSuccess is true, // all other error statuses are false. // NOTE: This is intentionally not explicit so that InsertStatus can be assigned correctly to // a bool or returned as a bool, since these are not boolean contexts that automatically apply // explicit bool operators (e.g. inside an if condition). operator bool() const { return fValue == kSuccess; } private: V fValue = kSuccess; std::string fMessage; int fNumPendingCommands = 0; int fNumPendingPasses = 0; }; /** * The fFinishedProc is called when the Recording has been submitted and finished on the GPU, or * when there is a failure that caused it not to be submitted. The callback will always be called * and the caller can use the callback to know it is safe to free any resources associated with * the Recording that they may be holding onto. If the Recording is successfully submitted to the * GPU the callback will be called with CallbackResult::kSuccess once the GPU has finished. All * other cases where some failure occurred it will be called with CallbackResult::kFailed. * * Alternatively, the client can provide fFinishedProcWithStats. This provides additional * information about execution of the recording on the GPU. Only the stats requested using * fStatsFlags will be valid and only if CallbackResult is kSuccess. If both fFinishedProc * and fFinishedProcWithStats are provided the latter is preferred and the former won't be * called. * * The fTargetSurface, if provided, is used as a target for any draws recorded onto a deferred * canvas returned from Recorder::makeDeferredCanvas. This target surface must be provided iff * the Recording contains any such draws. It must be Graphite-backed and its backing texture's * TextureInfo must match the info provided to the Recorder when making the deferred canvas. * * fTargetTranslation is an additional translation applied to draws targeting fTargetSurface. * * fTargetClip is an additional clip applied to draws targeting fTargetSurface. It is defined in the * local replay space, that is, with fTargetTranslation applied. An empty clip will not be applied. * * The client may pass in two arrays of initialized BackendSemaphores to be included in the * command stream. At some time before issuing commands in the Recording, the fWaitSemaphores will * be waited on by the gpu. We only guarantee these wait semaphores block transfer and fragment * shader work. Similarly, at some time after issuing the Recording's commands, the * fSignalSemaphores will be signaled by the gpu. Depending on the platform, the timing of the wait * and signal operations will either be immediately before or after the given Recording's command * stream, respectively, or before and after the entire CommandBuffer's command stream. The * semaphores are not sent to the GPU until the next Context::submit call is made. * * The client will own and be responsible for deleting the underlying semaphore objects after the * submission completes, however the BackendSemaphore objects themselves can be deleted as soon * as this function returns. */ struct InsertRecordingInfo { Recording* fRecording = nullptr; SkSurface* fTargetSurface = nullptr; SkIVector fTargetTranslation = {0, 0}; SkIRect fTargetClip = {0, 0, 0, 0}; MutableTextureState* fTargetTextureState = nullptr; size_t fNumWaitSemaphores = 0; BackendSemaphore* fWaitSemaphores = nullptr; size_t fNumSignalSemaphores = 0; BackendSemaphore* fSignalSemaphores = nullptr; GpuStatsFlags fGpuStatsFlags = GpuStatsFlags::kNone; GpuFinishedContext fFinishedContext = nullptr; GpuFinishedProc fFinishedProc = nullptr; GpuFinishedWithStatsProc fFinishedWithStatsProc = nullptr; // For unit testing purposes, this can be used to induce a known failure status from // Context::insertRecording(). When this set to anything other than kSuccess, insertRecording() // will operate as normal until the first condition that would normally return the simulated // status is encountered. At that point, operations are treated as if that condition had failed. // This leaves the Context in a state consistent with encountering the InsertStatus in a normal // application. // // NOTE: If the simulated failure status is one of the later error codes but the inserted // Recording would fail with an earlier error code normally, that error is still returned. InsertStatus fSimulatedStatus = InsertStatus::kSuccess; }; /** * The fFinishedProc is called when the Recording has been submitted and finished on the GPU, or * when there is a failure that caused it not to be submitted. The callback will always be called * and the caller can use the callback to know it is safe to free any resources associated with * the Recording that they may be holding onto. If the Recording is successfully submitted to the * GPU the callback will be called with CallbackResult::kSuccess once the GPU has finished. All * other cases where some failure occurred it will be called with CallbackResult::kFailed. */ struct InsertFinishInfo { InsertFinishInfo() = default; InsertFinishInfo(GpuFinishedContext context, GpuFinishedProc proc) : fFinishedContext{context}, fFinishedProc{proc} {} InsertFinishInfo(GpuFinishedContext context, GpuFinishedWithStatsProc proc) : fFinishedContext{context}, fFinishedWithStatsProc{proc} {} GpuFinishedContext fFinishedContext = nullptr; GpuFinishedProc fFinishedProc = nullptr; GpuFinishedWithStatsProc fFinishedWithStatsProc = nullptr; GpuStatsFlags fGpuStatsFlags = GpuStatsFlags::kNone; }; /** * Actually submit work to the GPU and track its completion */ enum class SyncToCpu : bool { kYes = true, kNo = false }; enum class MarkFrameBoundary : bool { kYes = true, kNo = false }; struct SubmitInfo { SyncToCpu fSync = SyncToCpu::kNo; MarkFrameBoundary fMarkBoundary = MarkFrameBoundary::kNo; uint64_t fFrameID = 0; // Optional finish proc that is invoked when all GPU work submitted by this call has // completed. If there is no pending work to submit, the proc is attached to the most // recently outstanding GPU submission, or invoked immediately if the GPU is idle. GpuFinishedProc fFinishedProc = nullptr; GpuFinishedContext fFinishedContext = nullptr; constexpr SubmitInfo() = default; constexpr SubmitInfo(SyncToCpu sync) : fSync(sync) , fMarkBoundary(MarkFrameBoundary::kNo) , fFrameID(0) {} constexpr SubmitInfo(SyncToCpu sync, uint64_t frameID) : fSync(sync) , fMarkBoundary(MarkFrameBoundary::kYes) , fFrameID(frameID) {} }; /* * For Promise Images - should the Promise Image be fulfilled every time a Recording that references * it is inserted into the Context. */ enum class Volatile : bool { kNo = false, // only fulfilled once kYes = true // fulfilled on every insertion call }; enum class DepthStencilFlags : int { kNone = 0b000, kDepth = 0b001, kStencil = 0b010, kDepthStencil = kDepth | kStencil, }; enum class SampleCount : uint8_t { k1 = 1, k2 = 2, k4 = 4, k8 = 8, k16 = 16 }; /** * Convert an integer value to a strictly typed SampleCount value, rounding down to the lowest * valid sample count if needed if `sampleCount` is not already equivalent. */ constexpr SampleCount ToSampleCount(uint32_t sampleCount) { return sampleCount >= 16 ? SampleCount::k16 : sampleCount >= 8 ? SampleCount::k8 : sampleCount >= 4 ? SampleCount::k4 : sampleCount >= 2 ? SampleCount::k2 : SampleCount::k1; } /* * This enum allows mapping from a set of observed RenderSteps (e.g., from a GraphicsPipeline * printout) to the correct 'drawTypes' parameter needed by the Precompilation API. */ enum DrawTypeFlags : uint16_t { kNone = 0, // kBitmapText_Mask should be used for the BitmapTextRenderStep[mask] RenderStep kBitmapText_Mask = 1 << 0, // kBitmapText_LCD should be used for the BitmapTextRenderStep[LCD] RenderStep kBitmapText_LCD = 1 << 1, // kBitmapText_Color should be used for the BitmapTextRenderStep[color] RenderStep kBitmapText_Color = 1 << 2, // kSDFText should be used for the SDFTextRenderStep RenderStep kSDFText = 1 << 3, // kSDFText_LCD should be used for the SDFTextLCDRenderStep RenderStep kSDFText_LCD = 1 << 4, // kDrawVertices should be used to generate Pipelines that use the following RenderSteps: // VerticesRenderStep[*] for: // [Pos], [PosTexCoords], [PosColor], [PosColorTexCoords], kDrawVertices = 1 << 5, // kCircularArc renders filled circular arcs, with or without the center included, and // stroked circular arcs with butt or round caps that don't include the center point. // It corresponds to the CircularArcRenderStep. kCircularArc = 1 << 6, // kSimpleShape should be used to generate Pipelines that use the following RenderSteps: // AnalyticRRectRenderStep // PerEdgeAAQuadRenderStep // CoverBoundsRenderStep[NonAAFill] kAnalyticRRect = 1 << 7, kPerEdgeAAQuad = 1 << 8, kNonAAFillRect = 1 << 9, kSimpleShape = kAnalyticRRect | kPerEdgeAAQuad | kNonAAFillRect, // kNonSimpleShape should be used to generate Pipelines that use the following RenderSteps: // CoverageMaskRenderStep // CoverBoundsRenderStep[*] for [InverseCover], [RegularCover] // TessellateStrokeRenderStep // TessellateWedgesRenderStep[*] for [Convex], [EvenOdd], [Winding] // TessellateCurvesRenderStep[*] for [EvenOdd], [Winding] // MiddleOutFanRenderStep[*] for [EvenOdd], [Winding] kNonSimpleShape = 1 << 10, // This draw type covers all the methods Skia uses to draw drop shadows. It can be used to // generate Pipelines which, as part of their labels, have: // the AnalyticBlurRenderStep // VerticesRenderStep[PosColor] with a GaussianColorFilter // For this draw type the PaintOptions parameter to Precompile() will be ignored. kDropShadows = 1 << 11, // kAnalyticClip should be combined with the primary drawType for Pipelines that contain // either of the following sub-strings: // AnalyticClip // AnalyticAndAtlasClip kAnalyticClip = 1 << 12, kDrawMesh = 1 << 13, kSparseStrips = 1 << 14, kLast = kSparseStrips, }; } // namespace skgpu::graphite #endif // skgpu_graphite_GraphiteTypes_DEFINED