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) 39 : fLocalToDevice(localToDevice), fLocalToDevice33(localToDevice) {} 40 SkMatrixProvider(const SkM44 & localToDevice)41 SkMatrixProvider(const SkM44& localToDevice) 42 : fLocalToDevice(localToDevice), fLocalToDevice33(localToDevice.asM33()) {} 43 44 // These should return the "same" matrix, as either a 3x3 or 4x4. Most sites in Skia still 45 // call localToDevice, and operate on SkMatrix. localToDevice()46 const SkMatrix& localToDevice() const { return fLocalToDevice33; } localToDevice44()47 const SkM44& localToDevice44() const { return fLocalToDevice; } 48 49 private: 50 friend class SkBaseDevice; 51 52 SkM44 fLocalToDevice; 53 SkMatrix fLocalToDevice33; // Cached SkMatrix version of above, for legacy usage 54 }; 55 56 class SkPostTranslateMatrixProvider : public SkMatrixProvider { 57 public: SkPostTranslateMatrixProvider(const SkMatrixProvider & parent,SkScalar dx,SkScalar dy)58 SkPostTranslateMatrixProvider(const SkMatrixProvider& parent, SkScalar dx, SkScalar dy) 59 : SkMatrixProvider(SkM44::Translate(dx, dy) * parent.localToDevice44()) {} 60 }; 61 62 class SkPreConcatMatrixProvider : public SkMatrixProvider { 63 public: SkPreConcatMatrixProvider(const SkMatrixProvider & parent,const SkMatrix & preMatrix)64 SkPreConcatMatrixProvider(const SkMatrixProvider& parent, const SkMatrix& preMatrix) 65 : SkMatrixProvider(parent.localToDevice44() * SkM44(preMatrix)) {} 66 }; 67 68 #endif 69