initial commit

This commit is contained in:
maguoqun 2024-10-08 11:14:06 +08:00
commit 1018ee28cf
30 changed files with 16611 additions and 0 deletions

36
.bianbu-ci.yml Normal file
View file

@ -0,0 +1,36 @@
image: harbor.bianbu.xyz/gitlab/ci-pack
stages:
- pack
pack-job:
stage: pack
script:
- echo "Building for tag $CI_COMMIT_TAG"
- eval $(ssh-agent -s)
- echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
- mkdir -p ~/.ssh
- chmod 700 ~/.ssh
- ssh-keyscan gitlab.dc.com >> ~/.ssh/known_hosts
- chmod 644 ~/.ssh/known_hosts
- git config --global user.email "bianbu-ci@spacemit.com"
- git config --global user.name "bianbu-ci"
# 准备打包脚本
- cd ..
- git clone git@gitlab.dc.com:bianbu/bianbu-devscripts.git
- export PATH=$CI_PROJECT_DIR/../bianbu-devscripts:$PATH
# 准备打包所需的源码从detach切换到分支
- cd $CI_PROJECT_DIR
- git checkout ${CI_COMMIT_TAG%%/*}
- bianbu-dev set-default-dist ${CI_COMMIT_TAG%%/*}
- bianbu-pkg -u local -w . -t $CI_COMMIT_TAG
- changes_file=$(find ../ -maxdepth 1 -type f -name "*.changes" | head -n 1)
# 上传结果
- ssh-keyscan reprepro-headless-service.buildsystem.svc.cluster.local >> ~/.ssh/known_hosts
- bianbu-dev upload --sync $changes_file
# 修改为ssh协议
- git remote set-url origin git@gitlab.dc.com:$CI_PROJECT_NAMESPACE/$CI_PROJECT_NAME.git
- git push origin --all
only:
- tags

9
CMakeLists.txt Normal file
View file

@ -0,0 +1,9 @@
cmake_minimum_required(VERSION 3.10)
project(k1x-gpu-test VERSION 1.0.2 LANGUAGES C)
# set(CMAKE_INSTALL_RPATH /usr/lib)
# set(CMAKE_BUILD_RPATH /usr/lib)
add_subdirectory(openGLDemo)
add_subdirectory(openCLDemo)

8
debian/README.Debian vendored Normal file
View file

@ -0,0 +1,8 @@
k1x-gpu-test for Debian
Please edit this to provide information specific to
this k1x-gpu-test Debian package.
(Automatically generated by debmake Version 4.4.0)
-- root <> Tue, 20 Aug 2024 09:55:38 +0800

4
debian/bianbu.conf vendored Normal file
View file

@ -0,0 +1,4 @@
[package]
upstream = False
targetsuite = noble-porting

5
debian/changelog vendored Normal file
View file

@ -0,0 +1,5 @@
k1x-gpu-test (0.0.1) mantic-porting; urgency=medium
* Initial for bianbu-23.10
-- root <root@localhost> Tue, 20 Aug 2024 09:55:42 +0800

16
debian/control vendored Normal file
View file

@ -0,0 +1,16 @@
Source: k1x-gpu-test
Section: graphics
Priority: optional
Maintainer: baihui-spacemit <>
Build-Depends: cmake, debhelper-compat (= 12), libegl1-mesa-dev, libgles2-mesa-dev, libwayland-dev, libwayland-egl1-mesa, libwayland-cursor0, libc6-dev, ocl-icd-opencl-dev, img-gpu-powervr, libgbm-dev, libdrm-dev
Standards-Version: 1.0.2
Package: k1x-gpu-test
Architecture: any
Multi-Arch: foreign
Depends: ${misc:Depends}, ${shlibs:Depends}, img-gpu-powervr, libgbm-dev
Description: A simple OpenGL/OpenCL test application
.
This package contains a simple test application that demonstrates basic
functionality of OpenGL ES & OpenCL on the RISC-V architecture.

141
debian/copyright vendored Normal file
View file

@ -0,0 +1,141 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: k1x-gpu-test
Upstream-Contact: <preferred name and address to reach the upstream project>
Source: <url://example.com>
#
# Please double check copyright with the licensecheck(1) command.
Files: CMakeLists.txt
common/include/utils_opengles.h
common/source/utils_opengles.c
cube_demo.c
data/bianbu.png
square_demo.c
texture_square_rotation_demo.c
triangle_demo.c
Copyright: __NO_COPYRIGHT_NOR_LICENSE__
License: __NO_COPYRIGHT_NOR_LICENSE__
Files: common/include/xdg-shell-client-protocol.h
Copyright: 2008-2013 Kristian Høgsberg
2010-2013 Intel Corporation
2013 Jasper St. Pierre
2013 Rafael Antognolli
2015-2017 Red Hat Inc.
2015-2017 Samsung Electronics Co., Ltd
License: MIT
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
.
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
</pre>
Files: common/source/xdg-shell-protocol.c
Copyright: 2008-2013 Kristian Høgsberg
2010-2013 Intel Corporation
2013 Jasper St. Pierre
2013 Rafael Antognolli
2015-2017 Red Hat Inc.
2015-2017 Samsung Electronics Co., Ltd
License: MIT
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
.
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
Files: common/include/stb_image.h
Copyright: 2017 Sean Barrett
License: __UNKNOWN__
Permission is hereby granted, free of charge, to any person obtaining a copy of
__MANY_TOTAL_LINES__(7954lines) truncating at: this software and associated documentation files (the "Software"
this software and associated documentation files (the "Software"), to deal in
__MANY_TOTAL_LINES__(7955lines) truncating at: the Software without restriction, including without limitation t
the Software without restriction, including without limitation the rights to
__MANY_TOTAL_LINES__(7956lines) truncating at: use, copy, modify, merge, publish, distribute, sublicense, and/o
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
__MANY_TOTAL_LINES__(7957lines) truncating at: of the Software, and to permit persons to whom the Software is f
of the Software, and to permit persons to whom the Software is furnished to do
__MANY_TOTAL_LINES__(7958lines) truncating at: so, subject to the following conditions:
so, subject to the following conditions:
__MANY_TOTAL_LINES__(7959lines) truncating at: The above copyright notice and this permission notice shall be i
The above copyright notice and this permission notice shall be included in all
__MANY_TOTAL_LINES__(7960lines) truncating at: copies or substantial portions of the Software.
copies or substantial portions of the Software.
__MANY_TOTAL_LINES__(7961lines) truncating at: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
__MANY_TOTAL_LINES__(7962lines) truncating at: IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANT
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
__MANY_TOTAL_LINES__(7963lines) truncating at: FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVEN
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
__MANY_TOTAL_LINES__(7964lines) truncating at: AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
__MANY_TOTAL_LINES__(7965lines) truncating at: LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
__MANY_TOTAL_LINES__(7966lines) truncating at: OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DE
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
__MANY_TOTAL_LINES__(7967lines) truncating at: SOFTWARE.
SOFTWARE.
__MANY_TOTAL_LINES__(7968lines) truncating at: ----------------------------------------------------------------
Files: README.md
Copyright: 2024 SpacemiT
License: BSD-3-Clause
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
.
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.
On Debian systems, the complete text of the BSD 3-clause "New" or "Revised"
License can be found in `/usr/share/common-licenses/BSD'.
#----------------------------------------------------------------------------
# Files marked as NO_LICENSE_TEXT_FOUND may be covered by the following
# license/copyright files.

17
debian/rules vendored Executable file
View file

@ -0,0 +1,17 @@
#!/usr/bin/make -f
include /usr/share/dpkg/pkg-info.mk
SUPPORT = https://www.debian.org/support
export DEB_BUILD_OPTIONS = noopt
# Include common rules from debhelper
%:
dh $@
override_dh_auto_clean:
@echo "Cleaning up..."
rm -rf build
override_dh_shlibdeps:
dh_shlibdeps --dpkg-shlibdeps-params="--ignore-missing-info"

10
debian/salsa-ci.yml vendored Normal file
View file

@ -0,0 +1,10 @@
# For more information on what jobs are run see:
# https://salsa.debian.org/salsa-ci-team/pipeline
#
# To enable the jobs, go to your repository (at salsa.debian.org)
# and click over Settings > CI/CD > Expand (in General pipelines).
# In "CI/CD configuration file" write debian/salsa-ci.yml and click
# in "Save Changes". The CI tests will run after the next commit.
---
include:
- https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/recipes/debian.yml

1
debian/source/format vendored Normal file
View file

@ -0,0 +1 @@
3.0 (native)

9
debian/tests/control vendored Normal file
View file

@ -0,0 +1,9 @@
#
# DEP-8: autopkgtest - automatic as-installed package testing
# Please check * https://dep-team.pages.debian.net/deps/dep8/
# * /usr/share/doc/autopkgtest
#
# !!! Please make sure to edit this to a valid test, otherwise build will fails
#
#Tests: testcode.sh
#Restrictions: allow-stderr, breaks-testbed, needs-internet, needs-root

16
debian/upstream/metadata vendored Normal file
View file

@ -0,0 +1,16 @@
#
# DEP-12: Per-package machine-readable metadata about Upstream
# Please check * https://dep-team.pages.debian.net/deps/dep12/
# * https://wiki.debian.org/UpstreamMetadata
Reference:
Author: <please use full names and separate multiple author by the keyword "and">
Title:
Journal:
Year:
Volume:
Number:
Pages:
DOI:
PMID:
URL:
eprint:

2
debian/watch vendored Normal file
View file

@ -0,0 +1,2 @@
# You must remove unused comment lines for the released package.
version=3

16
openCLDemo/CMakeLists.txt Normal file
View file

@ -0,0 +1,16 @@
# Define the OpenCL version
add_definitions(-DCL_TARGET_OPENCL_VERSION=300) # For OpenCL 3.0
# Add Link Library
set(LINK_LIBRARIES
PVROCL
)
add_executable(gpu-addDemo ${CMAKE_CURRENT_SOURCE_DIR}/add_demo.c)
target_link_libraries(gpu-addDemo ${LINK_LIBRARIES})
install(
TARGETS
gpu-addDemo
DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")

50
openCLDemo/ReadMe.md Normal file
View file

@ -0,0 +1,50 @@
# openGL Demo
## 1.简介
OpenCLOpen Computing Language即开放计算语言最初由苹果公司(Apple)提出后交由非盈利组织Khronos维护。使用OpenCL可以让程序内部并发地执行。
## 2.使用指南
### 2.1克隆仓库
```git
git clone git@gitlab.dc.com:bianbu/graphics/k1x-gpu-test.git
```
### 2.2进到源码目录使用cmake进行编译
```bash
cd k1x-gpu-test/openGLDemo
cmake .
make -j
```
编译完成后会在当前目录下生成 gpu-addDemo 文件,直接运行即可:./gpu-addDemo。如需安装可在当前目录即源码目录下执行 make install 命令,会自动将可执行文件安装到 /usr/local/bin/ 目录下安装完成后可直接运行gpu-addDemo。
### 2.3添加Demo
如果增加一个名为 testDemo.c 的文件,并希望编译得到名为 testDemo 的可执行文件可按以下示例修改CMakeLists.txt
```CMake
# 定义 OpenCL 版本为 300
add_definitions(-DCL_TARGET_OPENCL_VERSION=300)
# 添加链接库
set(LINK_LIBRARIES PVROCL) //设置链接库变量,指定链接库名称
add_executable(gpu-addDemo ${CMAKE_CURRENT_SOURCE_DIR}/add_demo.c)
add_executable(testDemo ${CMAKE_CURRENT_SOURCE_DIR}/testDemo.c) # 创建新的可执行文件
# 链接库,将指定的链接库与可执行文件链接
target_link_libraries(gpu-addDemo ${LINK_LIBRARIES})
target_link_libraries(testDemo ${LINK_LIBRARIES})
# 安装, 将可执行文件安装到指定目录
install(TARGETS
gpu-addDemo
testDemo #安装新的可执行文件
DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
```
然后再次执行 make -j 即可。

299
openCLDemo/add_demo.c Normal file
View file

@ -0,0 +1,299 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <sys/time.h>
#include <CL/cl.h>
// OpenCL kernel to perform an element-wise addition
#if 1
const char *programSource =
"__kernel \n"
"void vec_add(__global float *A, \n"
" __global float *B, \n"
" __global float *C) \n"
"{ \n"
" // Get the work-item's unique ID \n"
" int idx = (get_global_id(0) << 2) & (16384 - 1); \n"
" float4 vector_a = vload4(0, A + idx); \n"
" float4 vector_b = vload4(0, B + idx); \n"
" float4 vector_c = vector_a + vector_b; \n"
" \n"
" // Add the corresponding locations of \n"
" // 'A' and 'B', and store the reasult in 'C' \n"
" vstore4(vector_c, 0, C + idx); \n"
"} \n";
#else
// OpenCL kernel to perform an element-wise addition
const char *programSource =
"__kernel \n"
"void vec_add(__global float *A, \n"
" __global float *B, \n"
" __global float *C) \n"
"{ \n"
" // Get the work-item's unique ID \n"
" int idx = get_global_id(0); \n"
" \n"
" // Add the corresponding locations of \n"
" // 'A' and 'B', and store the reasult in 'C' \n"
" C[idx] = A[idx] + B[idx]; \n"
"} \n";
#endif
// Choose OpenCL platform and create a context
cl_context CreateContext()
{
/* 1. get platform information */
cl_uint num_platforms;
cl_platform_id first_platform_id;
cl_int err_num;
// get num_platforms and platforms ID
err_num = clGetPlatformIDs(1, &first_platform_id, &num_platforms);
if (err_num != CL_SUCCESS || num_platforms <= 0)
{
fprintf(stderr, "Failed to get number of platforms: %d\n", err_num);
return NULL;
}
/* 2. create context */
cl_context context = NULL;
cl_context_properties context_prop[] = {
CL_CONTEXT_PLATFORM,
(cl_context_properties)first_platform_id,
0};
context = clCreateContextFromType(context_prop, CL_DEVICE_TYPE_ALL, NULL, NULL, &err_num);
if (err_num != CL_SUCCESS)
{
fprintf(stderr, "Failed to create context: %d\n", err_num);
return NULL;
}
return context;
}
/* Create command queue */
cl_command_queue CreateCommandQueue(cl_context context, cl_device_id *device)
{
cl_int err_num;
cl_device_id *devices_arr;
cl_command_queue command_queue = NULL;
size_t deviceBufferSize = -1;
// Get device buffer size
err_num = clGetContextInfo(context, CL_CONTEXT_DEVICES, 0, NULL, &deviceBufferSize);
if (deviceBufferSize <= 0)
{
fprintf(stderr, "No devices available: %d\n", err_num);
return NULL;
}
// Allocate cache space for devices
devices_arr = malloc(deviceBufferSize / sizeof(cl_device_id));
err_num = clGetContextInfo(context, CL_CONTEXT_DEVICES, deviceBufferSize, devices_arr, NULL);
// Select the first available device
command_queue = clCreateCommandQueueWithProperties(context, devices_arr[0], 0, NULL);
*device = devices_arr[0];
free(devices_arr);
return command_queue;
}
// Create and build program objects
cl_program CreateProgram(cl_context context, cl_device_id device, const char *srcStr)
{
cl_int err_num;
cl_program program;
program = clCreateProgramWithSource(context, 1, (const char **)&srcStr, NULL, &err_num);
if (err_num != CL_SUCCESS)
{
fprintf(stderr, "Failed to create program: %d\n", err_num);
return NULL;
}
// err_num = clBuildProgram(program, 1, &device, NULL, NULL, NULL);
err_num = clBuildProgram(program, 0, NULL, NULL, NULL, NULL);
if (err_num != CL_SUCCESS)
{
fprintf(stderr, "Failed to build program: %d\n", err_num);
return NULL;
}
return program;
}
// Create memory object
bool CreateMemObjects(cl_context context, cl_mem mem_objects[3], float *a, float *b, size_t datasize)
{
mem_objects[0] = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,
datasize, a, NULL);
mem_objects[1] = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,
datasize, b, NULL);
mem_objects[2] = clCreateBuffer(context, CL_MEM_READ_WRITE,
datasize, NULL, NULL);
return true;
}
// Clean up
void Cleanup(cl_context context, cl_command_queue command_queue,
cl_program program, cl_kernel kernel, cl_mem mem_objects[3])
{
for (int i = 0; i < 3; i++)
{
if (mem_objects[i] != 0)
clReleaseMemObject(mem_objects[i]);
}
if (command_queue != 0)
clReleaseCommandQueue(command_queue);
if (kernel != 0)
clReleaseKernel(kernel);
if (program != 0)
clReleaseProgram(program);
if (context != 0)
clReleaseContext(context);
}
int main(void)
{
struct timeval tv_start, tv_end;
uint64_t time_start, time_end;
cl_int err_num = 0;
cl_context context = 0;
cl_command_queue command_queue = 0;
cl_program program = 0;
cl_device_id device = 0;
cl_kernel kernel = 0;
cl_mem mem_objects[3] = {0, 0, 0};
/* 1. Choose OpenCL platform and create a context */
context = CreateContext();
fprintf(stderr, "Create context success.\n");
/* 2. Create command queue */
command_queue = CreateCommandQueue(context, &device);
fprintf(stderr, "Create command queue success.\n");
/* 3. Create and build program objects */
program = CreateProgram(context, device, programSource);
fprintf(stderr, "Create program success.\n");
/* 4. create kernel */
kernel = clCreateKernel(program, "vec_add", &err_num);
if (err_num != CL_SUCCESS)
{
fprintf(stderr, "Failed to create kernel: %d\n", err_num);
return -1;
}
/* 5. set input data && create memory object */
// Elements in each array
const int elements = 102400000;
// Compute the size of the data
size_t datasize = sizeof(float) * (16384);
// Allocate space for input/output host data
float *A = (float *)malloc(datasize); // Input array
float *B = (float *)malloc(datasize); // Input array
float *C = (float *)malloc(datasize); // Output array
// Initialize the input data
for (int i = 0; i < (16384); i++)
{
A[i] = (float)i;
B[i] = 3.0 * (float)i;
}
// Create MemObjects
if (!CreateMemObjects(context, mem_objects, A, B, datasize))
{
Cleanup(context, command_queue, program, kernel, mem_objects);
return 1;
}
// Write data from the input arrays to the buffers
err_num = clEnqueueWriteBuffer(command_queue, mem_objects[0], CL_FALSE, 0, datasize, A, 0, NULL, NULL);
err_num = clEnqueueWriteBuffer(command_queue, mem_objects[1], CL_FALSE, 0, datasize, B, 0, NULL, NULL);
/* 6. set kernel argument */
err_num = clSetKernelArg(kernel, 0, sizeof(cl_mem), &mem_objects[0]);
if (err_num != CL_SUCCESS)
{
fprintf(stderr, "Failed to set kernel argument 0: %d\n", err_num);
Cleanup(context, command_queue, program, kernel, mem_objects);
}
err_num = clSetKernelArg(kernel, 1, sizeof(cl_mem), &mem_objects[1]);
if (err_num != CL_SUCCESS)
{
fprintf(stderr, "Failed to set kernel argument 1: %d\n", err_num);
Cleanup(context, command_queue, program, kernel, mem_objects);
}
err_num = clSetKernelArg(kernel, 2, sizeof(cl_mem), &mem_objects[2]);
if (err_num != CL_SUCCESS)
{
fprintf(stderr, "Failed to set kernel argument 2: %d\n", err_num);
Cleanup(context, command_queue, program, kernel, mem_objects);
}
gettimeofday(&tv_start, NULL);
/* 7. send kernel to execute */
size_t globalWorkSize[] = {elements / 4, 1, 1};
size_t localWorkSize[] = {32, 1, 1};
int num_loops = 1;
for (int batch = 0; batch < num_loops; batch += 1)
{
err_num = clEnqueueNDRangeKernel(command_queue, kernel, 1, NULL, globalWorkSize,
localWorkSize, 0, NULL, NULL);
if (err_num != CL_SUCCESS)
{
fprintf(stderr, "Failed to enqueue kernel: %d\n", err_num);
Cleanup(context, command_queue, program, kernel, mem_objects);
}
}
#if 1
/* 8. read data from output */
err_num = clEnqueueReadBuffer(command_queue, mem_objects[2], CL_TRUE, 0, datasize, C, 0, NULL, NULL);
if (err_num != CL_SUCCESS)
{
fprintf(stderr, "Failed to read buffer: %d\n", err_num);
Cleanup(context, command_queue, program, kernel, mem_objects);
}
#endif
clFinish(command_queue);
gettimeofday(&tv_end, NULL);
#if 1
for (int i = 0; i < 16384; i++)
{
printf("%f ", C[i]);
}
printf("\n");
#endif
long int start_time_us = tv_start.tv_sec * 1000000L + tv_start.tv_usec;
long int end_time_us = tv_end.tv_sec * 1000000L + tv_end.tv_usec;
long int diff_time_us = end_time_us - start_time_us;
printf("Start time: %ld sec, %ld usec\n", tv_start.tv_sec, tv_start.tv_usec);
printf("End time: %ld sec, %ld usec\n", tv_end.tv_sec, tv_end.tv_usec);
printf("Calculate time for %d addition operations: %ld us\n", elements * num_loops, diff_time_us);
/* 9. clean up */
free(A);
free(B);
free(C);
Cleanup(context, command_queue, program, kernel, mem_objects);
return 0;
}

56
openGLDemo/CMakeLists.txt Normal file
View file

@ -0,0 +1,56 @@
add_definitions(-DSTB_IMAGE_IMPLEMENTATION)
add_definitions(-DNDEBUG)
# Define a public source file list
set(COMMON_SOURCE_FILES
${CMAKE_CURRENT_SOURCE_DIR}/common/source/xdg-shell-protocol.c
${CMAKE_CURRENT_SOURCE_DIR}/common/source/utils_opengles.c
)
# set(CMAKE_BUILD_TYPE Debug)
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/common/include/
)
# Add Link Library
set(LINK_LIBRARIES
EGL
GLESv2
wayland-client
wayland-server
wayland-egl
m
wayland-cursor
gbm
)
add_executable(gpu-cubeDemo ${CMAKE_CURRENT_SOURCE_DIR}/cube_demo.c ${COMMON_SOURCE_FILES})
add_executable(gpu-textureDemo ${CMAKE_CURRENT_SOURCE_DIR}/texture_square_rotation_demo.c ${COMMON_SOURCE_FILES})
add_executable(gpu-squareDemo ${CMAKE_CURRENT_SOURCE_DIR}/square_demo.c ${COMMON_SOURCE_FILES})
add_executable(gpu-triangleDemo ${CMAKE_CURRENT_SOURCE_DIR}/triangle_demo.c ${COMMON_SOURCE_FILES})
add_executable(gpu-cubeTextureDemo ${CMAKE_CURRENT_SOURCE_DIR}/cube_texture_demo.c ${COMMON_SOURCE_FILES})
add_executable(gpu-externalTextureDemo ${CMAKE_CURRENT_SOURCE_DIR}/cube_externalTexture_demo.c ${COMMON_SOURCE_FILES})
target_link_libraries(gpu-cubeDemo ${LINK_LIBRARIES})
target_link_libraries(gpu-textureDemo ${LINK_LIBRARIES})
target_link_libraries(gpu-squareDemo ${LINK_LIBRARIES})
target_link_libraries(gpu-triangleDemo ${LINK_LIBRARIES})
target_link_libraries(gpu-cubeTextureDemo ${LINK_LIBRARIES})
target_link_libraries(gpu-externalTextureDemo ${LINK_LIBRARIES})
install(
TARGETS
gpu-cubeDemo
gpu-textureDemo
gpu-squareDemo
gpu-triangleDemo
gpu-cubeTextureDemo
gpu-externalTextureDemo
DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
file(GLOB IMAGE_FILES "data/*.png")
install(
FILES ${IMAGE_FILES}
DESTINATION "${CMAKE_INSTALL_PREFIX}/data")

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,359 @@
/*
* Copyright © 2011 Benjamin Franzke
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef UTILS_OPENGLES_H
#define UTILS_OPENGLES_H
#include <stdbool.h>
#include <signal.h>
#include <sys/time.h>
#include <GLES3/gl3.h>
#include <GLES3/gl3ext.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include "xdg-shell-client-protocol.h"
#ifndef EGL_WL_bind_wayland_display
#define EGL_WL_bind_wayland_display 1
#ifdef EGL_EGLEXT_PROTOTYPES
EGLAPI EGLBoolean EGLAPIENTRY eglBindWaylandDisplayWL(EGLDisplay dpy, struct wl_display *display);
EGLAPI EGLBoolean EGLAPIENTRY eglUnbindWaylandDisplayWL(EGLDisplay dpy, struct wl_display *display);
#endif
typedef EGLBoolean(EGLAPIENTRYP PFNEGLBINDWAYLANDDISPLAYWL)(EGLDisplay dpy, struct wl_display *display);
typedef EGLBoolean(EGLAPIENTRYP PFNEGLUNBINDWAYLANDDISPLAYWL)(EGLDisplay dpy, struct wl_display *display);
#endif
/*
* This is a little different to the tests shipped with EGL implementations,
* which wrap the entire thing in #ifndef EGL_WL_bind_wayland_display, then go
* on to define both BindWaylandDisplay and QueryWaylandBuffer.
*
* Unfortunately, some implementations (particularly the version of Mesa shipped
* in Ubuntu 12.04) define EGL_WL_bind_wayland_display, but then only provide
* prototypes for (Un)BindWaylandDisplay, completely omitting
* QueryWaylandBuffer.
*
* Detect this, and provide our own definitions if necessary.
*/
#ifndef EGL_WAYLAND_BUFFER_WL
#define EGL_WAYLAND_BUFFER_WL 0x31D5 /* eglCreateImageKHR target */
#define EGL_WAYLAND_PLANE_WL 0x31D6 /* eglCreateImageKHR target */
#define EGL_TEXTURE_Y_U_V_WL 0x31D7
#define EGL_TEXTURE_Y_UV_WL 0x31D8
#define EGL_TEXTURE_Y_XUXV_WL 0x31D9
#define EGL_TEXTURE_EXTERNAL_WL 0x31DA
struct wl_resource;
#ifdef EGL_EGLEXT_PROTOTYPES
EGLAPI EGLBoolean EGLAPIENTRY eglQueryWaylandBufferWL(EGLDisplay dpy, struct wl_resource *buffer, EGLint attribute, EGLint *value);
#endif
typedef EGLBoolean(EGLAPIENTRYP PFNEGLQUERYWAYLANDBUFFERWL)(EGLDisplay dpy, struct wl_resource *buffer, EGLint attribute, EGLint *value);
#endif
#ifndef EGL_WL_create_wayland_buffer_from_image
#define EGL_WL_create_wayland_buffer_from_image 1
#ifdef EGL_EGLEXT_PROTOTYPES
EGLAPI struct wl_buffer *EGLAPIENTRY eglCreateWaylandBufferFromImageWL(EGLDisplay dpy, EGLImageKHR image);
#endif
typedef struct wl_buffer *(EGLAPIENTRYP PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWL)(EGLDisplay dpy, EGLImageKHR image);
#endif
#ifndef EGL_TEXTURE_EXTERNAL_WL
#define EGL_TEXTURE_EXTERNAL_WL 0x31DA
#endif
#ifndef EGL_BUFFER_AGE_EXT
#define EGL_BUFFER_AGE_EXT 0x313D
#endif
#ifndef EGL_WAYLAND_Y_INVERTED_WL
#define EGL_WAYLAND_Y_INVERTED_WL 0x31DB /* eglQueryWaylandBufferWL attribute */
#endif
#ifndef GL_EXT_unpack_subimage
#define GL_EXT_unpack_subimage 1
#define GL_UNPACK_ROW_LENGTH_EXT 0x0CF2
#define GL_UNPACK_SKIP_ROWS_EXT 0x0CF3
#define GL_UNPACK_SKIP_PIXELS_EXT 0x0CF4
#endif /* GL_EXT_unpack_subimage */
/* Mesas gl2ext.h and probably Khronos upstream defined
* GL_EXT_unpack_subimage with non _EXT suffixed GL_UNPACK_* tokens.
* In case we're using that mess, manually define the _EXT versions
* of the tokens here.*/
#if defined(GL_EXT_unpack_subimage) && !defined(GL_UNPACK_ROW_LENGTH_EXT)
#define GL_UNPACK_ROW_LENGTH_EXT 0x0CF2
#define GL_UNPACK_SKIP_ROWS_EXT 0x0CF3
#define GL_UNPACK_SKIP_PIXELS_EXT 0x0CF4
#endif
/* Define needed tokens from EGL_EXT_image_dma_buf_import extension
* here to avoid having to add ifdefs everywhere.*/
#ifndef EGL_EXT_image_dma_buf_import
#define EGL_LINUX_DMA_BUF_EXT 0x3270
#define EGL_LINUX_DRM_FOURCC_EXT 0x3271
#define EGL_DMA_BUF_PLANE0_FD_EXT 0x3272
#define EGL_DMA_BUF_PLANE0_OFFSET_EXT 0x3273
#define EGL_DMA_BUF_PLANE0_PITCH_EXT 0x3274
#define EGL_DMA_BUF_PLANE1_FD_EXT 0x3275
#define EGL_DMA_BUF_PLANE1_OFFSET_EXT 0x3276
#define EGL_DMA_BUF_PLANE1_PITCH_EXT 0x3277
#define EGL_DMA_BUF_PLANE2_FD_EXT 0x3278
#define EGL_DMA_BUF_PLANE2_OFFSET_EXT 0x3279
#define EGL_DMA_BUF_PLANE2_PITCH_EXT 0x327A
#endif
/* Define tokens from EGL_EXT_image_dma_buf_import_modifiers */
#ifndef EGL_EXT_image_dma_buf_import_modifiers
#define EGL_EXT_image_dma_buf_import_modifiers 1
#define EGL_DMA_BUF_PLANE3_FD_EXT 0x3440
#define EGL_DMA_BUF_PLANE3_OFFSET_EXT 0x3441
#define EGL_DMA_BUF_PLANE3_PITCH_EXT 0x3442
#define EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT 0x3443
#define EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT 0x3444
#define EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT 0x3445
#define EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT 0x3446
#define EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT 0x3447
#define EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT 0x3448
#define EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT 0x3449
#define EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT 0x344A
typedef EGLBoolean(EGLAPIENTRYP PFNEGLQUERYDMABUFFORMATSEXTPROC)(EGLDisplay dpy, EGLint max_formats, EGLint *formats, EGLint *num_formats);
typedef EGLBoolean(EGLAPIENTRYP PFNEGLQUERYDMABUFMODIFIERSEXTPROC)(EGLDisplay dpy, EGLint format, EGLint max_modifiers, EGLuint64KHR *modifiers, EGLBoolean *external_only, EGLint *num_modifiers);
#endif
/* Define tokens from EGL_EXT_device_base */
#ifndef EGL_EXT_device_base
#define EGL_EXT_device_base 1
typedef void *EGLDeviceEXT;
#define EGL_NO_DEVICE_EXT EGL_CAST(EGLDeviceEXT, 0)
#define EGL_BAD_DEVICE_EXT 0x322B
#define EGL_DEVICE_EXT 0x322C
typedef EGLBoolean(EGLAPIENTRYP PFNEGLQUERYDEVICEATTRIBEXTPROC)(EGLDeviceEXT device, EGLint attribute, EGLAttrib *value);
typedef const char *(EGLAPIENTRYP PFNEGLQUERYDEVICESTRINGEXTPROC)(EGLDeviceEXT device, EGLint name);
typedef EGLBoolean(EGLAPIENTRYP PFNEGLQUERYDEVICESEXTPROC)(EGLint max_devices, EGLDeviceEXT *devices, EGLint *num_devices);
typedef EGLBoolean(EGLAPIENTRYP PFNEGLQUERYDISPLAYATTRIBEXTPROC)(EGLDisplay dpy, EGLint attribute, EGLAttrib *value);
#ifdef EGL_EGLEXT_PROTOTYPES
EGLAPI EGLBoolean EGLAPIENTRY eglQueryDeviceAttribEXT(EGLDeviceEXT device, EGLint attribute, EGLAttrib *value);
EGLAPI const char *EGLAPIENTRY eglQueryDeviceStringEXT(EGLDeviceEXT device, EGLint name);
EGLAPI EGLBoolean EGLAPIENTRY eglQueryDevicesEXT(EGLint max_devices, EGLDeviceEXT *devices, EGLint *num_devices);
EGLAPI EGLBoolean EGLAPIENTRY eglQueryDisplayAttribEXT(EGLDisplay dpy, EGLint attribute, EGLAttrib *value);
#endif
#endif /* EGL_EXT_device_base */
/* Define tokens from EGL_EXT_device_drm */
#ifndef EGL_EXT_device_drm
#define EGL_EXT_device_drm 1
#define EGL_DRM_DEVICE_FILE_EXT 0x3233
#define EGL_DRM_MASTER_FD_EXT 0x333C
#endif /* EGL_EXT_device_drm */
/* Define tokens from EGL_EXT_device_drm_render_node */
#ifndef EGL_EXT_device_drm_render_node
#define EGL_EXT_device_drm_render_node 1
#define EGL_DRM_RENDER_NODE_FILE_EXT 0x3377
#endif /* EGL_EXT_device_drm_render_node */
#ifndef EGL_EXT_swap_buffers_with_damage
#define EGL_EXT_swap_buffers_with_damage 1
typedef EGLBoolean(EGLAPIENTRYP PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC)(EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint n_rects);
#endif /* EGL_EXT_swap_buffers_with_damage */
#ifndef EGL_MESA_configless_context
#define EGL_MESA_configless_context 1
#define EGL_NO_CONFIG_MESA ((EGLConfig)0)
#endif
#ifndef EGL_NO_CONFIG_KHR
#define EGL_NO_CONFIG_KHR ((EGLConfig)0)
#endif
#ifndef EGL_EXT_platform_base
#define EGL_EXT_platform_base 1
typedef EGLDisplay(EGLAPIENTRYP PFNEGLGETPLATFORMDISPLAYEXTPROC)(EGLenum platform, void *native_display, const EGLint *attrib_list);
typedef EGLSurface(EGLAPIENTRYP PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC)(EGLDisplay dpy, EGLConfig config, void *native_window, const EGLint *attrib_list);
typedef EGLSurface(EGLAPIENTRYP PFNEGLCREATEPLATFORMPIXMAPSURFACEEXTPROC)(EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLint *attrib_list);
#endif /* EGL_EXT_platform_base */
#ifndef EGL_PLATFORM_GBM_KHR
#define EGL_PLATFORM_GBM_KHR 0x31D7
#endif
#ifndef EGL_PLATFORM_WAYLAND_KHR
#define EGL_PLATFORM_WAYLAND_KHR 0x31D8
#endif
#ifndef EGL_PLATFORM_X11_KHR
#define EGL_PLATFORM_X11_KHR 0x31D5
#endif
#ifndef EGL_PLATFORM_SURFACELESS_MESA
#define EGL_PLATFORM_SURFACELESS_MESA 0x31DD
#endif
#ifndef EGL_KHR_cl_event2
#define EGL_KHR_cl_event2 1
typedef void *EGLSyncKHR;
#endif /* EGL_KHR_cl_event2 */
#ifndef EGL_NO_SYNC_KHR
#define EGL_NO_SYNC_KHR ((EGLSyncKHR)0)
#endif
#ifndef EGL_KHR_fence_sync
#define EGL_KHR_fence_sync 1
typedef EGLSyncKHR(EGLAPIENTRYP PFNEGLCREATESYNCKHRPROC)(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list);
typedef EGLBoolean(EGLAPIENTRYP PFNEGLDESTROYSYNCKHRPROC)(EGLDisplay dpy, EGLSyncKHR sync);
#endif /* EGL_KHR_fence_sync */
#ifndef EGL_ANDROID_native_fence_sync
#define EGL_ANDROID_native_fence_sync 1
typedef EGLint(EGLAPIENTRYP PFNEGLDUPNATIVEFENCEFDANDROIDPROC)(EGLDisplay dpy, EGLSyncKHR sync);
#endif /* EGL_ANDROID_native_fence_sync */
#ifndef EGL_SYNC_NATIVE_FENCE_ANDROID
#define EGL_SYNC_NATIVE_FENCE_ANDROID 0x3144
#endif
#ifndef EGL_NO_NATIVE_FENCE_FD_ANDROID
#define EGL_NO_NATIVE_FENCE_FD_ANDROID -1
#endif
#define PI 3.1415926535897932384626433832795f
struct Display
{
struct wl_display *display;
struct wl_registry *registry;
struct wl_compositor *compositor;
struct xdg_wm_base *wm_base;
struct wl_seat *seat;
struct wl_pointer *pointer;
struct wl_touch *touch;
struct wl_keyboard *keyboard;
struct wl_shm *shm;
struct wl_cursor_theme *cursor_theme;
struct wl_cursor *default_cursor;
struct wl_surface *cursor_surface;
struct
{
EGLDisplay dpy;
EGLContext ctx;
EGLConfig conf;
// for external texture
bool has_dma_buf_import_modifiers;
bool has_no_config_context;
} egl;
// for external texture
struct
{
int drm_fd;
struct gbm_device *device;
} gbm;
struct Window *window;
PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC swap_buffers_with_damage;
};
struct geometry
{
int width, height;
};
struct Window
{
struct Display *display;
struct geometry geometry, window_size;
struct
{
GLuint rotation_uniform;
GLuint pos;
GLuint col;
} gl;
uint32_t benchmark_time, frames;
struct wl_egl_window *native;
struct wl_surface *surface;
struct xdg_surface *xdg_surface;
struct xdg_toplevel *xdg_toplevel;
EGLSurface egl_surface;
struct wl_callback *callback;
int fullscreen, maximized, opaque, buffer_size, frame_sync, delay;
bool wait_for_configure;
void *userData;
};
typedef struct
{
int running;
} RunningState;
extern RunningState global_state;
void log_error(const char *message);
void init_egl(struct Display *display, struct Window *window);
void init_gl(struct Window *window);
void create_surface(struct Window *window);
void destroy_surface(struct Window *window);
void registry_handle_global(void *data, struct wl_registry *registry,
uint32_t name, const char *interface, uint32_t version);
void registry_handle_global_remove(void *data, struct wl_registry *registry,
uint32_t name);
void usage(int error_code);
int create_window(struct Window *window, struct Display *display, int ret);
void destroy_window(struct Window *window, struct Display *display);
GLuint load_shader(const char *source, GLenum shader_type);
GLint load_program(const char *vertShaderSrc, const char *fragShaderSrc);
GLuint loadTexture(const char *filename);
unsigned char *load_imageData(const char *filename, int *width, int *height, int *channels, int req_comp);
void free_imageData(unsigned char *data);
void checkProgramLinking(GLuint program);
typedef struct
{
GLfloat m[4][4];
} ESMatrix;
void esScale(ESMatrix *result, GLfloat sx, GLfloat sy, GLfloat sz);
void esTranslate(ESMatrix *result, GLfloat tx, GLfloat ty, GLfloat tz);
void esRotate(ESMatrix *result, GLfloat angle, GLfloat x, GLfloat y, GLfloat z);
void esFrustum(ESMatrix *result, float left, float right, float bottom, float top, float nearZ, float farZ);
void esPerspective(ESMatrix *result, float fovy, float aspect, float nearZ, float farZ);
void esOrtho(ESMatrix *result, float left, float right, float bottom, float top, float nearZ, float farZ);
void esMatrixMultiply(ESMatrix *result, ESMatrix *srcA, ESMatrix *srcB);
void esMatrixLoadIdentity(ESMatrix *result);
void esMatrixLookAt(ESMatrix *result,
float posX, float posY, float posZ,
float lookAtX, float lookAtY, float lookAtZ,
float upX, float upY, float upZ);
#endif

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,183 @@
/* Generated by wayland-scanner 1.21.0 */
/*
* Copyright © 2008-2013 Kristian Høgsberg
* Copyright © 2013 Rafael Antognolli
* Copyright © 2013 Jasper St. Pierre
* Copyright © 2010-2013 Intel Corporation
* Copyright © 2015-2017 Samsung Electronics Co., Ltd
* Copyright © 2015-2017 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <stdlib.h>
#include <stdint.h>
#include "wayland-util.h"
#ifndef __has_attribute
# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
#endif
#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
#define WL_PRIVATE __attribute__ ((visibility("hidden")))
#else
#define WL_PRIVATE
#endif
extern const struct wl_interface wl_output_interface;
extern const struct wl_interface wl_seat_interface;
extern const struct wl_interface wl_surface_interface;
extern const struct wl_interface xdg_popup_interface;
extern const struct wl_interface xdg_positioner_interface;
extern const struct wl_interface xdg_surface_interface;
extern const struct wl_interface xdg_toplevel_interface;
static const struct wl_interface *xdg_shell_types[] = {
NULL,
NULL,
NULL,
NULL,
&xdg_positioner_interface,
&xdg_surface_interface,
&wl_surface_interface,
&xdg_toplevel_interface,
&xdg_popup_interface,
&xdg_surface_interface,
&xdg_positioner_interface,
&xdg_toplevel_interface,
&wl_seat_interface,
NULL,
NULL,
NULL,
&wl_seat_interface,
NULL,
&wl_seat_interface,
NULL,
NULL,
&wl_output_interface,
&wl_seat_interface,
NULL,
&xdg_positioner_interface,
NULL,
};
static const struct wl_message xdg_wm_base_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "create_positioner", "n", xdg_shell_types + 4 },
{ "get_xdg_surface", "no", xdg_shell_types + 5 },
{ "pong", "u", xdg_shell_types + 0 },
};
static const struct wl_message xdg_wm_base_events[] = {
{ "ping", "u", xdg_shell_types + 0 },
};
WL_PRIVATE const struct wl_interface xdg_wm_base_interface = {
"xdg_wm_base", 5,
4, xdg_wm_base_requests,
1, xdg_wm_base_events,
};
static const struct wl_message xdg_positioner_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "set_size", "ii", xdg_shell_types + 0 },
{ "set_anchor_rect", "iiii", xdg_shell_types + 0 },
{ "set_anchor", "u", xdg_shell_types + 0 },
{ "set_gravity", "u", xdg_shell_types + 0 },
{ "set_constraint_adjustment", "u", xdg_shell_types + 0 },
{ "set_offset", "ii", xdg_shell_types + 0 },
{ "set_reactive", "3", xdg_shell_types + 0 },
{ "set_parent_size", "3ii", xdg_shell_types + 0 },
{ "set_parent_configure", "3u", xdg_shell_types + 0 },
};
WL_PRIVATE const struct wl_interface xdg_positioner_interface = {
"xdg_positioner", 5,
10, xdg_positioner_requests,
0, NULL,
};
static const struct wl_message xdg_surface_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "get_toplevel", "n", xdg_shell_types + 7 },
{ "get_popup", "n?oo", xdg_shell_types + 8 },
{ "set_window_geometry", "iiii", xdg_shell_types + 0 },
{ "ack_configure", "u", xdg_shell_types + 0 },
};
static const struct wl_message xdg_surface_events[] = {
{ "configure", "u", xdg_shell_types + 0 },
};
WL_PRIVATE const struct wl_interface xdg_surface_interface = {
"xdg_surface", 5,
5, xdg_surface_requests,
1, xdg_surface_events,
};
static const struct wl_message xdg_toplevel_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "set_parent", "?o", xdg_shell_types + 11 },
{ "set_title", "s", xdg_shell_types + 0 },
{ "set_app_id", "s", xdg_shell_types + 0 },
{ "show_window_menu", "ouii", xdg_shell_types + 12 },
{ "move", "ou", xdg_shell_types + 16 },
{ "resize", "ouu", xdg_shell_types + 18 },
{ "set_max_size", "ii", xdg_shell_types + 0 },
{ "set_min_size", "ii", xdg_shell_types + 0 },
{ "set_maximized", "", xdg_shell_types + 0 },
{ "unset_maximized", "", xdg_shell_types + 0 },
{ "set_fullscreen", "?o", xdg_shell_types + 21 },
{ "unset_fullscreen", "", xdg_shell_types + 0 },
{ "set_minimized", "", xdg_shell_types + 0 },
};
static const struct wl_message xdg_toplevel_events[] = {
{ "configure", "iia", xdg_shell_types + 0 },
{ "close", "", xdg_shell_types + 0 },
{ "configure_bounds", "4ii", xdg_shell_types + 0 },
{ "wm_capabilities", "5a", xdg_shell_types + 0 },
};
WL_PRIVATE const struct wl_interface xdg_toplevel_interface = {
"xdg_toplevel", 5,
14, xdg_toplevel_requests,
4, xdg_toplevel_events,
};
static const struct wl_message xdg_popup_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "grab", "ou", xdg_shell_types + 22 },
{ "reposition", "3ou", xdg_shell_types + 24 },
};
static const struct wl_message xdg_popup_events[] = {
{ "configure", "iiii", xdg_shell_types + 0 },
{ "popup_done", "", xdg_shell_types + 0 },
{ "repositioned", "3u", xdg_shell_types + 0 },
};
WL_PRIVATE const struct wl_interface xdg_popup_interface = {
"xdg_popup", 5,
3, xdg_popup_requests,
3, xdg_popup_events,
};

383
openGLDemo/cube_demo.c Executable file
View file

@ -0,0 +1,383 @@
/*
* 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;
}

View file

@ -0,0 +1,828 @@
/*
* GPU test for Spacemit
* Copyright (C) 2024 Spacemit Co., Ltd.
*
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <utils_opengles.h>
#include <pthread.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <gbm.h>
#include <libdrm/drm_fourcc.h>
#include <GLES2/gl2ext.h>
#include <sys/ioctl.h>
#include <linux/dma-heap.h>
#include <drm/drm_fourcc.h>
#include <errno.h>
bool ready_to_render = false;
pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
#define USE_GBM_BUF 1
#define USE_DMA_BUF 0
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;
GLuint textureID;
GLuint *textures;
int current_texture_index;
} 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 vec3 vPosition;\n"
"layout(location = 1) in vec2 aTexCoord;\n"
"layout(location = 2) in vec4 aColor;\n"
"out vec2 vTextureCoord;\n"
"out vec4 vColor;\n"
"uniform mat4 u_mvpMatrix;\n"
"void main() {\n"
" gl_Position = u_mvpMatrix * vec4(vPosition, 1.0f);\n"
" vTextureCoord = vec2(aTexCoord.x, 1.0 - aTexCoord.y);\n"
" vColor = aColor.argb;\n"
"}\n"};
char fragShaderSrc[] = {
"#version 300 es\n"
"precision mediump float;\n"
"uniform sampler2D uSampler;\n"
"uniform bool useTexture;\n"
"in vec2 vTextureCoord;\n"
"in vec4 vColor;\n"
"out vec4 outColor;\n"
"void main() {\n"
" if(useTexture){\n"
" outColor = texture(uSampler, vTextureCoord).bgra;\n"
" } else{\n"
" outColor = vColor;\n"
" }"
"}\n"};
userData->programObject = load_program(vertShaderSrc, fragShaderSrc);
// Define the vertex positions of the cube
GLfloat vertices[] = {
// vertex // texture
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, // point 0
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, // point 1
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, // point 2
0.5f, 0.5f, 0.5f, 1.0f, 1.0f, // point 3
0.5f, -0.5f, -0.5f, 0.0f, 0.0f, // point 4
-0.5f, -0.5f, -0.5f, 1.0f, 0.0f, // point 5
-0.5f, 0.5f, -0.5f, 1.0f, 1.0f, // point 6
0.5f, 0.5f, -0.5f, 0.0f, 1.0f, // point 7
0.5f, -0.5f, 0.5f, 1.0f, 1.0f, // point 0->8
-0.5f, -0.5f, 0.5f, 0.0f, 1.0f, // point 1->9
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, // point 2->10
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, // point 3->11
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, // point 4->12
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, // point 5->13
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, // point 6->14
0.5f, 0.5f, -0.5f, 1.0f, 1.0f, // point 7->15
};
// Define the vertex index of a cube for drawing solid faces
GLuint indices[] = {
0, 1, 2, 2, 3, 0, // front
1, 5, 6, 6, 2, 1, // left
4, 5, 6, 6, 7, 4, // back
0, 4, 7, 7, 3, 0, // right
8, 12, 13, 13, 9, 8, // bottom
11, 10, 15, 15, 14, 10, // top
};
// Define the wireframe index of the cube
GLuint 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 pointer attribute
GLuint positionAttrib = glGetAttribLocation(userData->programObject, "vPosition");
glVertexAttribPointer(positionAttrib, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (void *)0);
glEnableVertexAttribArray(positionAttrib);
// Texture position attribute
GLuint textureAttrib = glGetAttribLocation(userData->programObject, "aTexCoord");
glVertexAttribPointer(textureAttrib, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (void *)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(textureAttrib);
// 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.5, 1.0, 0.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 = 3;
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.5, 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
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDepthMask(GL_TRUE);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glDisable(GL_BLEND);
// 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);
GLenum error = glGetError();
if (error != GL_NO_ERROR)
{
printf("OpenGL Error: %d\n", error);
}
// Rendering Cube
glUniform1i(glGetUniformLocation(userData->programObject, "useTexture"), GL_TRUE);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, userData->textures[userData->current_texture_index]); // Bind the correct texture
glUniform1i(glGetUniformLocation(userData->programObject, "uSampler"), 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, userData->ebo);
glDrawElements(GL_TRIANGLES, userData->num_indices[0], GL_UNSIGNED_INT, 0);
// Rendering wireframe
glUniform1i(glGetUniformLocation(userData->programObject, "useTexture"), GL_FALSE);
glBindTexture(GL_TEXTURE_2D, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, userData->lineEbo);
glLineWidth(5.0f); // Set line width
const GLfloat wireframeColor[] = {1.0f, 1.0f, 1.0f, 1.0f};
glVertexAttrib4fv(2, wireframeColor); // Set color
glDrawElements(GL_LINES, userData->num_indices[1], GL_UNSIGNED_INT, 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);
}
#if USE_GBM_BUF
#define MAX_BUFFER_PLANES 4
struct Buffer
{
struct Display *display;
struct wl_buffer *buffer;
int busy;
struct gbm_bo *bo;
void *map;
void *map_data;
int width;
int height;
int format;
uint64_t modifier;
int plane_count;
int dmabuf_fds[MAX_BUFFER_PLANES];
uint32_t strides[MAX_BUFFER_PLANES];
uint32_t offsets[MAX_BUFFER_PLANES];
EGLImageKHR egl_image;
GLuint gl_texture;
GLuint gl_fbo;
struct zwp_linux_buffer_release_v1 *buffer_release;
/* The buffer owns the release_fence_fd, until it passes ownership
* to it to EGL (see wait_for_buffer_release_fence). */
int release_fence_fd;
};
static bool display_set_up_gbm(struct Display *display, const char *drm_render_node)
{
fprintf(stdout, "display_set_up_gbm...\n");
display->gbm.drm_fd = open(drm_render_node, O_RDWR);
if (display->gbm.drm_fd < 0)
{
fprintf(stderr, "Failed to open drm render node %s\n",
drm_render_node);
return false;
}
display->gbm.device = gbm_create_device(display->gbm.drm_fd);
if (display->gbm.device == NULL)
{
fprintf(stderr, "Failed to create gbm device\n");
return false;
}
return true;
}
// Create GBM buffer
bool create_gbm_buffer(struct Display *display, struct Buffer *buffer, int width, int height)
{
buffer->format = GBM_FORMAT_ARGB8888;
// fprintf(stdout, "buffer format: %x\n", buffer->format);
buffer->bo = gbm_bo_create(display->gbm.device, width, height, buffer->format, GBM_BO_USE_RENDERING);
if (!buffer->bo)
{
fprintf(stderr, "Failed to create GBM buffer\n");
return false;
}
// Specify the area to be mapped
uint32_t x = 0;
uint32_t y = 0;
uint32_t flags = GBM_BO_TRANSFER_WRITE;
uint32_t stride;
void *map;
void *map_data;
map = gbm_bo_map(buffer->bo, x, y, width, height, flags, &stride, &map_data);
if (!map)
{
fprintf(stderr, "Failed to map GBM buffer\n");
gbm_bo_destroy(buffer->bo);
return false;
}
// Save the mapped pointer to gbm_buf ->map
buffer->map = map;
buffer->strides[0] = stride;
buffer->offsets[0] = 0;
buffer->dmabuf_fds[0] = gbm_bo_get_fd(buffer->bo);
buffer->width = width;
buffer->height = height;
buffer->map_data = map_data;
return true;
}
bool save_buffer_to_bin(struct Buffer *buffer, const char *filename, int total_size)
{
FILE *file = fopen(filename, "wb"); // Open file in binary write mode
if (!file)
{
fprintf(stderr, "Failed to open file '%s' for writing: %s\n", filename, strerror(errno));
return false;
}
size_t bytes_written = fwrite(buffer->map, 1, total_size, file); // Write data
if (bytes_written != total_size)
{
fprintf(stderr, "Failed to write all data to file '%s'\n", filename);
fclose(file);
return false;
}
fclose(file);
return true;
}
GLuint create_texture_gbm(struct Display *display, const char *drm_render_node, struct Buffer *buffer, const char *filename)
{
if (!display_set_up_gbm(display, drm_render_node))
{
fprintf(stderr, "init gbm faild!");
return -1;
}
int width, height, nrChannels, total_size;
unsigned char *image_data = load_imageData(filename, &width, &height, &nrChannels, 0);
if (!image_data)
{
fprintf(stderr, "Failed to load image\n");
free_imageData(image_data);
return EXIT_FAILURE;
}
total_size = width * height * nrChannels;
create_gbm_buffer(display, buffer, width, height);
memcpy(buffer->map, image_data, total_size);
free_imageData(image_data);
EGLint attribs[] = {
EGL_WIDTH, buffer->width,
EGL_HEIGHT, buffer->height,
EGL_LINUX_DRM_FOURCC_EXT, buffer->format,
EGL_DMA_BUF_PLANE0_FD_EXT, buffer->dmabuf_fds[0],
EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0,
EGL_DMA_BUF_PLANE0_PITCH_EXT, gbm_bo_get_stride(buffer->bo),
EGL_NONE};
fprintf(stdout, "GBM-BUF data, width: %d, height: %d, format: %x, dmabuf_fds: %d,\n",
buffer->width, buffer->height, buffer->format, buffer->dmabuf_fds[0]);
PFNEGLCREATEIMAGEKHRPROC create_image;
create_image = (void *)eglGetProcAddress("eglCreateImageKHR");
buffer->egl_image = create_image(display->egl.dpy, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT,
NULL, attribs);
if (buffer->egl_image == EGL_NO_IMAGE_KHR)
{
fprintf(stderr, "EGLImageKHR creation failed, eglGetError():0x%x\n", eglGetError());
return false;
}
GLuint ex_texture;
glGenTextures(1, &ex_texture);
glBindTexture(GL_TEXTURE_2D, ex_texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
PFNGLEGLIMAGETARGETTEXTURE2DOESPROC image_target_texture_2d; // require openGL ES2.0
image_target_texture_2d = (void *)eglGetProcAddress("glEGLImageTargetTexture2DOES");
image_target_texture_2d(GL_TEXTURE_2D, buffer->egl_image);
// fprintf(stdout, "debug:image_target_texture_2d: glGetError(): %d\n", glGetError());
glBindTexture(GL_TEXTURE_2D, 0);
return ex_texture;
}
// Define a structure to store image data
typedef struct
{
unsigned char *data;
int width;
int height;
int nrChannels;
size_t size;
} ImageData;
// Dma buf updates thread function
void *dmabuf_update_thread(void *arg)
{
struct Buffer *buffer = (struct Buffer *)arg;
char *file_names[] = {"/usr/data/bianbu2.png", "/usr/data/bianbu.png"};
int num_imgs = sizeof(file_names) / sizeof(file_names[0]);
ImageData images[num_imgs];
for (int i = 0; i < num_imgs; ++i)
{
images[i].data = load_imageData(file_names[i], &images[i].width, &images[i].height, &images[i].nrChannels, 0);
if (images[i].data == NULL)
{
fprintf(stderr, "Failed to load image %d.\n", i);
exit(EXIT_FAILURE);
}
images[i].size = images[i].width * images[i].height * images[i].nrChannels;
}
int current_image_index = 0;
while (1)
{
current_image_index = (current_image_index + 1) % num_imgs;
// Update buffer ->map content
if (images[current_image_index].data != NULL)
{
pthread_mutex_lock(&mtx);
memcpy(buffer->map, images[current_image_index].data, images[current_image_index].size);
ready_to_render = 1;
pthread_cond_signal(&cv);
pthread_mutex_unlock(&mtx);
}
sleep(3);
}
return NULL;
}
#endif
#if USE_DMA_BUF
GLuint create_texture_dma(struct Display *display, const char *filename)
{
int width, height, nrChannels;
// Load image data
unsigned char *image_data = load_imageData(filename, &width, &height, &nrChannels, 0);
if (!image_data)
{
fprintf(stderr, "Failed to load image\n");
free_imageData(image_data);
return EXIT_FAILURE;
}
// printf("Image loaded with dimensions %dx%d and %d channels.\n", width, height, nrChannels);
int img_size = width * height * nrChannels;
// 1. Allocate DMA-BUF through dma-heap
int dma_heap_fd = open("/dev/dma_heap/system", O_RDWR | O_CLOEXEC);
if (dma_heap_fd < 0)
{
perror("Failed to open dma_heap");
return -1;
}
struct dma_heap_allocation_data alloc_data = {
.len = img_size,
.fd_flags = O_RDWR | O_CLOEXEC,
.heap_flags = 0};
if (ioctl(dma_heap_fd, DMA_HEAP_IOCTL_ALLOC, &alloc_data) < 0)
{
perror("Failed to allocate DMA-BUF");
close(dma_heap_fd);
return -1;
}
fprintf(stdout, "DMA-BUF data, len: %zu, fd: %d, fd_flags: %d, heap_flags: %u\n",
alloc_data.len, alloc_data.fd, alloc_data.fd_flags, alloc_data.heap_flags);
int dma_buf_fd = alloc_data.fd;
close(dma_heap_fd); // No longer need dma-heap file descriptor
// 2. Map DMA-BUF to user space
void *buffer = mmap(NULL, img_size, PROT_READ | PROT_WRITE, MAP_SHARED, dma_buf_fd, 0);
if (buffer == MAP_FAILED)
{
perror("Failed to mmap DMA-BUF");
close(dma_buf_fd);
return -1;
}
// 3. Write data to buffer
// memset(buffer, 0xF0, img_size); // Fill in 0xF0 (ARGB8888 format)
memcpy(buffer, image_data, img_size);
// 4. Cancel mapping
munmap(buffer, img_size);
EGLint attribs[] = {
EGL_WIDTH, width,
EGL_HEIGHT, height,
EGL_LINUX_DRM_FOURCC_EXT, DRM_FORMAT_ARGB8888,
EGL_DMA_BUF_PLANE0_FD_EXT, dma_buf_fd,
EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0,
EGL_DMA_BUF_PLANE0_PITCH_EXT, width * 4,
EGL_NONE};
PFNEGLCREATEIMAGEKHRPROC create_image;
create_image = (void *)eglGetProcAddress("eglCreateImageKHR");
EGLImageKHR egl_image = create_image(display->egl.dpy, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT,
NULL, attribs);
if (egl_image == EGL_NO_IMAGE_KHR)
{
fprintf(stderr, "EGLImageKHR creation failed, eglGetError():0x%x\n", eglGetError());
return false;
}
GLuint ex_texture;
glGenTextures(1, &ex_texture);
glBindTexture(GL_TEXTURE_2D, ex_texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
PFNGLEGLIMAGETARGETTEXTURE2DOESPROC image_target_texture_2d; // for openGL ES2.0
image_target_texture_2d = (void *)eglGetProcAddress("glEGLImageTargetTexture2DOES");
image_target_texture_2d(GL_TEXTURE_2D, egl_image);
// fprintf(stdout, "debug:image_target_texture_2d: glGetError(): %d\n", glGetError());
glBindTexture(GL_TEXTURE_2D, 0);
return ex_texture;
}
// Texture update thread function
void *texture_update_thread(void *arg))
{
UserData *userData = (UserData *)arg while (1)
{
// Protecting critical areas
pthread_mutex_lock(&mtx);
userData->current_texture_index = (userData->current_texture_index + 1) % 2;
pthread_cond_signal(&cv); // Notify rendering thread
pthread_mutex_unlock(&mtx);
ready_to_render = 1;
// Pause for a period of time to observe the effect
sleep(3);
}
return NULL;
}
#endif
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);
char *file_names[2] = {"/usr/data/bianbu.png", "/usr/data/bianbu2.png"};
UserData *userData = window.userData;
userData->textures = malloc(2 * sizeof(GLuint)); // Allocate space for 2 textures
userData->current_texture_index = 0;
pthread_t buf_tid;
fprintf(stdout, "create_texture via %s...\n", USE_GBM_BUF ? "GBM BUF" : "DMA BUF");
#if USE_GBM_BUF
struct Buffer *buffer = malloc(sizeof(struct Buffer));
buffer->display = &display;
userData->textures[0] = create_texture_gbm(&display, "/dev/dri/card1", buffer, file_names[0]);
// save_buffer_to_bin(buffer, "./test-buffer.bin", total_size);
// Create dma buf update thread
if (pthread_create(&buf_tid, NULL, &dmabuf_update_thread, buffer) != 0)
{
perror("Failed to create texture update thread");
return EXIT_FAILURE;
}
#endif
#if USE_DMA_BUF
// Create texture update thread
if (pthread_create(&buf_tid, NULL, &texture_update_thread, userData) != 0)
{
perror("Failed to create texture update thread");
return EXIT_FAILURE;
}
userData->textures[0] = create_texture_dma(&display, file_names[0]);
userData->textures[1] = create_texture_dma(&display, file_names[1]);
#endif
while (global_state.running && ret != -1)
{
ret = wl_display_dispatch_pending(display.display);
Draw(&window, NULL, 0);
}
if (pthread_join(buf_tid, NULL) != 0)
{
fprintf(stderr, "Failed to join texture update thread");
return EXIT_FAILURE;
}
fprintf(stdout, "simple-egl exiting\n");
#if USE_GBM_BUF
free(buffer);
#endif
pthread_mutex_destroy(&mtx);
pthread_cond_destroy(&cv);
destroy_window(&window, &display);
Shutdown(&window);
return 0;
}

432
openGLDemo/cube_texture_demo.c Executable file
View file

@ -0,0 +1,432 @@
/*
* GPU test for Spacemit
* Copyright (C) 2024 Spacemit Co., Ltd.
*
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <utils_opengles.h>
#include <pthread.h>
bool ready_to_render = false;
pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
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;
GLuint textureID;
} 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 vec3 vPosition;\n"
"layout(location = 1) in vec2 aTexCoord;\n"
"layout(location = 2) in vec4 aColor;\n"
"out vec2 vTextureCoord;\n"
"out vec4 vColor;\n"
"uniform mat4 u_mvpMatrix;\n"
"void main() {\n"
" gl_Position = u_mvpMatrix * vec4(vPosition, 1.0f);\n"
" vTextureCoord = vec2(aTexCoord.x, 1.0 - aTexCoord.y);\n"
" vColor = aColor;\n"
"}\n"};
char fragShaderSrc[] = {
"#version 300 es\n"
"precision mediump float;\n"
"uniform sampler2D uSampler;\n"
"uniform bool useTexture;\n"
"in vec2 vTextureCoord;\n"
"in vec4 vColor;\n"
"out vec4 outColor;\n"
"void main() {\n"
" if(useTexture){\n"
" outColor = texture(uSampler, vTextureCoord);\n"
" } else{\n"
" outColor = vColor;\n"
" }"
"}\n"};
userData->programObject = load_program(vertShaderSrc, fragShaderSrc);
// Define the vertex positions of the cube
GLfloat vertices[] = {
// vertex // texture
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, // point 0
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, // point 1
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, // point 2
0.5f, 0.5f, 0.5f, 1.0f, 1.0f, // point 3
0.5f, -0.5f, -0.5f, 0.0f, 0.0f, // point 4
-0.5f, -0.5f, -0.5f, 1.0f, 0.0f, // point 5
-0.5f, 0.5f, -0.5f, 1.0f, 1.0f, // point 6
0.5f, 0.5f, -0.5f, 0.0f, 1.0f, // point 7
0.5f, -0.5f, 0.5f, 1.0f, 1.0f, // point 0->8
-0.5f, -0.5f, 0.5f, 0.0f, 1.0f, // point 1->9
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, // point 2->10
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, // point 3->11
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, // point 4->12
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, // point 5->13
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, // point 6->14
0.5f, 0.5f, -0.5f, 1.0f, 1.0f, // point 7->15
};
// Define the vertex index of a cube for drawing solid faces
GLuint indices[] = {
0, 1, 2, 2, 3, 0, // front
1, 5, 6, 6, 2, 1, // left
4, 5, 6, 6, 7, 4, // back
0, 4, 7, 7, 3, 0, // right
8, 12, 13, 13, 9, 8, // bottom
11, 10, 15, 15, 14, 10, // top
};
// Define the wireframe index of the cube
GLuint 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 pointer attribute
GLuint positionAttrib = glGetAttribLocation(userData->programObject, "vPosition");
glVertexAttribPointer(positionAttrib, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (void *)0);
glEnableVertexAttribArray(positionAttrib);
// Texture position attribute
GLuint textureAttrib = glGetAttribLocation(userData->programObject, "aTexCoord");
glVertexAttribPointer(textureAttrib, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (void *)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(textureAttrib);
// Load texture
GLuint textureID = loadTexture("/usr/data/bianbu2.png");
userData->textureID = textureID;
glBindTexture(GL_TEXTURE_2D, textureID);
// 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.5, 1.0, 0.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.5, 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
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDepthMask(GL_TRUE);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glDisable(GL_BLEND);
// 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);
GLenum error = glGetError();
if (error != GL_NO_ERROR)
{
printf("OpenGL Error: %d\n", error);
}
// Rendering Cube
glUniform1i(glGetUniformLocation(userData->programObject, "useTexture"), GL_TRUE);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, userData->textureID);
glUniform1i(glGetUniformLocation(userData->programObject, "uSampler"), 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, userData->ebo);
glDrawElements(GL_TRIANGLES, userData->num_indices[0], GL_UNSIGNED_INT, 0);
// Rendering wireframe
glUniform1i(glGetUniformLocation(userData->programObject, "useTexture"), GL_FALSE);
glBindTexture(GL_TEXTURE_2D, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, userData->lineEbo);
glLineWidth(5.0f); // Set line width
const GLfloat wireframeColor[] = {1.0f, 1.0f, 1.0f, 1.0f};
glVertexAttrib4fv(2, wireframeColor); // Set color
glDrawElements(GL_LINES, userData->num_indices[1], GL_UNSIGNED_INT, 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;
}

BIN
openGLDemo/data/bianbu.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
openGLDemo/data/bianbu2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 KiB

263
openGLDemo/square_demo.c Executable file
View file

@ -0,0 +1,263 @@
/*
* 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;
// Rotation angle
GLfloat angle;
uint32_t rotate_benchmark_time;
// MVP matrix
ESMatrix mvpMatrix;
ESMatrix perspective;
ESMatrix modelview;
// vertex array, buffer
GLuint vao, vbo, ebo;
} 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"
"void main() {\n"
" gl_Position = vPosition;\n"
"}\n"};
char fragShaderSrc[] = {
"#version 300 es\n"
"precision mediump float;\n"
"out vec4 outColor;\n"
"void main() {\n"
" outColor = vec4 (0.0, 1.0, 0.0, 1.0);\n"
"}\n"};
userData->programObject = load_program(vertShaderSrc, fragShaderSrc);
// Vertex data matrix
float vertices[] = {
0.5f, 0.5f, 0.0f, // point 1
0.5f, -0.5f, 0.0f, // point 2
-0.5f, -0.5f, 0.0f, // point 3
-0.5f, 0.5f, 0.0f, // point 4
};
unsigned int indices[] = {
0, 1, 3, // The first triangle
1, 2, 3, // The second triangle
};
userData->vertices = (GLfloat *)malloc(sizeof(vertices));
memcpy(userData->vertices, vertices, sizeof(vertices));
userData->num_indices = sizeof(indices) / sizeof(indices[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);
glGenBuffers(1, &userData->ebo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, userData->ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (void *)0);
glEnableVertexAttribArray(0);
return 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;
}
// 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);
glBindVertexArray(userData->vao);
glDrawElements(GL_TRIANGLES, userData->num_indices, GL_UNSIGNED_INT, 0);
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;
}

View file

@ -0,0 +1,348 @@
/*
* 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;
// Rotation angle
GLfloat angle;
uint32_t rotate_benchmark_time;
// MVP matrix
ESMatrix mvpMatrix;
ESMatrix perspective;
ESMatrix modelview;
// vertex array, buffer
GLuint vao, vbo, ebo;
} 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 vec2 aTextureCoord;\n"
"uniform mat4 u_mvpMatrix;\n"
"out vec2 vTextureCoord;\n"
"void main() {\n"
" gl_Position = u_mvpMatrix * vPosition;\n"
" vTextureCoord = aTextureCoord;\n"
"}\n"};
char fragShaderSrc[] = {
"#version 300 es\n"
"precision mediump float;\n"
"uniform sampler2D uSampler;\n"
"in vec2 vTextureCoord;\n"
"out vec4 outColor;\n"
"void main() {\n"
" outColor = texture(uSampler, vTextureCoord);\n"
"}\n"};
userData->programObject = load_program(vertShaderSrc, fragShaderSrc);
// Get the uniform locations
userData->mvpLoc = glGetUniformLocation(userData->programObject, "u_mvpMatrix");
float vertices[] = {
// Vertex // texture
0.5f, 0.5f, 0.0f, 1.0f, 0.0f, // point 1
0.5f, -0.5f, 0.0f, 1.0f, 1.0f, // point 2
-0.5f, -0.5f, 0.0f, 0.0f, 1.0f, // point 3
-0.5f, 0.5f, 0.0f, 0.0f, 0.0f // point 4
};
unsigned int indices[] = {
0, 1, 3,
1, 2, 3};
userData->vertices = (GLfloat *)malloc(sizeof(vertices));
memcpy(userData->vertices, vertices, sizeof(vertices));
userData->num_indices = sizeof(indices) / sizeof(indices[0]);
// Load texture
GLuint textureID = loadTexture("/usr/data/bianbu.png");
glBindTexture(GL_TEXTURE_2D, textureID);
// 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);
glGenBuffers(1, &userData->ebo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, userData->ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
// Vertex position attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (void *)0);
glEnableVertexAttribArray(0);
// Texture position attribute
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (void *)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);
// 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 += 5.0f;
if (userData->angle > 12.0f)
{
userData->angle = 2.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]);
// printf("mvpMatrix: %f\n", userData->mvpMatrix[0]);
glBindVertexArray(userData->vao);
glDrawElements(GL_TRIANGLES, userData->num_indices, GL_UNSIGNED_INT, 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;
}

255
openGLDemo/triangle_demo.c Executable file
View file

@ -0,0 +1,255 @@
/*
* 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;
// Vertex data
GLfloat *vertices;
GLuint *indices;
// vertex array, buffer
GLuint vao, vbo;
} 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"
"void main() {\n"
" gl_Position = vPosition;\n"
"}"};
char fragShaderSrc[] = {
"#version 300 es\n"
"precision mediump float;\n"
"out vec4 outColor;\n"
"void main() {\n"
" outColor = vec4(0.0, 0.0, 1.0, 1.0);\n"
"}"};
char *pszVertShader = (char *)vertShaderSrc;
char *pszFragShader = (char *)fragShaderSrc;
GLuint textureVertShader = 0; // Handle used to store Vertex and Fragment shader
GLuint textureFragShader = 0;
GLuint textureProgramObject = 0; // Used to store the handle of the created program
// Create Vertex Shader
textureVertShader = load_shader(pszVertShader, GL_VERTEX_SHADER);
// Create Fragment Shader
textureFragShader = load_shader(pszFragShader, GL_FRAGMENT_SHADER);
// Create rogramObject
textureProgramObject = glCreateProgram();
// Bind Vertex and Fragment Shader
glAttachShader(textureProgramObject, textureVertShader);
glAttachShader(textureProgramObject, textureFragShader);
// Link program
glLinkProgram(textureProgramObject);
checkProgramLinking(textureProgramObject);
userData->programObject = textureProgramObject;
// data
float vertices[] =
{
-0.5f, -0.5f, 0.0f, // point 1
0.5f, -0.5f, 0.0f, // point 2
0.0f, 0.5f, 0.0f, // point 3
};
userData->vertices = (GLfloat *)malloc(sizeof(vertices));
memcpy(userData->vertices, vertices, sizeof(vertices));
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);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (void *)0);
glEnableVertexAttribArray(0);
return 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;
}
// 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);
// Bind program object
glUseProgram(userData->programObject);
// Bind vao
glBindVertexArray(userData->vao);
glDrawArrays(GL_TRIANGLES, 0, 3);
// 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->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");
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;
}