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

#include "components/viz/service/display/test_resource_factory.h"

#include <unordered_map>
#include <vector>

#include "components/viz/client/client_resource_provider.h"
#include "components/viz/common/resources/resource_id.h"
#include "components/viz/service/display/display_resource_provider_skia.h"
#include "components/viz/test/fake_skia_output_surface.h"
#include "components/viz/test/test_context_provider.h"
#include "gpu/command_buffer/client/client_shared_image.h"

namespace viz {
namespace {

static ResourceId CreateResourceInLayerTree(
    ClientResourceProvider* child_resource_provider,
    const gfx::Size& size,
    const TestResourceFactory::TestResourceContext& resource_context,
    SharedImageFormat format) {
  gpu::SharedImageUsageSet usage = gpu::SHARED_IMAGE_USAGE_DISPLAY_READ;
  if (resource_context.is_overlay_candidate) {
    usage |= gpu::SHARED_IMAGE_USAGE_SCANOUT;
  }
  if (resource_context.is_low_latency_rendering) {
    usage |= gpu::SHARED_IMAGE_USAGE_CONCURRENT_READ_WRITE;
  }
  auto resource = TransferableResource::Make(
      gpu::ClientSharedImage::CreateForTesting(
          {format, size, gfx::ColorSpace(), kTopLeft_GrSurfaceOrigin,
           kPremul_SkAlphaType, usage},
          GL_TEXTURE_2D),
      TransferableResource::ResourceSource::kTest, gpu::SyncToken());

  ResourceId resource_id =
      child_resource_provider->ImportResource(resource, base::DoNothing());

  return resource_id;
}

}  // namespace

TestResourceFactory::TestResourceFactory() {
  output_surface_ = FakeSkiaOutputSurface::Create3d();
  output_surface_->BindToClient(&output_surface_client_);

  display_resource_provider_ = std::make_unique<DisplayResourceProviderSkia>();
  lock_set_for_external_use_.emplace(display_resource_provider_.get(),
                                     output_surface_.get());

  client_context_provider_ = TestContextProvider::CreateGLES();
  client_context_provider_->BindToCurrentSequence();
  client_resource_provider_ = std::make_unique<ClientResourceProvider>();
}

TestResourceFactory::~TestResourceFactory() {
  client_resource_provider_->ShutdownAndReleaseAllResources();
  client_resource_provider_ = nullptr;
  client_context_provider_ = nullptr;
  lock_set_for_external_use_.reset();
  display_resource_provider_ = nullptr;
  output_surface_ = nullptr;
}

ResourceId TestResourceFactory::CreateResource(
    const gfx::Size& size,
    const TestResourceContext& resource_context,
    SharedImageFormat format,
    SurfaceId test_surface_id) {
  ResourceId resource_id = CreateResourceInLayerTree(
      client_resource_provider_.get(), size, resource_context, format);

  const int child_id = display_resource_provider_->CreateChild(
      base::DoNothing(), test_surface_id);

  // Transfer resource to the parent.
  std::vector<ResourceId> resource_ids_to_transfer;
  resource_ids_to_transfer.push_back(resource_id);
  std::vector<TransferableResource> list;

  CHECK(client_context_provider_);
  client_resource_provider_->PrepareSendToParent(
      resource_ids_to_transfer, &list,
      client_context_provider_->SharedImageInterface());
  display_resource_provider_->ReceiveFromChild(child_id, list);

  // Delete it in the child so it won't be leaked, and will be released once
  // returned from the parent.
  client_resource_provider_->RemoveImportedResource(resource_id);

  // In DisplayResourceProvider's namespace, use the mapped resource id.
  std::unordered_map<ResourceId, ResourceId, ResourceIdHasher> resource_map =
      display_resource_provider_->GetChildToParentMap(child_id);
  return resource_map[list[0].id];
}

}  // namespace viz
