c1ad77cf48
The callback lets the caller know when the data uploads to the texture from the create call are finished. This is important since the caller cannot delete the backend texture till the gpu is finished on vulkan and d3d. This change also removes the hard sync in vulkan during creation. Change-Id: I660d142219474e22b1337d2b0c81cda66fe18a4b Reviewed-on: https://skia-review.googlesource.com/c/skia/+/286517 Commit-Queue: Greg Daniel <egdaniel@google.com> Reviewed-by: Brian Salomon <bsalomon@google.com> Reviewed-by: Robert Phillips <robertphillips@google.com>
493 lines
23 KiB
C++
493 lines
23 KiB
C++
/*
|
|
* Copyright 2017 Google Inc.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
|
|
#include "include/core/SkTypes.h"
|
|
|
|
#include "include/core/SkCanvas.h"
|
|
#include "include/core/SkPoint.h"
|
|
#include "include/core/SkSurface.h"
|
|
#include "include/gpu/GrBackendSurface.h"
|
|
#include "include/gpu/GrContext.h"
|
|
#include "src/gpu/GrBackendTextureImageGenerator.h"
|
|
#include "src/gpu/GrContextPriv.h"
|
|
#include "src/gpu/GrDrawingManager.h"
|
|
#include "src/gpu/GrGpu.h"
|
|
#include "src/gpu/GrProxyProvider.h"
|
|
#include "src/gpu/GrRecordingContextPriv.h"
|
|
#include "src/gpu/GrRenderTargetContext.h"
|
|
#include "src/gpu/GrSemaphore.h"
|
|
#include "src/gpu/GrSurfaceProxyPriv.h"
|
|
#include "src/gpu/GrTexturePriv.h"
|
|
#include "src/gpu/GrTextureProxy.h"
|
|
#include "src/gpu/SkGpuDevice.h"
|
|
#include "src/image/SkImage_Base.h"
|
|
#include "src/image/SkSurface_Gpu.h"
|
|
#include "tests/Test.h"
|
|
#include "tests/TestUtils.h"
|
|
|
|
static constexpr int kSize = 8;
|
|
|
|
// Test that the correct mip map states are on the GrTextures when wrapping GrBackendTextures in
|
|
// SkImages and SkSurfaces
|
|
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrWrappedMipMappedTest, reporter, ctxInfo) {
|
|
GrContext* context = ctxInfo.grContext();
|
|
if (!context->priv().caps()->mipMapSupport()) {
|
|
return;
|
|
}
|
|
|
|
for (auto mipMapped : {GrMipMapped::kNo, GrMipMapped::kYes}) {
|
|
for (auto renderable : {GrRenderable::kNo, GrRenderable::kYes}) {
|
|
// createBackendTexture currently doesn't support uploading data to mip maps
|
|
// so we don't send any. However, we pretend there is data for the checks below which is
|
|
// fine since we are never actually using these textures for any work on the gpu.
|
|
GrBackendTexture backendTex;
|
|
CreateBackendTexture(context, &backendTex, kSize, kSize, kRGBA_8888_SkColorType,
|
|
SkColors::kTransparent, mipMapped, renderable);
|
|
|
|
sk_sp<GrTextureProxy> proxy;
|
|
sk_sp<SkImage> image;
|
|
if (GrRenderable::kYes == renderable) {
|
|
sk_sp<SkSurface> surface = SkSurface::MakeFromBackendTexture(
|
|
context,
|
|
backendTex,
|
|
kTopLeft_GrSurfaceOrigin,
|
|
0,
|
|
kRGBA_8888_SkColorType,
|
|
nullptr,
|
|
nullptr);
|
|
|
|
SkGpuDevice* device = ((SkSurface_Gpu*)surface.get())->getDevice();
|
|
proxy = device->accessRenderTargetContext()->asTextureProxyRef();
|
|
} else {
|
|
image = SkImage::MakeFromTexture(context, backendTex,
|
|
kTopLeft_GrSurfaceOrigin,
|
|
kRGBA_8888_SkColorType,
|
|
kPremul_SkAlphaType, nullptr,
|
|
nullptr, nullptr);
|
|
const GrSurfaceProxyView* view = as_IB(image)->view(context);
|
|
REPORTER_ASSERT(reporter, view);
|
|
if (!view) {
|
|
context->deleteBackendTexture(backendTex);
|
|
return;
|
|
}
|
|
proxy = view->asTextureProxyRef();
|
|
}
|
|
REPORTER_ASSERT(reporter, proxy);
|
|
if (!proxy) {
|
|
context->deleteBackendTexture(backendTex);
|
|
return;
|
|
}
|
|
|
|
REPORTER_ASSERT(reporter, proxy->isInstantiated());
|
|
|
|
GrTexture* texture = proxy->peekTexture();
|
|
REPORTER_ASSERT(reporter, texture);
|
|
if (!texture) {
|
|
context->deleteBackendTexture(backendTex);
|
|
return;
|
|
}
|
|
|
|
if (GrMipMapped::kYes == mipMapped) {
|
|
REPORTER_ASSERT(reporter, GrMipMapped::kYes == texture->texturePriv().mipMapped());
|
|
if (GrRenderable::kYes == renderable) {
|
|
REPORTER_ASSERT(reporter, texture->texturePriv().mipMapsAreDirty());
|
|
} else {
|
|
REPORTER_ASSERT(reporter, !texture->texturePriv().mipMapsAreDirty());
|
|
}
|
|
} else {
|
|
REPORTER_ASSERT(reporter, GrMipMapped::kNo == texture->texturePriv().mipMapped());
|
|
}
|
|
context->deleteBackendTexture(backendTex);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Test that we correctly copy or don't copy GrBackendTextures in the GrBackendTextureImageGenerator
|
|
// based on if we will use mips in the draw and the mip status of the GrBackendTexture.
|
|
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrBackendTextureImageMipMappedTest, reporter, ctxInfo) {
|
|
GrContext* context = ctxInfo.grContext();
|
|
if (!context->priv().caps()->mipMapSupport()) {
|
|
return;
|
|
}
|
|
|
|
for (auto betMipMapped : {GrMipMapped::kNo, GrMipMapped::kYes}) {
|
|
for (auto requestMipMapped : {GrMipMapped::kNo, GrMipMapped::kYes}) {
|
|
GrBackendTexture backendTex;
|
|
CreateBackendTexture(context, &backendTex, kSize, kSize, kRGBA_8888_SkColorType,
|
|
SkColors::kTransparent, betMipMapped, GrRenderable::kNo);
|
|
|
|
sk_sp<SkImage> image = SkImage::MakeFromTexture(context, backendTex,
|
|
kTopLeft_GrSurfaceOrigin,
|
|
kRGBA_8888_SkColorType,
|
|
kPremul_SkAlphaType, nullptr,
|
|
nullptr, nullptr);
|
|
|
|
GrTextureProxy* proxy = as_IB(image)->peekProxy();
|
|
REPORTER_ASSERT(reporter, proxy);
|
|
if (!proxy) {
|
|
context->deleteBackendTexture(backendTex);
|
|
return;
|
|
}
|
|
|
|
REPORTER_ASSERT(reporter, proxy->isInstantiated());
|
|
|
|
sk_sp<GrTexture> texture = sk_ref_sp(proxy->peekTexture());
|
|
REPORTER_ASSERT(reporter, texture);
|
|
if (!texture) {
|
|
context->deleteBackendTexture(backendTex);
|
|
return;
|
|
}
|
|
|
|
std::unique_ptr<SkImageGenerator> imageGen = GrBackendTextureImageGenerator::Make(
|
|
texture, kTopLeft_GrSurfaceOrigin, nullptr, kRGBA_8888_SkColorType,
|
|
kPremul_SkAlphaType, nullptr);
|
|
REPORTER_ASSERT(reporter, imageGen);
|
|
if (!imageGen) {
|
|
context->deleteBackendTexture(backendTex);
|
|
return;
|
|
}
|
|
|
|
SkIPoint origin = SkIPoint::Make(0,0);
|
|
SkImageInfo imageInfo = SkImageInfo::Make(kSize, kSize, kRGBA_8888_SkColorType,
|
|
kPremul_SkAlphaType);
|
|
GrSurfaceProxyView genView = imageGen->generateTexture(
|
|
context, imageInfo, origin, requestMipMapped, GrImageTexGenPolicy::kDraw);
|
|
GrSurfaceProxy* genProxy = genView.proxy();
|
|
|
|
REPORTER_ASSERT(reporter, genProxy);
|
|
if (!genProxy) {
|
|
context->deleteBackendTexture(backendTex);
|
|
return;
|
|
}
|
|
|
|
if (genProxy->isLazy()) {
|
|
genProxy->priv().doLazyInstantiation(context->priv().resourceProvider());
|
|
} else if (!genProxy->isInstantiated()) {
|
|
genProxy->instantiate(context->priv().resourceProvider());
|
|
}
|
|
|
|
REPORTER_ASSERT(reporter, genProxy->isInstantiated());
|
|
if (!genProxy->isInstantiated()) {
|
|
context->deleteBackendTexture(backendTex);
|
|
return;
|
|
}
|
|
|
|
GrTexture* genTexture = genProxy->peekTexture();
|
|
REPORTER_ASSERT(reporter, genTexture);
|
|
if (!genTexture) {
|
|
context->deleteBackendTexture(backendTex);
|
|
return;
|
|
}
|
|
|
|
GrBackendTexture genBackendTex = genTexture->getBackendTexture();
|
|
|
|
if (GrBackendApi::kOpenGL == genBackendTex.backend()) {
|
|
GrGLTextureInfo genTexInfo;
|
|
GrGLTextureInfo origTexInfo;
|
|
if (genBackendTex.getGLTextureInfo(&genTexInfo) &&
|
|
backendTex.getGLTextureInfo(&origTexInfo)) {
|
|
if (requestMipMapped == GrMipMapped::kYes && betMipMapped == GrMipMapped::kNo) {
|
|
// We did a copy so the texture IDs should be different
|
|
REPORTER_ASSERT(reporter, origTexInfo.fID != genTexInfo.fID);
|
|
} else {
|
|
REPORTER_ASSERT(reporter, origTexInfo.fID == genTexInfo.fID);
|
|
}
|
|
} else {
|
|
ERRORF(reporter, "Failed to get GrGLTextureInfo");
|
|
}
|
|
#ifdef SK_VULKAN
|
|
} else if (GrBackendApi::kVulkan == genBackendTex.backend()) {
|
|
GrVkImageInfo genImageInfo;
|
|
GrVkImageInfo origImageInfo;
|
|
if (genBackendTex.getVkImageInfo(&genImageInfo) &&
|
|
backendTex.getVkImageInfo(&origImageInfo)) {
|
|
if (requestMipMapped == GrMipMapped::kYes && betMipMapped == GrMipMapped::kNo) {
|
|
// We did a copy so the texture IDs should be different
|
|
REPORTER_ASSERT(reporter, origImageInfo.fImage != genImageInfo.fImage);
|
|
} else {
|
|
REPORTER_ASSERT(reporter, origImageInfo.fImage == genImageInfo.fImage);
|
|
}
|
|
} else {
|
|
ERRORF(reporter, "Failed to get GrVkImageInfo");
|
|
}
|
|
#endif
|
|
#ifdef SK_METAL
|
|
} else if (GrBackendApi::kMetal == genBackendTex.backend()) {
|
|
GrMtlTextureInfo genImageInfo;
|
|
GrMtlTextureInfo origImageInfo;
|
|
if (genBackendTex.getMtlTextureInfo(&genImageInfo) &&
|
|
backendTex.getMtlTextureInfo(&origImageInfo)) {
|
|
if (requestMipMapped == GrMipMapped::kYes && betMipMapped == GrMipMapped::kNo) {
|
|
// We did a copy so the texture IDs should be different
|
|
REPORTER_ASSERT(reporter, origImageInfo.fTexture != genImageInfo.fTexture);
|
|
} else {
|
|
REPORTER_ASSERT(reporter, origImageInfo.fTexture == genImageInfo.fTexture);
|
|
}
|
|
} else {
|
|
ERRORF(reporter, "Failed to get GrMtlTextureInfo");
|
|
}
|
|
#endif
|
|
} else {
|
|
REPORTER_ASSERT(reporter, false);
|
|
}
|
|
|
|
// Must make sure the uses of the backend texture have finished (we possibly have a
|
|
// queued up copy) before we delete the backend texture.
|
|
context->flush();
|
|
|
|
context->priv().getGpu()->testingOnly_flushGpuAndSync();
|
|
|
|
context->deleteBackendTexture(backendTex);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Test that when we call makeImageSnapshot on an SkSurface we retains the same mip status as the
|
|
// resource we took the snapshot of.
|
|
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrImageSnapshotMipMappedTest, reporter, ctxInfo) {
|
|
GrContext* context = ctxInfo.grContext();
|
|
if (!context->priv().caps()->mipMapSupport()) {
|
|
return;
|
|
}
|
|
|
|
auto resourceProvider = context->priv().resourceProvider();
|
|
|
|
for (auto willUseMips : {false, true}) {
|
|
for (auto isWrapped : {false, true}) {
|
|
GrMipMapped mipMapped = willUseMips ? GrMipMapped::kYes : GrMipMapped::kNo;
|
|
sk_sp<SkSurface> surface;
|
|
GrBackendTexture backendTex;
|
|
CreateBackendTexture(context, &backendTex, kSize, kSize, kRGBA_8888_SkColorType,
|
|
SkColors::kTransparent, mipMapped, GrRenderable::kYes);
|
|
if (isWrapped) {
|
|
surface = SkSurface::MakeFromBackendTexture(context,
|
|
backendTex,
|
|
kTopLeft_GrSurfaceOrigin,
|
|
0,
|
|
kRGBA_8888_SkColorType,
|
|
nullptr,
|
|
nullptr);
|
|
} else {
|
|
SkImageInfo info = SkImageInfo::Make(kSize, kSize, kRGBA_8888_SkColorType,
|
|
kPremul_SkAlphaType);
|
|
surface = SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, info, 0,
|
|
kTopLeft_GrSurfaceOrigin, nullptr,
|
|
willUseMips);
|
|
}
|
|
REPORTER_ASSERT(reporter, surface);
|
|
if (!surface) {
|
|
context->deleteBackendTexture(backendTex);
|
|
}
|
|
SkGpuDevice* device = ((SkSurface_Gpu*)surface.get())->getDevice();
|
|
GrTextureProxy* texProxy = device->accessRenderTargetContext()->asTextureProxy();
|
|
REPORTER_ASSERT(reporter, mipMapped == texProxy->mipMapped());
|
|
|
|
texProxy->instantiate(resourceProvider);
|
|
GrTexture* texture = texProxy->peekTexture();
|
|
REPORTER_ASSERT(reporter, mipMapped == texture->texturePriv().mipMapped());
|
|
|
|
sk_sp<SkImage> image = surface->makeImageSnapshot();
|
|
REPORTER_ASSERT(reporter, image);
|
|
if (!image) {
|
|
context->deleteBackendTexture(backendTex);
|
|
}
|
|
texProxy = as_IB(image)->peekProxy();
|
|
REPORTER_ASSERT(reporter, mipMapped == texProxy->mipMapped());
|
|
|
|
texProxy->instantiate(resourceProvider);
|
|
texture = texProxy->peekTexture();
|
|
REPORTER_ASSERT(reporter, mipMapped == texture->texturePriv().mipMapped());
|
|
|
|
// Must flush the context to make sure all the cmds (copies, etc.) from above are sent
|
|
// to the gpu before we delete the backendHandle.
|
|
context->flush();
|
|
context->priv().getGpu()->testingOnly_flushGpuAndSync();
|
|
context->deleteBackendTexture(backendTex);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Test that we don't create a mip mapped texture if the size is 1x1 even if the filter mode is set
|
|
// to use mips. This test passes by not crashing or hitting asserts in code.
|
|
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(Gr1x1TextureMipMappedTest, reporter, ctxInfo) {
|
|
GrContext* context = ctxInfo.grContext();
|
|
if (!context->priv().caps()->mipMapSupport()) {
|
|
return;
|
|
}
|
|
|
|
// Make surface to draw into
|
|
SkImageInfo info = SkImageInfo::MakeN32(16, 16, kPremul_SkAlphaType);
|
|
sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info);
|
|
|
|
// Make 1x1 raster bitmap
|
|
SkBitmap bmp;
|
|
bmp.allocN32Pixels(1, 1);
|
|
SkPMColor* pixel = reinterpret_cast<SkPMColor*>(bmp.getPixels());
|
|
*pixel = 0;
|
|
|
|
sk_sp<SkImage> bmpImage = SkImage::MakeFromBitmap(bmp);
|
|
|
|
// Make sure we scale so we don't optimize out the use of mips.
|
|
surface->getCanvas()->scale(0.5f, 0.5f);
|
|
|
|
SkPaint paint;
|
|
// This should upload the image to a non mipped GrTextureProxy.
|
|
surface->getCanvas()->drawImage(bmpImage, 0, 0, &paint);
|
|
surface->flush();
|
|
|
|
// Now set the filter quality to high so we use mip maps. We should find the non mipped texture
|
|
// in the cache for the SkImage. Since the texture is 1x1 we should just use that texture
|
|
// instead of trying to do a copy to a mipped texture.
|
|
paint.setFilterQuality(kHigh_SkFilterQuality);
|
|
surface->getCanvas()->drawImage(bmpImage, 0, 0, &paint);
|
|
surface->flush();
|
|
}
|
|
|
|
// Create a new render target and draw 'mipmapView' into it using the provided 'filter'.
|
|
static std::unique_ptr<GrRenderTargetContext> draw_mipmap_into_new_render_target(
|
|
GrRecordingContext* context, GrProxyProvider* proxyProvider, GrColorType colorType,
|
|
SkAlphaType alphaType, GrSurfaceProxyView mipmapView, GrSamplerState::Filter filter) {
|
|
sk_sp<GrSurfaceProxy> renderTarget = proxyProvider->createProxy(
|
|
mipmapView.proxy()->backendFormat(), {1, 1}, GrRenderable::kYes, 1, GrMipMapped::kNo,
|
|
SkBackingFit::kApprox, SkBudgeted::kYes, GrProtected::kNo);
|
|
|
|
auto rtc = GrRenderTargetContext::Make(
|
|
context, colorType, nullptr, std::move(renderTarget), kTopLeft_GrSurfaceOrigin,
|
|
nullptr);
|
|
|
|
rtc->drawTexture(GrNoClip(), std::move(mipmapView), alphaType, filter, SkBlendMode::kSrcOver,
|
|
{1,1,1,1}, SkRect::MakeWH(4, 4), SkRect::MakeWH(1,1), GrAA::kYes,
|
|
GrQuadAAFlags::kAll, SkCanvas::kFast_SrcRectConstraint, SkMatrix::I(),
|
|
nullptr);
|
|
return rtc;
|
|
}
|
|
|
|
// Test that two opsTasks using the same mipmaps both depend on the same GrTextureResolveRenderTask.
|
|
DEF_GPUTEST(GrManyDependentsMipMappedTest, reporter, /* options */) {
|
|
using CanClearFullscreen = GrRenderTargetContext::CanClearFullscreen;
|
|
using Enable = GrContextOptions::Enable;
|
|
using Filter = GrSamplerState::Filter;
|
|
|
|
for (auto enableSortingAndReduction : {Enable::kYes, Enable::kNo}) {
|
|
GrMockOptions mockOptions;
|
|
mockOptions.fMipMapSupport = true;
|
|
GrContextOptions ctxOptions;
|
|
ctxOptions.fReduceOpsTaskSplitting = enableSortingAndReduction;
|
|
sk_sp<GrContext> context = GrContext::MakeMock(&mockOptions, ctxOptions);
|
|
if (!context) {
|
|
ERRORF(reporter, "could not create mock context with fReduceOpsTaskSplitting %s.",
|
|
(Enable::kYes == enableSortingAndReduction) ? "enabled" : "disabled");
|
|
continue;
|
|
}
|
|
|
|
SkASSERT(context->priv().caps()->mipMapSupport());
|
|
|
|
GrBackendFormat format = context->defaultBackendFormat(
|
|
kRGBA_8888_SkColorType, GrRenderable::kYes);
|
|
GrColorType colorType = GrColorType::kRGBA_8888;
|
|
SkAlphaType alphaType = kPremul_SkAlphaType;
|
|
|
|
GrProxyProvider* proxyProvider = context->priv().proxyProvider();
|
|
|
|
// Create a mipmapped render target.
|
|
|
|
sk_sp<GrTextureProxy> mipmapProxy = proxyProvider->createProxy(
|
|
format, {4, 4}, GrRenderable::kYes, 1, GrMipMapped::kYes, SkBackingFit::kExact,
|
|
SkBudgeted::kYes, GrProtected::kNo);
|
|
|
|
// Mark the mipmaps clean to ensure things still work properly when they won't be marked
|
|
// dirty again until GrRenderTask::makeClosed().
|
|
mipmapProxy->markMipMapsClean();
|
|
|
|
auto mipmapRTC = GrRenderTargetContext::Make(
|
|
context.get(), colorType, nullptr, mipmapProxy, kTopLeft_GrSurfaceOrigin, nullptr);
|
|
|
|
mipmapRTC->clear(nullptr, {.1f,.2f,.3f,.4f}, CanClearFullscreen::kYes);
|
|
REPORTER_ASSERT(reporter, mipmapProxy->getLastRenderTask());
|
|
// mipmapProxy's last render task should now just be the opsTask containing the clear.
|
|
REPORTER_ASSERT(reporter,
|
|
mipmapRTC->testingOnly_PeekLastOpsTask() == mipmapProxy->getLastRenderTask());
|
|
|
|
// Mipmaps don't get marked dirty until makeClosed().
|
|
REPORTER_ASSERT(reporter, !mipmapProxy->mipMapsAreDirty());
|
|
|
|
GrSwizzle swizzle = context->priv().caps()->getReadSwizzle(format, colorType);
|
|
GrSurfaceProxyView mipmapView(mipmapProxy, kTopLeft_GrSurfaceOrigin, swizzle);
|
|
|
|
// Draw the dirty mipmap texture into a render target.
|
|
auto rtc1 = draw_mipmap_into_new_render_target(context.get(), proxyProvider, colorType,
|
|
alphaType, mipmapView, Filter::kMipMap);
|
|
auto rtc1Task = sk_ref_sp(rtc1->testingOnly_PeekLastOpsTask());
|
|
|
|
// Mipmaps should have gotten marked dirty during makeClosed, then marked clean again as
|
|
// soon as a GrTextureResolveRenderTask was inserted. The way we know they were resolved is
|
|
// if mipmapProxy->getLastRenderTask() has switched from the opsTask that drew to it, to the
|
|
// task that resolved its mips.
|
|
GrRenderTask* initialMipmapRegenTask = mipmapProxy->getLastRenderTask();
|
|
REPORTER_ASSERT(reporter, initialMipmapRegenTask);
|
|
REPORTER_ASSERT(reporter,
|
|
initialMipmapRegenTask != mipmapRTC->testingOnly_PeekLastOpsTask());
|
|
REPORTER_ASSERT(reporter, !mipmapProxy->mipMapsAreDirty());
|
|
|
|
// Draw the now-clean mipmap texture into a second target.
|
|
auto rtc2 = draw_mipmap_into_new_render_target(context.get(), proxyProvider, colorType,
|
|
alphaType, mipmapView, Filter::kMipMap);
|
|
auto rtc2Task = sk_ref_sp(rtc2->testingOnly_PeekLastOpsTask());
|
|
|
|
// Make sure the mipmap texture still has the same regen task.
|
|
REPORTER_ASSERT(reporter, mipmapProxy->getLastRenderTask() == initialMipmapRegenTask);
|
|
SkASSERT(!mipmapProxy->mipMapsAreDirty());
|
|
|
|
// Reset everything so we can go again, this time with the first draw not mipmapped.
|
|
context->flush();
|
|
|
|
// Mip regen tasks don't get added as dependencies until makeClosed().
|
|
REPORTER_ASSERT(reporter, rtc1Task->dependsOn(initialMipmapRegenTask));
|
|
REPORTER_ASSERT(reporter, rtc2Task->dependsOn(initialMipmapRegenTask));
|
|
|
|
// Render something to dirty the mips.
|
|
mipmapRTC->clear(nullptr, {.1f,.2f,.3f,.4f}, CanClearFullscreen::kYes);
|
|
auto mipmapRTCTask = sk_ref_sp(mipmapRTC->testingOnly_PeekLastOpsTask());
|
|
REPORTER_ASSERT(reporter, mipmapRTCTask);
|
|
|
|
// mipmapProxy's last render task should now just be the opsTask containing the clear.
|
|
REPORTER_ASSERT(reporter, mipmapRTCTask.get() == mipmapProxy->getLastRenderTask());
|
|
|
|
// Mipmaps don't get marked dirty until makeClosed().
|
|
REPORTER_ASSERT(reporter, !mipmapProxy->mipMapsAreDirty());
|
|
|
|
// Draw the dirty mipmap texture into a render target, but don't do mipmap filtering.
|
|
rtc1 = draw_mipmap_into_new_render_target(context.get(), proxyProvider, colorType,
|
|
alphaType, mipmapView, Filter::kBilerp);
|
|
|
|
// Mipmaps should have gotten marked dirty during makeClosed() when adding the dependency.
|
|
// Since the last draw did not use mips, they will not have been regenerated and should
|
|
// therefore still be dirty.
|
|
REPORTER_ASSERT(reporter, mipmapProxy->mipMapsAreDirty());
|
|
|
|
// Since mips weren't regenerated, the last render task shouldn't have changed.
|
|
REPORTER_ASSERT(reporter, mipmapRTCTask.get() == mipmapProxy->getLastRenderTask());
|
|
|
|
// Draw the stil-dirty mipmap texture into a second target with mipmap filtering.
|
|
rtc2 = draw_mipmap_into_new_render_target(context.get(), proxyProvider, colorType,
|
|
alphaType, std::move(mipmapView),
|
|
Filter::kMipMap);
|
|
rtc2Task = sk_ref_sp(rtc2->testingOnly_PeekLastOpsTask());
|
|
|
|
// Make sure the mipmap texture now has a new last render task that regenerates the mips,
|
|
// and that the mipmaps are now clean.
|
|
auto mipRegenTask2 = mipmapProxy->getLastRenderTask();
|
|
REPORTER_ASSERT(reporter, mipRegenTask2);
|
|
REPORTER_ASSERT(reporter, mipmapRTCTask.get() != mipRegenTask2);
|
|
SkASSERT(!mipmapProxy->mipMapsAreDirty());
|
|
|
|
// Mip regen tasks don't get added as dependencies until makeClosed().
|
|
context->flush();
|
|
REPORTER_ASSERT(reporter, rtc2Task->dependsOn(mipRegenTask2));
|
|
}
|
|
}
|