// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/camera/bin/device/sysmem_allocator.h"

#include <lib/async-loop/default.h>
#include <lib/async/cpp/task.h>
#include <lib/fit/bridge.h>
#include <lib/fit/defer.h>
#include <lib/fit/scope.h>
#include <lib/syslog/cpp/macros.h>

namespace camera {
namespace {

constexpr uint32_t kNamePriority = 30;  // Higher than Scenic but below the maximum.
constexpr uint32_t kMaxAttempts = 10;
constexpr uint32_t kInitialDelayMs = 200;
constexpr uint32_t kFinalDelayMs = 1000;

// After freeing a non-shared buffer collection, we wait some time to give sysmem a chance to fully
// free that memory.
constexpr zx::duration TimeoutForAttempt(uint32_t attempt) {
  return zx::msec(kInitialDelayMs +
                  ((kFinalDelayMs - kInitialDelayMs) * attempt) / (kMaxAttempts - 1));
}

// Returns a promise that completes after calling |WaitForBuffersAllocated| on the provided
// BufferCollection.
//
// The |collection| is consumed by this operation and will be closed upon both success and failure.
fit::promise<fuchsia::sysmem::BufferCollectionInfo_2, zx_status_t> WaitForBuffersAllocated(
    fuchsia::sysmem::BufferCollectionPtr collection) {
  // Move the bridge completer into a shared_ptr so that we can share the completer between the
  // FIDL error handler and the WaitForBuffersAllocated callback.
  fit::bridge<fuchsia::sysmem::BufferCollectionInfo_2, zx_status_t> bridge;
  auto completer =
      std::make_shared<fit::completer<fuchsia::sysmem::BufferCollectionInfo_2, zx_status_t>>(
          std::move(bridge.completer));
  std::weak_ptr<fit::completer<fuchsia::sysmem::BufferCollectionInfo_2, zx_status_t>>
      weak_completer(completer);
  collection.set_error_handler([completer](zx_status_t status) {
    // After calling SetConstraints, allocation may fail. This results in WaitForBuffersAllocated
    // returning NO_MEMORY followed by channel closure. Because the client may observe these in
    // either order, treat channel closure as if it were NO_MEMORY.
    FX_CHECK(status != ZX_OK);
    completer->complete_error(status == ZX_ERR_PEER_CLOSED ? ZX_ERR_NO_MEMORY : status);
  });
  collection->WaitForBuffersAllocated(
      [weak_completer](zx_status_t status,
                       fuchsia::sysmem::BufferCollectionInfo_2 buffers) mutable {
        auto completer = weak_completer.lock();
        if (completer) {
          if (status == ZX_OK) {
            completer->complete_ok(std::move(buffers));
          } else {
            completer->complete_error(status);
          }
        }
      });
  return bridge.consumer.promise().inspect(
      [collection = std::move(collection)](
          const fit::result<fuchsia::sysmem::BufferCollectionInfo_2, zx_status_t>& result) mutable {
        if (collection) {
          collection->Close();
          collection = nullptr;
        }
      });
}

}  // namespace

fit::promise<void, zx_status_t> SysmemAllocator::ProbeForFreeSpace(
    const fuchsia::sysmem::BufferCollectionConstraints& constraints,
    std::unique_ptr<SysmemAllocator::ProbeState> state) {
  TRACE_DURATION("camera", "SysmemAllocator::ProbeForFreeSpace", "attempt", state->attempt);
  // Attempt to allocate a non-shared collection.
  fuchsia::sysmem::BufferCollectionPtr collection;
  allocator_->AllocateNonSharedCollection(collection.NewRequest());
  collection->SetName(0, "FreeSpaceProbe");
  collection->SetConstraints(true, constraints);

  // Move the bridge completer into a shared_ptr so that we can share the completer between the
  return WaitForBuffersAllocated(std::move(collection))
      // Add a delay after completion to allow the prevous allocation to be free'd by sysmem.
      .and_then([this, state = state.get()](fuchsia::sysmem::BufferCollectionInfo_2&) {
        TRACE_DURATION("camera", "SysmemAllocator::ProbeForFreeSpace.delay");
        TRACE_FLOW_STEP("camera", "SysmemAllocator.probe_for_free_space", state->nonce);
        fit::bridge<void, zx_status_t> bridge;
        async::PostDelayedTask(
            dispatcher_,
            [completer = std::move(bridge.completer)]() mutable { completer.complete_ok(); },
            TimeoutForAttempt(state->attempt));
        return bridge.consumer.promise();
      })
      // Try again if appropriate, otherwise return ok or error.
      .then([this, state = std::move(state), constraints](
                fit::result<void, zx_status_t>& result) mutable -> fit::promise<void, zx_status_t> {
        TRACE_DURATION("camera", "SysmemAllocator::ProbeForFreeSpace.complete_or_retry");
        TRACE_FLOW_STEP("camera", "SysmemAllocator.probe_for_free_space", state->nonce);
        if (++state->attempt < kMaxAttempts && result.is_error() &&
            result.error() == ZX_ERR_NO_MEMORY) {
          return ProbeForFreeSpace(constraints, std::move(state));
        }
        return fit::make_result_promise(std::move(result));
      });
}

SysmemAllocator::SysmemAllocator(async_dispatcher_t* dispatcher,
                                 fuchsia::sysmem::AllocatorHandle allocator)
    : dispatcher_(dispatcher), allocator_(allocator.Bind()) {}

fit::promise<fuchsia::sysmem::BufferCollectionInfo_2, zx_status_t>
SysmemAllocator::SafelyBindSharedCollection(
    fuchsia::sysmem::BufferCollectionTokenHandle token,
    fuchsia::sysmem::BufferCollectionConstraints constraints, std::string name) {
  TRACE_DURATION("camera", "SysmemAllocator::BindSharedCollection");
  return WaitForFreeSpace(constraints)
      .then([this, token = std::move(token), constraints,
             name = std::move(name)](const fit::result<>& result) mutable
            -> fit::promise<fuchsia::sysmem::BufferCollectionInfo_2, zx_status_t> {
        if (result.is_error()) {
          return fit::make_result_promise<fuchsia::sysmem::BufferCollectionInfo_2, zx_status_t>(
              fit::error(ZX_ERR_NO_MEMORY));
        }
        // We expect sysmem to have free space, so bind the provided token now.
        fuchsia::sysmem::BufferCollectionPtr collection;
        allocator_->BindSharedCollection(std::move(token), collection.NewRequest());
        collection->SetName(kNamePriority, std::move(name));
        collection->SetConstraints(true, constraints);
        return WaitForBuffersAllocated(std::move(collection));
      })
      .wrap_with(serialize_requests_)
      .wrap_with(scope_);
}

fit::promise<> SysmemAllocator::WaitForFreeSpace(
    fuchsia::sysmem::BufferCollectionConstraints constraints) {
  auto nonce = TRACE_NONCE();
  TRACE_DURATION("camera", "SysmemAllocator::WaitForFreeSpace");
  TRACE_FLOW_BEGIN("camera", "SysmemAllocator.probe_for_free_space", nonce);
  // Incorporate typical client constraints.
  constexpr uint32_t kMaxClientBuffers = 5;
  constexpr uint32_t kBytesPerRowDivisor = 32 * 16;  // GPU-optimal stride.
  constraints.min_buffer_count_for_camping += kMaxClientBuffers;
  for (auto& format_constraints : constraints.image_format_constraints) {
    format_constraints.bytes_per_row_divisor =
        std::max(format_constraints.bytes_per_row_divisor, kBytesPerRowDivisor);
  }

  auto state = std::make_unique<ProbeState>();
  state->nonce = nonce;
  return ProbeForFreeSpace(constraints, std::move(state))
      .then([nonce](fit::result<void, zx_status_t>& result) -> fit::result<> {
        TRACE_DURATION("camera", "SysmemAllocator::ProbeForFreeSpace.completion");
        TRACE_FLOW_END("camera", "SysmemAllocator.probe_for_free_space", nonce);
        if (result.is_ok()) {
          return fit::ok();
        } else {
          return fit::error();
        }
      });
}

}  // namespace camera
