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

#include <iostream>
#include <math.h>
#include <vector>

#include "workload.h"

// Vertex buffer creation.
bool Workload::Initialize(int frame_count) {
#if defined (USE_OPENGLES)
  const char* exts = (const char*)glGetString(GL_EXTENSIONS);
  if (!strstr(exts, "GL_EXT_disjoint_timer_query")) {
    printf("# Error: QueryGetTest could not find query extension(s).\n");
    return false;
  }
#endif

  queries_.resize(frame_count);
  quad_counts_.resize(frame_count);
  glGenQueries(queries_.size(), queries_.data());

  glGenVertexArrays(1, &VAO_);
  glGenBuffers(1, &VBO_);
  glGenBuffers(1, &EBO_);
  glBindVertexArray(VAO_);

  glBindBuffer(GL_ARRAY_BUFFER, VBO_);
  glBufferData(GL_ARRAY_BUFFER,
               vertices_.size() * sizeof(GLfloat),
               vertices_.data(),
               GL_DYNAMIC_DRAW);

  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO_);
  glBufferData(GL_ELEMENT_ARRAY_BUFFER,
               indices_.size() * sizeof(GLuint),
               indices_.data(),
               GL_DYNAMIC_DRAW);

  glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void *)0);
  glEnableVertexAttribArray(0);

  glUniform1f(1, 10); // uniform float mod_size
  glUniform1f(2, 1);  // uniform float line_idx
  glUniform1f(3, 10); // uniform float start_size
  return true;
}

// Bind vertex buffer with a set number of instanced quads.
void Workload::UpdateWorkload(int num_quads) {
  num_quads_ = num_quads;
  // triangle size needs to be scaled by the sqrt of the number of triangles.
  GLfloat mod_size = std::floor(std::sqrt(num_quads_));
  glUniform1f(1, mod_size);
}

void Workload::Draw() {
  // Clear the screen before any rendering happens.
  glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
  glClear(GL_COLOR_BUFFER_BIT);

  // Create a vertical bar that moves across the screen.
  // Lets user know that application hasn't hung, and may help with detecting
  // screen tearing.
  static uint line_idx{1};
  ++line_idx;
  glUniform1f(2, line_idx);

  glDrawElementsInstanced(
        GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0, num_quads_);
}

bool NearlyEqual(double gpu_elapsed_time, double gpu_workload_ms) {
  double workload_ms_error = 0.1f;
  return abs(gpu_elapsed_time - gpu_workload_ms) < workload_ms_error;
}

void Workload::IncreaseWorkload() {
  UpdateWorkload(num_quads_ * gpu_workload_increase_);
}

void Workload::DecreaseWorkload(bool record_quads) {
  UpdateWorkload(static_cast<int>(std::floor(
      num_quads_ * gpu_workload_precision_)));
  // num_quads_ has been updated. store new value for logging
  if (record_quads) {
    quad_counts_[num_throttles_] = num_quads_;
    ++num_throttles_;
  }
}

void Workload::CalibrateWorkload(double gpu_workload_ms) {
  // give 100 frames max to get close to workload
  int max_frames = 100;
  int loading_window = 10;
  // Start at a reasonable number of quads.
  UpdateWorkload(10000);

  double gpu_elapsed_time = 0;
  int calibrate_count = 0;
  for (int num_frames = 0; num_frames < max_frames; ++num_frames) {
    if (num_frames > loading_window) {
      if (NearlyEqual(gpu_elapsed_time, gpu_workload_ms)){
        if (calibrate_count++ == 1) break;
      } else if (gpu_elapsed_time < gpu_workload_ms) {
        IncreaseWorkload();
        std::cout << "Updated num quads to: " << num_quads_ << std::endl;
      } else {
        DecreaseWorkload();
        std::cout << "Updated num quads to: " << num_quads_ << std::endl;
      }
    }

    UpdateWorkload(num_quads_);
    StartTimer(num_frames);
    Draw();
    EndTimer();
    gpu_elapsed_time = GetFrameGpuTime(num_frames);
    std::cout << "calibrating: gpu_elapsed_time: "
              << gpu_elapsed_time << " ms" << std::endl;
  }
  glUniform1f(3, std::floor(std::sqrt(num_quads_)));
  if (calibrate_count == 0) {
    std::cout << "Warning: Did not hit calibration target.\n" << std::endl;
  }
  if (calibrate_count > 0) {
    std::cout << "Finished calibrating workload.\n" << std::endl;
  }
}

void Workload::StartTimer(int frame) {
  const GLuint query = queries_[frame % queries_.size()];
  glBeginQuery(GL_TIME_ELAPSED, query);
}

void Workload::EndTimer() {
  glEndQuery(GL_TIME_ELAPSED);
}

double Workload::GetFrameGpuTime(int frame) {
  GLuint gpu_elapsed_time;
  glGetQueryObjectuiv(queries_[frame], GL_QUERY_RESULT, &gpu_elapsed_time);
  return NS_TO_MS(gpu_elapsed_time);
}

void Workload::PrintQuadHistory() {
  for (int i = 0; i < num_throttles_; ++i) {
    std::cout << "Quad count decreased to: " << quad_counts_[i] << std::endl;
  }
}

void Workload::TakeDown() {
  glDeleteQueries(queries_.size(), queries_.data());
}
