diff --git a/include/gpu/GrTextureAccess.h b/include/gpu/GrTextureAccess.h index 237485a9e2..1b5de0ce99 100644 --- a/include/gpu/GrTextureAccess.h +++ b/include/gpu/GrTextureAccess.h @@ -30,30 +30,25 @@ public: 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 @@ private: ProgramTexture fTexture; GrTextureParams fParams; GrShaderFlags fVisibility; - GrSLPrecision fPrecision; typedef SkNoncopyable INHERITED; }; diff --git a/src/gpu/GrTextureAccess.cpp b/src/gpu/GrTextureAccess.cpp index a62a4ddce0..675bc20777 100644 --- a/src/gpu/GrTextureAccess.cpp +++ b/src/gpu/GrTextureAccess.cpp @@ -18,30 +18,25 @@ GrTextureAccess::GrTextureAccess(GrTexture* texture, const GrTextureParams& para 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 e850dcabaf..fc2c8ce398 100644 --- a/src/gpu/gl/GrGLCaps.cpp +++ b/src/gpu/gl/GrGLCaps.cpp @@ -1197,6 +1197,7 @@ void GrGLCaps::initShaderPrecisionTable(const GrGLContextInfo& ctxInfo, 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 68020a92d5..5e9fe5fcc6 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 @@ static void add_texture_key(GrProcessorKeyBuilder* b, const GrProcessor& proc, uint16_t* k16 = SkTCast(b->add32n(word32Count)); for (int i = 0; i < numTextures; ++i) { const GrTextureAccess& access = proc.textureAccess(i); - GrGLTexture* texture = static_cast(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 c2404c6e52..60bea8663a 100755 --- a/src/gpu/glsl/GrGLSLCaps.cpp +++ b/src/gpu/glsl/GrGLSLCaps.cpp @@ -92,5 +92,60 @@ SkString GrGLSLCaps::dump() const { 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 7b0868ea92..a1d458a547 100755 --- a/src/gpu/glsl/GrGLSLCaps.h +++ b/src/gpu/glsl/GrGLSLCaps.h @@ -162,6 +162,11 @@ public: 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(fSamplerPrecisions[visibility][config]); + } + GrGLSLGeneration generation() const { return fGLSLGeneration; } /** @@ -170,6 +175,9 @@ public: 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 @@ private: 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 512d9d14d9..4e90452925 100644 --- a/src/gpu/glsl/GrGLSLProgramBuilder.cpp +++ b/src/gpu/glsl/GrGLSLProgramBuilder.cpp @@ -241,10 +241,12 @@ void GrGLSLProgramBuilder::emitSamplers(const GrProcessor& processor, 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 b72a512523..5b62a3767c 100644 --- a/src/gpu/vk/GrVkCaps.cpp +++ b/src/gpu/vk/GrVkCaps.cpp @@ -154,6 +154,21 @@ void GrVkCaps::initGLSLCaps(const VkPhysicalDeviceProperties& properties, 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 74e6bbb59d..f4bd2bf506 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 @@ static void add_texture_key(GrProcessorKeyBuilder* b, const GrProcessor& proc, 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) {