2017-10-12 16:27:11 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2017 Google Inc.
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
|
|
* found in the LICENSE file.
|
|
|
|
*/
|
|
|
|
|
2019-04-23 17:05:21 +00:00
|
|
|
#include "include/core/SkTypes.h"
|
2017-10-12 16:27:11 +00:00
|
|
|
|
2019-04-23 17:05:21 +00:00
|
|
|
#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"
|
2019-08-14 15:24:37 +00:00
|
|
|
#include "src/gpu/GrDrawingManager.h"
|
2019-04-23 17:05:21 +00:00
|
|
|
#include "src/gpu/GrGpu.h"
|
|
|
|
#include "src/gpu/GrRenderTargetContext.h"
|
|
|
|
#include "src/gpu/GrSemaphore.h"
|
|
|
|
#include "src/gpu/GrSurfaceProxyPriv.h"
|
|
|
|
#include "src/gpu/GrTexturePriv.h"
|
2019-06-18 13:58:02 +00:00
|
|
|
#include "src/gpu/GrTextureProxy.h"
|
2019-04-23 17:05:21 +00:00
|
|
|
#include "src/gpu/SkGpuDevice.h"
|
|
|
|
#include "src/image/SkImage_Base.h"
|
|
|
|
#include "src/image/SkSurface_Gpu.h"
|
|
|
|
#include "tests/Test.h"
|
2017-10-12 16:27:11 +00:00
|
|
|
|
2017-10-30 17:41:26 +00:00
|
|
|
static constexpr int kSize = 8;
|
|
|
|
|
2017-10-12 16:27:11 +00:00
|
|
|
// 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();
|
2019-02-04 18:26:26 +00:00
|
|
|
if (!context->priv().caps()->mipMapSupport()) {
|
2017-10-23 13:37:36 +00:00
|
|
|
return;
|
|
|
|
}
|
2018-01-22 15:48:15 +00:00
|
|
|
|
2017-10-12 16:27:11 +00:00
|
|
|
for (auto mipMapped : {GrMipMapped::kNo, GrMipMapped::kYes}) {
|
2019-05-13 14:40:06 +00:00
|
|
|
for (auto renderable : {GrRenderable::kNo, GrRenderable::kYes}) {
|
2019-05-17 14:01:21 +00:00
|
|
|
// createBackendTexture currently doesn't support uploading data to mip maps
|
2017-10-12 16:27:11 +00:00
|
|
|
// 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.
|
2019-06-04 15:03:06 +00:00
|
|
|
GrBackendTexture backendTex = context->createBackendTexture(
|
2019-06-04 11:16:10 +00:00
|
|
|
kSize, kSize, kRGBA_8888_SkColorType,
|
2019-07-01 19:04:06 +00:00
|
|
|
SkColors::kTransparent, mipMapped, renderable, GrProtected::kNo);
|
2017-10-12 16:27:11 +00:00
|
|
|
|
2017-11-13 17:47:24 +00:00
|
|
|
sk_sp<GrTextureProxy> proxy;
|
2017-10-12 16:27:11 +00:00
|
|
|
sk_sp<SkImage> image;
|
2019-05-13 14:40:06 +00:00
|
|
|
if (GrRenderable::kYes == renderable) {
|
2017-10-12 16:27:11 +00:00
|
|
|
sk_sp<SkSurface> surface = SkSurface::MakeFromBackendTexture(
|
|
|
|
context,
|
|
|
|
backendTex,
|
|
|
|
kTopLeft_GrSurfaceOrigin,
|
|
|
|
0,
|
2017-12-19 18:15:02 +00:00
|
|
|
kRGBA_8888_SkColorType,
|
2017-10-12 16:27:11 +00:00
|
|
|
nullptr,
|
|
|
|
nullptr);
|
|
|
|
|
|
|
|
SkGpuDevice* device = ((SkSurface_Gpu*)surface.get())->getDevice();
|
2017-11-13 17:47:24 +00:00
|
|
|
proxy = device->accessRenderTargetContext()->asTextureProxyRef();
|
2017-10-12 16:27:11 +00:00
|
|
|
} else {
|
|
|
|
image = SkImage::MakeFromTexture(context, backendTex,
|
|
|
|
kTopLeft_GrSurfaceOrigin,
|
2017-12-18 19:48:15 +00:00
|
|
|
kRGBA_8888_SkColorType,
|
|
|
|
kPremul_SkAlphaType, nullptr,
|
|
|
|
nullptr, nullptr);
|
2019-03-05 17:35:44 +00:00
|
|
|
proxy = as_IB(image)->asTextureProxyRef(context);
|
2017-10-12 16:27:11 +00:00
|
|
|
}
|
|
|
|
REPORTER_ASSERT(reporter, proxy);
|
|
|
|
if (!proxy) {
|
2019-05-20 12:38:07 +00:00
|
|
|
context->deleteBackendTexture(backendTex);
|
2017-10-12 16:27:11 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-07-31 21:25:29 +00:00
|
|
|
REPORTER_ASSERT(reporter, proxy->isInstantiated());
|
2017-10-12 16:27:11 +00:00
|
|
|
|
2018-07-31 21:25:29 +00:00
|
|
|
GrTexture* texture = proxy->peekTexture();
|
2017-10-12 16:27:11 +00:00
|
|
|
REPORTER_ASSERT(reporter, texture);
|
|
|
|
if (!texture) {
|
2019-05-20 12:38:07 +00:00
|
|
|
context->deleteBackendTexture(backendTex);
|
2017-10-12 16:27:11 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (GrMipMapped::kYes == mipMapped) {
|
2017-10-23 20:05:23 +00:00
|
|
|
REPORTER_ASSERT(reporter, GrMipMapped::kYes == texture->texturePriv().mipMapped());
|
2019-05-13 14:40:06 +00:00
|
|
|
if (GrRenderable::kYes == renderable) {
|
2017-10-12 16:27:11 +00:00
|
|
|
REPORTER_ASSERT(reporter, texture->texturePriv().mipMapsAreDirty());
|
|
|
|
} else {
|
|
|
|
REPORTER_ASSERT(reporter, !texture->texturePriv().mipMapsAreDirty());
|
|
|
|
}
|
|
|
|
} else {
|
2017-10-23 20:05:23 +00:00
|
|
|
REPORTER_ASSERT(reporter, GrMipMapped::kNo == texture->texturePriv().mipMapped());
|
2017-10-12 16:27:11 +00:00
|
|
|
}
|
2019-05-20 12:38:07 +00:00
|
|
|
context->deleteBackendTexture(backendTex);
|
2017-10-12 16:27:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-23 13:37:36 +00:00
|
|
|
// 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();
|
2019-02-04 18:26:26 +00:00
|
|
|
if (!context->priv().caps()->mipMapSupport()) {
|
2017-10-23 13:37:36 +00:00
|
|
|
return;
|
|
|
|
}
|
2018-01-22 15:48:15 +00:00
|
|
|
|
2017-10-23 13:37:36 +00:00
|
|
|
for (auto mipMapped : {GrMipMapped::kNo, GrMipMapped::kYes}) {
|
|
|
|
for (auto willUseMips : {false, true}) {
|
2019-06-04 15:03:06 +00:00
|
|
|
GrBackendTexture backendTex = context->createBackendTexture(
|
2019-06-04 11:16:10 +00:00
|
|
|
kSize, kSize, kRGBA_8888_SkColorType,
|
2019-07-01 19:04:06 +00:00
|
|
|
SkColors::kTransparent, mipMapped, GrRenderable::kNo, GrProtected::kNo);
|
2017-10-23 13:37:36 +00:00
|
|
|
|
|
|
|
sk_sp<SkImage> image = SkImage::MakeFromTexture(context, backendTex,
|
|
|
|
kTopLeft_GrSurfaceOrigin,
|
2017-12-18 19:48:15 +00:00
|
|
|
kRGBA_8888_SkColorType,
|
|
|
|
kPremul_SkAlphaType, nullptr,
|
|
|
|
nullptr, nullptr);
|
2017-10-23 13:37:36 +00:00
|
|
|
|
|
|
|
GrTextureProxy* proxy = as_IB(image)->peekProxy();
|
|
|
|
REPORTER_ASSERT(reporter, proxy);
|
|
|
|
if (!proxy) {
|
2019-05-20 12:38:07 +00:00
|
|
|
context->deleteBackendTexture(backendTex);
|
2017-10-23 13:37:36 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-07-31 21:25:29 +00:00
|
|
|
REPORTER_ASSERT(reporter, proxy->isInstantiated());
|
2017-10-23 13:37:36 +00:00
|
|
|
|
2018-07-31 21:25:29 +00:00
|
|
|
sk_sp<GrTexture> texture = sk_ref_sp(proxy->peekTexture());
|
2017-10-23 13:37:36 +00:00
|
|
|
REPORTER_ASSERT(reporter, texture);
|
|
|
|
if (!texture) {
|
2019-05-20 12:38:07 +00:00
|
|
|
context->deleteBackendTexture(backendTex);
|
2017-10-23 13:37:36 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::unique_ptr<SkImageGenerator> imageGen = GrBackendTextureImageGenerator::Make(
|
2018-03-27 13:56:31 +00:00
|
|
|
texture, kTopLeft_GrSurfaceOrigin, nullptr, kRGBA_8888_SkColorType,
|
|
|
|
kPremul_SkAlphaType, nullptr);
|
2017-10-23 13:37:36 +00:00
|
|
|
REPORTER_ASSERT(reporter, imageGen);
|
|
|
|
if (!imageGen) {
|
2019-05-20 12:38:07 +00:00
|
|
|
context->deleteBackendTexture(backendTex);
|
2017-10-23 13:37:36 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
SkIPoint origin = SkIPoint::Make(0,0);
|
|
|
|
SkImageInfo imageInfo = SkImageInfo::Make(kSize, kSize, kRGBA_8888_SkColorType,
|
|
|
|
kPremul_SkAlphaType);
|
|
|
|
sk_sp<GrTextureProxy> genProxy = imageGen->generateTexture(context, imageInfo,
|
2018-07-11 13:08:46 +00:00
|
|
|
origin, willUseMips);
|
2017-10-23 13:37:36 +00:00
|
|
|
|
|
|
|
REPORTER_ASSERT(reporter, genProxy);
|
|
|
|
if (!genProxy) {
|
2019-05-20 12:38:07 +00:00
|
|
|
context->deleteBackendTexture(backendTex);
|
2017-10-23 13:37:36 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-08-30 20:19:42 +00:00
|
|
|
if (genProxy->isLazy()) {
|
2019-02-04 18:26:26 +00:00
|
|
|
genProxy->priv().doLazyInstantiation(context->priv().resourceProvider());
|
2018-07-31 21:25:29 +00:00
|
|
|
} else if (!genProxy->isInstantiated()) {
|
2019-02-04 18:26:26 +00:00
|
|
|
genProxy->instantiate(context->priv().resourceProvider());
|
2018-01-17 15:52:04 +00:00
|
|
|
}
|
|
|
|
|
2018-07-31 21:25:29 +00:00
|
|
|
REPORTER_ASSERT(reporter, genProxy->isInstantiated());
|
|
|
|
if (!genProxy->isInstantiated()) {
|
2019-05-20 12:38:07 +00:00
|
|
|
context->deleteBackendTexture(backendTex);
|
2018-01-24 18:22:24 +00:00
|
|
|
return;
|
|
|
|
}
|
2017-10-23 13:37:36 +00:00
|
|
|
|
2018-07-31 21:25:29 +00:00
|
|
|
GrTexture* genTexture = genProxy->peekTexture();
|
2017-10-23 13:37:36 +00:00
|
|
|
REPORTER_ASSERT(reporter, genTexture);
|
|
|
|
if (!genTexture) {
|
2019-05-20 12:38:07 +00:00
|
|
|
context->deleteBackendTexture(backendTex);
|
2017-10-23 13:37:36 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-12-13 20:00:45 +00:00
|
|
|
GrBackendTexture genBackendTex = genTexture->getBackendTexture();
|
2017-10-23 13:37:36 +00:00
|
|
|
|
2018-10-12 13:31:11 +00:00
|
|
|
if (GrBackendApi::kOpenGL == genBackendTex.backend()) {
|
2018-04-10 13:34:07 +00:00
|
|
|
GrGLTextureInfo genTexInfo;
|
|
|
|
GrGLTextureInfo origTexInfo;
|
|
|
|
if (genBackendTex.getGLTextureInfo(&genTexInfo) &&
|
|
|
|
backendTex.getGLTextureInfo(&origTexInfo)) {
|
|
|
|
if (willUseMips && GrMipMapped::kNo == mipMapped) {
|
|
|
|
// 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);
|
|
|
|
}
|
2017-10-23 13:37:36 +00:00
|
|
|
} else {
|
2018-04-10 13:34:07 +00:00
|
|
|
ERRORF(reporter, "Failed to get GrGLTextureInfo");
|
2017-10-23 13:37:36 +00:00
|
|
|
}
|
|
|
|
#ifdef SK_VULKAN
|
2018-10-12 13:31:11 +00:00
|
|
|
} else if (GrBackendApi::kVulkan == genBackendTex.backend()) {
|
2018-04-10 13:34:07 +00:00
|
|
|
GrVkImageInfo genImageInfo;
|
|
|
|
GrVkImageInfo origImageInfo;
|
|
|
|
if (genBackendTex.getVkImageInfo(&genImageInfo) &&
|
|
|
|
backendTex.getVkImageInfo(&origImageInfo)) {
|
|
|
|
if (willUseMips && GrMipMapped::kNo == mipMapped) {
|
|
|
|
// 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);
|
|
|
|
}
|
2017-10-23 13:37:36 +00:00
|
|
|
} else {
|
2018-04-10 13:34:07 +00:00
|
|
|
ERRORF(reporter, "Failed to get GrVkImageInfo");
|
2017-10-23 13:37:36 +00:00
|
|
|
}
|
2019-04-10 19:11:12 +00:00
|
|
|
#endif
|
|
|
|
#ifdef SK_METAL
|
|
|
|
} else if (GrBackendApi::kMetal == genBackendTex.backend()) {
|
|
|
|
GrMtlTextureInfo genImageInfo;
|
|
|
|
GrMtlTextureInfo origImageInfo;
|
|
|
|
if (genBackendTex.getMtlTextureInfo(&genImageInfo) &&
|
|
|
|
backendTex.getMtlTextureInfo(&origImageInfo)) {
|
|
|
|
if (willUseMips && GrMipMapped::kNo == mipMapped) {
|
|
|
|
// 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");
|
|
|
|
}
|
2017-10-23 13:37:36 +00:00
|
|
|
#endif
|
|
|
|
} else {
|
|
|
|
REPORTER_ASSERT(reporter, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Must make sure the uses of the backend texture have finished (we possibly have a
|
2018-03-08 14:49:58 +00:00
|
|
|
// queued up copy) before we delete the backend texture.
|
|
|
|
context->flush();
|
2017-10-23 13:37:36 +00:00
|
|
|
|
2019-05-17 14:01:21 +00:00
|
|
|
context->priv().getGpu()->testingOnly_flushGpuAndSync();
|
|
|
|
|
2019-05-20 12:38:07 +00:00
|
|
|
context->deleteBackendTexture(backendTex);
|
2017-10-23 13:37:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-30 17:41:26 +00:00
|
|
|
// 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();
|
2019-02-04 18:26:26 +00:00
|
|
|
if (!context->priv().caps()->mipMapSupport()) {
|
2017-10-30 17:41:26 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-02-04 18:26:26 +00:00
|
|
|
auto resourceProvider = context->priv().resourceProvider();
|
2018-01-16 20:07:54 +00:00
|
|
|
|
2017-10-30 17:41:26 +00:00
|
|
|
for (auto willUseMips : {false, true}) {
|
|
|
|
for (auto isWrapped : {false, true}) {
|
|
|
|
GrMipMapped mipMapped = willUseMips ? GrMipMapped::kYes : GrMipMapped::kNo;
|
|
|
|
sk_sp<SkSurface> surface;
|
2019-06-04 15:03:06 +00:00
|
|
|
GrBackendTexture backendTex = context->createBackendTexture(
|
2019-06-04 11:16:10 +00:00
|
|
|
kSize, kSize, kRGBA_8888_SkColorType,
|
2019-07-01 19:04:06 +00:00
|
|
|
SkColors::kTransparent, mipMapped, GrRenderable::kYes, GrProtected::kNo);
|
2017-10-30 17:41:26 +00:00
|
|
|
if (isWrapped) {
|
|
|
|
surface = SkSurface::MakeFromBackendTexture(context,
|
|
|
|
backendTex,
|
|
|
|
kTopLeft_GrSurfaceOrigin,
|
|
|
|
0,
|
2017-12-19 18:15:02 +00:00
|
|
|
kRGBA_8888_SkColorType,
|
2017-10-30 17:41:26 +00:00
|
|
|
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) {
|
2019-05-20 12:38:07 +00:00
|
|
|
context->deleteBackendTexture(backendTex);
|
2017-10-30 17:41:26 +00:00
|
|
|
}
|
|
|
|
SkGpuDevice* device = ((SkSurface_Gpu*)surface.get())->getDevice();
|
|
|
|
GrTextureProxy* texProxy = device->accessRenderTargetContext()->asTextureProxy();
|
|
|
|
REPORTER_ASSERT(reporter, mipMapped == texProxy->mipMapped());
|
|
|
|
|
2018-01-16 20:07:54 +00:00
|
|
|
texProxy->instantiate(resourceProvider);
|
2018-07-31 21:25:29 +00:00
|
|
|
GrTexture* texture = texProxy->peekTexture();
|
2017-10-30 17:41:26 +00:00
|
|
|
REPORTER_ASSERT(reporter, mipMapped == texture->texturePriv().mipMapped());
|
|
|
|
|
|
|
|
sk_sp<SkImage> image = surface->makeImageSnapshot();
|
|
|
|
REPORTER_ASSERT(reporter, image);
|
|
|
|
if (!image) {
|
2019-05-20 12:38:07 +00:00
|
|
|
context->deleteBackendTexture(backendTex);
|
2017-10-30 17:41:26 +00:00
|
|
|
}
|
|
|
|
texProxy = as_IB(image)->peekProxy();
|
|
|
|
REPORTER_ASSERT(reporter, mipMapped == texProxy->mipMapped());
|
|
|
|
|
2018-01-16 20:07:54 +00:00
|
|
|
texProxy->instantiate(resourceProvider);
|
2018-07-31 21:25:29 +00:00
|
|
|
texture = texProxy->peekTexture();
|
2017-10-30 17:41:26 +00:00
|
|
|
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();
|
2019-05-17 14:01:21 +00:00
|
|
|
context->priv().getGpu()->testingOnly_flushGpuAndSync();
|
2019-05-20 12:38:07 +00:00
|
|
|
context->deleteBackendTexture(backendTex);
|
2017-10-30 17:41:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-07-20 14:30:48 +00:00
|
|
|
|
|
|
|
// 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();
|
2019-02-04 18:26:26 +00:00
|
|
|
if (!context->priv().caps()->mipMapSupport()) {
|
2018-07-20 14:30:48 +00:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2019-08-14 15:24:37 +00:00
|
|
|
// Create a new render target and draw 'mipmapProxy' into it using the provided 'filter'.
|
2019-08-21 13:38:10 +00:00
|
|
|
static std::unique_ptr<GrRenderTargetContext> draw_mipmap_into_new_render_target(
|
2019-08-14 15:24:37 +00:00
|
|
|
GrDrawingManager* drawingManager, GrProxyProvider* proxyProvider, GrColorType colorType,
|
|
|
|
sk_sp<GrTextureProxy> mipmapProxy, GrSamplerState::Filter filter) {
|
|
|
|
GrSurfaceDesc desc;
|
|
|
|
desc.fWidth = 1;
|
|
|
|
desc.fHeight = 1;
|
|
|
|
desc.fConfig = mipmapProxy->config();
|
|
|
|
sk_sp<GrSurfaceProxy> renderTarget = proxyProvider->createProxy(
|
|
|
|
mipmapProxy->backendFormat(), desc, GrRenderable::kYes, 1, kTopLeft_GrSurfaceOrigin,
|
2019-08-30 20:19:42 +00:00
|
|
|
GrMipMapped::kNo, SkBackingFit::kApprox, SkBudgeted::kYes, GrProtected::kNo);
|
2019-08-21 13:38:10 +00:00
|
|
|
auto rtc = drawingManager->makeRenderTargetContext(
|
2019-08-14 15:24:37 +00:00
|
|
|
std::move(renderTarget), colorType, nullptr, nullptr, true);
|
2019-10-15 18:01:49 +00:00
|
|
|
rtc->drawTexture(GrNoClip(), mipmapProxy, colorType, 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);
|
2019-08-14 15:24:37 +00:00
|
|
|
return rtc;
|
|
|
|
}
|
|
|
|
|
2019-08-22 20:19:24 +00:00
|
|
|
// Test that two opsTasks using the same mipmaps both depend on the same GrTextureResolveRenderTask.
|
2019-08-21 16:22:50 +00:00
|
|
|
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;
|
2019-08-22 21:15:39 +00:00
|
|
|
ctxOptions.fReduceOpsTaskSplitting = enableSortingAndReduction;
|
2019-08-21 16:22:50 +00:00
|
|
|
sk_sp<GrContext> context = GrContext::MakeMock(&mockOptions, ctxOptions);
|
|
|
|
if (!context) {
|
2019-08-22 20:19:24 +00:00
|
|
|
ERRORF(reporter, "could not create mock context with fReduceOpsTaskSplitting %s.",
|
2019-08-21 16:22:50 +00:00
|
|
|
(Enable::kYes == enableSortingAndReduction) ? "enabled" : "disabled");
|
|
|
|
continue;
|
|
|
|
}
|
2019-08-14 15:24:37 +00:00
|
|
|
|
2019-08-21 16:22:50 +00:00
|
|
|
SkASSERT(context->priv().caps()->mipMapSupport());
|
|
|
|
|
|
|
|
GrBackendFormat format = context->defaultBackendFormat(
|
|
|
|
kRGBA_8888_SkColorType, GrRenderable::kYes);
|
|
|
|
GrPixelConfig config = kRGBA_8888_GrPixelConfig;
|
|
|
|
GrColorType colorType = GrColorType::kRGBA_8888;
|
|
|
|
|
|
|
|
GrDrawingManager* drawingManager = context->priv().drawingManager();
|
|
|
|
GrProxyProvider* proxyProvider = context->priv().proxyProvider();
|
|
|
|
|
|
|
|
// Create a mipmapped render target.
|
|
|
|
GrSurfaceDesc desc;
|
|
|
|
desc.fWidth = 4;
|
|
|
|
desc.fHeight = 4;
|
|
|
|
desc.fConfig = config;
|
2019-08-30 20:19:42 +00:00
|
|
|
sk_sp<GrTextureProxy> mipmapProxy = proxyProvider->createProxy(
|
|
|
|
format, desc, GrRenderable::kYes, 1, kTopLeft_GrSurfaceOrigin, GrMipMapped::kYes,
|
|
|
|
SkBackingFit::kExact, SkBudgeted::kYes, GrProtected::kNo);
|
2019-08-21 16:22:50 +00:00
|
|
|
|
2019-08-21 06:01:21 +00:00
|
|
|
// Mark the mipmaps clean to ensure things still work properly when they won't be marked
|
|
|
|
// dirty again until GrRenderTask::makeClosed().
|
|
|
|
mipmapProxy->markMipMapsClean();
|
|
|
|
|
2019-08-21 16:22:50 +00:00
|
|
|
// Render something to dirty the mips.
|
|
|
|
auto mipmapRTC = drawingManager->makeRenderTargetContext(
|
|
|
|
mipmapProxy, colorType, nullptr, nullptr, true);
|
|
|
|
mipmapRTC->clear(nullptr, {.1f,.2f,.3f,.4f}, CanClearFullscreen::kYes);
|
|
|
|
REPORTER_ASSERT(reporter, mipmapProxy->getLastRenderTask());
|
2019-08-22 20:19:24 +00:00
|
|
|
// mipmapProxy's last render task should now just be the opsTask containing the clear.
|
2019-08-21 16:22:50 +00:00
|
|
|
REPORTER_ASSERT(reporter,
|
2019-08-22 20:19:24 +00:00
|
|
|
mipmapRTC->testingOnly_PeekLastOpsTask() == mipmapProxy->getLastRenderTask());
|
2019-08-21 16:22:50 +00:00
|
|
|
|
2019-08-21 06:01:21 +00:00
|
|
|
// Mipmaps don't get marked dirty until makeClosed().
|
|
|
|
REPORTER_ASSERT(reporter, !mipmapProxy->mipMapsAreDirty());
|
|
|
|
|
2019-08-21 16:22:50 +00:00
|
|
|
// Draw the dirty mipmap texture into a render target.
|
|
|
|
auto rtc1 = draw_mipmap_into_new_render_target(
|
|
|
|
drawingManager, proxyProvider, colorType, mipmapProxy, Filter::kMipMap);
|
|
|
|
|
2019-08-21 06:01:21 +00:00
|
|
|
// 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
|
2019-08-22 20:19:24 +00:00
|
|
|
// if mipmapProxy->getLastRenderTask() has switched from the opsTask that drew to it, to the
|
2019-08-21 06:01:21 +00:00
|
|
|
// task that resolved its mips.
|
2019-08-21 16:22:50 +00:00
|
|
|
GrRenderTask* initialMipmapRegenTask = mipmapProxy->getLastRenderTask();
|
|
|
|
REPORTER_ASSERT(reporter, initialMipmapRegenTask);
|
|
|
|
REPORTER_ASSERT(reporter,
|
2019-08-22 20:19:24 +00:00
|
|
|
initialMipmapRegenTask != mipmapRTC->testingOnly_PeekLastOpsTask());
|
2019-08-21 16:22:50 +00:00
|
|
|
REPORTER_ASSERT(reporter, !mipmapProxy->mipMapsAreDirty());
|
|
|
|
|
|
|
|
// Draw the now-clean mipmap texture into a second target.
|
|
|
|
auto rtc2 = draw_mipmap_into_new_render_target(
|
|
|
|
drawingManager, proxyProvider, colorType, mipmapProxy, Filter::kMipMap);
|
|
|
|
|
|
|
|
// 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();
|
|
|
|
|
2019-09-18 19:41:50 +00:00
|
|
|
// Mip regen tasks don't get added as dependencies until makeClosed().
|
|
|
|
REPORTER_ASSERT(reporter,
|
|
|
|
rtc1->testingOnly_PeekLastOpsTask()->dependsOn(initialMipmapRegenTask));
|
|
|
|
REPORTER_ASSERT(reporter,
|
|
|
|
rtc2->testingOnly_PeekLastOpsTask()->dependsOn(initialMipmapRegenTask));
|
|
|
|
|
2019-08-21 16:22:50 +00:00
|
|
|
// Render something to dirty the mips.
|
|
|
|
mipmapRTC->clear(nullptr, {.1f,.2f,.3f,.4f}, CanClearFullscreen::kYes);
|
|
|
|
REPORTER_ASSERT(reporter, mipmapProxy->getLastRenderTask());
|
2019-08-22 20:19:24 +00:00
|
|
|
// mipmapProxy's last render task should now just be the opsTask containing the clear.
|
2019-08-21 16:22:50 +00:00
|
|
|
REPORTER_ASSERT(reporter,
|
2019-08-22 20:19:24 +00:00
|
|
|
mipmapRTC->testingOnly_PeekLastOpsTask() == mipmapProxy->getLastRenderTask());
|
2019-08-21 16:22:50 +00:00
|
|
|
|
2019-08-21 06:01:21 +00:00
|
|
|
// Mipmaps don't get marked dirty until makeClosed().
|
|
|
|
REPORTER_ASSERT(reporter, !mipmapProxy->mipMapsAreDirty());
|
|
|
|
|
2019-08-21 16:22:50 +00:00
|
|
|
// Draw the dirty mipmap texture into a render target, but don't do mipmap filtering.
|
|
|
|
rtc1 = draw_mipmap_into_new_render_target(
|
|
|
|
drawingManager, proxyProvider, colorType, mipmapProxy, Filter::kBilerp);
|
|
|
|
|
2019-08-21 06:01:21 +00:00
|
|
|
// 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.
|
2019-08-21 16:22:50 +00:00
|
|
|
REPORTER_ASSERT(reporter, mipmapProxy->mipMapsAreDirty());
|
2019-08-21 06:01:21 +00:00
|
|
|
|
|
|
|
// Since mips weren't regenerated, the last render task shouldn't have changed.
|
2019-08-21 16:22:50 +00:00
|
|
|
REPORTER_ASSERT(reporter,
|
2019-08-22 20:19:24 +00:00
|
|
|
mipmapRTC->testingOnly_PeekLastOpsTask() == mipmapProxy->getLastRenderTask());
|
2019-08-21 16:22:50 +00:00
|
|
|
|
2019-08-21 06:01:21 +00:00
|
|
|
// Draw the stil-dirty mipmap texture into a second target with mipmap filtering.
|
2019-08-21 16:22:50 +00:00
|
|
|
rtc2 = draw_mipmap_into_new_render_target(
|
|
|
|
drawingManager, proxyProvider, colorType, mipmapProxy, Filter::kMipMap);
|
|
|
|
|
2019-08-21 06:01:21 +00:00
|
|
|
// Make sure the mipmap texture now has a new last render task that regenerates the mips,
|
|
|
|
// and that the mipmaps are now clean.
|
2019-09-18 19:41:50 +00:00
|
|
|
auto mipRegenTask2 = mipmapProxy->getLastRenderTask();
|
|
|
|
REPORTER_ASSERT(reporter, mipRegenTask2);
|
2019-08-21 16:22:50 +00:00
|
|
|
REPORTER_ASSERT(reporter,
|
2019-09-18 19:41:50 +00:00
|
|
|
mipmapRTC->testingOnly_PeekLastOpsTask() != mipRegenTask2);
|
2019-08-21 16:22:50 +00:00
|
|
|
SkASSERT(!mipmapProxy->mipMapsAreDirty());
|
2019-09-18 19:41:50 +00:00
|
|
|
|
|
|
|
// Mip regen tasks don't get added as dependencies until makeClosed().
|
|
|
|
context->flush();
|
|
|
|
REPORTER_ASSERT(reporter, rtc2->testingOnly_PeekLastOpsTask()->dependsOn(mipRegenTask2));
|
2019-08-21 16:22:50 +00:00
|
|
|
}
|
2019-08-14 15:24:37 +00:00
|
|
|
}
|