diff --git a/src/core/SkSpecialImage.cpp b/src/core/SkSpecialImage.cpp index 48a144cdd86..2d719b331ad 100644 --- a/src/core/SkSpecialImage.cpp +++ b/src/core/SkSpecialImage.cpp @@ -61,6 +61,18 @@ sk_sp SkSpecialImage::asShader(SkTileMode tileMode, this->asImage(), subset, tileMode, tileMode, sampling, &subsetOrigin); } else { // Ignore 'subset' other than its origin translation applied to the local matrix. + // ===== POC INSTRUMENTATION ===== + SkISize backing = this->backingStoreDimensions(); + SkIRect sub = this->subset(); + if (backing.width() > sub.right() || backing.height() > sub.bottom()) { + SkDebugf("[POC] asShader strict=FALSE tileMode=%d subset=[%d,%d %dx%d] " + "backing=%dx%d -> HW-tiling at backing edge, %dx%d px past subset " + "is uninitialized scratch\n", + (int)tileMode, sub.left(), sub.top(), sub.width(), sub.height(), + backing.width(), backing.height(), + backing.width() - sub.right(), backing.height() - sub.bottom()); + } + // ===== END POC INSTRUMENTATION ===== return this->asImage()->makeShader(tileMode, tileMode, sampling, subsetOrigin); } } diff --git a/src/gpu/ganesh/GrSurfaceProxy.cpp b/src/gpu/ganesh/GrSurfaceProxy.cpp index 18dc73ddaf1..11fa6bc464e 100644 --- a/src/gpu/ganesh/GrSurfaceProxy.cpp +++ b/src/gpu/ganesh/GrSurfaceProxy.cpp @@ -416,9 +416,16 @@ void GrSurfaceProxyPriv::exactify() { // the proxy is instantiated, update the proxy's dimensions to match. Otherwise update them // to the backing-store dimensions. SkASSERT(SkBackingFit::kApprox == fProxy->fFit); + SkISize old = fProxy->fDimensions; fProxy->fDimensions = fProxy->fTarget ? fProxy->fTarget->dimensions() : fProxy->backingStoreDimensions(); fProxy->fFit = SkBackingFit::kExact; + if (old != fProxy->fDimensions) { + SkDebugf("[POC] exactify() widened proxy %dx%d -> %dx%d " + "(invariant 'sampling will not access beyond safe region' assumed)\n", + old.width(), old.height(), + fProxy->fDimensions.width(), fProxy->fDimensions.height()); + } } bool GrSurfaceProxyPriv::doLazyInstantiation(GrResourceProvider* resourceProvider) { diff --git a/src/gpu/ganesh/SurfaceFillContext.cpp b/src/gpu/ganesh/SurfaceFillContext.cpp index 32fc545f673..1ab0c71da97 100644 --- a/src/gpu/ganesh/SurfaceFillContext.cpp +++ b/src/gpu/ganesh/SurfaceFillContext.cpp @@ -232,6 +232,16 @@ void SurfaceFillContext::internalClear(const SkIRect* scissor, if (!scissorState.enabled()) { // This is a fullscreen clear, so could be handled as a load op. Regardless, we can also // discard all prior ops in the current task since the color buffer will be overwritten. + // ===== POC INSTRUMENTATION ===== + SkISize logical = this->dimensions(); + SkISize backing = this->asSurfaceProxy()->backingStoreDimensions(); + if (logical != backing) { + SkDebugf("[POC] internalClear FULLSCREEN (logical=%dx%d backing=%dx%d) " + "color=(%.2f,%.2f,%.2f,%.2f) -> kApprox padding IS cleared\n", + logical.width(), logical.height(), backing.width(), backing.height(), + color[0], color[1], color[2], color[3]); + } + // ===== END POC INSTRUMENTATION ===== auto opsTask = this->getOpsTask(); if (opsTask->resetForFullscreenClear(this->canDiscardPreviousOpsOnFullClear()) && !this->caps()->performColorClearsAsDraws()) { diff --git a/src/gpu/ganesh/image/GrImageUtils.cpp b/src/gpu/ganesh/image/GrImageUtils.cpp index 8fd9ea6a55e..b6e3bd1d9d9 100644 --- a/src/gpu/ganesh/image/GrImageUtils.cpp +++ b/src/gpu/ganesh/image/GrImageUtils.cpp @@ -756,15 +756,27 @@ public: kPremul_SkAlphaType, std::move(colorSpace)); - return fContext->priv().createDevice(skgpu::Budgeted::kYes, - imageInfo, - SkBackingFit::kApprox, - 1, - skgpu::Mipmapped::kNo, - GrProtected::kNo, - fOrigin, - props ? *props : this->surfaceProps(), - skgpu::ganesh::Device::InitContents::kUninit); + sk_sp dev = fContext->priv().createDevice( + skgpu::Budgeted::kYes, + imageInfo, + SkBackingFit::kApprox, + 1, + skgpu::Mipmapped::kNo, + GrProtected::kNo, + fOrigin, + props ? *props : this->surfaceProps(), + skgpu::ganesh::Device::InitContents::kUninit); + // ===== POC INSTRUMENTATION ===== + if (dev) { + auto* gdev = static_cast(dev.get()); + auto* sdc = gdev->surfaceDrawContext(); + SkISize backing = sdc->asSurfaceProxy()->backingStoreDimensions(); + SkDebugf("[POC] makeDevice logical=%dx%d backing=%dx%d (kApprox padding=%dx%d)\n", + size.width(), size.height(), backing.width(), backing.height(), + backing.width() - size.width(), backing.height() - size.height()); + } + // ===== END POC INSTRUMENTATION ===== + return dev; } sk_sp makeImage(const SkIRect& subset, sk_sp image) const override { @@ -808,15 +820,38 @@ public: // SkShaderBlurAlgorithm sk_sp makeDevice(const SkImageInfo& imageInfo) const override { - return fContext->priv().createDevice(skgpu::Budgeted::kYes, - imageInfo, - SkBackingFit::kApprox, - 1, - skgpu::Mipmapped::kNo, - GrProtected::kNo, - fOrigin, - this->surfaceProps(), - skgpu::ganesh::Device::InitContents::kUninit); + sk_sp dev = fContext->priv().createDevice( + skgpu::Budgeted::kYes, + imageInfo, + SkBackingFit::kApprox, + 1, + skgpu::Mipmapped::kNo, + GrProtected::kNo, + fOrigin, + this->surfaceProps(), + skgpu::ganesh::Device::InitContents::kUninit); + // ===== POC INSTRUMENTATION: simulate stale cross-origin scratch ===== + // SkShaderBlurAlgorithm::renderBlur() does NOT clear before drawing + // (unlike AutoSurface, which fullscreen-clears). The kApprox padding + // here retains whatever the recycled scratch resource last held. Fill + // the FULL backing with a sentinel so the leak is observable. + if (dev) { + auto* gdev = static_cast(dev.get()); + auto* sdc = gdev->surfaceDrawContext(); + SkISize backing = sdc->asSurfaceProxy()->backingStoreDimensions(); + SkDebugf("[POC] blur::makeDevice logical=%dx%d backing=%dx%d " + "(kApprox padding=%dx%d, NO clear -> uninit scratch)\n", + imageInfo.width(), imageInfo.height(), + backing.width(), backing.height(), + backing.width() - imageInfo.width(), + backing.height() - imageInfo.height()); + // Sentinel #C0FFEE. renderBlur()'s drawRect (with shader, kSrc) is + // clipped to dstRect = logical, so padding retains this. + sdc->clear(SkIRect::MakeSize(backing), + SkPMColor4f{0.7529f, 1.0f, 0.9333f, 1.0f}); + } + // ===== END POC INSTRUMENTATION ===== + return dev; } private: