chromium/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc

// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif

#include "components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h"

#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <utility>
#include <vector>

#include "base/debug/crash_logging.h"
#include "base/debug/dump_without_crashing.h"
#include "base/feature_list.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/notreached.h"
#include "base/task/bind_post_task.h"
#include "base/threading/thread_checker.h"
#include "base/time/time.h"
#include "base/trace_event/typed_macros.h"
#include "build/build_config.h"
#include "components/viz/common/features.h"
#include "components/viz/common/frame_sinks/blit_request.h"
#include "components/viz/common/frame_sinks/copy_output_request.h"
#include "components/viz/common/frame_sinks/copy_output_util.h"
#include "components/viz/common/gpu/vulkan_context_provider.h"
#include "components/viz/common/resources/release_callback.h"
#include "components/viz/common/resources/shared_image_format_utils.h"
#include "components/viz/common/skia_helper.h"
#include "components/viz/common/viz_utils.h"
#include "components/viz/service/debugger/viz_debugger.h"
#include "components/viz/service/display/output_surface_frame.h"
#include "components/viz/service/display_embedder/image_context_impl.h"
#include "components/viz/service/display_embedder/output_presenter_gl.h"
#include "components/viz/service/display_embedder/skia_output_device.h"
#include "components/viz/service/display_embedder/skia_output_device_buffer_queue.h"
#include "components/viz/service/display_embedder/skia_output_device_gl.h"
#include "components/viz/service/display_embedder/skia_output_device_offscreen.h"
#include "components/viz/service/display_embedder/skia_output_device_webview.h"
#include "components/viz/service/display_embedder/skia_output_surface_dependency.h"
#include "components/viz/service/display_embedder/skia_output_surface_impl_on_gpu_debug_capture.h"
#include "components/viz/service/display_embedder/skia_render_copy_results.h"
#include "gpu/command_buffer/common/mailbox.h"
#include "gpu/command_buffer/common/mailbox_holder.h"
#include "gpu/command_buffer/common/shared_image_usage.h"
#include "gpu/command_buffer/common/swap_buffers_complete_params.h"
#include "gpu/command_buffer/common/sync_token.h"
#include "gpu/command_buffer/service/display_compositor_memory_and_task_controller_on_gpu.h"
#include "gpu/command_buffer/service/feature_info.h"
#include "gpu/command_buffer/service/gr_shader_cache.h"
#include "gpu/command_buffer/service/memory_tracking.h"
#include "gpu/command_buffer/service/scheduler.h"
#include "gpu/command_buffer/service/shared_image/shared_image_factory.h"
#include "gpu/command_buffer/service/shared_image/shared_image_representation.h"
#include "gpu/command_buffer/service/skia_utils.h"
#include "gpu/command_buffer/service/sync_point_manager.h"
#include "gpu/config/gpu_finch_features.h"
#include "gpu/config/gpu_preferences.h"
#include "gpu/ipc/common/gpu_client_ids.h"
#include "gpu/vulkan/buildflags.h"
#include "skia/buildflags.h"
#include "skia/ext/rgba_to_yuva.h"
#include "third_party/libyuv/include/libyuv/planar_functions.h"
#include "third_party/skia/include/core/SkAlphaType.h"
#include "third_party/skia/include/core/SkBlendMode.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/core/SkColorFilter.h"
#include "third_party/skia/include/core/SkColorSpace.h"
#include "third_party/skia/include/core/SkColorType.h"
#include "third_party/skia/include/core/SkImageInfo.h"
#include "third_party/skia/include/core/SkSamplingOptions.h"
#include "third_party/skia/include/core/SkSwizzle.h"
#include "third_party/skia/include/core/SkYUVAInfo.h"
#include "third_party/skia/include/gpu/GpuTypes.h"
#include "third_party/skia/include/gpu/GrTypes.h"
#include "third_party/skia/include/gpu/ganesh/SkSurfaceGanesh.h"
#include "third_party/skia/include/gpu/ganesh/gl/GrGLBackendSurface.h"
#include "third_party/skia/include/gpu/graphite/Context.h"
#include "third_party/skia/include/gpu/graphite/Surface.h"
#include "third_party/skia/include/private/chromium/GrDeferredDisplayList.h"
#include "third_party/skia/include/private/chromium/GrPromiseImageTexture.h"
#include "ui/base/ozone_buildflags.h"
#include "ui/gfx/color_space.h"
#include "ui/gfx/geometry/skia_conversions.h"
#include "ui/gfx/gpu_fence_handle.h"
#include "ui/gl/gl_features.h"
#include "ui/gl/gl_fence.h"
#include "ui/gl/gl_surface.h"
#include "ui/gl/presenter.h"
#include "ui/gl/progress_reporter.h"
#include "url/gurl.h"

#if BUILDFLAG(IS_WIN)
#include "components/viz/service/display/dc_layer_overlay.h"
#include "components/viz/service/display_embedder/skia_output_device_dcomp.h"
#endif

#if BUILDFLAG(ENABLE_VULKAN)
#include "components/viz/service/display_embedder/skia_output_device_vulkan.h"
#include "gpu/vulkan/vulkan_device_queue.h"
#include "gpu/vulkan/vulkan_fence_helper.h"
#include "gpu/vulkan/vulkan_function_pointers.h"
#include "gpu/vulkan/vulkan_implementation.h"
#include "gpu/vulkan/vulkan_util.h"
#include "third_party/skia/include/gpu/ganesh/vk/GrVkBackendSemaphore.h"
#if BUILDFLAG(IS_ANDROID)
#include "components/viz/service/display_embedder/skia_output_device_vulkan_secondary_cb.h"
#endif
#endif

#if BUILDFLAG(IS_OZONE)
#include "ui/ozone/public/ozone_platform.h"
#include "ui/ozone/public/platform_window_surface.h"
#include "ui/ozone/public/surface_factory_ozone.h"
#endif

#if (BUILDFLAG(ENABLE_VULKAN) || BUILDFLAG(SKIA_USE_DAWN)) && \
    BUILDFLAG(IS_OZONE_X11)
#include "components/viz/service/display_embedder/skia_output_device_x11.h"
#endif

#if BUILDFLAG(SKIA_USE_DAWN) && (BUILDFLAG(IS_WIN) || BUILDFLAG(IS_ANDROID))
#include "components/viz/service/display_embedder/skia_output_device_dawn.h"
#endif

#if BUILDFLAG(IS_FUCHSIA)
#include "components/viz/service/display_embedder/output_presenter_fuchsia.h"
#endif

namespace viz {

namespace {

template <typename... Args>
void PostAsyncTaskRepeatedly(
    base::WeakPtr<SkiaOutputSurfaceImplOnGpu> impl_on_gpu,
    const base::RepeatingCallback<void(Args...)>& callback,
    Args... args) {}

template <typename... Args>
base::RepeatingCallback<void(Args...)> CreateSafeRepeatingCallback(
    base::WeakPtr<SkiaOutputSurfaceImplOnGpu> impl_on_gpu,
    const base::RepeatingCallback<void(Args...)>& callback) {}

void FailedSkiaFlush(std::string_view msg) {}

#if BUILDFLAG(ENABLE_VULKAN)
// Returns whether SkiaOutputDeviceX11 can be instantiated on this platform.
bool MayFallBackToSkiaOutputDeviceX11() {}
#endif  // BUILDFLAG(ENABLE_VULKAN)

}  // namespace

SkiaOutputSurfaceImplOnGpu::PromiseImageAccessHelper::PromiseImageAccessHelper(
    SkiaOutputSurfaceImplOnGpu* impl_on_gpu)
    :{}

SkiaOutputSurfaceImplOnGpu::PromiseImageAccessHelper::
    ~PromiseImageAccessHelper() {}

void SkiaOutputSurfaceImplOnGpu::PromiseImageAccessHelper::BeginAccess(
    std::vector<raw_ptr<ImageContextImpl, VectorExperimental>> image_contexts,
    std::vector<GrBackendSemaphore>* begin_semaphores,
    std::vector<GrBackendSemaphore>* end_semaphores) {}

void SkiaOutputSurfaceImplOnGpu::PromiseImageAccessHelper::EndAccess() {}

namespace {

scoped_refptr<gpu::SyncPointClientState> CreateSyncPointClientState(
    SkiaOutputSurfaceDependency* deps,
    gpu::CommandBufferId command_buffer_id,
    gpu::SequenceId sequence_id) {}

std::unique_ptr<gpu::SharedImageFactory> CreateSharedImageFactory(
    SkiaOutputSurfaceDependency* deps,
    gpu::MemoryTracker* memory_tracker) {}

std::unique_ptr<gpu::SharedImageRepresentationFactory>
CreateSharedImageRepresentationFactory(SkiaOutputSurfaceDependency* deps,
                                       gpu::MemoryTracker* memory_tracker) {}

}  // namespace

SkiaOutputSurfaceImplOnGpu::ReleaseCurrent::ReleaseCurrent(
    scoped_refptr<gl::GLSurface> gl_surface,
    scoped_refptr<gpu::SharedContextState> context_state)
    :{}

SkiaOutputSurfaceImplOnGpu::ReleaseCurrent::~ReleaseCurrent() {}

// static
std::unique_ptr<SkiaOutputSurfaceImplOnGpu> SkiaOutputSurfaceImplOnGpu::Create(
    SkiaOutputSurfaceDependency* deps,
    const RendererSettings& renderer_settings,
    const gpu::SequenceId sequence_id,
    gpu::DisplayCompositorMemoryAndTaskControllerOnGpu* shared_gpu_deps,
    DidSwapBufferCompleteCallback did_swap_buffer_complete_callback,
    BufferPresentedCallback buffer_presented_callback,
    ContextLostCallback context_lost_callback,
    ScheduleGpuTaskCallback schedule_gpu_task,
    AddChildWindowToBrowserCallback add_child_window_to_browser_callback,
    SkiaOutputDevice::ReleaseOverlaysCallback release_overlays_callback) {}

SkiaOutputSurfaceImplOnGpu::SkiaOutputSurfaceImplOnGpu(
    base::PassKey<SkiaOutputSurfaceImplOnGpu> /* pass_key */,
    SkiaOutputSurfaceDependency* deps,
    scoped_refptr<gpu::gles2::FeatureInfo> feature_info,
    const RendererSettings& renderer_settings,
    const gpu::SequenceId sequence_id,
    gpu::DisplayCompositorMemoryAndTaskControllerOnGpu* shared_gpu_deps,
    DidSwapBufferCompleteCallback did_swap_buffer_complete_callback,
    BufferPresentedCallback buffer_presented_callback,
    ContextLostCallback context_lost_callback,
    ScheduleGpuTaskCallback schedule_gpu_task,
    AddChildWindowToBrowserCallback add_child_window_to_browser_callback,
    SkiaOutputDevice::ReleaseOverlaysCallback release_overlays_callback)
    :{}

void SkiaOutputSurfaceImplOnGpu::ReleaseAsyncReadResultHelpers() {}

SkiaOutputSurfaceImplOnGpu::~SkiaOutputSurfaceImplOnGpu() {}

void SkiaOutputSurfaceImplOnGpu::Reshape(
    const SkiaOutputDevice::ReshapeParams& params) {}

void SkiaOutputSurfaceImplOnGpu::DrawOverdraw(
    sk_sp<GrDeferredDisplayList> overdraw_ddl,
    SkCanvas& canvas) {}

void SkiaOutputSurfaceImplOnGpu::FinishPaintCurrentFrame(
    sk_sp<GrDeferredDisplayList> ddl,
    sk_sp<GrDeferredDisplayList> overdraw_ddl,
    std::unique_ptr<skgpu::graphite::Recording> graphite_recording,
    std::vector<raw_ptr<ImageContextImpl, VectorExperimental>> image_contexts,
    std::vector<gpu::SyncToken> sync_tokens,
    base::OnceClosure on_finished,
    base::OnceCallback<void(gfx::GpuFenceHandle)> return_release_fence_cb) {}

void SkiaOutputSurfaceImplOnGpu::SwapBuffers(OutputSurfaceFrame frame) {}

void SkiaOutputSurfaceImplOnGpu::SetDependenciesResolvedTimings(
    base::TimeTicks task_ready) {}

void SkiaOutputSurfaceImplOnGpu::SetDrawTimings(base::TimeTicks task_posted) {}

void SkiaOutputSurfaceImplOnGpu::SwapBuffersSkipped() {}

void SkiaOutputSurfaceImplOnGpu::FinishPaintRenderPass(
    const gpu::Mailbox& mailbox,
    sk_sp<GrDeferredDisplayList> ddl,
    sk_sp<GrDeferredDisplayList> overdraw_ddl,
    std::unique_ptr<skgpu::graphite::Recording> graphite_recording,
    std::vector<raw_ptr<ImageContextImpl, VectorExperimental>> image_contexts,
    std::vector<gpu::SyncToken> sync_tokens,
    base::OnceClosure on_finished,
    base::OnceCallback<void(gfx::GpuFenceHandle)> return_release_fence_cb,
    const gfx::Rect& update_rect,
    bool is_overlay) {}

std::unique_ptr<gpu::SkiaImageRepresentation>
SkiaOutputSurfaceImplOnGpu::CreateSharedImageRepresentationSkia(
    SharedImageFormat format,
    const gfx::Size& size,
    const gfx::ColorSpace& color_space,
    std::string_view debug_label) {}

void SkiaOutputSurfaceImplOnGpu::CopyOutputRGBAInMemory(
    SkSurface* surface,
    copy_output::RenderPassGeometry geometry,
    const gfx::ColorSpace& color_space,
    const SkIRect& src_rect,
    SkSurface::RescaleMode rescale_mode,
    bool is_downscale_or_identity_in_both_dimensions,
    std::unique_ptr<CopyOutputRequest> request) {}

namespace {
bool IsValidInTextureCopyOutputRequest(
    const copy_output::RenderPassGeometry& geometry,
    const CopyOutputRequest& request) {}
}  // namespace

void SkiaOutputSurfaceImplOnGpu::CopyOutputRGBA(
    SkSurface* surface,
    copy_output::RenderPassGeometry geometry,
    const gfx::ColorSpace& color_space,
    const SkIRect& src_rect,
    SkSurface::RescaleMode rescale_mode,
    bool is_downscale_or_identity_in_both_dimensions,
    std::unique_ptr<CopyOutputRequest> request) {}

void SkiaOutputSurfaceImplOnGpu::CopyOutputRGBAInTexture(
    SkSurface* surface,
    copy_output::RenderPassGeometry geometry,
    const gfx::ColorSpace& color_space,
    const SkIRect& src_rect,
    SkSurface::RescaleMode rescale_mode,
    bool is_downscale_or_identity_in_both_dimensions,
    std::unique_ptr<CopyOutputRequest> request) {}

void SkiaOutputSurfaceImplOnGpu::RenderSurface(
    SkSurface* surface,
    const SkIRect& source_selection,
    std::optional<SkVector> scaling,
    bool is_downscale_or_identity_in_both_dimensions,
    SkSurface* dest_surface,
    gfx::Point destination_origin) {}

bool SkiaOutputSurfaceImplOnGpu::FlushSurface(
    SkSurface* surface,
    std::vector<GrBackendSemaphore>& end_semaphores,
    gpu::SkiaImageRepresentation::ScopedWriteAccess* scoped_write_access,
    GrGpuFinishedProc ganesh_finished_proc,
    skgpu::graphite::GpuFinishedProc graphite_finished_proc,
    void* finished_context) {}

SkiaOutputSurfaceImplOnGpu::MailboxAccessData::MailboxAccessData() = default;
SkiaOutputSurfaceImplOnGpu::MailboxAccessData::~MailboxAccessData() = default;

bool SkiaOutputSurfaceImplOnGpu::CreateDestinationImageIfNeededAndBeginAccess(
    CopyOutputRequest* request,
    gfx::Size intermediate_dst_size,
    const gfx::ColorSpace& color_space,
    MailboxAccessData& mailbox_access_data) {}

void SkiaOutputSurfaceImplOnGpu::BlendBitmapOverlays(
    SkCanvas* canvas,
    const BlitRequest& blit_request) {}

void SkiaOutputSurfaceImplOnGpu::CopyOutputNV12(
    SkSurface* surface,
    copy_output::RenderPassGeometry geometry,
    const gfx::ColorSpace& color_space,
    const SkIRect& src_rect,
    SkSurface::RescaleMode rescale_mode,
    bool is_downscale_or_identity_in_both_dimensions,
    std::unique_ptr<CopyOutputRequest> request) {}

ReleaseCallback
SkiaOutputSurfaceImplOnGpu::CreateDestroyCopyOutputResourcesOnGpuThreadCallback(
    std::unique_ptr<gpu::SkiaImageRepresentation> representation) {}

void SkiaOutputSurfaceImplOnGpu::DestroyCopyOutputResourcesOnGpuThread(
    const gpu::Mailbox& mailbox) {}

void SkiaOutputSurfaceImplOnGpu::CopyOutput(
    const copy_output::RenderPassGeometry& geometry,
    const gfx::ColorSpace& color_space,
    std::unique_ptr<CopyOutputRequest> request,
    const gpu::Mailbox& mailbox) {}

DBG_FLAG_FBOOL("skia_gpu.buffer_capture.enable", buffer_capture)

void SkiaOutputSurfaceImplOnGpu::BeginAccessImages(
    const std::vector<raw_ptr<ImageContextImpl, VectorExperimental>>&
        image_contexts,
    std::vector<GrBackendSemaphore>* begin_semaphores,
    std::vector<GrBackendSemaphore>* end_semaphores) {}

void SkiaOutputSurfaceImplOnGpu::ResetStateOfImages() {}

void SkiaOutputSurfaceImplOnGpu::EndAccessImages(
    const base::flat_set<raw_ptr<ImageContextImpl, CtnExperimental>>&
        image_contexts) {}

void SkiaOutputSurfaceImplOnGpu::ReleaseImageContexts(
    std::vector<std::unique_ptr<ExternalUseClient::ImageContext>>
        image_contexts) {}

void SkiaOutputSurfaceImplOnGpu::ScheduleOverlays(
    SkiaOutputSurface::OverlayList overlays) {}

void SkiaOutputSurfaceImplOnGpu::SetVSyncDisplayID(int64_t display_id) {}

void SkiaOutputSurfaceImplOnGpu::SetFrameRate(float frame_rate) {}

void SkiaOutputSurfaceImplOnGpu::SetCapabilitiesForTesting(
    const OutputSurface::Capabilities& capabilities) {}

bool SkiaOutputSurfaceImplOnGpu::Initialize() {}

bool SkiaOutputSurfaceImplOnGpu::InitializeForGL() {}

#if BUILDFLAG(ENABLE_VULKAN)
bool SkiaOutputSurfaceImplOnGpu::InitializeForVulkan() {}
#else   // BUILDFLAG(ENABLE_VULKAN)
bool SkiaOutputSurfaceImplOnGpu::InitializeForVulkan() {
  return false;
}
#endif  // !BUILDFLAG(ENABLE_VULKAN)

bool SkiaOutputSurfaceImplOnGpu::InitializeForDawn() {}

bool SkiaOutputSurfaceImplOnGpu::InitializeForMetal() {}

bool SkiaOutputSurfaceImplOnGpu::MakeCurrent(bool need_framebuffer) {}

void SkiaOutputSurfaceImplOnGpu::ReleaseFenceSync(uint64_t sync_fence_release) {}

void SkiaOutputSurfaceImplOnGpu::SwapBuffersInternal(
    std::optional<OutputSurfaceFrame> frame) {}

void SkiaOutputSurfaceImplOnGpu::PostSubmit(
    std::optional<OutputSurfaceFrame> frame) {}

#if BUILDFLAG(IS_WIN)
void SkiaOutputSurfaceImplOnGpu::AddChildWindowToBrowser(
    gpu::SurfaceHandle child_window) {
  PostTaskToClientThread(
      base::BindOnce(add_child_window_to_browser_callback_, child_window));
}
#endif

const gpu::gles2::FeatureInfo* SkiaOutputSurfaceImplOnGpu::GetFeatureInfo()
    const {}

void SkiaOutputSurfaceImplOnGpu::DidSwapBuffersCompleteInternal(
    gpu::SwapBuffersCompleteParams params,
    const gfx::Size& pixel_size,
    gfx::GpuFenceHandle release_fence) {}

void SkiaOutputSurfaceImplOnGpu::ReleaseOverlays(
    const std::vector<gpu::Mailbox> released_overlays) {}

SkiaOutputSurfaceImplOnGpu::DidSwapBufferCompleteCallback
SkiaOutputSurfaceImplOnGpu::GetDidSwapBuffersCompleteCallback() {}

SkiaOutputDevice::ReleaseOverlaysCallback
SkiaOutputSurfaceImplOnGpu::GetReleaseOverlaysCallback() {}

void SkiaOutputSurfaceImplOnGpu::OnContextLost() {}

void SkiaOutputSurfaceImplOnGpu::MarkContextLost(ContextLostReason reason) {}

void SkiaOutputSurfaceImplOnGpu::ScheduleCheckReadbackCompletion() {}

void SkiaOutputSurfaceImplOnGpu::CheckReadbackCompletion() {}

void SkiaOutputSurfaceImplOnGpu::PreserveChildSurfaceControls() {}

void SkiaOutputSurfaceImplOnGpu::InitDelegatedInkPointRendererReceiver(
    mojo::PendingReceiver<gfx::mojom::DelegatedInkPointRenderer>
        pending_receiver) {}

const scoped_refptr<AsyncReadResultLock>
SkiaOutputSurfaceImplOnGpu::GetAsyncReadResultLock() const {}

void SkiaOutputSurfaceImplOnGpu::AddAsyncReadResultHelperWithLock(
    AsyncReadResultHelper* helper) {}

void SkiaOutputSurfaceImplOnGpu::RemoveAsyncReadResultHelperWithLock(
    AsyncReadResultHelper* helper) {}

void SkiaOutputSurfaceImplOnGpu::EnsureBackbuffer() {}
void SkiaOutputSurfaceImplOnGpu::DiscardBackbuffer() {}

#if BUILDFLAG(ENABLE_VULKAN)
gfx::GpuFenceHandle SkiaOutputSurfaceImplOnGpu::CreateReleaseFenceForVulkan(
    const GrBackendSemaphore& semaphore) {}

bool SkiaOutputSurfaceImplOnGpu::CreateAndStoreExternalSemaphoreVulkan(
    std::vector<GrBackendSemaphore>& end_semaphores) {}
#endif

gfx::GpuFenceHandle SkiaOutputSurfaceImplOnGpu::CreateReleaseFenceForGL() {}

void SkiaOutputSurfaceImplOnGpu::CreateSharedImage(
    gpu::Mailbox mailbox,
    SharedImageFormat format,
    const gfx::Size& size,
    const gfx::ColorSpace& color_space,
    SkAlphaType alpha_type,
    gpu::SharedImageUsageSet usage,
    std::string debug_label,
    gpu::SurfaceHandle surface_handle) {}

void SkiaOutputSurfaceImplOnGpu::CreateSolidColorSharedImage(
    gpu::Mailbox mailbox,
    const SkColor4f& color,
    const gfx::ColorSpace& color_space) {}

void SkiaOutputSurfaceImplOnGpu::DestroySharedImage(gpu::Mailbox mailbox) {}

void SkiaOutputSurfaceImplOnGpu::SetSharedImagePurgeable(
    const gpu::Mailbox& mailbox,
    bool purgeable) {}

gpu::SkiaImageRepresentation* SkiaOutputSurfaceImplOnGpu::GetSkiaRepresentation(
    gpu::Mailbox mailbox) {}

#if BUILDFLAG(IS_ANDROID)
base::ScopedClosureRunner SkiaOutputSurfaceImplOnGpu::GetCacheBackBufferCb() {
  if (gl_surface_) {
    DCHECK(!presenter_);
    return dependency_->CacheGLSurface(gl_surface_.get());
  }

  if (presenter_) {
    return dependency_->CachePresenter(presenter_.get());
  }

  return base::ScopedClosureRunner();
}
#endif

void SkiaOutputSurfaceImplOnGpu::CheckAsyncWorkCompletion() {}

#if BUILDFLAG(ENABLE_VULKAN) && BUILDFLAG(IS_CHROMEOS) && \
    BUILDFLAG(USE_V4L2_CODEC)
void SkiaOutputSurfaceImplOnGpu::DetileOverlay(
    gpu::Mailbox input,
    const gfx::Size& input_visible_size,
    gpu::Mailbox output,
    const gfx::RectF& display_rect,
    const gfx::RectF& crop_rect,
    gfx::OverlayTransform transform,
    bool is_10bit) {
  // TODO(greenjustin): Ideally we wouldn't have to recreate the entire
  // VulkanOverlayAdaptor when we change from MM21 to MT2T, since only the
  // shaders really need swapped out.
  if (!vulkan_overlay_adaptor_ ||
      (is_10bit && vulkan_overlay_adaptor_->GetTileFormat() == media::kMM21) ||
      (!is_10bit && vulkan_overlay_adaptor_->GetTileFormat() == media::kMT2T)) {
    vulkan_overlay_adaptor_ = media::VulkanOverlayAdaptor::Create(
        true, is_10bit ? media::kMT2T : media::kMM21);
  }

  // Note that we don't want to get the device queue from the
  // VulkanContextProvider because we actually need a special protected device
  // queue.
  auto input_representation =
      shared_image_representation_factory_->ProduceVulkan(
          input, vulkan_overlay_adaptor_->GetVulkanDeviceQueue(),
          vulkan_overlay_adaptor_->GetVulkanImplementation(),
          /*needs_detiling=*/true);
  auto output_representation =
      shared_image_representation_factory_->ProduceVulkan(
          output, vulkan_overlay_adaptor_->GetVulkanDeviceQueue(),
          vulkan_overlay_adaptor_->GetVulkanImplementation(),
          /*needs_detiling=*/true);

  if (!input_representation || !output_representation) {
    LOG(ERROR) << "Error creating Vulkan representations for detiling.";
    return;
  }

  {
    std::vector<VkSemaphore> begin_semaphores;
    std::vector<VkSemaphore> end_semaphores;
    auto input_access = input_representation->BeginScopedAccess(
        gpu::RepresentationAccessMode::kRead, begin_semaphores, end_semaphores);
    auto output_access = output_representation->BeginScopedAccess(
        gpu::RepresentationAccessMode::kWrite, begin_semaphores,
        end_semaphores);

    vulkan_overlay_adaptor_->Process(
        input_access->GetVulkanImage(), input_visible_size,
        output_access->GetVulkanImage(), display_rect, crop_rect, transform,
        begin_semaphores, end_semaphores);
  }

  output_representation->SetCleared();
}

void SkiaOutputSurfaceImplOnGpu::CleanupImageProcessor() {
  vulkan_overlay_adaptor_ = nullptr;
}
#endif

}  // namespace viz