| /* | |
| * Copyright 2020 Google LLC | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| #include "gm/gm.h" | |
| // This test only works with the Vulkan backend. | |
| #ifdef SK_VULKAN | |
| #include "include/core/SkCanvas.h" | |
| #include "include/core/SkColorSpace.h" | |
| #include "include/core/SkImage.h" | |
| #include "include/core/SkPaint.h" | |
| #include "include/core/SkSize.h" | |
| #include "include/core/SkString.h" | |
| #include "tools/gpu/vk/VkYcbcrSamplerHelper.h" | |
| #if defined(SK_GANESH) | |
| #include "include/gpu/ganesh/GrDirectContext.h" | |
| #include "include/gpu/ganesh/SkImageGanesh.h" | |
| #endif | |
| #if defined(SK_GRAPHITE) | |
| #include "include/gpu/graphite/Image.h" | |
| #include "include/gpu/graphite/Recorder.h" | |
| #include "include/gpu/vk/VulkanBackendContext.h" | |
| #include "src/gpu/graphite/RecorderPriv.h" | |
| #include "src/gpu/graphite/vk/VulkanSharedContext.h" | |
| #include "tools/graphite/vk/GraphiteVulkanTestContext.h" | |
| using VulkanTestContext = skiatest::graphite::VulkanTestContext; | |
| using SharedContext = skgpu::graphite::SharedContext; | |
| using VulkanSharedContext = skgpu::graphite::VulkanSharedContext; | |
| #endif | |
| static void release_ycbcrhelper(void* releaseContext) { | |
| VkYcbcrSamplerHelper* ycbcrHelper = reinterpret_cast<VkYcbcrSamplerHelper*>(releaseContext); | |
| delete ycbcrHelper; | |
| } | |
| namespace skiagm { | |
| // This GM exercises the native YCbCr image format on Vulkan | |
| class YCbCrImageGM : public GM { | |
| public: | |
| YCbCrImageGM() { | |
| this->setBGColor(0xFFCCCCCC); | |
| } | |
| protected: | |
| SkString getName() const override { return SkString("ycbcrimage"); } | |
| SkISize getISize() override { | |
| return SkISize::Make(2*kPad+kImageSize, 2*kPad+kImageSize); | |
| } | |
| #if defined(SK_GRAPHITE) | |
| DrawResult createYCbCrImage(skgpu::graphite::Recorder* recorder, | |
| SkString* errorMsg) { | |
| if (!recorder) { | |
| *errorMsg = "Cannot generate a YCbCr image without a valid GraphiteTestContext and " | |
| "recorder."; | |
| return skiagm::DrawResult::kSkip; | |
| } | |
| SkASSERT_RELEASE(recorder->backend() == skgpu::BackendApi::kVulkan); | |
| const VulkanSharedContext* vulkanSharedCtxt = | |
| static_cast<const VulkanSharedContext*>(recorder->priv().sharedContext()); | |
| SkASSERT(vulkanSharedCtxt); | |
| auto ycbcrHelper = std::make_unique<VkYcbcrSamplerHelper>(vulkanSharedCtxt); | |
| if (!ycbcrHelper) { | |
| *errorMsg = "Failed to create VkYcbcrSamplerHelper."; | |
| return skiagm::DrawResult::kFail; | |
| } | |
| if (!ycbcrHelper->isYCbCrSupported()) { | |
| *errorMsg = "YCbCr sampling is not supported."; | |
| return skiagm::DrawResult::kSkip; | |
| } | |
| if (!ycbcrHelper->createBackendTexture(kImageSize, kImageSize)) { | |
| *errorMsg = "Failed to create I420 backend texture."; | |
| return skiagm::DrawResult::kFail; | |
| } | |
| SkASSERT(!fYCbCrImage); | |
| fYCbCrImage = SkImages::WrapTexture(recorder, | |
| ycbcrHelper->backendTexture(), | |
| kUnknown_SkAlphaType, // force alpha channel to 1 | |
| /*colorSpace=*/nullptr, | |
| release_ycbcrhelper, | |
| ycbcrHelper.get()); | |
| SkASSERT(fYCbCrImage); | |
| ycbcrHelper.release(); | |
| if (!fYCbCrImage) { | |
| *errorMsg = "Failed to create I420 SkImage."; | |
| return DrawResult::kFail; | |
| } | |
| return DrawResult::kOk; | |
| } | |
| #endif // SK_GRAPHITE | |
| #if defined(SK_GANESH) | |
| DrawResult createYCbCrImage(GrDirectContext* dContext, SkString* errorMsg) { | |
| auto ycbcrHelper = std::make_unique<VkYcbcrSamplerHelper>(dContext); | |
| if (!ycbcrHelper->isYCbCrSupported()) { | |
| *errorMsg = "YCbCr sampling not supported."; | |
| return skiagm::DrawResult::kSkip; | |
| } | |
| if (!ycbcrHelper->createGrBackendTexture(kImageSize, kImageSize)) { | |
| *errorMsg = "Failed to create I420 backend texture."; | |
| return skiagm::DrawResult::kFail; | |
| } | |
| SkASSERT(!fYCbCrImage); | |
| fYCbCrImage = SkImages::BorrowTextureFrom(dContext, | |
| ycbcrHelper->grBackendTexture(), | |
| kTopLeft_GrSurfaceOrigin, | |
| kRGB_888x_SkColorType, | |
| kPremul_SkAlphaType, | |
| nullptr, | |
| release_ycbcrhelper, | |
| ycbcrHelper.get()); | |
| ycbcrHelper.release(); | |
| if (!fYCbCrImage) { | |
| *errorMsg = "Failed to create I420 image."; | |
| return DrawResult::kFail; | |
| } | |
| return DrawResult::kOk; | |
| } | |
| #endif | |
| DrawResult onGpuSetup(SkCanvas* canvas, | |
| SkString* errorMsg, | |
| GraphiteTestContext* graphiteTestContext) override { | |
| #if defined(SK_GRAPHITE) | |
| skgpu::graphite::Recorder* recorder = canvas->recorder(); | |
| if (recorder) { | |
| if (recorder->backend() != skgpu::BackendApi::kVulkan) { | |
| *errorMsg = "This GM requires using Vulkan."; | |
| return DrawResult::kSkip; | |
| } | |
| return this->createYCbCrImage(recorder, errorMsg); | |
| } | |
| #endif | |
| #if defined(SK_GANESH) | |
| if (GrDirectContext* dContext = GrAsDirectContext(canvas->recordingContext())) { | |
| if (dContext->abandoned()) { | |
| return DrawResult::kSkip; | |
| } | |
| if (dContext->backend() != GrBackendApi::kVulkan) { | |
| *errorMsg = "This GM requires a Vulkan context."; | |
| return DrawResult::kSkip; | |
| } | |
| DrawResult result = this->createYCbCrImage(dContext, errorMsg); | |
| if (result != DrawResult::kOk) { | |
| return result; | |
| } | |
| return DrawResult::kOk; | |
| } | |
| #endif | |
| return DrawResult::kSkip; | |
| } | |
| void onGpuTeardown() override { | |
| fYCbCrImage = nullptr; | |
| } | |
| DrawResult onDraw(SkCanvas* canvas, SkString*) override { | |
| SkASSERT(fYCbCrImage); | |
| canvas->drawImage(fYCbCrImage, kPad, kPad, SkSamplingOptions(SkFilterMode::kLinear)); | |
| return DrawResult::kOk; | |
| } | |
| private: | |
| static const int kImageSize = 112; | |
| static const int kPad = 8; | |
| sk_sp<SkImage> fYCbCrImage; | |
| using INHERITED = GM; | |
| }; | |
| ////////////////////////////////////////////////////////////////////////////// | |
| DEF_GM(return new YCbCrImageGM;) | |
| } // namespace skiagm | |
| #endif // SK_VULKAN |