chromium/third_party/skia/src/gpu/ganesh/GrBlurUtils.cpp

/*
 * Copyright 2015 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "src/gpu/ganesh/GrBlurUtils.h"

#include "include/core/SkAlphaType.h"
#include "include/core/SkBitmap.h"
#include "include/core/SkBlendMode.h"
#include "include/core/SkBlurTypes.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkColorSpace.h"
#include "include/core/SkData.h"
#include "include/core/SkImageInfo.h"
#include "include/core/SkM44.h"
#include "include/core/SkMatrix.h"
#include "include/core/SkPaint.h"
#include "include/core/SkPath.h"
#include "include/core/SkPoint.h"
#include "include/core/SkRRect.h"
#include "include/core/SkRect.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkRegion.h"
#include "include/core/SkSamplingOptions.h"
#include "include/core/SkScalar.h"
#include "include/core/SkSize.h"
#include "include/core/SkSpan.h"
#include "include/core/SkString.h"
#include "include/core/SkStrokeRec.h"
#include "include/core/SkSurface.h"
#include "include/core/SkSurfaceProps.h"
#include "include/core/SkTileMode.h"
#include "include/effects/SkRuntimeEffect.h"
#include "include/gpu/GpuTypes.h"
#include "include/gpu/ganesh/GrDirectContext.h"
#include "include/gpu/ganesh/GrRecordingContext.h"
#include "include/gpu/ganesh/GrTypes.h"
#include "include/private/SkColorData.h"
#include "include/private/base/SkAssert.h"
#include "include/private/base/SkFixed.h"
#include "include/private/base/SkFloatingPoint.h"
#include "include/private/base/SkMath.h"
#include "include/private/base/SkTemplates.h"
#include "include/private/gpu/ganesh/GrTypesPriv.h"
#include "src/base/SkFloatBits.h"
#include "src/base/SkTLazy.h"
#include "src/core/SkBlurMaskFilterImpl.h"
#include "src/core/SkDraw.h"
#include "src/core/SkMask.h"
#include "src/core/SkMaskFilterBase.h"
#include "src/core/SkRRectPriv.h"
#include "src/core/SkRuntimeEffectPriv.h"
#include "src/core/SkTraceEvent.h"
#include "src/gpu/BlurUtils.h"
#include "src/gpu/ResourceKey.h"
#include "src/gpu/SkBackingFit.h"
#include "src/gpu/Swizzle.h"
#include "src/gpu/ganesh/GrCaps.h"
#include "src/gpu/ganesh/GrClip.h"
#include "src/gpu/ganesh/GrColorInfo.h"
#include "src/gpu/ganesh/GrColorSpaceXform.h"
#include "src/gpu/ganesh/GrDirectContextPriv.h"
#include "src/gpu/ganesh/GrFixedClip.h"
#include "src/gpu/ganesh/GrFragmentProcessor.h"
#include "src/gpu/ganesh/GrFragmentProcessors.h"
#include "src/gpu/ganesh/GrPaint.h"
#include "src/gpu/ganesh/GrRecordingContextPriv.h"
#include "src/gpu/ganesh/GrSamplerState.h"
#include "src/gpu/ganesh/GrShaderCaps.h"
#include "src/gpu/ganesh/GrStyle.h"
#include "src/gpu/ganesh/GrSurfaceProxy.h"
#include "src/gpu/ganesh/GrSurfaceProxyView.h"
#include "src/gpu/ganesh/GrTextureProxy.h"
#include "src/gpu/ganesh/GrThreadSafeCache.h"
#include "src/gpu/ganesh/GrUtil.h"
#include "src/gpu/ganesh/SkGr.h"
#include "src/gpu/ganesh/SurfaceContext.h"
#include "src/gpu/ganesh/SurfaceDrawContext.h"
#include "src/gpu/ganesh/SurfaceFillContext.h"
#include "src/gpu/ganesh/effects/GrBlendFragmentProcessor.h"
#include "src/gpu/ganesh/effects/GrMatrixEffect.h"
#include "src/gpu/ganesh/effects/GrSkSLFP.h"
#include "src/gpu/ganesh/effects/GrTextureEffect.h"
#include "src/gpu/ganesh/geometry/GrStyledShape.h"

#include <algorithm>
#include <array>
#include <cstdint>
#include <initializer_list>
#include <memory>
#include <tuple>
#include <utility>

namespace GrBlurUtils {

static bool clip_bounds_quick_reject(const SkIRect& clipBounds, const SkIRect& rect) {}

static constexpr auto kMaskOrigin =;

// Draw a mask using the supplied paint. Since the coverage/geometry
// is already burnt into the mask this boils down to a rect draw.
// Return true if the mask was successfully drawn.
static bool draw_mask(skgpu::ganesh::SurfaceDrawContext* sdc,
                      const GrClip* clip,
                      const SkMatrix& viewMatrix,
                      const SkIRect& maskBounds,
                      GrPaint&& paint,
                      GrSurfaceProxyView mask) {}

static void mask_release_proc(void* addr, void* /*context*/) {}

// This stores the mapping from an unclipped, integerized, device-space, shape bounds to
// the filtered mask's draw rect.
struct DrawRectData {};

static sk_sp<SkData> create_data(const SkIRect& drawRect, const SkIRect& origDevBounds) {}

static SkIRect extract_draw_rect_from_data(SkData* data, const SkIRect& origDevBounds) {}

static GrSurfaceProxyView sw_create_filtered_mask(GrRecordingContext* rContext,
                                                  const SkMatrix& viewMatrix,
                                                  const GrStyledShape& shape,
                                                  const SkMaskFilter* filter,
                                                  const SkIRect& unclippedDevShapeBounds,
                                                  const SkIRect& clipBounds,
                                                  SkIRect* drawRect,
                                                  skgpu::UniqueKey* key) {}

// Create a mask of 'shape' and return the resulting surfaceDrawContext
static std::unique_ptr<skgpu::ganesh::SurfaceDrawContext> create_mask_GPU(
        GrRecordingContext* rContext,
        const SkIRect& maskRect,
        const SkMatrix& origViewMatrix,
        const GrStyledShape& shape,
        int sampleCnt) {}

static bool get_unclipped_shape_dev_bounds(const GrStyledShape& shape, const SkMatrix& matrix,
                                           SkIRect* devBounds) {}

// Gets the shape bounds, the clip bounds, and the intersection (if any). Returns false if there
// is no intersection.
static bool get_shape_and_clip_bounds(skgpu::ganesh::SurfaceDrawContext* sdc,
                                      const GrClip* clip,
                                      const GrStyledShape& shape,
                                      const SkMatrix& matrix,
                                      SkIRect* unclippedDevShapeBounds,
                                      SkIRect* devClipBounds) {}

/**
 *  If we cannot create a FragmentProcess for a mask filter, we might have special logic for
 *  it here. That code path requires constructing a src mask as input. Since that is a potentially
 *  expensive operation, this function tests if filter_mask would succeed if the mask
 *  were to be created.
 *
 *  'maskRect' returns the device space portion of the mask that the filter needs. The mask
 *  passed into 'filter_mask' should have the same extent as 'maskRect' but be
 *  translated to the upper-left corner of the mask (i.e., (maskRect.fLeft, maskRect.fTop)
 *  appears at (0, 0) in the mask).
 *
 * Logically, how this works is:
 *    can_filter_mask is called
 *    if (it returns true)
 *        the returned mask rect is used for quick rejecting
 *            the mask rect is used to generate the mask
 *            filter_mask is called to filter the mask
 *
 * TODO: this should work as:
 *    if (can_filter_mask(devShape, ...)) // rect, rrect, drrect, path
 *        filter_mask(devShape, ...)
 * this would hide the RRect special case and the mask generation
 */
static bool can_filter_mask(const SkMaskFilterBase* maskFilter,
                            const GrStyledShape& shape,
                            const SkIRect& devSpaceShapeBounds,
                            const SkIRect& clipBounds,
                            const SkMatrix& ctm,
                            SkIRect* maskRect) {}

///////////////////////////////////////////////////////////////////////////////
//  Circle Blur
///////////////////////////////////////////////////////////////////////////////

static std::unique_ptr<GrFragmentProcessor> create_profile_effect(GrRecordingContext* rContext,
                                                                  const SkRect& circle,
                                                                  float sigma,
                                                                  float* solidRadius,
                                                                  float* textureRadius) {}

static std::unique_ptr<GrFragmentProcessor> make_circle_blur(GrRecordingContext* context,
                                                             const SkRect& circle,
                                                             float sigma) {}

///////////////////////////////////////////////////////////////////////////////
//  Rect Blur
///////////////////////////////////////////////////////////////////////////////

static std::unique_ptr<GrFragmentProcessor> make_rect_integral_fp(GrRecordingContext* rContext,
                                                                  float sixSigma) {}

static std::unique_ptr<GrFragmentProcessor> make_rect_blur(GrRecordingContext* context,
                                                           const GrShaderCaps& caps,
                                                           const SkRect& srcRect,
                                                           const SkMatrix& viewMatrix,
                                                           float transformedSigma) {}

///////////////////////////////////////////////////////////////////////////////
//  RRect Blur
///////////////////////////////////////////////////////////////////////////////

static constexpr auto kBlurredRRectMaskOrigin =;

static void make_blurred_rrect_key(skgpu::UniqueKey* key,
                                   const SkRRect& rrectToDraw,
                                   float xformedSigma) {}

static bool fillin_view_on_gpu(GrDirectContext* dContext,
                               const GrSurfaceProxyView& lazyView,
                               GrThreadSafeCache::Trampoline* trampoline,
                               const SkRRect& rrectToDraw,
                               const SkISize& dimensions,
                               float xformedSigma) {}

// Create a cpu-side blurred-rrect mask that is close to the version the gpu would've produced.
// The match needs to be close bc the cpu- and gpu-generated version must be interchangeable.
static GrSurfaceProxyView create_mask_on_cpu(GrRecordingContext* rContext,
                                             const SkRRect& rrectToDraw,
                                             const SkISize& dimensions,
                                             float xformedSigma) {}

static std::unique_ptr<GrFragmentProcessor> find_or_create_rrect_blur_mask_fp(
        GrRecordingContext* rContext,
        const SkRRect& rrectToDraw,
        const SkISize& dimensions,
        float xformedSigma) {}

static std::unique_ptr<GrFragmentProcessor> make_rrect_blur(GrRecordingContext* context,
                                                            float sigma,
                                                            float xformedSigma,
                                                            const SkRRect& srcRRect,
                                                            const SkRRect& devRRect) {}

/**
 *  Try to directly render the mask filter into the target. Returns true if drawing was
 *  successful. If false is returned then paint is unmodified.
 */
static bool direct_filter_mask(GrRecordingContext* context,
                               const SkMaskFilterBase* maskFilter,
                               skgpu::ganesh::SurfaceDrawContext* sdc,
                               GrPaint&& paint,
                               const GrClip* clip,
                               const SkMatrix& viewMatrix,
                               const GrStyledShape& shape) {}

// The key and clip-bounds are computed together because the caching decision can impact the
// clip-bound - since we only cache un-clipped masks the clip can be removed entirely.
// A 'false' return value indicates that the shape is known to be clipped away.
static bool compute_key_and_clip_bounds(skgpu::UniqueKey* maskKey,
                                        SkIRect* boundsForClip,
                                        const GrCaps* caps,
                                        const SkMatrix& viewMatrix,
                                        bool inverseFilled,
                                        const SkMaskFilterBase* maskFilter,
                                        const GrStyledShape& shape,
                                        const SkIRect& unclippedDevShapeBounds,
                                        const SkIRect& devClipBounds) {}

/**
 * This function is used to implement filters that require an explicit src mask. It should only
 * be called if can_filter_mask returned true and the maskRect param should be the output from
 * that call.
 * Implementations are free to get the GrContext from the src texture in order to create
 * additional textures and perform multiple passes.
 */
static GrSurfaceProxyView filter_mask(GrRecordingContext* context,
                                      const SkMaskFilterBase* maskFilter,
                                      GrSurfaceProxyView srcView,
                                      GrColorType srcColorType,
                                      SkAlphaType srcAlphaType,
                                      const SkMatrix& ctm,
                                      const SkIRect& maskRect) {}

static GrSurfaceProxyView hw_create_filtered_mask(GrDirectContext* dContext,
                                                  skgpu::ganesh::SurfaceDrawContext* sdc,
                                                  const SkMatrix& viewMatrix,
                                                  const GrStyledShape& shape,
                                                  const SkMaskFilterBase* filter,
                                                  const SkIRect& unclippedDevShapeBounds,
                                                  const SkIRect& clipBounds,
                                                  SkIRect* maskRect,
                                                  skgpu::UniqueKey* key) {}

static void draw_shape_with_mask_filter(GrRecordingContext* rContext,
                                        skgpu::ganesh::SurfaceDrawContext* sdc,
                                        const GrClip* clip,
                                        GrPaint&& paint,
                                        const SkMatrix& viewMatrix,
                                        const SkMaskFilterBase* maskFilter,
                                        const GrStyledShape& origShape) {}

bool ComputeBlurredRRectParams(const SkRRect& srcRRect,
                               const SkRRect& devRRect,
                               SkScalar sigma,
                               SkScalar xformedSigma,
                               SkRRect* rrectToDraw,
                               SkISize* widthHeight,
                               SkScalar rectXs[kBlurRRectMaxDivisions],
                               SkScalar rectYs[kBlurRRectMaxDivisions],
                               SkScalar texXs[kBlurRRectMaxDivisions],
                               SkScalar texYs[kBlurRRectMaxDivisions]) {}

void DrawShapeWithMaskFilter(GrRecordingContext* rContext,
                             skgpu::ganesh::SurfaceDrawContext* sdc,
                             const GrClip* clip,
                             const GrStyledShape& shape,
                             GrPaint&& paint,
                             const SkMatrix& viewMatrix,
                             const SkMaskFilter* mf) {}

void DrawShapeWithMaskFilter(GrRecordingContext* rContext,
                             skgpu::ganesh::SurfaceDrawContext* sdc,
                             const GrClip* clip,
                             const SkPaint& paint,
                             const SkMatrix& ctm,
                             const GrStyledShape& shape) {}


// =================== Gaussian Blur =========================================

namespace {

enum class Direction {};

std::unique_ptr<GrFragmentProcessor> make_texture_effect(const GrCaps* caps,
                                                         GrSurfaceProxyView srcView,
                                                         SkAlphaType srcAlphaType,
                                                         const GrSamplerState& sampler,
                                                         const SkIRect& srcSubset,
                                                         const SkIRect& srcRelativeDstRect,
                                                         const SkISize& radii) {}

} // end namespace

/**
 * Draws 'dstRect' into 'surfaceFillContext' evaluating a 1D Gaussian over 'srcView'. The src rect
 * is 'dstRect' offset by 'dstToSrcOffset'. 'mode' and 'bounds' are applied to the src coords.
 */
static void convolve_gaussian_1d(skgpu::ganesh::SurfaceFillContext* sfc,
                                 GrSurfaceProxyView srcView,
                                 const SkIRect& srcSubset,
                                 SkIVector dstToSrcOffset,
                                 const SkIRect& dstRect,
                                 SkAlphaType srcAlphaType,
                                 Direction direction,
                                 int radius,
                                 float sigma,
                                 SkTileMode mode) {}

static std::unique_ptr<skgpu::ganesh::SurfaceDrawContext> convolve_gaussian_2d(
        GrRecordingContext* rContext,
        GrSurfaceProxyView srcView,
        GrColorType srcColorType,
        const SkIRect& srcBounds,
        const SkIRect& dstBounds,
        int radiusX,
        int radiusY,
        SkScalar sigmaX,
        SkScalar sigmaY,
        SkTileMode mode,
        sk_sp<SkColorSpace> finalCS,
        SkBackingFit dstFit) {}

static std::unique_ptr<skgpu::ganesh::SurfaceDrawContext> convolve_gaussian(
        GrRecordingContext* rContext,
        GrSurfaceProxyView srcView,
        GrColorType srcColorType,
        SkAlphaType srcAlphaType,
        SkIRect srcBounds,
        SkIRect dstBounds,
        Direction direction,
        int radius,
        float sigma,
        SkTileMode mode,
        sk_sp<SkColorSpace> finalCS,
        SkBackingFit fit) {}

// Expand the contents of 'src' to fit in 'dstSize'. At this point, we are expanding an intermediate
// image, so there's no need to account for a proxy offset from the original input.
static std::unique_ptr<skgpu::ganesh::SurfaceDrawContext> reexpand(
        GrRecordingContext* rContext,
        std::unique_ptr<skgpu::ganesh::SurfaceContext> src,
        const SkRect& srcBounds,
        SkISize dstSize,
        sk_sp<SkColorSpace> colorSpace,
        SkBackingFit fit) {}

static std::unique_ptr<skgpu::ganesh::SurfaceDrawContext> two_pass_gaussian(
        GrRecordingContext* rContext,
        GrSurfaceProxyView srcView,
        GrColorType srcColorType,
        SkAlphaType srcAlphaType,
        sk_sp<SkColorSpace> colorSpace,
        SkIRect srcBounds,
        SkIRect dstBounds,
        float sigmaX,
        float sigmaY,
        int radiusX,
        int radiusY,
        SkTileMode mode,
        SkBackingFit fit) {}

std::unique_ptr<skgpu::ganesh::SurfaceDrawContext> GaussianBlur(GrRecordingContext* rContext,
                                                                GrSurfaceProxyView srcView,
                                                                GrColorType srcColorType,
                                                                SkAlphaType srcAlphaType,
                                                                sk_sp<SkColorSpace> colorSpace,
                                                                SkIRect dstBounds,
                                                                SkIRect srcBounds,
                                                                float sigmaX,
                                                                float sigmaY,
                                                                SkTileMode mode,
                                                                SkBackingFit fit) {}

}  // namespace GrBlurUtils