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
15static 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
53void 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
71void 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