blob: ea8fc0e033b4dab6d5a85379f2e21ee1fba5e09b [file] [log] [blame]
// 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());
}