| /* | |
| * Copyright 2023 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/SkBitmap.h" | |
| #include "include/core/SkColorSpace.h" | |
| #include "include/core/SkRect.h" | |
| #include "include/core/SkTileMode.h" | |
| #include "include/gpu/graphite/Context.h" | |
| #include "include/gpu/graphite/Image.h" | |
| #include "include/gpu/graphite/Surface.h" | |
| #include "src/gpu/graphite/Caps.h" | |
| #include "src/gpu/graphite/ContextPriv.h" | |
| #include "src/gpu/graphite/Surface_Graphite.h" | |
| #include "src/shaders/SkImageShader.h" | |
| #include "tools/ToolUtils.h" | |
| #include "tools/gpu/ManagedBackendTexture.h" | |
| namespace skgpu::graphite { | |
| namespace { | |
| using DrawFn = void (*)(sk_sp<SkImage>, SkCanvas*, SkRect /*srcRect*/, SkRect /*dstRect*/); | |
| constexpr SkColor4f kTopColor = SkColors::kRed; | |
| constexpr SkColor4f kBottomColor = SkColors::kBlue; | |
| constexpr int32_t kHalfSize = 4; | |
| constexpr SkISize kImageSize = {2*kHalfSize, 2*kHalfSize}; | |
| void test_draw(skiatest::Reporter* reporter, | |
| Context* context, | |
| skgpu::Origin origin, | |
| SkRect srcRect, | |
| SkRect dstRect, | |
| DrawFn drawImageFn) { | |
| std::unique_ptr<Recorder> recorder = context->makeRecorder(); | |
| skgpu::Protected isProtected = skgpu::Protected(context->priv().caps()->protectedSupport()); | |
| SkBitmap bitmap; | |
| bitmap.allocPixels(SkImageInfo::Make(kImageSize, kRGBA_8888_SkColorType, kPremul_SkAlphaType), | |
| 0); | |
| bitmap.eraseColor(kTopColor); | |
| bitmap.erase(kBottomColor, | |
| SkIRect::MakeLTRB(0, kHalfSize, kImageSize.width(), kImageSize.height())); | |
| auto managedTexture = | |
| sk_gpu_test::ManagedGraphiteTexture::MakeFromPixmap(recorder.get(), | |
| bitmap.pixmap(), | |
| skgpu::Mipmapped::kNo, | |
| skgpu::Renderable::kNo, | |
| isProtected); | |
| REPORTER_ASSERT(reporter, managedTexture); | |
| if (!managedTexture) { | |
| return; | |
| } | |
| sk_sp<SkImage> image = SkImages::WrapTexture(recorder.get(), | |
| managedTexture->texture(), | |
| kPremul_SkAlphaType, | |
| /*colorSpace=*/nullptr, | |
| origin); | |
| REPORTER_ASSERT(reporter, image); | |
| if (!image) { | |
| return; | |
| } | |
| sk_sp<SkSurface> surface = SkSurfaces::RenderTarget( | |
| recorder.get(), | |
| SkImageInfo::Make(kImageSize, kRGBA_8888_SkColorType, kPremul_SkAlphaType)); | |
| REPORTER_ASSERT(reporter, surface); | |
| if (!surface) { | |
| return; | |
| } | |
| SkCanvas* canvas = surface->getCanvas(); | |
| drawImageFn(image, canvas, srcRect, dstRect); | |
| SkPixmap pm; | |
| SkBitmap result; | |
| result.allocPixels(SkImageInfo::Make(kImageSize, kRGBA_8888_SkColorType, kPremul_SkAlphaType)); | |
| bool peekPixelsSuccess = result.peekPixels(&pm); | |
| REPORTER_ASSERT(reporter, peekPixelsSuccess); | |
| bool readPixelsSuccess = surface->readPixels(pm, 0, 0); | |
| REPORTER_ASSERT(reporter, readPixelsSuccess); | |
| bool resultTopColorOnTop = origin == skgpu::Origin::kTopLeft; | |
| for (int32_t y = 0; y < kImageSize.height(); ++y) { | |
| for (int32_t x = 0; x < kImageSize.width(); ++x) { | |
| SkColor4f color = pm.getColor4f(x, y); | |
| SkColor4f expectedColor = ((y < kHalfSize) == resultTopColorOnTop) ? kTopColor | |
| : kBottomColor; | |
| REPORTER_ASSERT(reporter, | |
| color == expectedColor, | |
| "At position {%d, %d}, " | |
| "expected {%.1f, %.1f, %.1f, %.1f}, " | |
| "found {%.1f, %.1f, %.1f, %.1f}", | |
| x, y, | |
| expectedColor.fR, expectedColor.fG, expectedColor.fB, expectedColor.fA, | |
| color.fR, color.fG, color.fB, color.fA); | |
| } | |
| } | |
| } | |
| const SkRect kTestSrcRects[] = { | |
| // entire thing | |
| SkRect::MakeWH(kImageSize.width(), kImageSize.height()), | |
| // half rect still splitting top and bottom colors | |
| SkRect::MakeXYWH(2, 2, kHalfSize, kHalfSize), | |
| }; | |
| void test_draw_fn(skiatest::Reporter* reporter, | |
| Context* context, | |
| DrawFn drawImageFn) { | |
| for (auto origin : {skgpu::Origin::kTopLeft, skgpu::Origin::kBottomLeft}) { | |
| for (auto srcRect: kTestSrcRects) { | |
| test_draw(reporter, | |
| context, | |
| origin, | |
| srcRect, | |
| SkRect::MakeWH(kImageSize.width(), kImageSize.height()), | |
| drawImageFn); | |
| } | |
| } | |
| } | |
| void draw_image(sk_sp<SkImage> image, | |
| SkCanvas* canvas, | |
| SkRect srcRect, | |
| SkRect dstRect) { | |
| canvas->drawImageRect(image, | |
| srcRect, | |
| dstRect, | |
| SkSamplingOptions(), | |
| /*paint=*/nullptr, | |
| SkCanvas::kStrict_SrcRectConstraint); | |
| } | |
| void draw_image_with_shader(sk_sp<SkImage> image, | |
| SkCanvas* canvas, | |
| SkRect srcRect, | |
| SkRect dstRect) { | |
| SkPaint p; | |
| SkMatrix srcToDst = SkMatrix::RectToRectOrIdentity(srcRect, dstRect); | |
| p.setShader(SkImageShader::MakeSubset( | |
| std::move(image), | |
| srcRect, | |
| SkTileMode::kClamp, | |
| SkTileMode::kClamp, | |
| SkSamplingOptions(), | |
| &srcToDst)); | |
| canvas->drawRect(dstRect, p); | |
| } | |
| } // anonymous namespace | |
| DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(ImageOriginTest_drawImage_Graphite, reporter, context, | |
| CtsEnforcement::kApiLevel_202404) { | |
| test_draw_fn(reporter, context, draw_image); | |
| } | |
| DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(ImageOriginTest_imageShader_Graphite, reporter, context, | |
| CtsEnforcement::kApiLevel_202404) { | |
| test_draw_fn(reporter, context, draw_image_with_shader); | |
| } | |
| } // namespace skgpu::graphite |