| /* | |
| * 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_202404) { | |
| 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> recording = recorder->snap(); | |
| auto recordingFinishProc = [](void* context, CallbackResult) { | |
| std::unique_ptr<Recording>(static_cast<Recording*>(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.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<const SkImage::AsyncReadResult> result) { | |
| auto& readContext = *static_cast<ReadContext*>(context); | |
| readContext.called = true; | |
| if (result) { | |
| readContext.success = true; | |
| readContext.color = *static_cast<const uint32_t*>(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); | |
| } | |
| } |