Skip to content

Latest commit

 

History

History
293 lines (225 loc) · 13.6 KB

File metadata and controls

293 lines (225 loc) · 13.6 KB

Copyright Disclaimer: AI-Generated Content

This file was created by GitHub Copilot, an AI coding assistant.

AI-generated content is not subject to copyright protection and is provided

without any warranty, express or implied, including warranties of merchantability,

fitness for a particular purpose, or non-infringement.

Use at your own risk.

Implementation Summary: Open Source OpenGL Renderer

Overview

This document summarizes the implementation of the new open-source OpenGL renderer for Twoyi, as requested in the issue.

What Was Implemented

1. New Rust Renderer Module (app/rs/src/renderer_new/)

A complete open-source OpenGL renderer implementation in Rust that communicates with the container via QEMU pipes:

Files Created:

  • mod.rs - Module definition and public API
  • pipe.rs - QEMU pipe connection implementation (similar to Anbox's pipe_connection_creator.h)
  • opengles.rs - OpenGL ES protocol implementation
  • renderer.rs - High-level renderer interface that mimics the old renderer API

Key Features:

  • Connects to container's OpenGL ES endpoints (/opengles, /opengles2, /opengles3)
  • Automatic fallback from OpenGL ES 3 → 2 → 1
  • Thread-safe implementation using Rust's Mutex and atomic operations
  • Graceful fallback to old renderer if QEMU pipe is unavailable

2. Renderer Abstraction Layer (app/rs/src/core.rs)

Updated the core module to support both renderers:

Changes Made:

  • Added RendererType enum to distinguish between Old and New renderers
  • Added set_renderer_type() function to configure which renderer to use
  • Modified init_renderer() to dispatch to appropriate renderer based on configuration
  • Updated reset_window() and remove_window() to support both renderers

Preserved:

  • All old renderer code remains untouched
  • Old renderer is the default (backwards compatible)
  • Old renderer bindings unchanged

3. JNI Interface (app/rs/src/lib.rs)

Added new native method for renderer selection:

Changes Made:

  • Added set_renderer_type() JNI function
  • Registered new method in JNI_OnLoad
  • Updated Java bindings

4. Java/Android Layer

Renderer Class (app/src/main/java/io/twoyi/Renderer.java)

  • Added setRendererType(int useNewRenderer) native method

ProfileSettings (app/src/main/java/io/twoyi/utils/ProfileSettings.java)

  • Added USE_NEW_RENDERER setting key
  • Added useNewRenderer() and setUseNewRenderer() methods
  • Settings are profile-specific

Render2Activity (app/src/main/java/io/twoyi/Render2Activity.java)

  • Modified surfaceCreated() to check renderer preference
  • Calls Renderer.setRendererType() before initializing

SettingsActivity (app/src/main/java/io/twoyi/ui/SettingsActivity.java)

  • Added checkbox preference for new renderer
  • Displays reboot warning when changed
  • Properly saves to profile settings

5. UI Resources

Strings (app/src/main/res/values/strings.xml)

  • Added settings_key_use_new_renderer
  • Added settings_use_new_renderer_summary

Preferences (app/src/main/res/xml/pref_settings.xml)

  • Added CheckBoxPreference for renderer selection
  • Placed in Advanced settings category
  • Default value: false (uses old renderer)

6. Documentation

Created comprehensive documentation:

OPENGL_RENDERER.md:

  • Architecture overview
  • Component descriptions
  • Protocol details
  • Comparison table (Old vs New)
  • Usage instructions
  • Troubleshooting guide
  • Future improvement suggestions

Design Decisions

1. Why Rust?

As specified in the requirements, the new renderer is implemented in Rust (like libtwoyi) rather than C++:

  • Memory safety without garbage collection
  • Zero-cost abstractions
  • Strong type system prevents bugs
  • Excellent concurrency support
  • Consistent with existing libtwoyi implementation

2. Mimicking Old Renderer API

The new renderer provides the exact same function signatures as the old renderer:

  • start_renderer()startOpenGLRenderer()
  • set_native_window()setNativeWindow()
  • reset_window()resetSubWindow()
  • remove_window()removeSubWindow()
  • destroy_subwindow()destroyOpenGLSubwindow()
  • repaint_display()repaintOpenGLDisplay()

This allows seamless switching between renderers without changing the calling code.

3. Profile-Specific Settings

The renderer choice is stored per-profile, allowing users to:

  • Test the new renderer on one profile while keeping another stable
  • Use different renderers for different use cases
  • Revert easily if issues occur

4. Graceful Fallback

The new renderer includes intelligent fallback mechanisms:

  1. If QEMU pipe device doesn't exist → automatically uses old renderer
  2. If OpenGL ES 3 unavailable → falls back to ES 2
  3. If OpenGL ES 2 unavailable → falls back to ES 1
  4. If connection fails → logs error but doesn't crash

5. Old Renderer Preservation

Critical requirement met: The old renderer is completely untouched:

  • renderer_bindings.rs - unchanged
  • libOpenglRender.so - still included
  • Default behavior - uses old renderer
  • No breaking changes to existing functionality

Architecture Diagram

┌─────────────────────────────────────────────────────────────┐
│                     Android Application                      │
│  ┌──────────────────────────────────────────────────────┐   │
│  │           Render2Activity (Java)                     │   │
│  │  ┌────────────────────────────────────────────────┐  │   │
│  │  │  ProfileSettings.useNewRenderer() ?            │  │   │
│  │  │    ↓ true                    ↓ false           │  │   │
│  │  │  New Renderer              Old Renderer        │  │   │
│  │  └────────────────────────────────────────────────┘  │   │
│  └──────────────────────────────────────────────────────┘   │
│                           ↓                                  │
│  ┌──────────────────────────────────────────────────────┐   │
│  │              Renderer.java (JNI)                     │   │
│  │    - setRendererType(useNew ? 1 : 0)                 │   │
│  │    - init(), resetWindow(), removeWindow()           │   │
│  └──────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────┘
                           ↓ JNI
┌─────────────────────────────────────────────────────────────┐
│                    Native Layer (Rust)                       │
│  ┌──────────────────────────────────────────────────────┐   │
│  │                 lib.rs / core.rs                     │   │
│  │    RendererType = Old | New                          │   │
│  └──────────────────────────────────────────────────────┘   │
│         ↓ Old                           ↓ New               │
│  ┌──────────────────┐      ┌──────────────────────────┐    │
│  │ renderer_bindings│      │    renderer_new/         │    │
│  │   (unchanged)    │      │  ┌───────────────────┐   │    │
│  │  - Links to      │      │  │  renderer.rs      │   │    │
│  │  libOpenglRender │      │  │  (coordinator)    │   │    │
│  └──────────────────┘      │  └───────────────────┘   │    │
│         ↓                  │  ┌───────────────────┐   │    │
│  ┌──────────────────┐      │  │  opengles.rs      │   │    │
│  │ libOpenglRender  │      │  │  (GL protocol)    │   │    │
│  │  .so (binary)    │      │  └───────────────────┘   │    │
│  │  (proprietary)   │      │  ┌───────────────────┐   │    │
│  └──────────────────┘      │  │  pipe.rs          │   │    │
│                            │  │  (QEMU pipe)      │   │    │
│                            │  └───────────────────┘   │    │
│                            └──────────────────────────┘    │
└─────────────────────────────────────────────────────────────┘
                           ↓
┌─────────────────────────────────────────────────────────────┐
│                    Container Layer                           │
│  ┌──────────────────────────────────────────────────────┐   │
│  │            /dev/qemu_pipe                            │   │
│  │  ┌────────────────────────────────────────────────┐  │   │
│  │  │  OpenGL ES Services:                           │  │   │
│  │  │    - /opengles                                 │  │   │
│  │  │    - /opengles2                                │  │   │
│  │  │    - /opengles3                                │  │   │
│  │  └────────────────────────────────────────────────┘  │   │
│  └──────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────┘

Testing Strategy

Due to environment limitations, the following tests should be performed:

Unit Tests (Rust)

cd app/rs
cargo test --target x86_64-unknown-linux-gnu

Build Test (Android)

cd app/rs
./build_rs.sh --release

Integration Tests

  1. Old Renderer Test:

    • Launch app with "Use New Renderer" disabled
    • Verify container displays correctly
    • Test touch input, display rotation, etc.
  2. New Renderer Test:

    • Enable "Use New Renderer" in settings
    • Reboot container
    • Verify new renderer initializes
    • Check logcat for "Using renderer: New"
  3. Fallback Test:

    • On device without QEMU pipe
    • Enable new renderer
    • Verify automatic fallback to old renderer
    • Check logs for fallback message

Known Limitations

  1. Build Environment: Requires Android NDK and cargo-xdk for building
  2. QEMU Pipe Dependency: New renderer requires /dev/qemu_pipe device
  3. Protocol Assumptions: Based on Anbox implementation, may need tuning
  4. Testing: Requires physical Android device or emulator for full testing

Backwards Compatibility

Fully backwards compatible:

  • Old renderer is default
  • Old renderer code unchanged
  • No breaking changes to existing functionality
  • Users can opt-in to new renderer
  • Easy rollback if issues occur

Future Work

Potential enhancements:

  1. Implement more GL commands for better compatibility
  2. Add performance metrics and logging
  3. Support for additional graphics protocols
  4. Hardware acceleration integration
  5. Benchmark against old renderer
  6. Add visual tests and screenshots

References

Implementation based on:

Conclusion

The implementation successfully delivers:

✅ Open-source OpenGL renderer in Rust
✅ QEMU pipe communication (like Anbox)
✅ Mimics old renderer API
✅ Old renderer preserved and untouched
✅ Settings UI for renderer selection
✅ Profile-specific configuration
✅ Graceful fallback mechanisms
✅ Comprehensive documentation

The new renderer is ready for testing and can be built with the standard Twoyi build process.