mirror of
https://gitee.com/bianbu-linux/k1x-gpu-test
synced 2025-04-24 14:09:04 -04:00
383 lines
9.8 KiB
C
Executable file
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;
|
|
}
|