1 /* 2 * Copyright 2020 Google LLC 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 SkMatrixProvider_DEFINED 9 #define SkMatrixProvider_DEFINED 10 11 #include "include/core/SkM44.h" 12 #include "include/core/SkMatrix.h" 13 14 /** 15 * All matrix providers report a flag: "localToDeviceHitsPixelCenters". This is confusing. 16 * It doesn't say anything about the actual matrix in the provider. Instead, it means: "is it safe 17 * to tweak sampling based on the contents of the matrix". In other words, does the device end of 18 * the local-to-device matrix actually map to pixels, AND are the local coordinates being fed to 19 * the shader produced by the inverse of that matrix? For a normal device, this is trivially true. 20 * The matrix may be updated via transforms, but when we draw (and the local coordinates come from 21 * rasterization of primitives against that device), we can know that the device coordinates will 22 * land on pixel centers. 23 * 24 * In a few places, the matrix provider is lying about how sampling "works". When we invoke a child 25 * from runtime effects, we give that child a matrix provider with an identity matrix. However -- 26 * the coordinates being passed to that child are not the result of device -> local transformed 27 * coordinates. Runtime effects can generate coordinates arbitrarily - even though the provider has 28 * an identity matrix, we can't assume it's safe to (for example) convert linear -> nearest. 29 * Clip shaders are similar - they overwrite the local-to-device matrix (to match what it was when 30 * the clip shader was inserted). The CTM continues to change before drawing, though. In that case, 31 * the two matrices are not inverses, so the local coordinates may not land on texel centers in 32 * the clip shader. 33 * 34 * In cases where we need to inhibit filtering optimizations, use SkOverrideDeviceMatrixProvider. 35 */ 36 class SkMatrixProvider { 37 public: SkMatrixProvider(const SkMatrix & localToDevice)38 SkMatrixProvider(const SkMatrix& localToDevice) : SkMatrixProvider(localToDevice, true) {} SkMatrixProvider(const SkM44 & localToDevice)39 SkMatrixProvider(const SkM44& localToDevice) : SkMatrixProvider(localToDevice, true) {} 40 41 // These should return the "same" matrix, as either a 3x3 or 4x4. Most sites in Skia still 42 // call localToDevice, and operate on SkMatrix. localToDevice()43 const SkMatrix& localToDevice() const { return fLocalToDevice33; } localToDevice44()44 const SkM44& localToDevice44() const { return fLocalToDevice; } 45 localToDeviceHitsPixelCenters()46 bool localToDeviceHitsPixelCenters() const { return fHitsPixelCenters; } 47 48 protected: SkMatrixProvider(const SkMatrix & localToDevice,bool hitsPixelCenters)49 SkMatrixProvider(const SkMatrix& localToDevice, bool hitsPixelCenters) 50 : fLocalToDevice(localToDevice) 51 , fLocalToDevice33(localToDevice) 52 , fHitsPixelCenters(hitsPixelCenters) {} 53 SkMatrixProvider(const SkM44 & localToDevice,bool hitsPixelCenters)54 SkMatrixProvider(const SkM44& localToDevice, bool hitsPixelCenters) 55 : fLocalToDevice(localToDevice) 56 , fLocalToDevice33(localToDevice.asM33()) 57 , fHitsPixelCenters(hitsPixelCenters) {} 58 59 private: 60 friend class SkBaseDevice; 61 62 SkM44 fLocalToDevice; 63 SkMatrix fLocalToDevice33; // Cached SkMatrix version of above, for legacy usage 64 const bool fHitsPixelCenters; 65 }; 66 67 // Logically, this is equivalent to just making a new SkMatrixProvider, but we keep it distinct. 68 // This is for cases where there is an existing matrix provider, but we're replacing the 69 // local-to-device. In that scenario, we can't guarantee that we hit pixel centers anymore. 70 class SkOverrideDeviceMatrixProvider : public SkMatrixProvider { 71 public: SkOverrideDeviceMatrixProvider(const SkMatrix & localToDevice)72 SkOverrideDeviceMatrixProvider(const SkMatrix& localToDevice) 73 : SkMatrixProvider(localToDevice, /*hitsPixelCenters=*/false) {} 74 }; 75 76 class SkPostTranslateMatrixProvider : public SkMatrixProvider { 77 public: SkPostTranslateMatrixProvider(const SkMatrixProvider & parent,SkScalar dx,SkScalar dy)78 SkPostTranslateMatrixProvider(const SkMatrixProvider& parent, SkScalar dx, SkScalar dy) 79 : SkMatrixProvider(SkM44::Translate(dx, dy) * parent.localToDevice44(), 80 parent.localToDeviceHitsPixelCenters()) {} 81 }; 82 83 class SkPreConcatMatrixProvider : public SkMatrixProvider { 84 public: SkPreConcatMatrixProvider(const SkMatrixProvider & parent,const SkMatrix & preMatrix)85 SkPreConcatMatrixProvider(const SkMatrixProvider& parent, const SkMatrix& preMatrix) 86 : SkMatrixProvider(parent.localToDevice44() * SkM44(preMatrix), 87 parent.localToDeviceHitsPixelCenters()) {} 88 }; 89 90 #endif 91