// Copyright 2017 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/ui/lib/escher/renderer/frame.h"

#ifdef OS_FUCHSIA
#include <zircon/syscalls.h>
#endif

#include "src/lib/fxl/macros.h"
#include "src/ui/lib/escher/escher.h"
#include "src/ui/lib/escher/impl/frame_manager.h"
#include "src/ui/lib/escher/util/trace_macros.h"
#include "src/ui/lib/escher/vk/command_buffer.h"

namespace escher {

namespace {

// Generates a unique frame count for each created frame.
static uint64_t NextFrameNumber() {
  static std::atomic<uint64_t> counter(0);
  return ++counter;
}

}  // anonymous namespace

const ResourceTypeInfo Frame::kTypeInfo("Frame", ResourceType::kResource, ResourceType::kFrame);

Frame::Frame(impl::FrameManager* manager, escher::CommandBuffer::Type requested_type,
             BlockAllocator allocator, impl::UniformBufferPoolWeakPtr uniform_buffer_pool,
             uint64_t frame_number, const char* trace_literal, const char* gpu_vthread_literal,
             uint64_t gpu_vthread_id, bool enable_gpu_logging, bool use_protected_memory)
    : Resource(manager),
      frame_number_(frame_number),
      escher_frame_number_(NextFrameNumber()),
      trace_literal_(trace_literal),
      gpu_vthread_literal_(gpu_vthread_literal),
      gpu_vthread_id_(gpu_vthread_id),
      enable_gpu_logging_(enable_gpu_logging),
      use_protected_memory_(use_protected_memory),
      queue_(escher()->device()->vk_main_queue()),
      command_buffer_type_(requested_type),
      block_allocator_(std::move(allocator)),
      uniform_block_allocator_(std::move(uniform_buffer_pool)),
      // vkCmdBeginQuery, vkCmdEndQuery that is used in querying gpu cannot be executed on a
      // protected command buffer.
      // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkCmdBeginQuery.html
      profiler_((escher()->supports_timer_queries() && enable_gpu_logging && !use_protected_memory)
                    ? fxl::MakeRefCounted<TimestampProfiler>(escher()->vk_device(),
                                                             escher()->timestamp_period())
                    : TimestampProfilerPtr()) {
  FXL_DCHECK(queue_);
}

Frame::~Frame() {
  // Why can we confidently state that if this DCHECK fires, it is because
  // EndFrame() was not called?  Because when EndFrame() submits the command
  // buffer, it registers a closure that will only be called once the frame has
  // finished rendering, and because this closure both:
  // - refs the Frame, keeping it alive until the closure completes
  // - sets the state to kReadyToBegin.
  FXL_DCHECK(state_ == State::kReadyToBegin)
      << "EndFrame() was not called - state_: " << static_cast<int>(state_);
}

vk::CommandBuffer Frame::vk_command_buffer() const {
  FXL_DCHECK(command_buffer_) << "Cannot access command buffer.";
  return command_buffer_->vk();
}

void Frame::BeginFrame() {
  TRACE_DURATION("gfx", "escher::Frame::BeginFrame", "frame_number", frame_number_,
                 "escher_frame_number", escher_frame_number_);
  FXL_DCHECK(state_ == State::kReadyToBegin);
  IssueCommandBuffer();
  AddTimestamp("start of frame");
}

void Frame::IssueCommandBuffer() {
  FXL_DCHECK(!command_buffer_);
  state_ = State::kInProgress;

  command_buffer_ =
      CommandBuffer::NewForType(escher(), command_buffer_type_, use_protected_memory_);
  command_buffer_sequence_number_ = command_buffer_->sequence_number();
}

void Frame::SubmitPartialFrame(const SemaphorePtr& frame_done) {
  FXL_DCHECK(command_buffer_);

  ++submission_count_;
  TRACE_DURATION("gfx", "escher::Frame::SubmitPartialFrame", "frame_number", frame_number_,
                 "escher_frame_number", escher_frame_number_, "submission_index",
                 submission_count_);
  FXL_DCHECK(state_ == State::kInProgress);

  command_buffer_->AddSignalSemaphore(frame_done);
  command_buffer_->Submit(queue_, nullptr);

  // Command buffer has submitted, clear the current command buffer data to
  // recycle it.
  command_buffer_ = nullptr;
  command_buffer_sequence_number_ = 0;
  // Issue a new command buffer this frame can be used for more submits.
  IssueCommandBuffer();
}

void Frame::EndFrame(const SemaphorePtr& frame_done, FrameRetiredCallback frame_retired_callback) {
  FXL_DCHECK(command_buffer_);

  ++submission_count_;
  TRACE_DURATION("gfx", "escher::Frame::EndFrame", "frame_number", frame_number_,
                 "escher_frame_number", escher_frame_number_, "submission_index",
                 submission_count_);
  FXL_DCHECK(state_ == State::kInProgress);
  state_ = State::kFinishing;

  AddTimestamp("end of frame");

  command_buffer_->AddSignalSemaphore(frame_done);

  // Submit the final command buffer and register a callback to perform a
  // variety of bookkeeping and cleanup tasks.
  //
  // NOTE: this closure refs this Frame via a FramePtr, guaranteeing that it
  // will not be destroyed until the frame is finished rendering.
  command_buffer_->Submit(
      queue_, [client_callback{std::move(frame_retired_callback)}, profiler{std::move(profiler_)},
               frame_number = frame_number_, escher_frame_number = escher_frame_number_,
               trace_literal = trace_literal_, gpu_vthread_literal = gpu_vthread_literal_,
               gpu_vthread_id = gpu_vthread_id_, enable_gpu_logging = enable_gpu_logging_,
               this_frame = FramePtr(this)]() {
        // Run the client-specified callback.
        if (client_callback) {
          client_callback();
        }

        // If GPU profiling was enabled, read/interpret the query results and:
        // - add them to the system trace (if active).
        // - if specified, log a summary.
        if (profiler) {
          auto timestamps = profiler->GetQueryResults();
          auto trace_events = profiler->ProcessTraceEvents(timestamps);

          profiler->TraceGpuQueryResults(trace_events, frame_number, escher_frame_number,
                                         trace_literal, gpu_vthread_literal, gpu_vthread_id);

          if (enable_gpu_logging) {
            profiler->LogGpuQueryResults(escher_frame_number, timestamps);
          }
        }

        // |this_frame| refs the frame until rendering is finished, and
        // therefore keeps alive everything in |keep_alive_|.
        this_frame->keep_alive_.clear();

        // The frame is now ready for reuse or destruction.
        this_frame->state_ = State::kReadyToBegin;
      });

  command_buffer_ = nullptr;
  command_buffer_sequence_number_ = 0;

  // Keep per-frame uniform buffers alive until frame is finished rendering.
  for (auto& buf : uniform_block_allocator_.TakeBuffers()) {
    // TODO(ES-103): reconsider this keep-alive scheme.
    // TODO(ES-106): test that blocks make it back to the pool but only after
    // the frame is finished rendering.
    KeepAlive(std::move(buf));
  }

  // Immediately release per-frame CPU memory; it is no longer needed now that
  // all work has been submitted to the GPU.
  block_allocator_.Reset();

  escher()->Cleanup();
}

void Frame::AddTimestamp(const char* name, vk::PipelineStageFlagBits stages) {
  if (profiler_)
    profiler_->AddTimestamp(command_buffer_, stages, name);
}

void Frame::KeepAlive(ResourcePtr resource) { keep_alive_.push_back(std::move(resource)); }

CommandBufferPtr Frame::TakeCommandBuffer() { return std::move(command_buffer_); }

void Frame::PutCommandBuffer(CommandBufferPtr command_buffer) {
  FXL_DCHECK(!command_buffer_ && command_buffer);
  FXL_DCHECK(command_buffer_sequence_number_ == command_buffer->sequence_number());

  command_buffer_ = std::move(command_buffer);
}

GpuAllocator* Frame::gpu_allocator() { return escher()->gpu_allocator(); }

}  // namespace escher
