MainActivity.java
package pbbadd.opengl.gles30;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
public class MainActivity extends AppCompatActivity {
private GLSurfaceView mGLSurfaceView;
private GLES3Renderer mRenderer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 1. 创建GLES3渲染视图(核心载体)
mGLSurfaceView = new GLSurfaceView(this);
// 2. 明确指定使用GLES 3.0版本(必加)
mGLSurfaceView.setEGLContextClientVersion(3);
// 3. 设置自定义渲染器,核心GLES3调用在渲染器中执行
mRenderer = new GLES3Renderer();
mGLSurfaceView.setRenderer(mRenderer);
// 4. 设置渲染模式:仅绘制一次(满足「调用一次glBindBuffer」需求)
mGLSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
// 5. 显示渲染视图
setContentView(mGLSurfaceView);
}
// ✅ 重写Activity销毁方法【时机2:兜底释放】
// Activity退出时,主动触发渲染器的销毁逻辑,双重保障
@Override
protected void onDestroy() {
super.onDestroy();
if (mGLSurfaceView != null) {
// 终止GLES渲染线程,释放资源
mGLSurfaceView.onPause();
// 主动调用渲染器的销毁方法(在GL线程执行deinit)
mRenderer.onDestroy();
}
}
// ✅ 重写Activity暂停方法(规范GLES生命周期)
@Override
protected void onPause() {
super.onPause();
if (mGLSurfaceView != null) {
mGLSurfaceView.onPause();
}
}
// ✅ 重写Activity恢复方法(规范GLES生命周期)
@Override
protected void onResume() {
super.onResume();
if (mGLSurfaceView != null) {
mGLSurfaceView.onResume();
}
}
// 自定义GLES3渲染器,实现GLSurfaceView.Renderer接口
private class GLES3Renderer implements GLSurfaceView.Renderer {
// 回调1:GLES上下文创建时执行(仅执行一次,核心初始化入口)
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// 调用Native层C++代码,执行GLES3核心操作(含glBindBuffer)
nativeTestInit();
nativeTest2();
}
// 回调2:视图尺寸变化时执行
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
// 设置GLES视口大小
nativeGLES3SetViewport(width/2, height/2);
}
// 回调3:每帧绘制时执行
@Override
public void onDrawFrame(GL10 gl) {
nativeGLES3DrawFrame();
}
public void onDestroy() {
// 用GLSurfaceView的队列,在GL线程执行释放(保证线程安全)
mGLSurfaceView.queueEvent(MainActivity.this::nativeTestDeinit);
}
}
// 声明Native方法(与C++层JNI绑定)
static {
System.loadLibrary("gles3copydemo"); // 加载CMake编译的so库
}
private native void nativeTestInit();
private native void nativeTestDeinit();
private native void nativeTest2();
private native void nativeGLES3SetViewport(int width, int height);
private native void nativeGLES3DrawFrame();
}
native-lib.cpp
#include <jni.h>
#include <string>
#include <GLES3/gl3.h> // GLES3.0核心头文件(必加)
#include <android/log.h>
#include <__random/mersenne_twister_engine.h>
#include <__random/uniform_real_distribution.h>
#include <__random/random_device.h>
// 日志宏定义,方便调试
#define TAG "GLES3_COPY_DEMO"
#define LOGE(fmt,...) __android_log_print(ANDROID_LOG_ERROR, TAG, "pbbadd,bufferwriterandomtest,%d," fmt, __LINE__, ##__VA_ARGS__)
#define LOGW(fmt,...) __android_log_print(ANDROID_LOG_WARN, TAG, "pbbadd,bufferwriterandomtest,%d," fmt, __LINE__, ##__VA_ARGS__)
#define LOGI(fmt,...) __android_log_print(ANDROID_LOG_INFO, TAG, "pbbadd,bufferwriterandomtest,%d," fmt, __LINE__, ##__VA_ARGS__)
static GLuint srcBufferNo = 9999;
static GLuint dstBufferNo=9999;
static GLenum err;
#define print_error_indent {err = glGetError(); if(GL_NO_ERROR!=err) LOGE("err=0x%x",err);}
// 全局变量:存储COPY_READ_BUFFER的缓冲ID
static GLuint g_copyReadBufferId = 0;
#define MIN_SIZE 12 // 整数随机最小值
#define MAX_SIZE 32*1024 // 整数随机最大值
static std::random_device rd;
static std::mt19937 gen(rd());
// 浮点数分布器:固定生成 0.0f ~ 1.0f 浮点数
static std::uniform_real_distribution<float> dis_f(0.0f, 1.0f);
// 整数分布器:生成 [MIN_SIZE, MAX_SIZE] 范围内的整数
static std::uniform_int_distribution<int> sizeDist(MIN_SIZE, MAX_SIZE);
void generateRandomData(GLubyte* data, int size) {
for (int i = 0; i < size; i++) {
data[i] = static_cast<GLubyte>(dis_f(gen) * 256.0f);
}
}
static float getRandomFloat01() {
return dis_f(gen);
}
static float getRandomFloat(float min, float max) {
std::uniform_real_distribution<float> dis(min, max);
return dis(gen);
}
static int getRandomSize() {
return sizeDist(gen);
}
// ------------------------ JNI方法:GLES3初始化 ------------------------
// ------------------------ 适配新包名:pbbadd.opengl.gles30 ------------------------
extern "C" JNIEXPORT void JNICALL
Java_pbbadd_opengl_gles30_MainActivity_nativeGLES3Init(JNIEnv *env, jobject thiz) {
LOGI("=== enter ==="); print_error_indent;
glGenBuffers(1, &g_copyReadBufferId); print_error_indent;
LOGI("id=%d",g_copyReadBufferId);
glBindBuffer(GL_COPY_READ_BUFFER, g_copyReadBufferId); print_error_indent;
GLsizeiptr bufferSize = 1024 * sizeof(GLfloat);
glBufferData(GL_COPY_READ_BUFFER, bufferSize, nullptr, GL_STATIC_READ); print_error_indent;
LOGI("bufferSize=%ld", bufferSize);
glDeleteBuffers(1,&g_copyReadBufferId);
LOGI("=== finish ===");
}
extern "C" JNIEXPORT void JNICALL
Java_pbbadd_opengl_gles30_MainActivity_nativeTestInit(JNIEnv *env, jobject thiz) {
glGenBuffers(1,&srcBufferNo); print_error_indent;
glGenBuffers(1,&dstBufferNo); print_error_indent;
LOGW("glGenBuffers done");
}
extern "C" JNIEXPORT void JNICALL
Java_pbbadd_opengl_gles30_MainActivity_nativeTestDeinit(JNIEnv *env, jobject thiz) {
glDeleteBuffers(1,&srcBufferNo); print_error_indent;
glDeleteBuffers(1,&dstBufferNo); print_error_indent;
LOGW("glDeleteBuffers done");
}
extern "C" JNIEXPORT void JNICALL
Java_pbbadd_opengl_gles30_MainActivity_nativeTest2(JNIEnv *env, jobject thiz) {
int srcSize = sizeDist(gen);
int dstSize = srcSize;
GLubyte *srcData = new GLubyte[srcSize]();
GLubyte *dstData = new GLubyte[dstSize]();
generateRandomData(srcData,srcSize);
glBindBuffer(GL_COPY_READ_BUFFER, srcBufferNo); print_error_indent;
glBufferData(GL_COPY_READ_BUFFER,srcSize,srcData,GL_STREAM_DRAW); print_error_indent;
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,srcBufferNo); print_error_indent;
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER,0,srcSize,srcData); print_error_indent;
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER,0,srcSize,srcData); print_error_indent;
glBindBuffer(GL_ARRAY_BUFFER,srcBufferNo); print_error_indent;
glBufferSubData(GL_ARRAY_BUFFER,0,srcSize,srcData); print_error_indent;
glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER,srcBufferNo); print_error_indent;
glBufferSubData(GL_TRANSFORM_FEEDBACK_BUFFER,0,srcSize,srcData); print_error_indent;
glBindBuffer(GL_UNIFORM_BUFFER,srcBufferNo); print_error_indent;
glBufferSubData(GL_UNIFORM_BUFFER,0,srcSize,srcData); print_error_indent;
glBindBuffer(GL_PIXEL_UNPACK_BUFFER,srcBufferNo); print_error_indent;
glBufferSubData(GL_PIXEL_UNPACK_BUFFER,0,srcSize,srcData); print_error_indent;
LOGI("finish");
};
extern "C" JNIEXPORT void JNICALL
Java_pbbadd_opengl_gles30_MainActivity_nativeGLES3SetViewport(JNIEnv *env, jobject thiz, jint width, jint height) {
glViewport(0, 0, width, height); print_error_indent;
LOGI("w=%d, h=%d", width, height);
}
extern "C" JNIEXPORT void JNICALL
Java_pbbadd_opengl_gles30_MainActivity_nativeGLES3DrawFrame(JNIEnv *env, jobject thiz) {
glClearColor(0.5f, 0.5f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
print_error_indent;
LOGI("=== clear background ===");
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.22.1)
project("gles3copydemo")
# 1. 添加C++源文件编译成共享库
add_library(
gles3copydemo # so库名称,与Java层System.loadLibrary对应
SHARED
native-lib.cpp) # 核心C++源文件
# 2. 链接GLES3.0库(必加,否则无法调用gl3.h接口)
find_library(
GLES3-lib
GLESv3)
# 3. 链接日志库(打印调试信息)
find_library(
log-lib
log)
# 4. 关联库文件
target_link_libraries(
gles3copydemo
${GLES3-lib}
${log-lib})
# 适配Android15 16KB设备 + 解决LLD编译报错,兼容NDK23/25/26/27+
if(${ANDROID_ABI} STREQUAL "arm64-v8a")
set_target_properties(gles3copydemo PROPERTIES
# LLD专用参数:实现16KB(0x4000)页面对齐(替代废弃的--page-size)
LINK_FLAGS "-z common-page-size=0x4000 -z max-page-size=0x4000 -Wl,--emit-relocs"
)
endif()
# 全局加固配置(保留,提升SO库安全性)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,-z,relro,-z,now")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,relro,-z,now")
build.gradle
plugins {
alias(libs.plugins.android.application)
}
android {
namespace 'pbbadd.opengl.gles30'
compileSdk 36
defaultConfig {
applicationId "pbbadd.opengl.gles30"
minSdk 34
targetSdk 36
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
// 1. 配置NDK,指定支持的架构
ndk {
abiFilters 'arm64-v8a', 'armeabi-v7a'
}
// 2. 配置CMake构建
externalNativeBuild {
cmake {
cppFlags '-std=c++17' // C++17标准
arguments "-DANDROID_PLATFORM=android-26", "-DANDROID_STL=c++_shared"
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
// 3. 指定CMake脚本路径
externalNativeBuild {
cmake {
path file('src/main/cpp/CMakeLists.txt')
version '3.22.1'
}
}
}
dependencies {
implementation libs.appcompat
implementation libs.material
implementation libs.activity
implementation libs.constraintlayout
testImplementation libs.junit
androidTestImplementation libs.ext.junit
androidTestImplementation libs.espresso.core
}
gitee链接
https://gitee.com/ampbb/opengl-gles3-api-test