#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <cuda_runtime.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/imgproc.hpp>
#include "utils.h"
#include "main.h"
#define MAX_RECENT_FPS_DATA_POINTS 5
uchar4*
load_image_opencv(const char* filename, int* iw, int* ih)
{
cv::Mat img = cv::imread(filename, cv::IMREAD_UNCHANGED);
if (img.empty())
{
fprintf(stderr, "Error: could not load '%s'\n", filename);
return NULL;
}
/* convert bgra to rgba like a normal person */
if (img.channels() == 3)
{
cv::cvtColor(img, img, cv::COLOR_BGR2RGBA);
}
else if (img.channels() == 4)
{
cv::cvtColor(img, img, cv::COLOR_BGRA2RGBA);
}
*iw = img.cols;
*ih = img.rows;
uchar4* out = (uchar4*)malloc(img.cols * img.rows * sizeof(uchar4));
memcpy(out, img.data, img.cols * img.rows * sizeof(uchar4));
return out;
}
void
draw_bin_grid(int window_width, int window_height, int bin_dim_x, int bin_dim_y)
{
float bin_w = (float)window_width / bin_dim_x;
float bin_h = (float)window_height / bin_dim_y;
glDisable(GL_TEXTURE_2D);
/* green lines */
glColor3f(0.0f, 1.0f, 0.0f);
glBegin(GL_LINES);
/* vertical lines */
for (int x = 0; x <= bin_dim_x; x++)
{
float px = x * bin_w;
glVertex2f(px, 0.0f);
glVertex2f(px, (float)window_height);
}
/* horizontal lines */
for (int y = 0; y <= bin_dim_y; y++)
{
float py = y * bin_h;
glVertex2f(0.0f, py);
glVertex2f((float)window_width, py);
}
glEnd();
glEnable(GL_TEXTURE_2D);
}
typedef struct
{
float recent[MAX_RECENT_FPS_DATA_POINTS];
int idx;
int filled;
float total;
float data_points;
} FPSTracker;
static FPSTracker fps_tracker = {0};
void
fps_tracker_update(float current_fps, int active_count)
{
fps_tracker.data_points++;
fps_tracker.total += current_fps;
fps_tracker.recent[fps_tracker.idx] = current_fps;
fps_tracker.idx = (fps_tracker.idx + 1) % MAX_RECENT_FPS_DATA_POINTS;
if (fps_tracker.filled < MAX_RECENT_FPS_DATA_POINTS)
{
fps_tracker.filled++;
}
/* ignore the first data points because the data will massively skewed
* with the initial program startup, e.g., > 1000 fps for a few micro
* seconds, because there are not enough projectiles, etc.*/
if (fps_tracker.data_points <= 2)
{
printf("Warming up... (%d/2)\n", (int)fps_tracker.data_points);
return;
}
float rolling_sum = 0.0f;
for (int r = 0; r < fps_tracker.filled; r++)
{
rolling_sum += fps_tracker.recent[r];
}
float rolling_avg = rolling_sum / fps_tracker.filled;
printf("FPS: %.2f. Active: %d. Max: %d. "
"Avg FPS: %.2f. Avg Recent(%d) FPS: %.2f\n",
current_fps, active_count, MAX_PROJS,
fps_tracker.total / fps_tracker.data_points,
MAX_RECENT_FPS_DATA_POINTS, rolling_avg);
}
typedef struct
{
float total_ms;
int count;
} KernelTimer;
static KernelTimer kernel_timer = {0};
void
kernel_timer_record(cudaEvent_t start, cudaEvent_t stop)
{
float ms = 0.0f;
cudaEventElapsedTime(&ms, start, stop);
kernel_timer.total_ms += ms;
kernel_timer.count++;
}
void
kernel_timer_print()
{
if (kernel_timer.count == 0)
{
return;
}
printf("Avg GPU Kernel time: %.4f ms\n",
kernel_timer.total_ms / kernel_timer.count);
}
void
print_kernel_occupancy(const char* name, const void* kernel, size_t shared_mem,
int block_size)
{
int active_blocks;
cudaDeviceProp prop;
cudaGetDeviceProperties(&prop, 0);
cudaOccupancyMaxActiveBlocksPerMultiprocessor(&active_blocks, kernel,
block_size, shared_mem);
float occ =
(float)(active_blocks * block_size) / prop.maxThreadsPerMultiProcessor;
printf("%s: block=%d shared=%zu active_blocks/SM=%d occupancy=%.1f%%\n",
name, block_size, shared_mem, active_blocks, occ * 100.0f);
}