k1x-gpu-test/openGLDemo/cube_demo.c
2024-10-08 11:14:06 +08:00

383 lines
9.8 KiB
C
Executable file

/*
* GPU test for Spacemit
* Copyright (C) 2024 Spacemit Co., Ltd.
*
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <utils_opengles.h>
static void signal_int(int signum)
{
global_state.running = 0;
}
typedef struct
{
// Handle to a program object
GLuint programObject;
// Uniform locations
GLint mvpLoc;
// Vertex data
GLfloat *vertices;
GLuint *indices;
int num_indices[2];
// Rotation angle
GLfloat angle;
uint32_t rotate_benchmark_time;
// MVP matrix
ESMatrix mvpMatrix;
ESMatrix perspective;
ESMatrix modelview;
// vertex array, buffer
GLuint vao, vbo, ebo, lineEbo;
} UserData;
//
// Initialize the shader and program object
//
int Init(struct Window *window)
{
UserData *userData = (UserData *)window->userData;
char vertShaderSrc[] = {
"#version 300 es\n"
"layout(location = 0) in vec4 vPosition;\n"
"layout(location = 1) in vec4 aColor;\n"
"out vec4 vColor;\n"
"uniform mat4 u_mvpMatrix;\n"
"void main() {\n"
" gl_Position = u_mvpMatrix * vPosition;\n"
" vColor = aColor;\n"
"}\n"};
char fragShaderSrc[] = {
"#version 300 es\n"
"precision mediump float;\n"
"in vec4 vColor;\n"
"out vec4 outColor;\n"
"void main() {\n"
" outColor = vColor;\n"
"}\n"};
userData->programObject = load_program(vertShaderSrc, fragShaderSrc);
// Define the vertex positions of the cube
GLfloat vertices[] = {
0.5f, -0.5f, 0.5f, // point 1
-0.5f, -0.5f, 0.5f, // point 2
-0.5f, 0.5f, 0.5f, // point 3
0.5f, 0.5f, 0.5f, // point 4
0.5f, -0.5f, -0.5f, // point 5
-0.5f, -0.5f, -0.5f, // point 6
-0.5f, 0.5f, -0.5f, // point 7
0.5f, 0.5f, -0.5f // point 8
};
// Define the vertex index of a cube for drawing solid faces
GLuint indices[] = {
0, 1, 2, 2, 3, 0, // front
4, 5, 6, 6, 7, 4, // back
0, 4, 5, 5, 1, 0, // bottom
1, 5, 6, 6, 2, 1, // left
3, 2, 6, 6, 7, 3, // top
0, 4, 7, 7, 3, 0 // right
};
// Define the wireframe index of the cube
const GLushort lineIndices[] = {
0, 1, 1, 2, 2, 3, 3, 0, // front
4, 5, 5, 6, 6, 7, 7, 4, // back
0, 4, 1, 5, 2, 6, 3, 7, // sides
};
userData->vertices = (GLfloat *)malloc(sizeof(vertices));
memcpy(userData->vertices, vertices, sizeof(vertices));
userData->num_indices[0] = sizeof(indices) / sizeof(indices[0]);
userData->num_indices[1] = sizeof(lineIndices) / sizeof(lineIndices[0]);
// Bind Vertex Array Object (VAO) and Vertex Buffer Object (VBO), and send vertex data to GPU
glGenVertexArrays(1, &userData->vao);
glBindVertexArray(userData->vao);
glGenBuffers(1, &userData->vbo);
glBindBuffer(GL_ARRAY_BUFFER, userData->vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), userData->vertices, GL_STATIC_DRAW);
// Copy the index array into an index buffer for OpenGL to use
glGenBuffers(1, &userData->ebo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, userData->ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
// Create wireframe EBO
glGenBuffers(1, &userData->lineEbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, userData->lineEbo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(lineIndices), lineIndices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
// Set vertex attribute pointer
GLuint positionAttrib = glGetAttribLocation(userData->programObject, "vPosition");
glVertexAttribPointer(positionAttrib, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (void *)0);
glEnableVertexAttribArray(positionAttrib);
// Compute the window aspect ratio
float aspect;
aspect = (GLfloat)window->geometry.width / (GLfloat)window->geometry.height;
// Generate a perspective matrix with a 60 degree FOV
esMatrixLoadIdentity(&userData->perspective);
esPerspective(&userData->perspective, 60.0f, aspect, 1.0f, 15.0f);
// Generate a model view matrix to rotate/translate the cube
esMatrixLoadIdentity(&userData->modelview);
// Translate away from the viewer
esTranslate(&userData->modelview, 0.0, 0.0, -2.0);
// Starting rotation angle for the cube
userData->angle = 0.0f;
// rotate the matrix
esRotate(&userData->modelview, userData->angle, 0.0, 0.0, 1.0);
// Generate a mvp matrix
esMatrixMultiply(&userData->mvpMatrix, &userData->modelview, &userData->perspective);
return 1;
}
void Update(struct Window *window)
{
struct Display *display = window->display;
UserData *userData = (UserData *)window->userData;
// Rotation angle update interval
static uint8_t update_interval;
static const uint8_t initial_update_interval = 1.5;
static const uint8_t subsequent_update_interval = 3;
static uint8_t call_count = 0;
struct timeval tv;
if (gettimeofday(&tv, NULL) == -1)
{
printf("get time of day faild.");
}
uint32_t time = tv.tv_sec * 1000 + tv.tv_usec / 1000;
// Init rotate_benchmark_time and update_interval
if (call_count == 0)
{
userData->rotate_benchmark_time = time;
update_interval = initial_update_interval;
}
// Update rotate_benchmark_time and angle
if (time - userData->rotate_benchmark_time > (update_interval * 1000))
{
update_interval = subsequent_update_interval;
userData->rotate_benchmark_time = time;
userData->angle += 3.0f;
if (userData->angle > 6.0f)
{
userData->angle = 1.0f;
}
}
// Update the model view projection matrix
esRotate(&userData->modelview, userData->angle, 0.0, 1.0, 0.0);
esMatrixMultiply(&userData->mvpMatrix, &userData->modelview, &userData->perspective);
call_count = 1;
}
void Draw(struct Window *window, struct wl_callback *callback, uint32_t time)
{
struct Display *display = window->display;
UserData *userData = (UserData *)window->userData;
static const uint32_t benchmark_interval = 5;
struct wl_region *region;
struct timeval tv;
if (window->callback != callback)
{
log_error("window->callback != callback");
}
window->callback = NULL;
if (callback)
wl_callback_destroy(callback);
if (gettimeofday(&tv, NULL) == -1)
{
printf("get time of day faild.");
}
time = tv.tv_sec * 1000 + tv.tv_usec / 1000;
if (window->frames == 0)
window->benchmark_time = time;
if (time - window->benchmark_time > (benchmark_interval * 1000))
{
printf("%d frames in %d seconds: %f fps\n",
window->frames,
benchmark_interval,
(float)window->frames / benchmark_interval);
window->benchmark_time = time;
window->frames = 0;
}
// Update the model view projection matrix
Update(window);
// Set the viewport
glViewport(0, 0, window->geometry.width, window->geometry.height);
// Clear the color buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Use the program object
glUseProgram(userData->programObject);
// Load the MVP matrix
glUniformMatrix4fv(glGetUniformLocation(userData->programObject, "u_mvpMatrix"), 1, GL_FALSE, (GLfloat *)&userData->mvpMatrix.m[0][0]);
glBindVertexArray(userData->vao);
glDisable(GL_DEPTH_TEST);
// glDepthFunc(GL_LESS);
// glDisable(GL_BLEND);
// Rendering Cube
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, userData->ebo);
// Set color
const GLfloat frameColor[] = {0.0f, 1.0f, 0.0f, 1.0f};
glVertexAttrib4fv(1, frameColor);
glDrawElements(GL_TRIANGLES, userData->num_indices[0], GL_UNSIGNED_INT, 0);
// Rendering wireframe
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, userData->lineEbo);
// Set color
const GLfloat wireframeColor[] = {0.0f, 0.0f, 0.0f, 1.0f};
glVertexAttrib4fv(1, wireframeColor);
glDrawElements(GL_LINES, userData->num_indices[1], GL_UNSIGNED_SHORT, 0);
// Swap buffer
eglSwapBuffers(display->egl.dpy, window->egl_surface);
window->frames++;
}
// Cleanup
void Shutdown(void *data)
{
struct Window *window = data;
UserData *userData = window->userData;
if (userData->vbo != 0)
{
glDeleteBuffers(1, &userData->vbo);
userData->vbo = 0;
}
if (userData->vao != 0)
{
glDeleteBuffers(1, &userData->vao);
userData->vao = 0;
}
if (userData->ebo != 0)
{
glDeleteBuffers(1, &userData->ebo);
userData->ebo = 0;
}
if (userData->vertices != NULL)
{
free(userData->vertices);
}
if (userData->indices != NULL)
{
free(userData->indices);
}
// Delete program object
glDeleteProgram(userData->programObject);
}
int main(int argc, char **argv)
{
struct sigaction sigint;
struct Display display = {0};
struct Window window = {0};
int i, ret = 0;
window.display = &display;
display.window = &window;
window.geometry.width = 512;
window.geometry.height = 512;
window.window_size = window.geometry;
window.buffer_size = 0;
window.frame_sync = 1;
window.delay = 0;
window.userData = malloc(sizeof(UserData));
for (i = 1; i < argc; i++)
{
if (strcmp("-d", argv[i]) == 0 && i + 1 < argc)
window.delay = atoi(argv[++i]);
else if (strcmp("-f", argv[i]) == 0)
// Set full screen display
window.fullscreen = 1;
else if (strcmp("-m", argv[i]) == 0)
// Maximization mode
window.maximized = 1;
else if (strcmp("-o", argv[i]) == 0)
// Create an opaque surface
window.opaque = 1;
else if (strcmp("-s", argv[i]) == 0)
// EGL configuration using 16bpp (16 bit color mode)
window.buffer_size = 16;
else if (strcmp("-b", argv[i]) == 0)
window.frame_sync = 0;
else if (strcmp("-h", argv[i]) == 0)
usage(EXIT_SUCCESS);
else
usage(EXIT_FAILURE);
}
if (create_window(&window, &display, ret) == -1)
{
fprintf(stderr, "Create window faild!");
destroy_window(&window, &display);
Shutdown(&window);
return -1;
}
fprintf(stderr, "Create window success.\n");
if (!Init(&window))
{
fprintf(stderr, "Init openGL faild!");
return -1;
}
fprintf(stderr, "Init openGL success.\n");
// Handling SIGINT signals (usually interrupt signals triggered by pressing Ctrl+C)
sigint.sa_handler = signal_int;
sigemptyset(&sigint.sa_mask);
sigint.sa_flags = SA_RESETHAND;
sigaction(SIGINT, &sigint, NULL);
while (global_state.running && ret != -1)
{
ret = wl_display_dispatch_pending(display.display);
Draw(&window, NULL, 0);
}
fprintf(stderr, "Simple-egl exiting\n");
destroy_window(&window, &display);
Shutdown(&window);
return 0;
}