【Android GLSurfaceView源码学习】第二天:GLSurfaceView深度分析

GLSurfaceView

在Android图形渲染体系中,SurfaceView作为一种特殊的视图组件,为开发者提供了在独立线程中进行高效绘制的能力。

GLSurfaceView则是在SurfaceView基础上针对OpenGL ES渲染场景的深度扩展,它封装了复杂的EGL(Embedded Graphics Library)上下文管理、渲染线程调度等底层细节,极大简化了OpenGL在Android平台的应用开发。

本文将从代码实现角度,详细解析GLSurfaceView如何基于SurfaceView进行扩展。

核心能力

GLSurfaceView的扩展始于对SurfaceView的直接继承,这确保了它能够复用SurfaceView的核心特性:

java 复制代码
public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback2

通过继承SurfaceViewGLSurfaceView获得了以下基础能力:

  • 独立于UI线程的绘制表面(Surface),避免渲染操作阻塞UI响应
  • 通过SurfaceHolder管理Surface的生命周期(创建、销毁、尺寸变化)
  • 与Android视图系统的集成能力,可像普通视图一样布局和交互

针对OpenGL的核心扩展

OpenGL ES渲染需要与底层窗口系统建立连接,而EGL正是实现这一连接的中间层。

GLSurfaceView的核心扩展之一,就是对EGL上下文、配置和表面的自动化管理,这是SurfaceView不具备的关键能力。

1. EGL配置选择机制

SurfaceView仅提供绘制表面,而GLSurfaceView通过EGLConfigChooser接口封装了OpenGL渲染配置的选择逻辑:

java 复制代码
public interface EGLConfigChooser {
    EGLConfig chooseConfig(EGL10 egl, EGLDisplay display);
}

代码中实现了多种默认配置选择器(如SimpleEGLConfigChooserComponentSizeChooser),可根据需求选择RGB分量位数、深度缓冲、模板缓冲等参数。

例如默认配置会选择RGB_888格式且至少16位深度缓冲的配置,开发者也可通过setEGLConfigChooser方法自定义配置逻辑。

2. EGL上下文与表面工厂

为了解耦EGL上下文(EGLContext)和窗口表面(EGLSurface)的创建逻辑,GLSurfaceView定义了两个工厂接口:

  • EGLContextFactory:负责创建和销毁EGL上下文,默认实现DefaultContextFactory支持指定OpenGL ES版本(通过setEGLContextClientVersion设置)
  • EGLWindowSurfaceFactory:负责创建和销毁与Surface关联的EGL窗口表面,默认实现DefaultWindowSurfaceFactory处理表面创建的异常情况

这些工厂类封装了eglCreateContexteglDestroyContext等底层EGL调用,开发者无需直接操作EGL API。

渲染线程的封装与调度

SurfaceView需要开发者手动管理绘制线程,而GLSurfaceView内置了GLThread渲染线程,实现了渲染逻辑与UI线程的彻底分离:

1. 渲染线程的启动与管理

当调用setRenderer方法时,GLSurfaceView会启动GLThread

java 复制代码
public void setRenderer(Renderer renderer) {
    // 初始化默认配置器和工厂
    if (mEGLConfigChooser == null) {
        mEGLConfigChooser = new SimpleEGLConfigChooser(true);
    }
    // ... 初始化其他工厂
    mRenderer = renderer;
    mGLThread = new GLThread(mThisWeakRef);
    mGLThread.start();
}

GLThread作为内部类,负责执行OpenGL渲染的核心循环,包括EGL初始化、上下文创建、以及调用Renderer接口的渲染方法。

2. 两种渲染模式的支持

GLSurfaceView提供了灵活的渲染触发机制,通过setRenderMode支持两种模式:

  • RENDERMODE_CONTINUOUSLY:持续渲染模式(默认),渲染线程不断调用onDrawFrame
  • RENDERMODE_WHEN_DIRTY:按需渲染模式,仅在Surface创建或调用requestRender时触发渲染

这种设计既满足了游戏等需要高频刷新的场景,也支持了静态画面等低功耗场景。

3. 每次重启渲染线程

java 复制代码
    /**
     * This method is used as part of the View class and is not normally
     * called or subclassed by clients of GLSurfaceView.
     */
    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        if (LOG_ATTACH_DETACH) {
            Log.d(TAG, "onAttachedToWindow reattach =" + mDetached);
        }
        if (mDetached && (mRenderer != null)) {
            int renderMode = RENDERMODE_CONTINUOUSLY;
            if (mGLThread != null) {
                renderMode = mGLThread.getRenderMode();
            }
            mGLThread = new GLThread(mThisWeakRef);
            if (renderMode != RENDERMODE_CONTINUOUSLY) {
                mGLThread.setRenderMode(renderMode);
            }
            mGLThread.start();
        }
        mDetached = false;
    }

onAttachedToWindow()是 Android View 生命周期中的关键方法,当视图被添加到窗口管理器(WindowManager)时触发,此时视图开始具备绘制能力。

对于GLSurfaceView而言,此方法的核心作用是在视图重新附加到窗口时,恢复之前可能因脱离窗口而停止的渲染线程(GLThread)。

  • 创建新的GLThread实例,传入当前GLSurfaceView的弱引用(mThisWeakRef),避免因线程持有视图强引用导致的内存泄漏。
  • 若之前的渲染模式不是默认的持续渲染,则为新线程设置该模式。
  • 启动渲染线程,开始执行 OpenGL 渲染循环(调用Renderer的onSurfaceCreated、onDrawFrame等方法)。

Renderer接口:渲染逻辑的解耦

GLSurfaceView通过Renderer接口将渲染逻辑从视图组件中分离,这是对SurfaceView开发模式的重要改进:

java 复制代码
public interface Renderer {
    void onSurfaceCreated(GL10 gl, EGLConfig config);  // 表面创建时调用,初始化资源
    void onSurfaceChanged(GL10 gl, int width, int height);  // 表面尺寸变化时调用,设置视口
    void onDrawFrame(GL10 gl);  // 绘制每一帧
}

开发者只需实现该接口,专注于OpenGL渲染逻辑(如纹理加载、矩阵变换、绘制调用等),而GLSurfaceView会在合适的时机(由GLThread调度)自动调用这些方法。这种设计遵循了单一职责原则,降低了视图管理与渲染逻辑的耦合。

生命周期管理与状态恢复

在Android应用生命周期中,Surface可能因Activity暂停、屏幕旋转等原因销毁重建。

GLSurfaceView针对OpenGL场景强化了生命周期管理:

  1. 暂停与恢复机制

    • onPause():暂停渲染线程,根据setPreserveEGLContextOnPause配置决定是否保留EGL上下文
    • onResume():恢复渲染线程,重建EGL上下文(若已释放)并重启渲染
  2. EGL上下文丢失处理

    当设备休眠唤醒等场景导致EGL上下文丢失时,GLSurfaceView会自动触发onSurfaceCreated回调,通知开发者重建OpenGL资源(如纹理、缓冲等),避免渲染异常。

调试与线程通信支持

为简化OpenGL开发调试,GLSurfaceView提供了专门的调试功能:

  • DEBUG_CHECK_GL_ERROR:每次GL调用后检查错误并抛出异常
  • DEBUG_LOG_GL_CALLS:记录所有GL调用到系统日志

同时,为解决UI线程与渲染线程的通信问题,提供了queueEvent方法:

java 复制代码
public void queueEvent(Runnable r) {
    mGLThread.queueEvent(r);
}

通过该方法可将任务提交到渲染线程执行,避免多线程操作OpenGL资源导致的同步问题。

EglHelper

GLSurfaceView通过内部类EglHelper封装了所有与EGL相关的底层操作,为开发者屏蔽了复杂的EGL细节。

EglHelper的定位与核心职责

EglHelperGLSurfaceView的私有静态内部类,其核心职责是管理EGL生命周期的全流程,包括:

  • EGL实例初始化与终止
  • 显示设备(Display)的获取与管理
  • 渲染配置(EGLConfig)的选择
  • 渲染上下文(EGLContext)的创建与销毁
  • 渲染表面(EGLSurface)的创建、绑定与销毁
  • OpenGL接口(GL)的实例化与调试包装
  • EGL错误处理与日志记录

通过这些封装,EglHelperGLSurfaceView无需直接操作EGL API,同时为上层渲染逻辑提供了稳定的OpenGL环境。

核心成员

EglHelper的成员变量集中存储了EGL交互所需的核心对象,其设计体现了EGL的核心概念:

java 复制代码
private WeakReference<GLSurfaceView> mGLSurfaceViewWeakRef; // 弱引用避免内存泄漏
EGL10 mEgl; // EGL10接口实例
EGLDisplay mEglDisplay; // 关联的显示设备
EGLSurface mEglSurface; // 渲染表面(与SurfaceView的Surface绑定)
EGLConfig mEglConfig; // 渲染配置(包含颜色格式、缓冲等参数)
EGLContext mEglContext; // OpenGL渲染上下文(状态存储容器)

其中,mGLSurfaceViewWeakRef使用弱引用关联GLSurfaceView,既保证了EglHelper能访问GLSurfaceView的配置(如EGLConfigChooser),又避免了因强引用导致的GLSurfaceView无法被垃圾回收的内存泄漏问题。

核心方法

1. 初始化EGL环境:start()方法

start()EglHelper的核心初始化方法,负责建立EGL的基础环境,流程可分为5个关键步骤:

步骤1:获取EGL实例
java 复制代码
mEgl = (EGL10) EGLContext.getEGL();

通过EGLContext.getEGL()获取EGL10接口实例,这是所有EGL操作的入口。

步骤2:获取默认显示设备
java 复制代码
mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
if (mEglDisplay == EGL10.EGL_NO_DISPLAY) {
    throw new RuntimeException("eglGetDisplay failed");
}

EGL通过"显示设备"(Display)与物理屏幕关联,这里获取系统默认显示设备。若获取失败(返回EGL_NO_DISPLAY),则抛出异常终止初始化。

步骤3:初始化显示设备
java 复制代码
int[] version = new int[2];
if(!mEgl.eglInitialize(mEglDisplay, version)) {
    throw new RuntimeException("eglInitialize failed");
}

调用eglInitialize初始化显示设备,同时获取EGL的主版本号和次版本号(存储在version数组中)。初始化失败会直接抛出异常。

步骤4:选择EGL配置
java 复制代码
GLSurfaceView view = mGLSurfaceViewWeakRef.get();
if (view != null) {
    mEglConfig = view.mEGLConfigChooser.chooseConfig(mEgl, mEglDisplay);
}

通过GLSurfaceView中配置的EGLConfigChooser选择合适的渲染配置(EGLConfig)。EGLConfig定义了渲染表面的颜色格式(如RGB分量位数)、深度缓冲、模板缓冲等关键参数,是后续创建上下文和表面的基础。

步骤5:创建EGL上下文
java 复制代码
mEglContext = view.mEGLContextFactory.createContext(mEgl, mEglDisplay, mEglConfig);
if (mEglContext == null || mEglContext == EGL10.EGL_NO_CONTEXT) {
    throwEglException("createContext");
}

通过EGLContextFactory创建EGL上下文(EGLContext)。EGL上下文是OpenGL状态的存储容器,包含纹理、着色器、矩阵等所有渲染状态,是OpenGL渲染的核心。若创建失败(返回EGL_NO_CONTEXT),则通过throwEglException抛出详细错误信息。

2. 创建渲染表面:createSurface()方法

渲染表面(EGLSurface)是OpenGL的绘制目标,与SurfaceViewSurface绑定,其创建流程如下:

步骤1:销毁已有表面
java 复制代码
destroySurfaceImp(); // 确保旧表面被释放,避免资源泄漏
步骤2:创建新表面
java 复制代码
GLSurfaceView view = mGLSurfaceViewWeakRef.get();
if (view != null) {
    mEglSurface = view.mEGLWindowSurfaceFactory.createWindowSurface(
        mEgl, mEglDisplay, mEglConfig, view.getHolder()
    );
}

通过EGLWindowSurfaceFactory创建与SurfaceHolderSurfaceView的表面持有者)关联的窗口表面。SurfaceHolder提供了Surface的底层句柄,使EGL表面能与Android的窗口系统绑定。

步骤3:绑定上下文与表面
java 复制代码
if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
    logEglErrorAsWarning("EGLHelper", "eglMakeCurrent", mEgl.eglGetError());
    return false;
}

调用eglMakeCurrent将EGL上下文与当前表面绑定,此后所有OpenGL操作(如绘制、纹理加载)都会作用于该表面。若绑定失败(通常因Surface已销毁),则记录警告并返回false

3. 生成OpenGL接口:createGL()方法

createGL()用于创建可供开发者使用的OpenGL接口实例(GL),并支持调试增强:

java 复制代码
GL gl = mEglContext.getGL(); // 从EGL上下文获取基础GL接口
// 应用GL包装器(如自定义扩展)
if (view.mGLWrapper != null) {
    gl = view.mGLWrapper.wrap(gl);
}
// 启用调试功能(错误检查、调用日志)
if ((view.mDebugFlags & (DEBUG_CHECK_GL_ERROR | DEBUG_LOG_GL_CALLS)) != 0) {
    gl = GLDebugHelper.wrap(gl, configFlags, log);
}

通过GLDebugHelper,开发者可开启OpenGL调用的错误检查(每次调用后检查glGetError)和日志记录,极大简化调试过程。这是EglHelper对开发者友好的重要体现。

4. 提交渲染结果:swap()方法

OpenGL通常使用双缓冲机制(前缓冲用于显示,后缓冲用于绘制),swap()方法负责将后缓冲的渲染结果交换到前缓冲,完成画面显示:

java 复制代码
public int swap() {
    if (! mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) {
        return mEgl.eglGetError(); // 交换失败返回错误码
    }
    return EGL10.EGL_SUCCESS;
}

eglSwapBuffers是显示渲染结果的关键调用,失败通常意味着表面已失效(如Surface被销毁)。

5. 资源释放:destroySurface()finish()方法

EGL资源需及时释放以避免内存泄漏,EglHelper提供了两级释放机制:

  • 表面释放(destroySurface()

    通过destroySurfaceImp()解除上下文与表面的绑定(eglMakeCurrent设为EGL_NO_SURFACE),并调用工厂方法销毁表面:

    java 复制代码
    private void destroySurfaceImp() {
        if (mEglSurface != null) {
            mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
            view.mEGLWindowSurfaceFactory.destroySurface(mEgl, mEglDisplay, mEglSurface);
            mEglSurface = null;
        }
    }
  • 完整释放(finish()

    不仅销毁表面,还会销毁EGL上下文(通过EGLContextFactory)并终止显示设备,彻底释放所有EGL资源:

    java 复制代码
    public void finish() {
        if (mEglContext != null) {
            view.mEGLContextFactory.destroyContext(mEgl, mEglDisplay, mEglContext);
            mEglContext = null;
        }
        if (mEglDisplay != null) {
            mEgl.eglTerminate(mEglDisplay);
            mEglDisplay = null;
        }
    }

6. 错误处理机制

EGL操作可能因配置错误、资源不足等原因失败,EglHelper提供了完善的错误处理:

  • throwEglException():将EGL错误码转换为可读信息并抛出运行时异常,终止异常流程。
  • logEglErrorAsWarning():将错误记录为警告日志,适用于非致命错误(如表面暂时不可用)。
  • formatEglError():将错误码与操作名称组合为格式化字符串(如"eglMakeCurrent failed: EGL_BAD_SURFACE"),便于调试。

GLThread实现

内部的GLThread类则是实现异步渲染、线程隔离和资源管理的核心。

GLThread的定位与核心职责

GLThreadGLSurfaceView的私有静态内部类,继承自Thread,专门负责OpenGL渲染的所有操作。其核心职责包括:

  • 管理OpenGL渲染的独立线程,与UI线程隔离,避免渲染操作阻塞UI响应
  • 协调EGL上下文(EGLContext)和渲染表面(EGLSurface)的创建、绑定与销毁
  • 触发渲染器(Renderer)的生命周期回调(onSurfaceCreatedonSurfaceChangedonDrawFrame
  • 处理外部事件(如queueEvent提交的任务)和渲染请求(requestRender
  • 维护线程间同步,处理暂停/恢复、Surface创建/销毁等状态变化

通过这些职责,GLThread将复杂的渲染逻辑封装在独立线程中,为开发者提供了简洁的上层接口。

核心成员

GLThread的成员变量可分为状态标识资源引用同步工具三类,共同支撑渲染线程的运行逻辑:

类型 关键变量 作用描述
状态标识 mPausedmHasSurface 标记当前是否暂停、是否持有有效的Surface(渲染载体)
状态标识 mHaveEglContextmHaveEglSurface 标记EGL上下文和表面是否已创建并可用
状态标识 mRequestRendermRenderMode 标记是否需要触发渲染、渲染模式(持续渲染/按需渲染)
资源引用 mEglHelper 用于管理EGL资源的辅助类(上下文、表面等)
资源引用 mGLSurfaceViewWeakRef 弱引用指向GLSurfaceView,避免内存泄漏同时获取配置信息
同步工具 sGLThreadManager 全局锁对象,用于线程间同步(wait/notify)
事件队列 mEventQueue 存储需在GL线程执行的外部任务(通过queueEvent提交)

这些变量通过sGLThreadManager的同步机制进行保护,确保多线程环境下的状态一致性。

核心流程

1. 初始化与启动:run()guardedRun()

GLThread的生命周期从run()方法开始,其核心逻辑封装在guardedRun()中:

java 复制代码
@Override
public void run() {
    setName("GLThread " + getId());
    try {
        guardedRun(); // 核心逻辑入口
    } catch (InterruptedException e) {
        // 正常退出
    } finally {
        sGLThreadManager.threadExiting(this); // 线程退出清理
    }
}

guardedRun()是渲染线程的主循环,负责初始化EGL辅助工具、维护渲染循环、处理状态变化和事件:

java 复制代码
private void guardedRun() throws InterruptedException {
    mEglHelper = new EglHelper(mGLSurfaceViewWeakRef); // 初始化EGL辅助类
    // 初始化状态变量...
    while (true) { // 无限循环,直到收到退出信号
        synchronized (sGLThreadManager) {
            // 状态检查与更新(暂停、Surface变化、EGL资源释放等)
        }
        // 执行渲染或事件处理
    }
}
2. 核心循环:状态管理与渲染触发

guardedRun()中的无限循环是GLThread的核心,可分为同步块内的状态处理同步块外的渲染执行两部分。

(1)同步块内:状态检查与准备

同步块(synchronized (sGLThreadManager))内主要处理线程状态更新和渲染准备,关键逻辑包括:

  • 退出检查 :若mShouldExittrue,直接退出循环终止线程。

  • 事件队列处理 :若mEventQueue非空,取出事件并在同步块外执行(确保事件在GL线程运行)。

  • 暂停状态更新 :根据mRequestPaused更新mPaused,并通知其他线程状态变化。

  • EGL资源释放 :当需要释放EGL上下文(mShouldReleaseEglContext)或上下文丢失(lostEglContext)时,调用stopEglSurfaceLocked()stopEglContextLocked()释放资源。

  • Surface状态处理 :当Surface丢失(!mHasSurface)时,释放EGL表面;当Surface重新获取(mHasSurface)时,更新状态并通知等待线程。

  • 渲染就绪判断 :通过readyToDraw()判断是否满足渲染条件:

    java 复制代码
    private boolean readyToDraw() {
        return (!mPaused) && mHasSurface && (!mSurfaceIsBad)
            && (mWidth > 0) && (mHeight > 0)
            && (mRequestRender || (mRenderMode == RENDERMODE_CONTINUOUSLY));
    }

    即:非暂停、有有效Surface、尺寸有效、且需要渲染(主动请求或持续模式)。

  • EGL资源准备 :若就绪且无EGL上下文,通过mEglHelper.start()创建上下文;若有上下文但无表面,标记需创建表面(createEglSurface = true)。

(2)同步块外:渲染执行与回调触发

当同步块内完成准备后,同步块外执行实际渲染操作,步骤如下:

  • 执行外部事件 :若从事件队列取出event,执行事件(如开发者通过queueEvent提交的任务)。
  • 创建EGL表面 :若createEglSurfacetrue,调用mEglHelper.createSurface()创建与Surface绑定的EGL表面,失败则标记表面无效。
  • 创建GL接口 :通过mEglHelper.createGL()获取GL10实例,供渲染器使用。
  • 触发渲染器回调
    • 若上下文刚创建(createEglContext),调用onSurfaceCreated通知渲染器上下文就绪。
    • 若尺寸变化(sizeChanged),调用onSurfaceChanged通知渲染器尺寸更新。
    • 调用onDrawFrame执行实际绘制逻辑。
  • 交换缓冲 :通过mEglHelper.swap()交换前后缓冲,将绘制结果显示到屏幕。
  • 错误处理:若交换缓冲失败,根据错误码处理(如上下文丢失则标记需重建)。
3. 线程同步机制

GLThread通过sGLThreadManager(全局锁对象)实现线程间同步,核心机制包括:

  • 等待(wait) :当不满足渲染条件时,通过sGLThreadManager.wait()让线程进入等待状态,释放CPU资源。
  • 通知(notifyAll) :当状态变化(如Surface创建、渲染请求)时,调用notifyAll()唤醒等待线程重新检查状态。
  • 状态保护 :所有状态变量(如mPausedmHaveEglContext)的读写均在同步块内进行,避免多线程竞争导致的状态不一致。

例如,当UI线程调用requestRender()时,会在同步块内设置mRequestRender = true并通知GLThread

java 复制代码
public void requestRender() {
    synchronized(sGLThreadManager) {
        mRequestRender = true;
        sGLThreadManager.notifyAll(); // 唤醒GLThread检查渲染条件
    }
}
4. 渲染模式与触发逻辑

GLThread支持两种渲染模式(通过mRenderMode控制):

  • RENDERMODE_CONTINUOUSLY :持续渲染,只要满足readyToDraw()条件,就不断执行onDrawFrame
  • RENDERMODE_WHEN_DIRTY :按需渲染,仅当requestRender()被调用(mRequestRender = true)时才触发渲染。

两种模式的切换通过setRenderMode()实现,内部通过更新mRenderMode并通知线程生效。

5. 资源释放与生命周期管理

GLThread在多种场景下会释放EGL资源,确保内存安全:

  • 暂停时 :若preserveEGLContextOnPausefalse(默认),则释放EGL上下文和表面。
  • Surface销毁时:释放EGL表面(因Surface是EGL表面的载体)。
  • 上下文丢失时 :当eglSwapBuffers返回EGL_CONTEXT_LOST,释放旧上下文并重建。
  • 线程退出时 :在finally块中调用stopEglSurfaceLocked()stopEglContextLocked()彻底释放资源。

与渲染器(Renderer)的交互

GLThreadRenderer回调的直接触发者,三者的交互关系如下:

  1. GLSurfaceView通过setRenderer()注册渲染器实例。
  2. GLThread在EGL上下文创建后,调用renderer.onSurfaceCreated()
  3. 当Surface尺寸变化时,调用renderer.onSurfaceChanged()
  4. 每次渲染循环中,调用renderer.onDrawFrame()执行绘制逻辑。

这种设计将渲染逻辑与线程管理解耦,开发者只需实现Renderer接口即可专注于绘制逻辑,无需关注线程和EGL细节。

总结

GLSurfaceViewSurfaceView基础上,通过以下核心扩展实现了对OpenGL渲染的全面支持:

  1. 封装EGL上下文、配置和表面管理,屏蔽底层图形接口细节
  2. 内置渲染线程(GLThread),实现渲染与UI线程的解耦
  3. 定义Renderer接口,分离渲染逻辑与视图管理
  4. 提供灵活的渲染模式、生命周期管理和调试工具
相关推荐
秋深枫叶红5 小时前
嵌入式第三十七篇——linux系统编程——线程控制
linux·学习·线程·系统编程
猫天意5 小时前
【即插即用模块】AAAI2025 | 高频 + 空间感知!新 HS-FPN 让“极小目标”不再消失!SCI保二区争一区!彻底疯狂!!!
网络·人工智能·深度学习·学习·音视频
Voyager_45 小时前
算法学习记录17——力扣“股票系列题型”
学习·算法·leetcode
正经教主5 小时前
【Trae+AI】和Trae学习搭建App_2.1:第3章·手搓后端基础框架Express
人工智能·后端·学习·express
L.fountain5 小时前
图像自回归生成(Auto-regressive image generation)实战学习(二)
学习·数据挖掘·回归
元气满满-樱5 小时前
LNMP架构学习
android·学习·架构
geneculture5 小时前
融智学体系图谱(精确对应版)
大数据·人工智能·学习·融智学的重要应用·信智序位
秋深枫叶红5 小时前
嵌入式第三十六篇——linux系统编程——线程
linux·运维·服务器·学习
allk556 小时前
Android 渲染性能优化实战总结:从监控体系到架构落地
android·性能优化·架构