1 /*
2  * Copyright 2014 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 #include "GrCoordTransform.h"
9 #include "GrCaps.h"
10 #include "GrContext.h"
11 #include "GrGpu.h"
12 #include "GrResourceProvider.h"
13 #include "GrTextureProxy.h"
14 
compute_precision(const GrShaderCaps * caps,int width,int height,GrSamplerParams::FilterMode filter)15 static GrSLPrecision compute_precision(const GrShaderCaps* caps,
16                                        int width, int height,
17                                        GrSamplerParams::FilterMode filter) {
18     // Always start at kDefault. Then if precisions differ we see if the precision needs to be
19     // increased. Our rule is that we want at least 4 subpixel values in the representation for
20     // coords between 0 to 1 when bi- or tri-lerping and 1 value when nearest filtering. Note that
21     // this still might not be enough when drawing with repeat or mirror-repeat modes but that case
22     // can be arbitrarily bad.
23     int subPixelThresh = filter > GrSamplerParams::kNone_FilterMode ? 4 : 1;
24     GrSLPrecision precision = kDefault_GrSLPrecision;
25     if (caps) {
26         if (caps->floatPrecisionVaries()) {
27             int maxD = SkTMax(width, height);
28             const GrShaderCaps::PrecisionInfo* info;
29             info = &caps->getFloatShaderPrecisionInfo(kFragment_GrShaderType, precision);
30             do {
31                 SkASSERT(info->supported());
32                 // Make sure there is at least 2 bits of subpixel precision in the range of
33                 // texture coords from 0.5 to 1.0.
34                 if ((2 << info->fBits) / maxD > subPixelThresh) {
35                     break;
36                 }
37                 if (kHigh_GrSLPrecision == precision) {
38                     break;
39                 }
40                 GrSLPrecision nextP = static_cast<GrSLPrecision>(precision + 1);
41                 info = &caps->getFloatShaderPrecisionInfo(kFragment_GrShaderType, nextP);
42                 if (!info->supported()) {
43                     break;
44                 }
45                 precision = nextP;
46             } while (true);
47         }
48     }
49 
50     return precision;
51 }
52 
reset(const SkMatrix & m,const GrTexture * texture,GrSamplerParams::FilterMode filter,bool normalize)53 void GrCoordTransform::reset(const SkMatrix& m, const GrTexture* texture,
54                              GrSamplerParams::FilterMode filter, bool normalize) {
55     SkASSERT(texture);
56     SkASSERT(!fInProcessor);
57 
58     fMatrix = m;
59     fTexture = texture;
60     fNormalize = normalize;
61     fReverseY = kBottomLeft_GrSurfaceOrigin == texture->origin();
62 
63     if (texture->getContext()) {
64         fPrecision = compute_precision(texture->getContext()->caps()->shaderCaps(),
65                                        texture->width(), texture->height(), filter);
66     } else {
67         fPrecision = kDefault_GrSLPrecision;
68     }
69 }
70 
reset(GrResourceProvider * resourceProvider,const SkMatrix & m,GrTextureProxy * proxy,GrSamplerParams::FilterMode filter,bool normalize)71 void GrCoordTransform::reset(GrResourceProvider* resourceProvider, const SkMatrix& m,
72                              GrTextureProxy* proxy,
73                              GrSamplerParams::FilterMode filter, bool normalize) {
74     SkASSERT(proxy);
75     SkASSERT(!fInProcessor);
76 
77     fMatrix = m;
78     // MDB TODO: just GrCaps is needed for this method
79     // MDB TODO: once all the coord transforms take a proxy just store it here and
80     // instantiate later
81     fTexture = proxy->instantiate(resourceProvider);
82     fNormalize = normalize;
83     fReverseY = kBottomLeft_GrSurfaceOrigin == proxy->origin();
84 
85     const GrCaps* caps = resourceProvider->caps();
86     fPrecision = compute_precision(caps->shaderCaps(),
87                                    proxy->worstCaseWidth(*caps),
88                                    proxy->worstCaseHeight(*caps), filter);
89 }
90 
91