1 /* 2 * Copyright 2017 Google Inc. 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 GrTextureEffect_DEFINED 9 #define GrTextureEffect_DEFINED 10 11 #include "include/core/SkImageInfo.h" 12 #include "include/core/SkMatrix.h" 13 #include "src/gpu/GrFragmentProcessor.h" 14 #include "src/gpu/glsl/GrGLSLFragmentProcessor.h" 15 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h" 16 17 class GrTextureEffect : public GrFragmentProcessor { 18 public: 19 static constexpr float kDefaultBorder[4] = {0}; 20 21 /** Make from a filter. The sampler will be configured with clamp mode. */ 22 static std::unique_ptr<GrFragmentProcessor> Make( 23 GrSurfaceProxyView, 24 SkAlphaType, 25 const SkMatrix& = SkMatrix::I(), 26 GrSamplerState::Filter = GrSamplerState::Filter::kNearest, 27 GrSamplerState::MipmapMode mipmapMode = GrSamplerState::MipmapMode::kNone); 28 29 /** 30 * Make from a full GrSamplerState. Caps are required to determine support for kClampToBorder. 31 * This will be emulated in the shader if there is no hardware support. 32 */ 33 static std::unique_ptr<GrFragmentProcessor> Make(GrSurfaceProxyView, SkAlphaType, 34 const SkMatrix&, GrSamplerState, 35 const GrCaps& caps, 36 const float border[4] = kDefaultBorder); 37 38 /** 39 * Makes a texture effect that samples a subset of a texture. The wrap modes of the 40 * GrSampleState are applied to the subset in the shader rather than using HW samplers. 41 * The 'subset' parameter specifies the texels in the base level. The shader code will 42 * avoid allowing linear filtering to read outside the texel window. However, if MIP 43 * filtering is used and a shader invocation reads from a level other than the base 44 * then it may read texel values that were computed from in part from base level texels 45 * outside the window. More specifically, we treat the MIP map case exactly like the 46 * linear case in terms of how the final texture coords are computed. 47 */ 48 static std::unique_ptr<GrFragmentProcessor> MakeSubset(GrSurfaceProxyView, 49 SkAlphaType, 50 const SkMatrix&, 51 GrSamplerState, 52 const SkRect& subset, 53 const GrCaps& caps, 54 const float border[4] = kDefaultBorder); 55 56 /** 57 * The same as above but also takes a 'domain' that specifies any known limit on the post- 58 * matrix texture coords that will be used to sample the texture. Specifying this requires 59 * knowledge of how this effect will be nested into a paint, the local coords used with the 60 * draw, etc. It is only used to attempt to optimize away the shader subset calculations. 61 */ 62 static std::unique_ptr<GrFragmentProcessor> MakeSubset(GrSurfaceProxyView, 63 SkAlphaType, 64 const SkMatrix&, 65 GrSamplerState, 66 const SkRect& subset, 67 const SkRect& domain, 68 const GrCaps& caps, 69 const float border[4] = kDefaultBorder); 70 71 /** 72 * Like MakeSubset() but always uses kLinear filtering. MakeSubset() uses the subset rect 73 * dimensions to determine the period of the wrap mode (for repeat and mirror). Once it computes 74 * the wrapped texture coordinate inside subset rect it further clamps it to a 0.5 inset rect of 75 * subset. When subset is an integer rectangle this clamping avoids the hw linear filtering from 76 * reading texels just outside the subset rect. This factory allows a custom inset clamping 77 * distance rather than 0.5, allowing those neighboring texels to influence the linear filtering 78 * sample result. If there is a known restriction on the post-matrix texture coords it can be 79 * specified using domain. 80 */ 81 static std::unique_ptr<GrFragmentProcessor> MakeCustomLinearFilterInset( 82 GrSurfaceProxyView, 83 SkAlphaType, 84 const SkMatrix&, 85 GrSamplerState::WrapMode wx, 86 GrSamplerState::WrapMode wy, 87 const SkRect& subset, 88 const SkRect* domain, 89 SkVector inset, 90 const GrCaps& caps, 91 const float border[4] = kDefaultBorder); 92 93 std::unique_ptr<GrFragmentProcessor> clone() const override; usesExplicitReturn()94 bool usesExplicitReturn() const override { return true; } 95 name()96 const char* name() const override { return "TextureEffect"; } 97 samplerState()98 GrSamplerState samplerState() const { return fSamplerState; } 99 texture()100 GrTexture* texture() const { return fView.asTextureProxy()->peekTexture(); } 101 view()102 const GrSurfaceProxyView& view() const { return fView; } 103 104 class Impl : public GrGLSLFragmentProcessor { 105 public: 106 void emitCode(EmitArgs&) override; 107 void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override; 108 setSamplerHandle(GrGLSLShaderBuilder::SamplerHandle handle)109 void setSamplerHandle(GrGLSLShaderBuilder::SamplerHandle handle) { 110 fSamplerHandle = handle; 111 } 112 113 private: 114 UniformHandle fSubsetUni; 115 UniformHandle fClampUni; 116 UniformHandle fNormUni; 117 UniformHandle fBorderUni; 118 GrGLSLShaderBuilder::SamplerHandle fSamplerHandle; 119 }; 120 121 private: 122 struct Sampling; 123 124 /** 125 * Possible implementation of wrap mode in shader code. Some modes are specialized by 126 * filter. 127 */ 128 enum class ShaderMode : uint16_t { 129 kNone, // Using HW mode 130 kClamp, // Shader based clamp, no filter specialization 131 kRepeat_Nearest_None, // Simple repeat for nearest sampling, no mipmapping 132 kRepeat_Linear_None, // Filter the subset boundary for kRepeat mode, no mip mapping 133 kRepeat_Linear_Mipmap, // Logic for linear filtering and LOD selection with kRepeat mode. 134 kRepeat_Nearest_Mipmap, // Logic for nearest filtering and LOD selection with kRepeat mode. 135 kMirrorRepeat, // Mirror repeat (doesn't depend on filter)) 136 kClampToBorder_Nearest, // Logic for hard transition to border color when not filtering. 137 kClampToBorder_Filter, // Logic for fading to border color when filtering. 138 }; 139 static ShaderMode GetShaderMode(GrSamplerState::WrapMode, 140 GrSamplerState::Filter, 141 GrSamplerState::MipmapMode); 142 static bool ShaderModeIsClampToBorder(ShaderMode); 143 144 GrSurfaceProxyView fView; 145 GrSamplerState fSamplerState; 146 float fBorder[4]; 147 SkRect fSubset; 148 SkRect fClamp; 149 ShaderMode fShaderModes[2]; 150 // true if we are dealing with a fully lazy proxy which can't be normalized until runtime 151 bool fLazyProxyNormalization; 152 153 inline GrTextureEffect(GrSurfaceProxyView, SkAlphaType, const Sampling&, bool); 154 155 explicit GrTextureEffect(const GrTextureEffect& src); 156 157 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; 158 159 void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; 160 161 bool onIsEqual(const GrFragmentProcessor&) const override; 162 hasClampToBorderShaderMode()163 bool hasClampToBorderShaderMode() const { 164 return ShaderModeIsClampToBorder(fShaderModes[0]) || 165 ShaderModeIsClampToBorder(fShaderModes[1]); 166 } 167 168 GR_DECLARE_FRAGMENT_PROCESSOR_TEST 169 170 using INHERITED = GrFragmentProcessor; 171 }; 172 #endif 173