* 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/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"
static constexpr int kSize = 8;
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}) {
GrBackendTexture backendTex = context->createBackendTexture(
kSize, kSize, kRGBA_8888_SkColorType,
SkColors::kTransparent, mipMapped, renderable, GrProtected::kNo);
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);
proxy = as_IB(image)->asTextureProxyRef(context);
}
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);
}
}
}
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrBackendTextureImageMipMappedTest, reporter, ctxInfo) {
GrContext* context = ctxInfo.grContext();
if (!context->priv().caps()->mipMapSupport()) {
return;
}
for (auto mipMapped : {GrMipMapped::kNo, GrMipMapped::kYes}) {
for (auto willUseMips : {false, true}) {
GrBackendTexture backendTex = context->createBackendTexture(
kSize, kSize, kRGBA_8888_SkColorType,
SkColors::kTransparent, mipMapped, GrRenderable::kNo, GrProtected::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);
sk_sp<GrTextureProxy> genProxy = imageGen->generateTexture(context, imageInfo,
origin, willUseMips);
REPORTER_ASSERT(reporter, genProxy);
if (!genProxy) {
context->deleteBackendTexture(backendTex);
return;
}
if (GrSurfaceProxy::LazyState::kNot != genProxy->lazyInstantiationState()) {
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 (willUseMips && GrMipMapped::kNo == mipMapped) {
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 (willUseMips && GrMipMapped::kNo == mipMapped) {
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 (willUseMips && GrMipMapped::kNo == mipMapped) {
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);
}
context->flush();
context->priv().getGpu()->testingOnly_flushGpuAndSync();
context->deleteBackendTexture(backendTex);
}
}
}
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 = context->createBackendTexture(
kSize, kSize, kRGBA_8888_SkColorType,
SkColors::kTransparent, mipMapped, GrRenderable::kYes, GrProtected::kNo);
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());
context->flush();
context->priv().getGpu()->testingOnly_flushGpuAndSync();
context->deleteBackendTexture(backendTex);
}
}
}
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(Gr1x1TextureMipMappedTest, reporter, ctxInfo) {
GrContext* context = ctxInfo.grContext();
if (!context->priv().caps()->mipMapSupport()) {
return;
}
SkImageInfo info = SkImageInfo::MakeN32(16, 16, kPremul_SkAlphaType);
sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info);
SkBitmap bmp;
bmp.allocN32Pixels(1, 1);
SkPMColor* pixel = reinterpret_cast<SkPMColor*>(bmp.getPixels());
*pixel = 0;
sk_sp<SkImage> bmpImage = SkImage::MakeFromBitmap(bmp);
surface->getCanvas()->scale(0.5f, 0.5f);
SkPaint paint;
surface->getCanvas()->drawImage(bmpImage, 0, 0, &paint);
surface->flush();
paint.setFilterQuality(kHigh_SkFilterQuality);
surface->getCanvas()->drawImage(bmpImage, 0, 0, &paint);
surface->flush();
}
static sk_sp<GrRenderTargetContext> draw_mipmap_into_new_render_target(
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,
SkBackingFit::kApprox, SkBudgeted::kYes, GrProtected::kNo);
sk_sp<GrRenderTargetContext> rtc = drawingManager->makeRenderTargetContext(
std::move(renderTarget), colorType, nullptr, nullptr, true);
rtc->drawTexture(GrNoClip(), mipmapProxy, 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;
}
DEF_GPUTEST_FOR_ALL_CONTEXTS(GrManyDependentsMipMappedTest, reporter, ctxInfo) {
GrContext* context = ctxInfo.grContext();
if (!context->priv().caps()->mipMapSupport()) {
return;
}
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();
GrSurfaceDesc desc;
desc.fWidth = 4;
desc.fHeight = 4;
desc.fConfig = config;
sk_sp<GrTextureProxy> mipmapProxy = proxyProvider->createMipMapProxy(
format, desc, GrRenderable::kYes, 1, kTopLeft_GrSurfaceOrigin, SkBudgeted::kYes,
GrProtected::kNo);
sk_sp<GrRenderTargetContext> mipmapRTC = drawingManager->makeRenderTargetContext(
mipmapProxy, colorType, nullptr, nullptr, true);
mipmapRTC->clear(nullptr, {.1f,.2f,.3f,.4f}, GrRenderTargetContext::CanClearFullscreen::kYes);
REPORTER_ASSERT(reporter, mipmapProxy->mipMapsAreDirty());
REPORTER_ASSERT(reporter, mipmapProxy->getLastRenderTask());
REPORTER_ASSERT(
reporter, mipmapRTC->testingOnly_PeekLastOpList() == mipmapProxy->getLastRenderTask());
sk_sp<GrRenderTargetContext> rtc1 = draw_mipmap_into_new_render_target(
drawingManager, proxyProvider, colorType, mipmapProxy, GrSamplerState::Filter::kMipMap);
GrRenderTask* initialMipmapRegenTask = mipmapProxy->getLastRenderTask();
REPORTER_ASSERT(reporter, initialMipmapRegenTask);
REPORTER_ASSERT(reporter, initialMipmapRegenTask != mipmapRTC->testingOnly_PeekLastOpList());
REPORTER_ASSERT(
reporter, rtc1->testingOnly_PeekLastOpList()->dependsOn(initialMipmapRegenTask));
REPORTER_ASSERT(reporter, !mipmapProxy->mipMapsAreDirty());
SkASSERT(!mipmapProxy->mipMapsAreDirty());
sk_sp<GrRenderTargetContext> rtc2 = draw_mipmap_into_new_render_target(
drawingManager, proxyProvider, colorType, mipmapProxy, GrSamplerState::Filter::kMipMap);
REPORTER_ASSERT(reporter, mipmapProxy->getLastRenderTask() == initialMipmapRegenTask);
REPORTER_ASSERT(
reporter, rtc2->testingOnly_PeekLastOpList()->dependsOn(initialMipmapRegenTask));
SkASSERT(!mipmapProxy->mipMapsAreDirty());
context->flush();
mipmapRTC->clear(nullptr, {.1f,.2f,.3f,.4f}, GrRenderTargetContext::CanClearFullscreen::kYes);
REPORTER_ASSERT(reporter, mipmapProxy->mipMapsAreDirty());
REPORTER_ASSERT(reporter, mipmapProxy->getLastRenderTask());
REPORTER_ASSERT(
reporter, mipmapRTC->testingOnly_PeekLastOpList() == mipmapProxy->getLastRenderTask());
rtc1 = draw_mipmap_into_new_render_target(
drawingManager, proxyProvider, colorType, mipmapProxy, GrSamplerState::Filter::kBilerp);
REPORTER_ASSERT(reporter, mipmapProxy->mipMapsAreDirty());
REPORTER_ASSERT(
reporter, mipmapRTC->testingOnly_PeekLastOpList() == mipmapProxy->getLastRenderTask());
rtc2 = draw_mipmap_into_new_render_target(
drawingManager, proxyProvider, colorType, mipmapProxy, GrSamplerState::Filter::kMipMap);
REPORTER_ASSERT(reporter, mipmapProxy->getLastRenderTask());
REPORTER_ASSERT(reporter,
mipmapRTC->testingOnly_PeekLastOpList() != mipmapProxy->getLastRenderTask());
REPORTER_ASSERT(reporter,
rtc2->testingOnly_PeekLastOpList()->dependsOn(mipmapProxy->getLastRenderTask()));
SkASSERT(!mipmapProxy->mipMapsAreDirty());
}