/* * Copyright 2024 Google LLC * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "tests/Test.h" #include "include/core/SkCanvas.h" #include "include/gpu/graphite/BackendTexture.h" #include "include/gpu/graphite/Context.h" #include "include/gpu/graphite/Image.h" #include "include/gpu/graphite/Recorder.h" #include "include/gpu/graphite/Surface.h" #include "src/core/SkAutoPixmapStorage.h" #include "src/gpu/graphite/Caps.h" #include "src/gpu/graphite/ContextPriv.h" #include "tools/gpu/ManagedBackendTexture.h" #include "tools/graphite/GraphiteTestContext.h" using namespace skgpu; using namespace skgpu::graphite; DEF_CONDITIONAL_GRAPHITE_TEST_FOR_ALL_CONTEXTS(ImageWrapTextureMipmapsTest, reporter, context, testContext, true, CtsEnforcement::kApiLevel_V) { auto recorder = context->makeRecorder(); if (!recorder) { ERRORF(reporter, "Could not make recorder"); return; } skgpu::Protected isProtected = skgpu::Protected(context->priv().caps()->protectedSupport()); auto info = SkImageInfo::Make({2, 1}, kRGBA_8888_SkColorType, kPremul_SkAlphaType); SkAutoPixmapStorage basePM, topPM; basePM.alloc(info); basePM.erase(SK_ColorGREEN); topPM.alloc(info.makeDimensions({1, 1})); topPM.erase(SK_ColorBLUE); SkPixmap levelPMs[]{basePM, topPM}; auto mbet = sk_gpu_test::ManagedGraphiteTexture::MakeMipmappedFromPixmaps(recorder.get(), levelPMs, Renderable::kNo, isProtected); if (!mbet) { ERRORF(reporter, "Could not make backend texture"); return; } std::unique_ptr recording = recorder->snap(); auto recordingFinishProc = [](void* context, CallbackResult) { std::unique_ptr(static_cast(context)); }; skgpu::graphite::InsertRecordingInfo recordingInfo; recordingInfo.fFinishedProc = recordingFinishProc; recordingInfo.fRecording = recording.get(); recordingInfo.fFinishedContext = recording.release(); if (!context->insertRecording(recordingInfo)) { ERRORF(reporter, "Could not insert recording"); return; } static constexpr struct TestCase { SkImages::GenerateMipmapsFromBase genMipmaps; SkColor expectedColor; } kTestCases[]{{SkImages::GenerateMipmapsFromBase::kNo , 0xFFFF0000}, {SkImages::GenerateMipmapsFromBase::kYes, 0XFF00FF00}}; for (const auto& testCase : kTestCases) { recorder = context->makeRecorder(); if (!recorder) { ERRORF(reporter, "Could not make recorder"); return; } auto image = SkImages::WrapTexture(recorder.get(), mbet->texture(), info.colorType(), info.alphaType(), info.refColorSpace(), Origin::kTopLeft, testCase.genMipmaps, sk_gpu_test::ManagedGraphiteTexture::ImageReleaseProc, mbet->releaseContext()); if (!recorder) { ERRORF(reporter, "Could not make image"); return; } // We determe the contents of the image's top level by doing a downsampling draw to a // surface and then reading the surface's contents. auto surface = SkSurfaces::RenderTarget(recorder.get(), info.makeDimensions({1, 1})); if (!recorder) { ERRORF(reporter, "Could not make surface"); return; } auto shader = image->makeShader( SkTileMode::kRepeat, SkTileMode::kRepeat, SkSamplingOptions(SkFilterMode::kNearest, SkMipmapMode::kNearest)); surface->getCanvas()->scale(0.05f, 0.05f); SkPaint paint; paint.setShader(std::move(shader)); surface->getCanvas()->drawPaint(paint); recording = recorder->snap(); recordingInfo.fRecording = recording.get(); recordingInfo.fFinishedContext = recording.release(); if (!context->insertRecording(recordingInfo)) { ERRORF(reporter, "Could not insert recording"); return; } struct ReadContext { bool called = false; bool success = false; uint32_t color; }; auto readPixelsCallback = [](SkImage::ReadPixelsContext context, std::unique_ptr result) { auto& readContext = *static_cast(context); readContext.called = true; if (result) { readContext.success = true; readContext.color = *static_cast(result->data(0)); } }; ReadContext readContext; context->asyncRescaleAndReadPixels(surface.get(), surface->imageInfo(), SkIRect::MakeSize(surface->imageInfo().dimensions()), SkImage::RescaleGamma::kSrc, SkImage::RescaleMode::kNearest, readPixelsCallback, &readContext); context->submit(); while (!readContext.called) { testContext->tick(); context->checkAsyncWorkCompletion(); } if (!readContext.success) { ERRORF(reporter, "Read pixels failed"); return; } REPORTER_ASSERT(reporter, readContext.color == testCase.expectedColor); } }