aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu
diff options
context:
space:
mode:
authorGravatar bsalomon <bsalomon@google.com>2014-12-09 09:00:49 -0800
committerGravatar Commit bot <commit-bot@chromium.org>2014-12-09 09:00:49 -0800
commit17168df7798d0d12684f18df0556dc19e65b32e6 (patch)
treec146317e443c68d41d03f7e5b623cf22ef2386e7 /src/gpu
parent303044579913eacc177d4b28a674121725c565bb (diff)
Use texture size to determine precision of texture coord varyings.
Diffstat (limited to 'src/gpu')
-rw-r--r--src/gpu/GrCoordTransform.cpp61
-rw-r--r--src/gpu/GrDrawTarget.cpp49
-rw-r--r--src/gpu/GrDrawTargetCaps.h58
-rw-r--r--src/gpu/gl/GrGLCaps.cpp72
-rw-r--r--src/gpu/gl/GrGLCaps.h7
-rw-r--r--src/gpu/gl/GrGLProgramDesc.cpp53
-rw-r--r--src/gpu/gl/GrGLUtil.h9
-rw-r--r--src/gpu/gl/builders/GrGLProgramBuilder.cpp3
-rw-r--r--src/gpu/gl/builders/GrGLProgramBuilder.h12
9 files changed, 290 insertions, 34 deletions
diff --git a/src/gpu/GrCoordTransform.cpp b/src/gpu/GrCoordTransform.cpp
new file mode 100644
index 0000000000..53285a27eb
--- /dev/null
+++ b/src/gpu/GrCoordTransform.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrCoordTransform.h"
+#include "GrContext.h"
+#include "GrDrawTargetCaps.h"
+#include "GrGpu.h"
+
+void GrCoordTransform::reset(GrCoordSet sourceCoords, const SkMatrix& m, const GrTexture* texture) {
+ SkASSERT(texture);
+ SkASSERT(!fInProcessor);
+
+ fSourceCoords = sourceCoords;
+ fMatrix = m;
+ fReverseY = kBottomLeft_GrSurfaceOrigin == texture->origin();
+
+ // Always start at kDefault. Then if precisions differ we see if the precision needs to be
+ // increased. Our rule is that we want at least 4 subpixel values in the representation for
+ // coords between 0 to 1. Note that this still might not be enough when drawing with repeat
+ // or mirror-repeat modes but that case can be arbitrarily bad.
+ fPrecision = GrShaderVar::kDefault_Precision;
+ if (texture->getContext()) {
+ const GrDrawTargetCaps* caps = texture->getContext()->getGpu()->caps();
+ if (caps->floatPrecisionVaries()) {
+ int maxD = SkTMax(texture->width(), texture->height());
+ const GrDrawTargetCaps::PrecisionInfo* info;
+ info = &caps->getFloatShaderPrecisionInfo(kFragment_GrShaderType, fPrecision);
+ do {
+ SkASSERT(info->supported());
+ // Make sure there is at least 2 bits of subpixel precision in the range of
+ // texture coords from 0.5 to 1.0.
+ if ((2 << info->fBits) / maxD > 4) {
+ break;
+ }
+ if (GrShaderVar::kHigh_Precision == fPrecision) {
+ break;
+ }
+ GrShaderVar::Precision nextP = static_cast<GrShaderVar::Precision>(fPrecision + 1);
+ info = &caps->getFloatShaderPrecisionInfo(kFragment_GrShaderType, nextP);
+ if (!info->supported()) {
+ break;
+ }
+ fPrecision = nextP;
+ } while (true);
+ }
+ }
+}
+
+void GrCoordTransform::reset(GrCoordSet sourceCoords,
+ const SkMatrix& m,
+ GrShaderVar::Precision precision) {
+ SkASSERT(!fInProcessor);
+ fSourceCoords = sourceCoords;
+ fMatrix = m;
+ fReverseY = false;
+ fPrecision = precision;
+}
diff --git a/src/gpu/GrDrawTarget.cpp b/src/gpu/GrDrawTarget.cpp
index 65764b88ce..ed54bf9514 100644
--- a/src/gpu/GrDrawTarget.cpp
+++ b/src/gpu/GrDrawTarget.cpp
@@ -1011,6 +1011,8 @@ void GrDrawTargetCaps::reset() {
fMaxTextureSize = 0;
fMaxSampleCount = 0;
+ fShaderPrecisionVaries = false;
+
memset(fConfigRenderSupport, 0, sizeof(fConfigRenderSupport));
memset(fConfigTextureSupport, 0, sizeof(fConfigTextureSupport));
}
@@ -1042,6 +1044,12 @@ GrDrawTargetCaps& GrDrawTargetCaps::operator=(const GrDrawTargetCaps& other) {
memcpy(fConfigRenderSupport, other.fConfigRenderSupport, sizeof(fConfigRenderSupport));
memcpy(fConfigTextureSupport, other.fConfigTextureSupport, sizeof(fConfigTextureSupport));
+ fShaderPrecisionVaries = other.fShaderPrecisionVaries;
+ for (int s = 0; s < kGrShaderTypeCount; ++s) {
+ for (int p = 0; p < GrShaderVar::kPrecisionCount; ++p) {
+ fFloatPrecisions[s][p] = other.fFloatPrecisions[s][p];
+ }
+ }
return *this;
}
@@ -1065,6 +1073,30 @@ static SkString map_flags_to_string(uint32_t flags) {
return str;
}
+static const char* shader_type_to_string(GrShaderType type) {
+ switch (type) {
+ case kVertex_GrShaderType:
+ return "vertex";
+ case kGeometry_GrShaderType:
+ return "geometry";
+ case kFragment_GrShaderType:
+ return "fragment";
+ }
+ return "";
+}
+
+static const char* precision_to_string(GrShaderVar::Precision p) {
+ switch (p) {
+ case GrShaderVar::kLow_Precision:
+ return "low";
+ case GrShaderVar::kMedium_Precision:
+ return "medium";
+ case GrShaderVar::kHigh_Precision:
+ return "high";
+ }
+ return "";
+}
+
SkString GrDrawTargetCaps::dump() const {
SkString r;
static const char* gNY[] = {"NO", "YES"};
@@ -1140,6 +1172,23 @@ SkString GrDrawTargetCaps::dump() const {
gNY[fConfigTextureSupport[i]]);
}
+ r.appendf("Shader Float Precisions (varies: %s):\n", gNY[fShaderPrecisionVaries]);
+
+ for (int s = 0; s < kGrShaderTypeCount; ++s) {
+ GrShaderType shaderType = static_cast<GrShaderType>(s);
+ r.appendf("\t%s:\n", shader_type_to_string(shaderType));
+ for (int p = 0; p < GrShaderVar::kPrecisionCount; ++p) {
+ if (fFloatPrecisions[s][p].supported()) {
+ GrShaderVar::Precision precision = static_cast<GrShaderVar::Precision>(p);
+ r.appendf("\t\t%s: log_low: %d log_high: %d bits: %d\n",
+ precision_to_string(precision),
+ fFloatPrecisions[s][p].fLogRangeLow,
+ fFloatPrecisions[s][p].fLogRangeHigh,
+ fFloatPrecisions[s][p].fBits);
+ }
+ }
+ }
+
return r;
}
diff --git a/src/gpu/GrDrawTargetCaps.h b/src/gpu/GrDrawTargetCaps.h
index f13aa53c80..ae6a9ed749 100644
--- a/src/gpu/GrDrawTargetCaps.h
+++ b/src/gpu/GrDrawTargetCaps.h
@@ -9,6 +9,8 @@
#define GrDrawTargetCaps_DEFINED
#include "GrTypes.h"
+#include "GrTypesPriv.h"
+#include "GrShaderVar.h"
#include "SkRefCnt.h"
#include "SkString.h"
@@ -19,6 +21,41 @@ class GrDrawTargetCaps : public SkRefCnt {
public:
SK_DECLARE_INST_COUNT(GrDrawTargetCaps)
+ /** Info about shader variable precision within a given shader stage. That is, this info
+ is relevant to a float (or vecNf) variable declared with a GrShaderVar::Precision
+ in a given GrShaderType. The info here is hoisted from the OpenGL spec. */
+ struct PrecisionInfo {
+ PrecisionInfo() {
+ fLogRangeLow = 0;
+ fLogRangeHigh = 0;
+ fBits = 0;
+ }
+
+ /** Is this precision level allowed in the shader stage? */
+ bool supported() const { return 0 != fBits; }
+
+ bool operator==(const PrecisionInfo& that) const {
+ return fLogRangeLow == that.fLogRangeLow && fLogRangeHigh == that.fLogRangeHigh &&
+ fBits == that.fBits;
+ }
+ bool operator!=(const PrecisionInfo& that) const { return !(*this == that); }
+
+ /** floor(log2(|min_value|)) */
+ int fLogRangeLow;
+ /** floor(log2(|max_value|)) */
+ int fLogRangeHigh;
+ /** Number of bits of precision. As defined in OpenGL (with names modified to reflect this
+ struct) :
+ """
+ If the smallest representable value greater than 1 is 1 + e, then fBits will
+ contain floor(log2(e)), and every value in the range [2^fLogRangeLow,
+ 2^fLogRangeHigh] can be represented to at least one part in 2^fBits.
+ """
+ */
+ int fBits;
+ };
+
+
GrDrawTargetCaps() : fUniqueID(CreateUniqueID()) {
this->reset();
}
@@ -84,6 +121,24 @@ public:
}
/**
+ * Get the precision info for a variable of type kFloat_GrSLType, kVec2f_GrSLType, etc in a
+ * given shader type. If the shader type is not supported or the precision level is not
+ * supported in that shader type then the returned struct will report false when supported() is
+ * called.
+ */
+ const PrecisionInfo& getFloatShaderPrecisionInfo(GrShaderType shaderType,
+ GrShaderVar::Precision precision) const {
+ return fFloatPrecisions[shaderType][precision];
+ };
+
+ /**
+ * Is there any difference between the float shader variable precision types? If this is true
+ * then unless the shader type is not supported, any call to getFloatShaderPrecisionInfo() would
+ * report the same info for all precisions in all shader types.
+ */
+ bool floatPrecisionVaries() const { return fShaderPrecisionVaries; }
+
+ /**
* Gets an id that is unique for this GrDrawTargetCaps object. It is static in that it does
* not change when the content of the GrDrawTargetCaps object changes. This will never return
* 0.
@@ -119,6 +174,9 @@ protected:
bool fConfigRenderSupport[kGrPixelConfigCnt][2];
bool fConfigTextureSupport[kGrPixelConfigCnt];
+ bool fShaderPrecisionVaries;
+ PrecisionInfo fFloatPrecisions[kGrShaderTypeCount][GrShaderVar::kPrecisionCount];
+
private:
static uint32_t CreateUniqueID();
diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp
index cf442a0430..a510cb456b 100644
--- a/src/gpu/gl/GrGLCaps.cpp
+++ b/src/gpu/gl/GrGLCaps.cpp
@@ -386,6 +386,8 @@ bool GrGLCaps::init(const GrGLContextInfo& ctxInfo, const GrGLInterface* gli) {
this->initConfigTexturableTable(ctxInfo, gli);
this->initConfigRenderableTable(ctxInfo);
+ this->initShaderPrecisionTable(ctxInfo, gli);
+
return true;
}
@@ -774,6 +776,76 @@ void GrGLCaps::initStencilFormats(const GrGLContextInfo& ctxInfo) {
fStencilVerifiedColorConfigs.push_back_n(fStencilFormats.count());
}
+static GrGLenum precision_to_gl_float_type(GrShaderVar::Precision p) {
+ switch (p) {
+ case GrShaderVar::kLow_Precision:
+ return GR_GL_LOW_FLOAT;
+ case GrShaderVar::kMedium_Precision:
+ return GR_GL_MEDIUM_FLOAT;
+ case GrShaderVar::kHigh_Precision:
+ return GR_GL_HIGH_FLOAT;
+ }
+ SkFAIL("Unknown precision.");
+ return -1;
+}
+
+static GrGLenum shader_type_to_gl_shader(GrShaderType type) {
+ switch (type) {
+ case kVertex_GrShaderType:
+ return GR_GL_VERTEX_SHADER;
+ case kGeometry_GrShaderType:
+ return GR_GL_GEOMETRY_SHADER;
+ case kFragment_GrShaderType:
+ return GR_GL_FRAGMENT_SHADER;
+ }
+ SkFAIL("Unknown shader type.");
+ return -1;
+}
+
+void GrGLCaps::initShaderPrecisionTable(const GrGLContextInfo& ctxInfo, const GrGLInterface* intf) {
+ if (kGLES_GrGLStandard == ctxInfo.standard() || ctxInfo.version() >= GR_GL_VER(4,1) ||
+ ctxInfo.hasExtension("GL_ARB_ES2_compatibility")) {
+ for (int s = 0; s < kGrShaderTypeCount; ++s) {
+ if (kGeometry_GrShaderType != s || fGeometryShaderSupport) {
+ GrShaderType shaderType = static_cast<GrShaderType>(s);
+ GrGLenum glShader = shader_type_to_gl_shader(shaderType);
+ PrecisionInfo* first = NULL;
+ fShaderPrecisionVaries = false;
+ for (int p = 0; p < GrShaderVar::kPrecisionCount; ++p) {
+ GrShaderVar::Precision precision = static_cast<GrShaderVar::Precision>(p);
+ GrGLenum glPrecision = precision_to_gl_float_type(precision);
+ GrGLint range[2];
+ GrGLint bits;
+ GR_GL_GetShaderPrecisionFormat(intf, glShader, glPrecision, range, &bits);
+ if (bits) {
+ fFloatPrecisions[s][p].fLogRangeLow = range[0];
+ fFloatPrecisions[s][p].fLogRangeHigh = range[1];
+ fFloatPrecisions[s][p].fBits = bits;
+ if (!first) {
+ first = &fFloatPrecisions[s][p];
+ } else if (!fShaderPrecisionVaries) {
+ fShaderPrecisionVaries = (*first != fFloatPrecisions[s][p]);
+ }
+ }
+ }
+ }
+ }
+ } else {
+ // We're on a desktop GL that doesn't have precision info. Assume they're all 32bit float.
+ fShaderPrecisionVaries = false;
+ for (int s = 0; s < kGrShaderTypeCount; ++s) {
+ if (kGeometry_GrShaderType != s || fGeometryShaderSupport) {
+ for (int p = 0; p < GrShaderVar::kPrecisionCount; ++p) {
+ fFloatPrecisions[s][p].fLogRangeLow = 127;
+ fFloatPrecisions[s][p].fLogRangeHigh = 127;
+ fFloatPrecisions[s][p].fBits = 23;
+ }
+ }
+ }
+ }
+}
+
+
void GrGLCaps::markColorConfigAndStencilFormatAsVerified(
GrPixelConfig config,
const GrGLStencilBuffer::Format& format) {
diff --git a/src/gpu/gl/GrGLCaps.h b/src/gpu/gl/GrGLCaps.h
index f84019335c..19e9b878de 100644
--- a/src/gpu/gl/GrGLCaps.h
+++ b/src/gpu/gl/GrGLCaps.h
@@ -325,9 +325,10 @@ private:
void initConfigRenderableTable(const GrGLContextInfo&);
void initConfigTexturableTable(const GrGLContextInfo&, const GrGLInterface*);
- bool doReadPixelsSupported(const GrGLInterface* intf,
- GrGLenum format,
- GrGLenum type) const;
+ // Must be called after fGeometryShaderSupport is initialized.
+ void initShaderPrecisionTable(const GrGLContextInfo&, const GrGLInterface*);
+
+ bool doReadPixelsSupported(const GrGLInterface* intf, GrGLenum format, GrGLenum type) const;
// tracks configs that have been verified to pass the FBO completeness when
// used as a color attachment
diff --git a/src/gpu/gl/GrGLProgramDesc.cpp b/src/gpu/gl/GrGLProgramDesc.cpp
index 6867a1329b..16de1eab22 100644
--- a/src/gpu/gl/GrGLProgramDesc.cpp
+++ b/src/gpu/gl/GrGLProgramDesc.cpp
@@ -14,25 +14,6 @@
#include "gl/builders/GrGLFragmentShaderBuilder.h"
/**
- * The key for an individual coord transform is made up of a matrix type and a bit that
- * indicates the source of the input coords.
- */
-enum {
- kMatrixTypeKeyBits = 1,
- kMatrixTypeKeyMask = (1 << kMatrixTypeKeyBits) - 1,
- kPositionCoords_Flag = (1 << kMatrixTypeKeyBits),
- kTransformKeyBits = kMatrixTypeKeyBits + 1,
-};
-
-/**
- * We specialize the vertex code for each of these matrix types.
- */
-enum MatrixType {
- kNoPersp_MatrixType = 0,
- kGeneral_MatrixType = 1,
-};
-
-/**
* Do we need to either map r,g,b->a or a->r. configComponentMask indicates which channels are
* present in the texture's config. swizzleComponentMask indicates the channels present in the
* shader swizzle.
@@ -72,8 +53,33 @@ static uint32_t gen_attrib_key(const GrGeometryProcessor& proc) {
return key;
}
-static uint32_t gen_transform_key(const GrPendingFragmentStage& stage,
- bool useExplicitLocalCoords) {
+/**
+ * The key for an individual coord transform is made up of a matrix type, a precision, and a bit
+ * that indicates the source of the input coords.
+ */
+enum {
+ kMatrixTypeKeyBits = 1,
+ kMatrixTypeKeyMask = (1 << kMatrixTypeKeyBits) - 1,
+
+ kPrecisionBits = 2,
+ kPrecisionShift = kMatrixTypeKeyBits,
+
+ kPositionCoords_Flag = (1 << (kPrecisionShift + kPrecisionBits)),
+
+ kTransformKeyBits = kMatrixTypeKeyBits + kPrecisionBits + 1,
+};
+
+GR_STATIC_ASSERT(GrShaderVar::kHigh_Precision < (1 << kPrecisionBits));
+
+/**
+ * We specialize the vertex code for each of these matrix types.
+ */
+enum MatrixType {
+ kNoPersp_MatrixType = 0,
+ kGeneral_MatrixType = 1,
+};
+
+static uint32_t gen_transform_key(const GrPendingFragmentStage& stage, bool useExplicitLocalCoords) {
uint32_t totalKey = 0;
int numTransforms = stage.getProcessor()->numTransforms();
for (int t = 0; t < numTransforms; ++t) {
@@ -88,7 +94,12 @@ static uint32_t gen_transform_key(const GrPendingFragmentStage& stage,
if (kLocal_GrCoordSet != coordTransform.sourceCoords() && useExplicitLocalCoords) {
key |= kPositionCoords_Flag;
}
+
+ GR_STATIC_ASSERT(GrShaderVar::kPrecisionCount <= (1 << kPrecisionBits));
+ key |= (coordTransform.precision() << kPrecisionShift);
+
key <<= kTransformKeyBits * t;
+
SkASSERT(0 == (totalKey & key)); // keys for each transform ought not to overlap
totalKey |= key;
}
diff --git a/src/gpu/gl/GrGLUtil.h b/src/gpu/gl/GrGLUtil.h
index bc6fdf1757..570694af31 100644
--- a/src/gpu/gl/GrGLUtil.h
+++ b/src/gpu/gl/GrGLUtil.h
@@ -71,12 +71,21 @@ enum GrGLRenderer {
*(p) = GR_GL_INIT_ZERO; \
GR_GL_CALL(gl, GetRenderbufferParameteriv(t, pname, p)); \
} while (0)
+
#define GR_GL_GetTexLevelParameteriv(gl, t, l, pname, p) \
do { \
*(p) = GR_GL_INIT_ZERO; \
GR_GL_CALL(gl, GetTexLevelParameteriv(t, l, pname, p)); \
} while (0)
+#define GR_GL_GetShaderPrecisionFormat(gl, st, pt, range, precision) \
+ do { \
+ (range)[0] = GR_GL_INIT_ZERO; \
+ (range)[1] = GR_GL_INIT_ZERO; \
+ (*precision) = GR_GL_INIT_ZERO; \
+ GR_GL_CALL(gl, GetShaderPrecisionFormat(st, pt, range, precision)); \
+ } while (0)
+
////////////////////////////////////////////////////////////////////////////////
/**
diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.cpp b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
index 4d8011cd97..5ed566fa33 100644
--- a/src/gpu/gl/builders/GrGLProgramBuilder.cpp
+++ b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
@@ -413,7 +413,8 @@ void GrGLProgramBuilder::emitTransforms(const GrPendingFragmentStage& stage,
const char* coords = useLocalCoords ? fVS.localCoords() : fVS.positionCoords();
GrGLVertToFrag v(varyingType);
- this->addCoordVarying(varyingName, &v, uniName, coords);
+ this->addVarying(varyingName, &v, processor->coordTransform(t).precision());
+ fCoordVaryings.push_back(TransformVarying(v, uniName, coords));
SkASSERT(kVec2f_GrSLType == varyingType || kVec3f_GrSLType == varyingType);
SkNEW_APPEND_TO_TARRAY(outCoords, GrGLProcessor::TransformedCoords,
diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.h b/src/gpu/gl/builders/GrGLProgramBuilder.h
index 973ae5e078..b7458b3e8f 100644
--- a/src/gpu/gl/builders/GrGLProgramBuilder.h
+++ b/src/gpu/gl/builders/GrGLProgramBuilder.h
@@ -30,9 +30,9 @@
class GrGLUniformBuilder {
public:
enum ShaderVisibility {
- kVertex_Visibility = 0x1,
- kGeometry_Visibility = 0x2,
- kFragment_Visibility = 0x4,
+ kVertex_Visibility = 1 << kVertex_GrShaderType,
+ kGeometry_Visibility = 1 << kGeometry_GrShaderType,
+ kFragment_Visibility = 1 << kFragment_GrShaderType,
};
virtual ~GrGLUniformBuilder() {}
@@ -344,12 +344,6 @@ protected:
SkString fSourceCoords;
};
- void addCoordVarying(const char* name, GrGLVarying* v, const char* uniName,
- const char* sourceCoords) {
- this->addVarying(name, v);
- fCoordVaryings.push_back(TransformVarying(*v, uniName, sourceCoords));
- }
-
const char* rtAdjustment() const { return "rtAdjustment"; }
// number of each input/output type in a single allocation block, used by many builders