/* * 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 "SkTypes.h" #if SK_SUPPORT_GPU #include "GrBackendSurface.h" #include "GrBackendTextureImageGenerator.h" #include "GrContext.h" #include "GrContextPriv.h" #include "GrGpu.h" #include "GrRenderTargetContext.h" #include "GrSemaphore.h" #include "GrSurfaceProxyPriv.h" #include "GrTest.h" #include "GrTexturePriv.h" #include "GrTextureProxy.h" #include "SkCanvas.h" #include "SkImage_Base.h" #include "SkGpuDevice.h" #include "SkPoint.h" #include "SkSurface.h" #include "SkSurface_Gpu.h" #include "Test.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->caps()->mipMapSupport()) { return; } for (auto mipMapped : {GrMipMapped::kNo, GrMipMapped::kYes}) { for (auto isRT : {false, true}) { // CreateTestingOnlyBackendTexture 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 = context->getGpu()->createTestingOnlyBackendTexture( nullptr, kSize, kSize, kRGBA_8888_GrPixelConfig, isRT, mipMapped); sk_sp proxy; sk_sp image; if (isRT) { sk_sp surface = SkSurface::MakeFromBackendTexture( context, backendTex, kTopLeft_GrSurfaceOrigin, 0, nullptr, nullptr); SkGpuDevice* device = ((SkSurface_Gpu*)surface.get())->getDevice(); proxy = device->accessRenderTargetContext()->asTextureProxyRef(); } else { image = SkImage::MakeFromTexture(context, backendTex, kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, nullptr); proxy = as_IB(image)->asTextureProxyRef(); } REPORTER_ASSERT(reporter, proxy); if (!proxy) { context->getGpu()->deleteTestingOnlyBackendTexture(&backendTex); return; } REPORTER_ASSERT(reporter, proxy->priv().isInstantiated()); GrTexture* texture = proxy->priv().peekTexture(); REPORTER_ASSERT(reporter, texture); if (!texture) { context->getGpu()->deleteTestingOnlyBackendTexture(&backendTex); return; } if (GrMipMapped::kYes == mipMapped) { REPORTER_ASSERT(reporter, GrMipMapped::kYes == texture->texturePriv().mipMapped()); if (isRT) { REPORTER_ASSERT(reporter, texture->texturePriv().mipMapsAreDirty()); } else { REPORTER_ASSERT(reporter, !texture->texturePriv().mipMapsAreDirty()); } } else { REPORTER_ASSERT(reporter, GrMipMapped::kNo == texture->texturePriv().mipMapped()); } context->getGpu()->deleteTestingOnlyBackendTexture(&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->caps()->mipMapSupport()) { return; } for (auto mipMapped : {GrMipMapped::kNo, GrMipMapped::kYes}) { for (auto willUseMips : {false, true}) { GrBackendTexture backendTex = context->getGpu()->createTestingOnlyBackendTexture( nullptr, kSize, kSize, kRGBA_8888_GrPixelConfig, false, mipMapped); sk_sp image = SkImage::MakeFromTexture(context, backendTex, kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, nullptr); GrTextureProxy* proxy = as_IB(image)->peekProxy(); REPORTER_ASSERT(reporter, proxy); if (!proxy) { context->getGpu()->deleteTestingOnlyBackendTexture(&backendTex); return; } REPORTER_ASSERT(reporter, proxy->priv().isInstantiated()); sk_sp texture = sk_ref_sp(proxy->priv().peekTexture()); REPORTER_ASSERT(reporter, texture); if (!texture) { context->getGpu()->deleteTestingOnlyBackendTexture(&backendTex); return; } std::unique_ptr imageGen = GrBackendTextureImageGenerator::Make( texture, kTopLeft_GrSurfaceOrigin, nullptr, kPremul_SkAlphaType, nullptr); REPORTER_ASSERT(reporter, imageGen); if (!imageGen) { context->getGpu()->deleteTestingOnlyBackendTexture(&backendTex); return; } SkIPoint origin = SkIPoint::Make(0,0); // The transfer function behavior isn't used in the generator so set we set it // arbitrarily here. SkTransferFunctionBehavior behavior = SkTransferFunctionBehavior::kIgnore; SkImageInfo imageInfo = SkImageInfo::Make(kSize, kSize, kRGBA_8888_SkColorType, kPremul_SkAlphaType); sk_sp genProxy = imageGen->generateTexture(context, imageInfo, origin, behavior, willUseMips); REPORTER_ASSERT(reporter, genProxy); if (!genProxy) { context->getGpu()->deleteTestingOnlyBackendTexture(&backendTex); return; } REPORTER_ASSERT(reporter, genProxy->priv().isInstantiated()); GrTexture* genTexture = genProxy->priv().peekTexture(); REPORTER_ASSERT(reporter, genTexture); if (!genTexture) { context->getGpu()->deleteTestingOnlyBackendTexture(&backendTex); return; } GrBackendTexture genBackendTex = genTexture->getBackendTexture(); if (const GrGLTextureInfo* genTexInfo = genBackendTex.getGLTextureInfo()) { const GrGLTextureInfo* origTexInfo = backendTex.getGLTextureInfo(); 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); } #ifdef SK_VULKAN } else if (const GrVkImageInfo* genImageInfo = genBackendTex.getVkImageInfo()) { const GrVkImageInfo* origImageInfo = backendTex.getVkImageInfo(); 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); } #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. Thus we use readPixels here // just to force the synchronization. sk_sp surfContext = context->contextPriv().makeWrappedSurfaceContext(genProxy, nullptr); SkBitmap bitmap; bitmap.allocPixels(imageInfo); surfContext->readPixels(imageInfo, bitmap.getPixels(), 0, 0, 0, 0); context->getGpu()->deleteTestingOnlyBackendTexture(&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->caps()->mipMapSupport()) { return; } for (auto willUseMips : {false, true}) { for (auto isWrapped : {false, true}) { GrMipMapped mipMapped = willUseMips ? GrMipMapped::kYes : GrMipMapped::kNo; sk_sp surface; GrBackendTexture backendTex = context->getGpu()->createTestingOnlyBackendTexture( nullptr, kSize, kSize, kRGBA_8888_GrPixelConfig, true, mipMapped); if (isWrapped) { surface = SkSurface::MakeFromBackendTexture(context, backendTex, kTopLeft_GrSurfaceOrigin, 0, 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->getGpu()->deleteTestingOnlyBackendTexture(&backendTex); } SkGpuDevice* device = ((SkSurface_Gpu*)surface.get())->getDevice(); GrTextureProxy* texProxy = device->accessRenderTargetContext()->asTextureProxy(); REPORTER_ASSERT(reporter, mipMapped == texProxy->mipMapped()); texProxy->instantiate(context->resourceProvider()); GrTexture* texture = texProxy->priv().peekTexture(); REPORTER_ASSERT(reporter, mipMapped == texture->texturePriv().mipMapped()); sk_sp image = surface->makeImageSnapshot(); REPORTER_ASSERT(reporter, image); if (!image) { context->getGpu()->deleteTestingOnlyBackendTexture(&backendTex); } texProxy = as_IB(image)->peekProxy(); REPORTER_ASSERT(reporter, mipMapped == texProxy->mipMapped()); texProxy->instantiate(context->resourceProvider()); texture = texProxy->priv().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->getGpu()->deleteTestingOnlyBackendTexture(&backendTex); } } } #endif