Revert "Reland "Reland "Revert "Use OpenGL sampler objects when available.""""
This reverts commit 327955b1ba194eb010ff5a3ef1f32a913d52dd5c.
Bug: skia:8471
Change-Id: I56eb9509f0e2d5c4aa9e2a110a73a09723f77c4a
Reviewed-on: https://skia-review.googlesource.com/c/164617
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp
index c16dc40..962e496 100644
--- a/src/gpu/gl/GrGLCaps.cpp
+++ b/src/gpu/gl/GrGLCaps.cpp
@@ -2316,6 +2316,13 @@
void GrGLCaps::applyDriverCorrectnessWorkarounds(const GrGLContextInfo& ctxInfo,
const GrContextOptions& contextOptions,
GrShaderCaps* shaderCaps) {
+ bool isX86PowerVRRogue = false;
+#if defined(SK_CPU_X86)
+ if (kPowerVRRogue_GrGLRenderer == ctxInfo.renderer()) {
+ isX86PowerVRRogue = true;
+ }
+#endif
+
// A driver but on the nexus 6 causes incorrect dst copies when invalidate is called beforehand.
// Thus we are blacklisting this extension for now on Adreno4xx devices.
if (kAdreno430_GrGLRenderer == ctxInfo.renderer() ||
@@ -2333,7 +2340,7 @@
fClearTextureSupport = false;
}
- // Calling glClearTexImage crashes on the NexusPlayer.
+ // Calling glClearTexImage crashes on the NexusPlayer. TODO: Use isX86PowerVRRogue?
if (kPowerVRRogue_GrGLRenderer == ctxInfo.renderer()) {
fClearTextureSupport = false;
}
@@ -2383,6 +2390,7 @@
fMipMapSupport = false;
}
+ // TODO: Use isX86PowerVRRogue?
if (kPowerVRRogue_GrGLRenderer == ctxInfo.renderer()) {
// Temporarily disabling clip analytic fragments processors on Nexus player while we work
// around a driver bug related to gl_FragCoord.
@@ -2466,6 +2474,7 @@
fDetachStencilFromMSAABuffersBeforeReadPixels = true;
}
+ // TODO: Don't apply this on iOS?
if (kPowerVRRogue_GrGLRenderer == ctxInfo.renderer()) {
// Our Chromebook with kPowerVRRogue_GrGLRenderer crashes on large instanced draws. The
// current minimum number of instances observed to crash is somewhere between 2^14 and 2^15.
@@ -2701,6 +2710,11 @@
// https://bugreport.apple.com/web/?problemID=39948888
fUnpackRowLengthSupport = false;
#endif
+
+ if (isX86PowerVRRogue) {
+ // On Nexus Player we get incorrect filter modes when using sampler objects.
+ fSamplerObjectSupport = false;
+ }
}
void GrGLCaps::onApplyOptionsOverrides(const GrContextOptions& options) {
diff --git a/src/gpu/gl/GrGLCreateNullInterface.cpp b/src/gpu/gl/GrGLCreateNullInterface.cpp
index a14fc67..ebc11b4 100644
--- a/src/gpu/gl/GrGLCreateNullInterface.cpp
+++ b/src/gpu/gl/GrGLCreateNullInterface.cpp
@@ -419,6 +419,10 @@
SK_ABORT("Not implemented");
}
+ GrGLvoid genSamplers(GrGLsizei n, GrGLuint* samplers) override {
+ this->genGenericIds(n, samplers);
+ }
+
GrGLvoid genTextures(GrGLsizei n, GrGLuint *textures) override {
this->genGenericIds(n, textures);
}
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index 938ead1..91f9208 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -173,6 +173,123 @@
GR_STATIC_ASSERT(kGrBlendCoeffCnt == SK_ARRAY_COUNT(gXfermodeCoeff2Blend));
}
+static GrGLenum filter_to_gl_mag_filter(GrSamplerState::Filter filter) {
+ switch (filter) {
+ case GrSamplerState::Filter::kNearest: return GR_GL_NEAREST;
+ case GrSamplerState::Filter::kBilerp: return GR_GL_LINEAR;
+ case GrSamplerState::Filter::kMipMap: return GR_GL_LINEAR;
+ }
+ SK_ABORT("Unknown filter");
+ return 0;
+}
+
+static GrGLenum filter_to_gl_min_filter(GrSamplerState::Filter filter) {
+ switch (filter) {
+ case GrSamplerState::Filter::kNearest: return GR_GL_NEAREST;
+ case GrSamplerState::Filter::kBilerp: return GR_GL_LINEAR;
+ case GrSamplerState::Filter::kMipMap: return GR_GL_LINEAR_MIPMAP_LINEAR;
+ }
+ SK_ABORT("Unknown filter");
+ return 0;
+}
+
+static inline GrGLenum wrap_mode_to_gl_wrap(GrSamplerState::WrapMode wrapMode) {
+ switch (wrapMode) {
+ case GrSamplerState::WrapMode::kClamp: return GR_GL_CLAMP_TO_EDGE;
+ case GrSamplerState::WrapMode::kRepeat: return GR_GL_REPEAT;
+ case GrSamplerState::WrapMode::kMirrorRepeat: return GR_GL_MIRRORED_REPEAT;
+ };
+ SK_ABORT("Unknown wrap mode");
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+class GrGLGpu::SamplerObjectCache {
+public:
+ SamplerObjectCache(GrGLGpu* gpu) : fGpu(gpu) {
+ fNumTextureUnits = fGpu->glCaps().shaderCaps()->maxFragmentSamplers();
+ fHWBoundSamplers.reset(new GrGLuint[fNumTextureUnits]);
+ std::fill_n(fHWBoundSamplers.get(), fNumTextureUnits, 0);
+ std::fill_n(fSamplers, kNumSamplers, 0);
+ }
+
+ ~SamplerObjectCache() {
+ if (!fNumTextureUnits) {
+ // We've already been abandoned.
+ return;
+ }
+ GR_GL_CALL(fGpu->glInterface(), DeleteSamplers(kNumSamplers, fSamplers));
+ }
+
+ void bindSampler(int unitIdx, const GrSamplerState& state) {
+ int index = StateToIndex(state);
+ if (!fSamplers[index]) {
+ GrGLuint s;
+ GR_GL_CALL(fGpu->glInterface(), GenSamplers(1, &s));
+ if (!s) {
+ return;
+ }
+ fSamplers[index] = s;
+ auto minFilter = filter_to_gl_min_filter(state.filter());
+ auto magFilter = filter_to_gl_mag_filter(state.filter());
+ auto wrapX = wrap_mode_to_gl_wrap(state.wrapModeX());
+ auto wrapY = wrap_mode_to_gl_wrap(state.wrapModeY());
+ GR_GL_CALL(fGpu->glInterface(),
+ SamplerParameteri(s, GR_GL_TEXTURE_MIN_FILTER, minFilter));
+ GR_GL_CALL(fGpu->glInterface(),
+ SamplerParameteri(s, GR_GL_TEXTURE_MAG_FILTER, magFilter));
+ GR_GL_CALL(fGpu->glInterface(), SamplerParameteri(s, GR_GL_TEXTURE_WRAP_S, wrapX));
+ GR_GL_CALL(fGpu->glInterface(), SamplerParameteri(s, GR_GL_TEXTURE_WRAP_T, wrapY));
+ }
+ if (fHWBoundSamplers[unitIdx] != fSamplers[index]) {
+ GR_GL_CALL(fGpu->glInterface(), BindSampler(unitIdx, fSamplers[index]));
+ fHWBoundSamplers[unitIdx] = fSamplers[index];
+ }
+ }
+
+ void invalidateBindings() {
+ // When we have sampler support we always use samplers. So setting these to zero will cause
+ // a rebind on next usage.
+ std::fill_n(fHWBoundSamplers.get(), fNumTextureUnits, 0);
+ }
+
+ void abandon() {
+ fHWBoundSamplers.reset();
+ fNumTextureUnits = 0;
+ }
+
+ void release() {
+ if (!fNumTextureUnits) {
+ // We've already been abandoned.
+ return;
+ }
+ GR_GL_CALL(fGpu->glInterface(), DeleteSamplers(kNumSamplers, fSamplers));
+ std::fill_n(fSamplers, kNumSamplers, 0);
+ // Deleting a bound sampler implicitly binds sampler 0.
+ std::fill_n(fHWBoundSamplers.get(), fNumTextureUnits, 0);
+ }
+
+private:
+ static int StateToIndex(const GrSamplerState& state) {
+ int filter = static_cast<int>(state.filter());
+ SkASSERT(filter >= 0 && filter < 3);
+ int wrapX = static_cast<int>(state.wrapModeX());
+ SkASSERT(wrapX >= 0 && wrapX < 3);
+ int wrapY = static_cast<int>(state.wrapModeY());
+ SkASSERT(wrapY >= 0 && wrapY < 3);
+ int idx = 9 * filter + 3 * wrapX + wrapY;
+ SkASSERT(idx < kNumSamplers);
+ return idx;
+ }
+
+ GrGLGpu* fGpu;
+ static constexpr int kNumSamplers = 27;
+ std::unique_ptr<GrGLuint[]> fHWBoundSamplers;
+ GrGLuint fSamplers[kNumSamplers];
+ int fNumTextureUnits;
+};
+
///////////////////////////////////////////////////////////////////////////////
sk_sp<GrGpu> GrGLGpu::Make(sk_sp<const GrGLInterface> interface, const GrContextOptions& options,
@@ -208,6 +325,7 @@
, fStencilClearFBOID(0)
, fHWMinSampleShading(0.0) {
SkASSERT(fGLContext);
+ GrGLClearErr(this->glInterface());
fCaps = sk_ref_sp(fGLContext->caps());
fHWBoundTextureUniqueIDs.reset(this->caps()->shaderCaps()->maxFragmentSamplers());
@@ -234,7 +352,9 @@
fPathRendering.reset(new GrGLPathRendering(this));
}
- GrGLClearErr(this->glInterface());
+ if (this->glCaps().samplerObjectSupport()) {
+ fSamplerObjectCache.reset(new SamplerObjectCache(this));
+ }
}
GrGLGpu::~GrGLGpu() {
@@ -283,6 +403,7 @@
}
delete fProgramCache;
+ fSamplerObjectCache.reset();
}
void GrGLGpu::disconnect(DisconnectType type) {
@@ -317,10 +438,16 @@
if (fClearColorProgram.fProgram) {
GL_CALL(DeleteProgram(fClearColorProgram.fProgram));
}
+ if (fSamplerObjectCache) {
+ fSamplerObjectCache->release();
+ }
} else {
if (fProgramCache) {
fProgramCache->abandon();
}
+ if (fSamplerObjectCache) {
+ fSamplerObjectCache->abandon();
+ }
}
fHWProgram.reset();
@@ -432,6 +559,9 @@
for (int s = 0; s < fHWBoundTextureUniqueIDs.count(); ++s) {
fHWBoundTextureUniqueIDs[s].makeInvalid();
}
+ if (fSamplerObjectCache) {
+ fSamplerObjectCache->invalidateBindings();
+ }
}
if (resetBits & kBlend_GrGLBackendState) {
@@ -540,7 +670,10 @@
GrMipMapsStatus mipMapsStatus = backendTex.hasMipMaps() ? GrMipMapsStatus::kValid
: GrMipMapsStatus::kNotAllocated;
- return GrGLTexture::MakeWrapped(this, surfDesc, mipMapsStatus, idDesc);
+ auto texture = GrGLTexture::MakeWrapped(this, surfDesc, mipMapsStatus, idDesc);
+ // We don't know what parameters are already set on wrapped textures.
+ texture->textureParamsModified();
+ return std::move(texture);
}
sk_sp<GrTexture> GrGLGpu::onWrapRenderableBackendTexture(const GrBackendTexture& backendTex,
@@ -586,6 +719,8 @@
sk_sp<GrGLTextureRenderTarget> texRT(
GrGLTextureRenderTarget::MakeWrapped(this, surfDesc, idDesc, rtIDDesc, mipMapsStatus));
texRT->baseLevelWasBoundToFBO();
+ // We don't know what parameters are already set on wrapped textures.
+ texRT->textureParamsModified();
return std::move(texRT);
}
@@ -1247,36 +1382,21 @@
return nullptr;
}
-#if 0 && defined(SK_DEBUG)
-static size_t as_size_t(int x) {
- return x;
-}
-#endif
-
-static void set_initial_texture_params(const GrGLInterface* interface,
- const GrGLTextureInfo& info,
- GrGLTexture::TexParams* initialTexParams) {
+static GrGLTexture::SamplerParams set_initial_texture_params(const GrGLInterface* interface,
+ const GrGLTextureInfo& info) {
// Some drivers like to know filter/wrap before seeing glTexImage2D. Some
// drivers have a bug where an FBO won't be complete if it includes a
// texture that is not mipmap complete (considering the filter in use).
- // we only set a subset here so invalidate first
- initialTexParams->invalidate();
- initialTexParams->fMinFilter = GR_GL_NEAREST;
- initialTexParams->fMagFilter = GR_GL_NEAREST;
- initialTexParams->fWrapS = GR_GL_CLAMP_TO_EDGE;
- initialTexParams->fWrapT = GR_GL_CLAMP_TO_EDGE;
- GR_GL_CALL(interface, TexParameteri(info.fTarget,
- GR_GL_TEXTURE_MAG_FILTER,
- initialTexParams->fMagFilter));
- GR_GL_CALL(interface, TexParameteri(info.fTarget,
- GR_GL_TEXTURE_MIN_FILTER,
- initialTexParams->fMinFilter));
- GR_GL_CALL(interface, TexParameteri(info.fTarget,
- GR_GL_TEXTURE_WRAP_S,
- initialTexParams->fWrapS));
- GR_GL_CALL(interface, TexParameteri(info.fTarget,
- GR_GL_TEXTURE_WRAP_T,
- initialTexParams->fWrapT));
+ GrGLTexture::SamplerParams params;
+ params.fMinFilter = GR_GL_NEAREST;
+ params.fMagFilter = GR_GL_NEAREST;
+ params.fWrapS = GR_GL_CLAMP_TO_EDGE;
+ params.fWrapT = GR_GL_CLAMP_TO_EDGE;
+ GR_GL_CALL(interface, TexParameteri(info.fTarget, GR_GL_TEXTURE_MAG_FILTER, params.fMagFilter));
+ GR_GL_CALL(interface, TexParameteri(info.fTarget, GR_GL_TEXTURE_MIN_FILTER, params.fMinFilter));
+ GR_GL_CALL(interface, TexParameteri(info.fTarget, GR_GL_TEXTURE_WRAP_S, params.fWrapS));
+ GR_GL_CALL(interface, TexParameteri(info.fTarget, GR_GL_TEXTURE_WRAP_T, params.fWrapT));
+ return params;
}
sk_sp<GrTexture> GrGLGpu::onCreateTexture(const GrSurfaceDesc& desc,
@@ -1311,7 +1431,7 @@
GrGLTexture::IDDesc idDesc;
idDesc.fOwnership = GrBackendObjectOwnership::kOwned;
GrMipMapsStatus mipMapsStatus;
- GrGLTexture::TexParams initialTexParams;
+ GrGLTexture::SamplerParams initialTexParams;
if (!this->createTextureImpl(desc, &idDesc.fInfo, isRenderTarget, &initialTexParams, texels,
mipLevelCount, &mipMapsStatus)) {
return return_null_texture();
@@ -1333,7 +1453,9 @@
} else {
tex = sk_make_sp<GrGLTexture>(this, budgeted, desc, idDesc, mipMapsStatus);
}
- tex->setCachedTexParams(initialTexParams, this->getResetTimestamp());
+
+ tex->setCachedParams(&initialTexParams, tex->getCachedNonSamplerParams(),
+ this->getResetTimestamp());
#ifdef TRACE_TEXTURE_CREATION
SkDebugf("--- new texture [%d] size=(%d %d) config=%d\n",
idDesc.fInfo.fID, desc.fWidth, desc.fHeight, desc.fConfig);
@@ -1499,8 +1621,9 @@
}
bool GrGLGpu::createTextureImpl(const GrSurfaceDesc& desc, GrGLTextureInfo* info, bool renderTarget,
- GrGLTexture::TexParams* initialTexParams, const GrMipLevel texels[],
- int mipLevelCount, GrMipMapsStatus* mipMapsStatus) {
+ GrGLTexture::SamplerParams* initialTexParams,
+ const GrMipLevel texels[], int mipLevelCount,
+ GrMipMapsStatus* mipMapsStatus) {
info->fID = 0;
info->fTarget = GR_GL_TEXTURE_2D;
GL_CALL(GenTextures(1, &(info->fID)));
@@ -1520,7 +1643,7 @@
}
if (info) {
- set_initial_texture_params(this->glInterface(), *info, initialTexParams);
+ *initialTexParams = set_initial_texture_params(this->glInterface(), *info);
}
if (!this->uploadTexData(desc.fConfig, desc.fWidth, desc.fHeight, info->fTarget,
@@ -2690,73 +2813,19 @@
}
}
-static inline GrGLenum wrap_mode_to_gl_wrap(GrSamplerState::WrapMode wrapMode) {
- switch (wrapMode) {
- case GrSamplerState::WrapMode::kClamp:
- return GR_GL_CLAMP_TO_EDGE;
- case GrSamplerState::WrapMode::kRepeat:
- return GR_GL_REPEAT;
- case GrSamplerState::WrapMode::kMirrorRepeat:
- return GR_GL_MIRRORED_REPEAT;
- };
- SK_ABORT("Unknown wrap mode");
- return 0;
-}
-
-static GrGLenum get_component_enum_from_char(char component) {
- switch (component) {
- case 'r':
- return GR_GL_RED;
- case 'g':
- return GR_GL_GREEN;
- case 'b':
- return GR_GL_BLUE;
- case 'a':
- return GR_GL_ALPHA;
- default:
- SK_ABORT("Unsupported component");
- return 0;
- }
-}
-
-/** If texture swizzling is available using tex parameters then it is preferred over mangling
- the generated shader code. This potentially allows greater reuse of cached shaders. */
-static void get_tex_param_swizzle(GrPixelConfig config,
- const GrGLCaps& caps,
- GrGLenum* glSwizzle) {
- const GrSwizzle& swizzle = caps.configSwizzle(config);
+static void get_gl_swizzle_values(const GrSwizzle& swizzle, GrGLenum glValues[4]) {
for (int i = 0; i < 4; ++i) {
- glSwizzle[i] = get_component_enum_from_char(swizzle.c_str()[i]);
+ switch (swizzle[i]) {
+ case 'r': glValues[i] = GR_GL_RED; break;
+ case 'g': glValues[i] = GR_GL_GREEN; break;
+ case 'b': glValues[i] = GR_GL_BLUE; break;
+ case 'a': glValues[i] = GR_GL_ALPHA; break;
+ default: SK_ABORT("Unsupported component");
+ }
}
}
-static GrGLenum filter_to_gl_mag_filter(GrSamplerState::Filter filter) {
- switch (filter) {
- case GrSamplerState::Filter::kNearest:
- return GR_GL_NEAREST;
- case GrSamplerState::Filter::kBilerp:
- return GR_GL_LINEAR;
- case GrSamplerState::Filter::kMipMap:
- return GR_GL_LINEAR;
- }
- SK_ABORT("Unknown filter");
- return 0;
-}
-
-static GrGLenum filter_to_gl_min_filter(GrSamplerState::Filter filter) {
- switch (filter) {
- case GrSamplerState::Filter::kNearest:
- return GR_GL_NEAREST;
- case GrSamplerState::Filter::kBilerp:
- return GR_GL_LINEAR;
- case GrSamplerState::Filter::kMipMap:
- return GR_GL_LINEAR_MIPMAP_LINEAR;
- }
- SK_ABORT("Unknown filter");
- return 0;
-}
-
-void GrGLGpu::bindTexture(int unitIdx, const GrSamplerState& samplerState, GrGLTexture* texture) {
+void GrGLGpu::bindTexture(int unitIdx, GrSamplerState samplerState, GrGLTexture* texture) {
SkASSERT(texture);
#ifdef SK_DEBUG
@@ -2785,87 +2854,109 @@
fHWBoundTextureUniqueIDs[unitIdx] = textureID;
}
- ResetTimestamp timestamp;
- const GrGLTexture::TexParams& oldTexParams = texture->getCachedTexParams(×tamp);
- bool setAll = timestamp < this->getResetTimestamp();
- GrGLTexture::TexParams newTexParams;
-
- GrSamplerState::Filter filterMode = samplerState.filter();
-
- if (GrSamplerState::Filter::kMipMap == filterMode) {
+ if (samplerState.filter() == GrSamplerState::Filter::kMipMap) {
if (!this->caps()->mipMapSupport() ||
texture->texturePriv().mipMapped() == GrMipMapped::kNo) {
- filterMode = GrSamplerState::Filter::kBilerp;
+ samplerState.setFilterMode(GrSamplerState::Filter::kBilerp);
}
}
- newTexParams.fMinFilter = filter_to_gl_min_filter(filterMode);
- newTexParams.fMagFilter = filter_to_gl_mag_filter(filterMode);
-
#ifdef SK_DEBUG
// We were supposed to ensure MipMaps were up-to-date before getting here.
- if (GrSamplerState::Filter::kMipMap == filterMode) {
+ if (samplerState.filter() == GrSamplerState::Filter::kMipMap) {
SkASSERT(!texture->texturePriv().mipMapsAreDirty());
}
#endif
- newTexParams.fMaxMipMapLevel = texture->texturePriv().maxMipMapLevel();
+ ResetTimestamp timestamp = texture->getCachedParamsTimestamp();
+ bool setAll = timestamp < this->getResetTimestamp();
- newTexParams.fWrapS = wrap_mode_to_gl_wrap(samplerState.wrapModeX());
- newTexParams.fWrapT = wrap_mode_to_gl_wrap(samplerState.wrapModeY());
- get_tex_param_swizzle(texture->config(), this->glCaps(), newTexParams.fSwizzleRGBA);
- if (setAll || newTexParams.fMagFilter != oldTexParams.fMagFilter) {
- this->setTextureUnit(unitIdx);
- GL_CALL(TexParameteri(target, GR_GL_TEXTURE_MAG_FILTER, newTexParams.fMagFilter));
- }
- if (setAll || newTexParams.fMinFilter != oldTexParams.fMinFilter) {
- this->setTextureUnit(unitIdx);
- GL_CALL(TexParameteri(target, GR_GL_TEXTURE_MIN_FILTER, newTexParams.fMinFilter));
- }
- if (setAll || newTexParams.fMaxMipMapLevel != oldTexParams.fMaxMipMapLevel) {
- // These are not supported in ES2 contexts
+ const GrGLTexture::SamplerParams* samplerParamsToRecord = nullptr;
+ GrGLTexture::SamplerParams newSamplerParams;
+ if (fSamplerObjectCache) {
+ fSamplerObjectCache->bindSampler(unitIdx, samplerState);
+ } else {
+ const GrGLTexture::SamplerParams& oldSamplerParams = texture->getCachedSamplerParams();
+ samplerParamsToRecord = &newSamplerParams;
+
+ newSamplerParams.fMinFilter = filter_to_gl_min_filter(samplerState.filter());
+ newSamplerParams.fMagFilter = filter_to_gl_mag_filter(samplerState.filter());
+
+ newSamplerParams.fWrapS = wrap_mode_to_gl_wrap(samplerState.wrapModeX());
+ newSamplerParams.fWrapT = wrap_mode_to_gl_wrap(samplerState.wrapModeY());
+
+ // These are the OpenGL default values.
+ newSamplerParams.fMinLOD = -1000;
+ newSamplerParams.fMaxLOD = 1000;
+
+ if (setAll || newSamplerParams.fMagFilter != oldSamplerParams.fMagFilter) {
+ this->setTextureUnit(unitIdx);
+ GL_CALL(TexParameteri(target, GR_GL_TEXTURE_MAG_FILTER, newSamplerParams.fMagFilter));
+ }
+ if (setAll || newSamplerParams.fMinFilter != oldSamplerParams.fMinFilter) {
+ this->setTextureUnit(unitIdx);
+ GL_CALL(TexParameteri(target, GR_GL_TEXTURE_MIN_FILTER, newSamplerParams.fMinFilter));
+ }
if (this->glCaps().mipMapLevelAndLodControlSupport()) {
- if (newTexParams.fMaxMipMapLevel != 0) {
+ // Min and max LOD are actually floats. We don't curently support glTexParameterf.
+ // However, we only set these to integral floats (see above).
+ if (setAll || newSamplerParams.fMinLOD != oldSamplerParams.fMinLOD) {
this->setTextureUnit(unitIdx);
- GL_CALL(TexParameteri(target, GR_GL_TEXTURE_MIN_LOD, 0));
- GL_CALL(TexParameteri(target, GR_GL_TEXTURE_BASE_LEVEL, 0));
- GL_CALL(TexParameteri(target, GR_GL_TEXTURE_MAX_LOD,
- newTexParams.fMaxMipMapLevel));
- GL_CALL(TexParameteri(target, GR_GL_TEXTURE_MAX_LEVEL,
- newTexParams.fMaxMipMapLevel));
+ GL_CALL(TexParameteri(target, GR_GL_TEXTURE_MIN_LOD, newSamplerParams.fMinLOD));
+ }
+ if (setAll || newSamplerParams.fMaxLOD != oldSamplerParams.fMaxLOD) {
+ this->setTextureUnit(unitIdx);
+ GL_CALL(TexParameteri(target, GR_GL_TEXTURE_MAX_LOD, newSamplerParams.fMaxLOD));
+ }
+ }
+ if (setAll || newSamplerParams.fWrapS != oldSamplerParams.fWrapS) {
+ this->setTextureUnit(unitIdx);
+ GL_CALL(TexParameteri(target, GR_GL_TEXTURE_WRAP_S, newSamplerParams.fWrapS));
+ }
+ if (setAll || newSamplerParams.fWrapT != oldSamplerParams.fWrapT) {
+ this->setTextureUnit(unitIdx);
+ GL_CALL(TexParameteri(target, GR_GL_TEXTURE_WRAP_T, newSamplerParams.fWrapT));
+ }
+ }
+ GrGLTexture::NonSamplerParams newNonSamplerParams;
+ newNonSamplerParams.fBaseMipMapLevel = 0;
+ newNonSamplerParams.fMaxMipMapLevel = texture->texturePriv().maxMipMapLevel();
+
+ const GrGLTexture::NonSamplerParams& oldNonSamplerParams = texture->getCachedNonSamplerParams();
+ if (this->glCaps().textureSwizzleSupport()) {
+ auto swizzle = this->glCaps().configSwizzle(texture->config());
+ newNonSamplerParams.fSwizzleKey = swizzle.asKey();
+ if (setAll || swizzle.asKey() != oldNonSamplerParams.fSwizzleKey) {
+ GrGLenum glValues[4];
+ get_gl_swizzle_values(swizzle, glValues);
+ this->setTextureUnit(unitIdx);
+ if (this->glStandard() == kGLES_GrGLStandard) {
+ // ES3 added swizzle support but not GL_TEXTURE_SWIZZLE_RGBA.
+ GL_CALL(TexParameteri(target, GR_GL_TEXTURE_SWIZZLE_R, glValues[0]));
+ GL_CALL(TexParameteri(target, GR_GL_TEXTURE_SWIZZLE_G, glValues[1]));
+ GL_CALL(TexParameteri(target, GR_GL_TEXTURE_SWIZZLE_B, glValues[2]));
+ GL_CALL(TexParameteri(target, GR_GL_TEXTURE_SWIZZLE_A, glValues[3]));
+ } else {
+ GR_STATIC_ASSERT(sizeof(glValues[0]) == sizeof(GrGLint));
+ GL_CALL(TexParameteriv(target, GR_GL_TEXTURE_SWIZZLE_RGBA,
+ reinterpret_cast<const GrGLint*>(glValues)));
}
}
}
- if (setAll || newTexParams.fWrapS != oldTexParams.fWrapS) {
- this->setTextureUnit(unitIdx);
- GL_CALL(TexParameteri(target, GR_GL_TEXTURE_WRAP_S, newTexParams.fWrapS));
+ // These are not supported in ES2 contexts
+ if (this->glCaps().mipMapLevelAndLodControlSupport()) {
+ if (newNonSamplerParams.fBaseMipMapLevel != oldNonSamplerParams.fBaseMipMapLevel) {
+ this->setTextureUnit(unitIdx);
+ GL_CALL(TexParameteri(target, GR_GL_TEXTURE_BASE_LEVEL,
+ newNonSamplerParams.fBaseMipMapLevel));
+ }
+ if (newNonSamplerParams.fMaxMipMapLevel != oldNonSamplerParams.fMaxMipMapLevel) {
+ this->setTextureUnit(unitIdx);
+ GL_CALL(TexParameteri(target, GR_GL_TEXTURE_MAX_LEVEL,
+ newNonSamplerParams.fMaxMipMapLevel));
+ }
}
- if (setAll || newTexParams.fWrapT != oldTexParams.fWrapT) {
- this->setTextureUnit(unitIdx);
- GL_CALL(TexParameteri(target, GR_GL_TEXTURE_WRAP_T, newTexParams.fWrapT));
- }
- if (this->glCaps().textureSwizzleSupport() &&
- (setAll || memcmp(newTexParams.fSwizzleRGBA,
- oldTexParams.fSwizzleRGBA,
- sizeof(newTexParams.fSwizzleRGBA)))) {
- this->setTextureSwizzle(unitIdx, target, newTexParams.fSwizzleRGBA);
- }
- texture->setCachedTexParams(newTexParams, this->getResetTimestamp());
-}
-
-void GrGLGpu::setTextureSwizzle(int unitIdx, GrGLenum target, const GrGLenum swizzle[]) {
- this->setTextureUnit(unitIdx);
- if (this->glStandard() == kGLES_GrGLStandard) {
- // ES3 added swizzle support but not GL_TEXTURE_SWIZZLE_RGBA.
- GL_CALL(TexParameteri(target, GR_GL_TEXTURE_SWIZZLE_R, swizzle[0]));
- GL_CALL(TexParameteri(target, GR_GL_TEXTURE_SWIZZLE_G, swizzle[1]));
- GL_CALL(TexParameteri(target, GR_GL_TEXTURE_SWIZZLE_B, swizzle[2]));
- GL_CALL(TexParameteri(target, GR_GL_TEXTURE_SWIZZLE_A, swizzle[3]));
- } else {
- GR_STATIC_ASSERT(sizeof(swizzle[0]) == sizeof(GrGLint));
- GL_CALL(TexParameteriv(target, GR_GL_TEXTURE_SWIZZLE_RGBA,
- reinterpret_cast<const GrGLint*>(swizzle)));
- }
+ texture->setCachedParams(samplerParamsToRecord, newNonSamplerParams, this->getResetTimestamp());
}
void GrGLGpu::flushColorWrite(bool writeColor) {
@@ -3854,12 +3945,15 @@
GrGLIRect viewport;
viewport.fLeft = 0;
viewport.fBottom = 0;
+
for (GrGLint level = 1; level < levelCount; ++level) {
// Get and bind the program for this particular downsample (filter shape can vary):
int progIdx = TextureSizeToMipmapProgramIdx(width, height);
if (!fMipmapPrograms[progIdx].fProgram) {
if (!this->createMipmapProgram(progIdx)) {
SkDebugf("Failed to create mipmap program.\n");
+ // Invalidate all params to cover base level change in a previous iteration.
+ glTex->textureParamsModified();
return false;
}
}
@@ -3892,7 +3986,10 @@
GR_GL_TEXTURE_2D, 0, 0));
// We modified the base level param.
- texture->textureParamsModified();
+ GrGLTexture::NonSamplerParams params = glTex->getCachedNonSamplerParams();
+ params.fBaseMipMapLevel = levelCount - 2; // we drew the 2nd to last level into the last level.
+ glTex->setCachedParams(nullptr, params, this->getResetTimestamp());
+
return true;
}
diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h
index 87f452f..1fa18c5 100644
--- a/src/gpu/gl/GrGLGpu.h
+++ b/src/gpu/gl/GrGLGpu.h
@@ -56,7 +56,7 @@
}
// Used by GrGLProgram to configure OpenGL state.
- void bindTexture(int unitIdx, const GrSamplerState& samplerState, GrGLTexture* texture);
+ void bindTexture(int unitIdx, GrSamplerState samplerState, GrGLTexture* texture);
// These functions should be used to bind GL objects. They track the GL state and skip redundant
// bindings. Making the equivalent glBind calls directly will confuse the state tracking.
@@ -208,7 +208,7 @@
// The texture is populated with |texels|, if it exists.
// The texture parameters are cached in |initialTexParams|.
bool createTextureImpl(const GrSurfaceDesc& desc, GrGLTextureInfo* info, bool renderTarget,
- GrGLTexture::TexParams* initialTexParams, const GrMipLevel texels[],
+ GrGLTexture::SamplerParams* initialTexParams, const GrMipLevel texels[],
int mipLevelCount, GrMipMapsStatus* mipMapsStatus);
// Checks whether glReadPixels can be called to get pixel values in readConfig from the
@@ -631,6 +631,9 @@
GrPrimitiveType fLastPrimitiveType;
bool fRequiresFlushBeforeNextInstancedDraw = false;
+ class SamplerObjectCache;
+ std::unique_ptr<SamplerObjectCache> fSamplerObjectCache;
+
std::unique_ptr<GrGLGpuRTCommandBuffer> fCachedRTCommandBuffer;
std::unique_ptr<GrGLGpuTextureCommandBuffer> fCachedTexCommandBuffer;
diff --git a/src/gpu/gl/GrGLTexture.cpp b/src/gpu/gl/GrGLTexture.cpp
index 7cdf505..47878da 100644
--- a/src/gpu/gl/GrGLTexture.cpp
+++ b/src/gpu/gl/GrGLTexture.cpp
@@ -68,8 +68,7 @@
void GrGLTexture::init(const GrSurfaceDesc& desc, const IDDesc& idDesc) {
SkASSERT(0 != idDesc.fInfo.fID);
SkASSERT(0 != idDesc.fInfo.fFormat);
- fTexParams.invalidate();
- fTexParamsTimestamp = GrGpu::kExpiredTimestamp;
+ fParamsTimestamp = GrGpu::kExpiredTimestamp;
fID = idDesc.fInfo.fID;
fFormat = idDesc.fInfo.fFormat;
fTextureIDOwnership = idDesc.fOwnership;
diff --git a/src/gpu/gl/GrGLTexture.h b/src/gpu/gl/GrGLTexture.h
index cb029cc..5f662e0 100644
--- a/src/gpu/gl/GrGLTexture.h
+++ b/src/gpu/gl/GrGLTexture.h
@@ -17,14 +17,37 @@
class GrGLTexture : public GrTexture {
public:
- struct TexParams {
- GrGLenum fMinFilter;
- GrGLenum fMagFilter;
- GrGLenum fWrapS;
- GrGLenum fWrapT;
- GrGLenum fMaxMipMapLevel;
- GrGLenum fSwizzleRGBA[4];
- void invalidate() { memset(this, 0xff, sizeof(TexParams)); }
+ // Texture state that overlaps with sampler object state. We don't need to track this if we
+ // are using sampler objects.
+ struct SamplerParams {
+ // These are the OpenGL defaults.
+ GrGLenum fMinFilter = GR_GL_NEAREST_MIPMAP_LINEAR;
+ GrGLenum fMagFilter = GR_GL_LINEAR;
+ GrGLenum fWrapS = GR_GL_REPEAT;
+ GrGLenum fWrapT = GR_GL_REPEAT;
+ GrGLfloat fMinLOD = -1000.f;
+ GrGLfloat fMaxLOD = 1000.f;
+ void invalidate() {
+ fMinFilter = ~0U;
+ fMagFilter = ~0U;
+ fWrapS = ~0U;
+ fWrapT = ~0U;
+ fMinLOD = SK_ScalarNaN;
+ fMaxLOD = SK_ScalarNaN;
+ }
+ };
+
+ // Texture state that does not overlap with sampler object state.
+ struct NonSamplerParams {
+ // These are the OpenGL defaults.
+ uint32_t fSwizzleKey = GrSwizzle::RGBA().asKey();
+ GrGLint fBaseMipMapLevel = 0;
+ GrGLint fMaxMipMapLevel = 1000;
+ void invalidate() {
+ fSwizzleKey = ~0U;
+ fBaseMipMapLevel = ~0;
+ fMaxMipMapLevel = ~0;
+ }
};
struct IDDesc {
@@ -43,22 +66,28 @@
GrBackendTexture getBackendTexture() const override;
- void textureParamsModified() override { fTexParams.invalidate(); }
+ void textureParamsModified() override {
+ fSamplerParams.invalidate();
+ fNonSamplerParams.invalidate();
+ }
void setRelease(sk_sp<GrReleaseProcHelper> releaseHelper) override {
fReleaseHelper = std::move(releaseHelper);
}
// These functions are used to track the texture parameters associated with the texture.
- const TexParams& getCachedTexParams(GrGpu::ResetTimestamp* timestamp) const {
- *timestamp = fTexParamsTimestamp;
- return fTexParams;
- }
+ GrGpu::ResetTimestamp getCachedParamsTimestamp() const { return fParamsTimestamp; }
+ const SamplerParams& getCachedSamplerParams() const { return fSamplerParams; }
+ const NonSamplerParams& getCachedNonSamplerParams() const { return fNonSamplerParams; }
- void setCachedTexParams(const TexParams& texParams,
- GrGpu::ResetTimestamp timestamp) {
- fTexParams = texParams;
- fTexParamsTimestamp = timestamp;
+ void setCachedParams(const SamplerParams* samplerParams,
+ const NonSamplerParams& nonSamplerParams,
+ GrGpu::ResetTimestamp currTimestamp) {
+ if (samplerParams) {
+ fSamplerParams = *samplerParams;
+ }
+ fNonSamplerParams = nonSamplerParams;
+ fParamsTimestamp = currTimestamp;
}
GrGLuint textureID() const { return fID; }
@@ -97,14 +126,14 @@
}
}
- TexParams fTexParams;
- GrGpu::ResetTimestamp fTexParamsTimestamp;
- GrGLuint fID;
- GrGLenum fFormat;
- GrBackendObjectOwnership fTextureIDOwnership;
- bool fBaseLevelHasBeenBoundToFBO = false;
-
- sk_sp<GrReleaseProcHelper> fReleaseHelper;
+ SamplerParams fSamplerParams;
+ NonSamplerParams fNonSamplerParams;
+ GrGpu::ResetTimestamp fParamsTimestamp;
+ sk_sp<GrReleaseProcHelper> fReleaseHelper;
+ GrGLuint fID;
+ GrGLenum fFormat;
+ GrBackendObjectOwnership fTextureIDOwnership;
+ bool fBaseLevelHasBeenBoundToFBO = false;
typedef GrTexture INHERITED;
};