Issues porting Blender to Android tablets

Hi everyone, I recently ported blender 4.0.0 to a Samsung Android tablet. I have made some progress, as shown below, switching to different modules of blender.

  1. At present, the problem I urgently need to solve is how to handle the actions of pressing, popping up, swiping, double-clicking, etc. on touch screens such as Android tablets so that they can adapt to the current event framework of blender.
    After browsing the code, analyzing the process, and trying in the past few days, I encountered several problems. I hope you can provide some ideas.
    a) After starting the program, clicking the button and drop-down box on the startup page, there is no response, just closing the startup page (see the picture above).
    b) Open the layout page, press, move, and pop up the box selection, no matter where the press is, the starting point of the box selection rectangle is in the upper left corner of the screen (see the picture above).
    c) On all modules, after clicking the button, only the tooltip information can be popped up, and the corresponding events cannot be responded to, such as switching modes, opening the corresponding property page, opening the dialog box, etc. (see the picture above).
  2. It feels that these problems are caused by the same problem, but I have no idea, and I don’t know which part of the code can view relevant information. For touch screens such as Android tablets, this is how I currently handle its pressing, popping up, and swiping actions.

//	Global function 
//	Used to handle Android touch related events
//	android_app: 	Android Environment
//	AInputEvent:	Touch event class
GHOST_EventButton *processButtonEvent(struct android_app *app,
 AInputEvent *event) {
    GHOST_SystemAndroid *system = (GHOST_SystemAndroid *)
	GHOST_ISystem::getSystem();

    GHOST_WindowNULL *window = (GHOST_WindowNULL *) 
	system->getWindowManager()->getWindowAssociatedWithEglWindow(app->window);
    if (!window) {
        window = (GHOST_WindowNULL *) system->getWindowManager()->
getActiveWindow();
    }
	
	//  Input sources.
//    int32_t source=AInputEvent_getSource(event);     
	//  key flags           
//    int32_t keyflags=AKeyEvent_getFlags(event);                 
		//  key code AKEYCODE_0  AKEYCODE_NUMPAD_3 Keyboard Symbols
//    int32_t keycode=AKeyEvent_getKeyCode(event);                

	//  Motion event actions. AMOTION_EVENT_ACTION_BUTTON_PRESS Button Type
    int32_t motionaction = AMotionEvent_getAction(event);         
    GHOST_TButton mask = GHOST_kButtonMaskLeft;
    float msgPosX = AMotionEvent_getX(event, 0);    //  x(Pixel coordinates)
    float msgPosY = AMotionEvent_getY(event, 0);    //  y(Pixel coordinates)
	//  Move event time(ns)
    int64_t eventTime = AMotionEvent_getEventTime(event);         

    //  print log debug
    std::string strInfo = "move "+std::to_string(motionaction)+" "+
	std::to_string(msgPosX) + " " + std::to_string(msgPosY);
    CLOG_ERROR(&LOG, "%s", strInfo.c_str());

    GHOST_TabletData td;
    GHOST_TEventType eventType = GHOST_TEventType::GHOST_kEventCursorMove;
    uint64_t currentTime=system->getMilliSeconds();
    if (motionaction == AMOTION_EVENT_ACTION_DOWN) {
        //  Press Event
        eventType = GHOST_TEventType::GHOST_kEventButtonDown;
        system->pushEvent(new GHOST_EventCursor(currentTime,
		GHOST_kEventCursorMove, window, msgPosX, msgPosY,td));
        system->pushEvent( new GHOST_EventButton(currentTime, 
		eventType, window, mask, td));
    } else if (motionaction == AMOTION_EVENT_ACTION_UP) {
        //  Popup event
        eventType = GHOST_TEventType::GHOST_kEventButtonUp;
        system->pushEvent( new GHOST_EventButton(currentTime, 
		eventType, window, mask, td));
    } else if (motionaction == AMOTION_EVENT_ACTION_MOVE) {
        //  Move event
        eventType = GHOST_TEventType::GHOST_kEventCursorMove;
        system->pushEvent(new GHOST_EventCursor(currentTime, 
		GHOST_kEventCursorMove, window, msgPosX, msgPosY,td));
    }
    return nullptr;
}

//	Global function  
//	Android event triggers callback function 
//	When the callback is called, the specific processing function of 
//	processButtonEvent above is actually called
static int32_t engine_handle_input(struct android_app *app, 
AInputEvent *event) {
    GHOST_Event *eventToPush = nullptr;
    int inputEventType = AInputEvent_getType(event);
    eventToPush = processButtonEvent(app, event);
    return 1;
}

//	GHOST_SystemAndroid: Android system 
//	Constructor
//	Externally pass in the Android environment object, initialize the Android 
//	environment object, and set the event processing callback function
GHOST_SystemAndroid::GHOST_SystemAndroid(void *nativeWindow) : 
GHOST_System() { /* nop */
    timeval tv;
    if (gettimeofday(&tv, nullptr) == -1) {
        GHOST_ASSERT(false, "Could not instantiate timer!");
    }
    m_start_time = uint64_t(tv.tv_sec) * 1000 + tv.tv_usec / 1000;
    m_nativeWindow = nativeWindow;
    struct android_app *app = (struct android_app *) m_nativeWindow;
    app->onInputEvent = engine_handle_input;
}

//	GHOST_SystemAndroid: Android system 
//	Get the system time since startup
uint64_t GHOST_SystemAndroid::getMilliSeconds() const override
{
	timeval tv;
	if (gettimeofday(&tv, nullptr) == -1) {
		GHOST_ASSERT(false, "Could not compute time!");
	}

	/* Taking care not to overflow the tv.tv_sec * 1000 */
	return uint64_t(tv.tv_sec) * 1000 + tv.tv_usec / 1000 - m_start_time;
}

//	GHOST_SystemAndroid: Android system 
//	Event processing interface function
bool GHOST_SystemAndroid::processEvents(bool waitForEvent) {
    bool hasEventHandled = false;
    /* Process all the events waiting for us. */
    struct android_app *app = (struct android_app *) m_nativeWindow;
    int ident;
    int events;
    struct android_poll_source *source;
    // we loop until all events are read, then continue
    // to draw the next frame of animation.
    while ((ident = ALooper_pollAll(0, nullptr, &events,
                                    (void **) &source)) >= 0) {

        // Process this event.
        if (source != nullptr) {
            source->process(app, source);
            hasEventHandled = true;
        }
        // If a sensor has data, process it now.
        if (ident == LOOPER_ID_USER) {

        }
        // Check if we are exiting.
        if (app->destroyRequested != 0) {
            return hasEventHandled;
        }
    }
    hasEventHandled |= this->m_eventManager->getNumEvents() > 0;
    return hasEventHandled;
}

7 Likes

Hi, this is one of those topics where it is not very trivial to give solutions by just looking into a code snippet. The hypothesis could be that Blender might expect mouse-move to happen before the click, to update some internal state of a button. Is just a wild guess, but maybe you need to generate mouse-move to the position of button-press.

There are a number of command line arguments, like --debug-events which could provide some insights about what is going on.

Also, there was a GSoC back in 2012 related on the Android port, so maybe you can dig some useful things from there: archive/blender-archive: Archive of Blender with old branches - blender-archive - Blender Projects

1 Like

Thanks! I debugged and checked the code again and found some clues. After modification, it can now respond to touch operations. More detailed adjustments are needed in the future. The video shows some operation effects of the modeling part.

6 Likes

Hello everyone, I would like to ask, after clicking on a blank area in the scene, the scene will flicker.

After debugging, I found that the swapBuffer interface was called multiple times in succession. Each time it was called, the scene would be updated, and the updated content was different, so it looked like it was flickering.

I wonder if you have any ideas or clues, such as why the background color of the 1st, 2nd, and 3rd pictures is like this. Thank you everyone.








you are running blender on android? thats interesting :thinking:

Hello everyone, I wonder if you have encountered such a situation during modeling and rendering after compiling and running blender?

  1. Some extra white dots on the wireframe in Figure 1
  2. Color blocks that are inconsistent with the model in Figures 2 and 3
  3. The background of the scene in Figure 4 is a mess.
  4. In the scenes in Figures 2 and 3, if I rotate the scene, these extra color blocks are also changing.

Yes. Blender is an excellent 3D modeling software. I want to operate it on a tablet, so I will try it to see if I can do it. :smiley:

1 Like

Moderation notice: I merged two other threads into this one and made it generic, it’s much better to discuss all issues related to the Android port in one topic. :slight_smile:

1 Like

There is only that far we can give guidance based on description of a problem and its screenshots.
We don’t even know if the work is based on OpenGL, OpenGL ES, Vulkan, or something else.

If some graphics artifacts happen on a desktop, then is better to report them as a bug.

For the Blender port on Android, being able to see code and changes might make certain investigations easier.

Btw, are you planning on upstreaming the changes you’re working on?

1 It is based on OpenGL ES 3.1.

2 The porting process has just begun, and there are still many major problems that have not been solved.

3 Will share it later.

1 Like

Hello everyone!
On the 2D Animation page, there are big differences between the desktop version and the ported version.

I debugged the gpencil code repeatedly, but no problems were found.

Could you explain the drawing principle of the gpencil module and some opengl APIs used?

If you can provide some clues, I believe the problem can be found.

Background Solid Fill Mode
desktop version The background is white Filling polygons
Ported version The background is black Only the outline, and the outline is not continuous

1 Like

It goes via the Grease Pencil render engine, found at source/blender/draw/engines/gpencil/gpencil_engine_c.cc.

Not sure there is an overview of exact algorithms, but the GPENCIL_draw_scene() would be a good starting point to see what is is going on.

Also, keep in mind, quite some stuff has changed with GPv3, so it might be good idea to check the latest main branch.

2 Likes

OK ! Thanks a lot. I will step into the function.

Hello everyone! I have encountered several problems during the porting process recently. If you encounter similar problems during the development process, please feel free to give me some advice and provide some clues or ideas. Thank you.

Question 1:

After adding a texture to the model, the model is displayed as a solid color in the material preview mode and display rendering mode, and no matter what texture is added, it displays the same solid color.

However, in texture drawing mode and solid display mode, the map can be displayed normally.

In addition, adding a background image to the scene will also display normally regardless of the rendering mode.

Question 2:

Add a spline curve to the scene. The added spline curve has an additional straight line and a point at the end of the straight line.

Question 3:

After adding the translation module and switching to Chinese, some opened pages can be displayed normally, but some Chinese characters on menus and toolbars that need to be expanded are not fully displayed. What can be confirmed is that the translation content in the translation file can be correctly obtained through msgID. After restarting, some can be displayed completely, but some still cannot be displayed completely.

There appears to be more going on than just a change to the Chinese language. Some English portions are displaying with very odd spacing. From your sample, see “View Layer” and “Collection” looking much wider than we see them normally. Is the font changed from the one we distribute (Inter) ?

image

2 Likes

The text is probably being culled, and the root problem is probably the same as why english text is rendered differently.

The missing texture might be just a missing feature in OpenGL ES. Maybe stepping through IMB_create_gpu_texture could give some clues.

1 Like

Oh. I changed the font and changed the original font to HarmonyOS font to support Chinese fonts.

before fixing

/* File name of the default variable-width font. */
#define BLF_DEFAULT_PROPORTIONAL_FONT "DejaVuSans.woff2"

/* File name of the default fixed-pitch font. */
#define BLF_DEFAULT_MONOSPACED_FONT "DejaVuSansMono.woff2"

After

/* File name of the default variable-width font. */
#define BLF_DEFAULT_PROPORTIONAL_FONT "HarmonyOS_Sans_SC_Regular.ttf"


/* File name of the default fixed-pitch font. */
#define BLF_DEFAULT_MONOSPACED_FONT "HarmonyOS_Sans_SC_Regular.ttf"

Hello everyone,finally started to get in touch with blender. I have a few questions to ask. I hope you can give me some diagnostic advice or provide some debugging tools and tips.

Question 1

  1. As shown in the figure below, when the solid mode is displayed, if the lighting mode is changed to studio light, snapshot, or plane mode, it can be rendered normally and efficiently.

  1. As shown in the figure below, change the renderer to workbench. At this time, the viewport rendering is normal in both material preview and display rendering modes, and rendering to the image is also normal.

  1. At this time, the materials and textures added to the model cannot be rendered. Of course, this is also to improve the display efficiency during modeling and sculpting. I don’t know if there is any way to render materials and textures under this setting, without particularly good effects. In this way, even if eevee renders very slowly or even fails to render, you can still see the rendering effect.

Question 2

  1. In display rendering mode, when adding color, brick texture, image texture, and grid texture to the model, only part of the surface is displayed, and the display is incomplete. The same effect is achieved when rendering to an image.

  1. In the material preview mode, adding textures to the model will display black. However, if you turn on the scene light switch in the view rendering, the rendering effect will be the same as the display rendering mode.

Question 3

  1. In display rendering mode, if you keep the Render Pass in the viewport rendering as Combined, the rendering is slow and only part of the rendering effect can be seen. There are no extra pixels when moving or rotating the scene. This is the same as the description in 1) of question 2.

  1. In display rendering mode, if you change the Render Pass in the viewport rendering from Combined to Diffuse Color, the added texture can be displayed normally. And there will be no extra pixels when moving or rotating the scene.

  1. In display rendering mode, if you change the Render Pass in the viewport rendering from Combined to Diffuse Light, only some areas will have bright colors. If you change to other types except Diffuse Color, all will only display black.

Question 4

  1. Some buttons are not fully displayed or missed。

022

Regarding rendering, because OpenGL 3.1 ES uses medium float precision, does not have sampler1D, sampler1DArray, and the glsl program does not support the ##splicing macro, the most modified areas are the various glsl shader programs.

I observed the rendering results above and personally feel that there is a problem with the lighting-related calculations of Eevee. The glsl programs that I modified the most are closure_eval_surface_lib.glsl and effect_reflection_resolve_frag.glsl, which expanded the original function containing the ##splicing macro.

1 Like

Such usually require checking for something obvious like errors in the console (possibly with --debug-gpu), or attaching to the actual process with RenderDoc to see what happens at which render pipeline stage.
It is not something that can be easily troubleshooted over an offline forum conversation.