/* * GPU test for Spacemit * Copyright (C) 2024 Spacemit Co., Ltd. * */ #include #include #include #include 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; }