Infer sampler precision from pixel config
Adds a "samplerPrecision" method to GrGLSLCaps and updates
GrGLSLProgramBuilder to infer a sampler's precision based on its
config and visibility.
BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1846963004
Review URL: https://codereview.chromium.org/1846963004
diff --git a/include/gpu/GrTextureAccess.h b/include/gpu/GrTextureAccess.h
index 237485a..1b5de0c 100644
--- a/include/gpu/GrTextureAccess.h
+++ b/include/gpu/GrTextureAccess.h
@@ -30,30 +30,25 @@
explicit GrTextureAccess(GrTexture*,
GrTextureParams::FilterMode = GrTextureParams::kNone_FilterMode,
SkShader::TileMode tileXAndY = SkShader::kClamp_TileMode,
- GrShaderFlags visibility = kFragment_GrShaderFlag,
- GrSLPrecision = kDefault_GrSLPrecision);
+ GrShaderFlags visibility = kFragment_GrShaderFlag);
void reset(GrTexture*, const GrTextureParams&,
- GrShaderFlags visibility = kFragment_GrShaderFlag,
- GrSLPrecision = kDefault_GrSLPrecision);
+ GrShaderFlags visibility = kFragment_GrShaderFlag);
void reset(GrTexture*,
GrTextureParams::FilterMode = GrTextureParams::kNone_FilterMode,
SkShader::TileMode tileXAndY = SkShader::kClamp_TileMode,
- GrShaderFlags visibility = kFragment_GrShaderFlag,
- GrSLPrecision = kDefault_GrSLPrecision);
+ GrShaderFlags visibility = kFragment_GrShaderFlag);
bool operator==(const GrTextureAccess& that) const {
return this->getTexture() == that.getTexture() &&
fParams == that.fParams &&
- fVisibility == that.fVisibility &&
- fPrecision == that.fPrecision;
+ fVisibility == that.fVisibility;
}
bool operator!=(const GrTextureAccess& other) const { return !(*this == other); }
GrTexture* getTexture() const { return fTexture.get(); }
GrShaderFlags getVisibility() const { return fVisibility; }
- GrSLPrecision getPrecision() const { return fPrecision; }
/**
* For internal use by GrProcessor.
@@ -69,7 +64,6 @@
ProgramTexture fTexture;
GrTextureParams fParams;
GrShaderFlags fVisibility;
- GrSLPrecision fPrecision;
typedef SkNoncopyable INHERITED;
};
diff --git a/src/gpu/GrTextureAccess.cpp b/src/gpu/GrTextureAccess.cpp
index a62a4dd..675bc20 100644
--- a/src/gpu/GrTextureAccess.cpp
+++ b/src/gpu/GrTextureAccess.cpp
@@ -18,30 +18,25 @@
GrTextureAccess::GrTextureAccess(GrTexture* texture,
GrTextureParams::FilterMode filterMode,
SkShader::TileMode tileXAndY,
- GrShaderFlags visibility,
- GrSLPrecision precision) {
- this->reset(texture, filterMode, tileXAndY, visibility, precision);
+ GrShaderFlags visibility) {
+ this->reset(texture, filterMode, tileXAndY, visibility);
}
void GrTextureAccess::reset(GrTexture* texture,
const GrTextureParams& params,
- GrShaderFlags visibility,
- GrSLPrecision precision) {
+ GrShaderFlags visibility) {
SkASSERT(texture);
fTexture.set(SkRef(texture), kRead_GrIOType);
fParams = params;
fVisibility = visibility;
- fPrecision = precision;
}
void GrTextureAccess::reset(GrTexture* texture,
GrTextureParams::FilterMode filterMode,
SkShader::TileMode tileXAndY,
- GrShaderFlags visibility,
- GrSLPrecision precision) {
+ GrShaderFlags visibility) {
SkASSERT(texture);
fTexture.set(SkRef(texture), kRead_GrIOType);
fParams.reset(tileXAndY, filterMode);
fVisibility = visibility;
- fPrecision = precision;
}
diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp
index e850dca..fc2c8ce 100644
--- a/src/gpu/gl/GrGLCaps.cpp
+++ b/src/gpu/gl/GrGLCaps.cpp
@@ -1197,6 +1197,7 @@
glslCaps->fFloatPrecisions[kVertex_GrShaderType][p];
}
}
+ glslCaps->initSamplerPrecisionTable();
}
bool GrGLCaps::bgraIsInternalFormat() const {
diff --git a/src/gpu/gl/GrGLProgramDesc.cpp b/src/gpu/gl/GrGLProgramDesc.cpp
index 68020a9..5e9fe5f 100644
--- a/src/gpu/gl/GrGLProgramDesc.cpp
+++ b/src/gpu/gl/GrGLProgramDesc.cpp
@@ -17,24 +17,27 @@
#include "glsl/GrGLSLFragmentShaderBuilder.h"
#include "glsl/GrGLSLCaps.h"
-static uint8_t texture_target_key(GrGLenum target) {
- switch (target) {
- case GR_GL_TEXTURE_2D:
- return 0;
- case GR_GL_TEXTURE_EXTERNAL:
- return 1;
- case GR_GL_TEXTURE_RECTANGLE:
- return 2;
- default:
- SkFAIL("Unexpected texture target.");
- return 0;
- }
+static uint16_t texture_key(GrSLType samplerType, GrPixelConfig config, GrShaderFlags visibility,
+ const GrGLSLCaps& caps) {
+ enum {
+ kFirstSamplerType = kSampler2D_GrSLType,
+ kLastSamplerType = kSampler2DRect_GrSLType,
+ kSamplerTypeKeyBits = 4
+ };
+ GR_STATIC_ASSERT(kLastSamplerType - kFirstSamplerType < (1 << kSamplerTypeKeyBits));
+
+ SkASSERT((int)samplerType >= kFirstSamplerType && (int)samplerType <= kLastSamplerType);
+ int samplerTypeKey = samplerType - kFirstSamplerType;
+
+ return SkToU16(caps.configTextureSwizzle(config).asKey() |
+ (samplerTypeKey << 8) |
+ (caps.samplerPrecision(config, visibility) << (8 + kSamplerTypeKeyBits)));
}
static void add_texture_key(GrProcessorKeyBuilder* b, const GrProcessor& proc,
const GrGLSLCaps& caps) {
int numTextures = proc.numTextures();
- // Need two bytes per key (swizzle and target).
+ // Need two bytes per key (swizzle, sampler type, and precision).
int word32Count = (proc.numTextures() + 1) / 2;
if (0 == word32Count) {
return;
@@ -42,9 +45,8 @@
uint16_t* k16 = SkTCast<uint16_t*>(b->add32n(word32Count));
for (int i = 0; i < numTextures; ++i) {
const GrTextureAccess& access = proc.textureAccess(i);
- GrGLTexture* texture = static_cast<GrGLTexture*>(access.getTexture());
- k16[i] = SkToU16(caps.configTextureSwizzle(texture->config()).asKey() |
- (texture_target_key(texture->target()) << 8));
+ const GrTexture* tex = access.getTexture();
+ k16[i] = texture_key(tex->samplerType(), tex->config(), access.getVisibility(), caps);
}
// zero the last 16 bits if the number of textures is odd.
if (numTextures & 0x1) {
diff --git a/src/gpu/glsl/GrGLSLCaps.cpp b/src/gpu/glsl/GrGLSLCaps.cpp
index c2404c6..60bea86 100755
--- a/src/gpu/glsl/GrGLSLCaps.cpp
+++ b/src/gpu/glsl/GrGLSLCaps.cpp
@@ -92,5 +92,60 @@
return r;
}
+void GrGLSLCaps::initSamplerPrecisionTable() {
+ // Determine the largest precision qualifiers that are effectively the same as lowp/mediump.
+ // e.g. if lowp == mediump, then use mediump instead of lowp.
+ GrSLPrecision effectiveMediumP[kGrShaderTypeCount];
+ GrSLPrecision effectiveLowP[kGrShaderTypeCount];
+ for (int s = 0; s < kGrShaderTypeCount; ++s) {
+ const PrecisionInfo* info = fFloatPrecisions[s];
+ effectiveMediumP[s] = info[kHigh_GrSLPrecision] == info[kMedium_GrSLPrecision] ?
+ kHigh_GrSLPrecision : kMedium_GrSLPrecision;
+ effectiveLowP[s] = info[kMedium_GrSLPrecision] == info[kLow_GrSLPrecision] ?
+ effectiveMediumP[s] : kLow_GrSLPrecision;
+ }
+
+ // Determine which precision qualifiers should be used with samplers.
+ for (int visibility = 0; visibility < (1 << kGrShaderTypeCount); ++visibility) {
+ GrSLPrecision mediump = kHigh_GrSLPrecision;
+ GrSLPrecision lowp = kHigh_GrSLPrecision;
+ for (int s = 0; s < kGrShaderTypeCount; ++s) {
+ if (visibility & (1 << s)) {
+ mediump = SkTMin(mediump, effectiveMediumP[s]);
+ lowp = SkTMin(lowp, effectiveLowP[s]);
+ }
+
+ GR_STATIC_ASSERT(0 == kLow_GrSLPrecision);
+ GR_STATIC_ASSERT(1 == kMedium_GrSLPrecision);
+ GR_STATIC_ASSERT(2 == kHigh_GrSLPrecision);
+
+ GR_STATIC_ASSERT((1 << kVertex_GrShaderType) == kVertex_GrShaderFlag);
+ GR_STATIC_ASSERT((1 << kGeometry_GrShaderType) == kGeometry_GrShaderFlag);
+ GR_STATIC_ASSERT((1 << kFragment_GrShaderType) == kFragment_GrShaderFlag);
+ GR_STATIC_ASSERT(3 == kGrShaderTypeCount);
+ }
+
+ uint8_t* table = fSamplerPrecisions[visibility];
+ table[kUnknown_GrPixelConfig] = kDefault_GrSLPrecision;
+ table[kAlpha_8_GrPixelConfig] = lowp;
+ table[kIndex_8_GrPixelConfig] = lowp;
+ table[kRGB_565_GrPixelConfig] = lowp;
+ table[kRGBA_4444_GrPixelConfig] = lowp;
+ table[kRGBA_8888_GrPixelConfig] = lowp;
+ table[kBGRA_8888_GrPixelConfig] = lowp;
+ table[kSRGBA_8888_GrPixelConfig] = lowp;
+ table[kSBGRA_8888_GrPixelConfig] = lowp;
+ table[kETC1_GrPixelConfig] = lowp;
+ table[kLATC_GrPixelConfig] = lowp;
+ table[kR11_EAC_GrPixelConfig] = lowp;
+ table[kASTC_12x12_GrPixelConfig] = lowp;
+ table[kRGBA_float_GrPixelConfig] = kHigh_GrSLPrecision;
+ table[kAlpha_half_GrPixelConfig] = mediump;
+ table[kRGBA_half_GrPixelConfig] = mediump;
+
+ GR_STATIC_ASSERT(16 == kGrPixelConfigCnt);
+ }
+}
+
void GrGLSLCaps::onApplyOptionsOverrides(const GrContextOptions& options) {
}
diff --git a/src/gpu/glsl/GrGLSLCaps.h b/src/gpu/glsl/GrGLSLCaps.h
index 7b0868e..a1d458a 100755
--- a/src/gpu/glsl/GrGLSLCaps.h
+++ b/src/gpu/glsl/GrGLSLCaps.h
@@ -162,6 +162,11 @@
return fConfigOutputSwizzle[config];
}
+ /** Precision qualifier that should be used with a sampler, given its config and visibility. */
+ GrSLPrecision samplerPrecision(GrPixelConfig config, GrShaderFlags visibility) const {
+ return static_cast<GrSLPrecision>(fSamplerPrecisions[visibility][config]);
+ }
+
GrGLSLGeneration generation() const { return fGLSLGeneration; }
/**
@@ -170,6 +175,9 @@
SkString dump() const override;
private:
+ /** GrCaps subclasses must call this after filling in the shader precision table. */
+ void initSamplerPrecisionTable();
+
void onApplyOptionsOverrides(const GrContextOptions& options) override;
GrGLSLGeneration fGLSLGeneration;
@@ -216,6 +224,8 @@
GrSwizzle fConfigTextureSwizzle[kGrPixelConfigCnt];
GrSwizzle fConfigOutputSwizzle[kGrPixelConfigCnt];
+ uint8_t fSamplerPrecisions[(1 << kGrShaderTypeCount)][kGrPixelConfigCnt];
+
friend class GrGLCaps; // For initialization.
friend class GrVkCaps;
diff --git a/src/gpu/glsl/GrGLSLProgramBuilder.cpp b/src/gpu/glsl/GrGLSLProgramBuilder.cpp
index 512d9d1..4e90452 100644
--- a/src/gpu/glsl/GrGLSLProgramBuilder.cpp
+++ b/src/gpu/glsl/GrGLSLProgramBuilder.cpp
@@ -241,10 +241,12 @@
1 << GrGLSLShaderBuilder::kExternalTexture_GLSLPrivateFeature,
externalFeatureString);
}
+ GrSLPrecision precision = this->glslCaps()->samplerPrecision(access.getTexture()->config(),
+ visibility);
name.printf("Sampler%d", t);
- localSamplerUniforms[t] = this->uniformHandler()->addUniform(access.getVisibility(),
+ localSamplerUniforms[t] = this->uniformHandler()->addUniform(visibility,
samplerType,
- access.getPrecision(),
+ precision,
name.c_str());
outSamplers->emplace_back(localSamplerUniforms[t], access);
}
diff --git a/src/gpu/vk/GrVkCaps.cpp b/src/gpu/vk/GrVkCaps.cpp
index b72a512..5b62a37 100644
--- a/src/gpu/vk/GrVkCaps.cpp
+++ b/src/gpu/vk/GrVkCaps.cpp
@@ -154,6 +154,21 @@
glslCaps->fIntegerSupport = true;
+ // Assume the minimum precisions mandated by the SPIR-V spec.
+ glslCaps->fShaderPrecisionVaries = true;
+ for (int s = 0; s < kGrShaderTypeCount; ++s) {
+ auto& highp = glslCaps->fFloatPrecisions[s][kHigh_GrSLPrecision];
+ highp.fLogRangeLow = highp.fLogRangeHigh = 127;
+ highp.fBits = 23;
+
+ auto& mediump = glslCaps->fFloatPrecisions[s][kMedium_GrSLPrecision];
+ mediump.fLogRangeLow = mediump.fLogRangeHigh = 14;
+ mediump.fBits = 10;
+
+ glslCaps->fFloatPrecisions[s][kLow_GrSLPrecision] = mediump;
+ }
+ glslCaps->initSamplerPrecisionTable();
+
glslCaps->fMaxVertexSamplers =
glslCaps->fMaxGeometrySamplers =
glslCaps->fMaxFragmentSamplers = SkTMin(properties.limits.maxPerStageDescriptorSampledImages,
diff --git a/src/gpu/vk/GrVkProgramDesc.cpp b/src/gpu/vk/GrVkProgramDesc.cpp
index 74e6bbb..f4bd2bf 100644
--- a/src/gpu/vk/GrVkProgramDesc.cpp
+++ b/src/gpu/vk/GrVkProgramDesc.cpp
@@ -22,7 +22,7 @@
static void add_texture_key(GrProcessorKeyBuilder* b, const GrProcessor& proc,
const GrGLSLCaps& caps) {
int numTextures = proc.numTextures();
- // Need two bytes per key (swizzle and target).
+ // Need two bytes per key (swizzle, sampler type, and precision).
int word32Count = (proc.numTextures() + 1) / 2;
if (0 == word32Count) {
return;
@@ -31,7 +31,8 @@
for (int i = 0; i < numTextures; ++i) {
const GrTextureAccess& access = proc.textureAccess(i);
GrTexture* texture = access.getTexture();
- k16[i] = SkToU16(caps.configTextureSwizzle(texture->config()).asKey());
+ k16[i] = SkToU16(caps.configTextureSwizzle(texture->config()).asKey() |
+ (caps.samplerPrecision(texture->config(), access.getVisibility()) << 8));
}
// zero the last 16 bits if the number of textures is odd.
if (numTextures & 0x1) {