kivymd / KivyMD

KivyMD is a collection of Material Design compliant widgets for use with Kivy, a framework for cross-platform, touch-enabled graphical applications. https://youtube.com/c/KivyMD https://twitter.com/KivyMD https://habr.com/ru/users/kivymd https://stackoverflow.com/tags/kivymd
https://kivymd.readthedocs.io
MIT License
2.2k stars 661 forks source link

Extremely LowFPS when using KivyMD in low-end devices #812

Open AM-ash-OR-AM-I opened 3 years ago

AM-ash-OR-AM-I commented 3 years ago

Description of the Bug

I've built a kivymd App but problem is extreme Frame drop lot, specially on low end devices.. Even when other apps that aren't created using kivymd work absolutely normally. It might be caused by SDL2 but what I know for sure is the earlier version of KivyMD like the one Demo in playstore work fine in lowend devices. Also lag is in general for all things I recorded only nav drawer as its 60fps video and max size is 10 MB to upload.

Here are 2 videos showing problem.

VIDEOS

Low-end processor(SD 430)

https://user-images.githubusercontent.com/59698257/107117182-6f846080-689e-11eb-8abf-ce3f61f7ba4b.mp4

Mid-range processor(Snapdragon 660)

https://user-images.githubusercontent.com/59698257/107116913-875ae500-689c-11eb-9986-1a4e715267bd.mp4

Versions

P.S. Any solution other than downgrading to previous version is much appreciated.

HeaTTheatR commented 3 years ago

@AM-ash-OR-AM-I In the video that you attached, I did not see that applications created using the KivyMD library slow down ...

AM-ash-OR-AM-I commented 3 years ago

@AM-ash-OR-AM-I In the video that you attached, I did not see that applications created using the KivyMD library slow down ...

The app that u saw i.e. passlock was made by me using kivymd

HeaTTheatR commented 3 years ago

@AM-ash-OR-AM-I I didn't see any problems in your videos ...

AM-ash-OR-AM-I commented 3 years ago

@AM-ash-OR-AM-I In the video that you attached, I did not see that applications created using the KivyMD library slow down ...

Also I noted that lag in navigation drawer nullifies if phone is connected to laptop via USB(Due to charging? but this doesn't not work with any other external source for charging). However in loweend devices lag is still

@AM-ash-OR-AM-I I didn't see any problems in your videos ...

If u see the video closely preferably in a smartphone screen you will see how smooth apps like Gmail were while My app(using KivyMD) was having Frame Drops.. See the low end device video with my app vs Gmail navigation drawer

HeaTTheatR commented 3 years ago

@AM-ash-OR-AM-I I do not understand the essence of your problem ...

AM-ash-OR-AM-I commented 3 years ago

@AM-ash-OR-AM-I I do not understand the essence of your problem ...

The problem is when I am tapping on navigation drawer and in general all UI Elements there is either a delay or frame drop while using my app causing jittering effect and that makes it unusable on all the low end devices..

HeaTTheatR commented 3 years ago

@AM-ash-OR-AM-I I don't understand what you are talking about ...

AM-ash-OR-AM-I commented 3 years ago

https://user-images.githubusercontent.com/59698257/107118703-757f3f00-68a8-11eb-9601-687ab7a1b6a5.mp4

I've uploaded the video once again hope you can see it when Navigation drawer opens there is a clear evident frame drop in UI.(I've used gmail as Reference to show the frame drop in my app) If u want I can provide code of Navigation drawer but still u might not see problem as You might be using mid-range or high-end devices.

HeaTTheatR commented 3 years ago

@AM-ash-OR-AM-I https://kivymd.readthedocs.io/en/latest/themes/material-app/#module-kivymd.app

HeaTTheatR commented 3 years ago

@AM-ash-OR-AM-I Try building an app with FPS monitoring...

AM-ash-OR-AM-I commented 3 years ago

@AM-ash-OR-AM-I Try building an app with FPS monitoring...

https://user-images.githubusercontent.com/59698257/107120829-2d1a4e00-68b5-11eb-8970-6e32af4a50ab.mp4

See this still I'm getting less than 20 fps ...

HeaTTheatR commented 3 years ago

@AM-ash-OR-AM-I I can't do anything with these...

HeaTTheatR commented 3 years ago

@AM-ash-OR-AM-I https://github.com/kivy/python-for-android/issues/2002

podraco commented 3 years ago

For the analysis we need to know the spects of the device you're using Ram Cpu Gpu Ram Model Company

podraco commented 3 years ago

And we also would need to se your kv files

AM-ash-OR-AM-I commented 3 years ago

For the analysis we need to know the spects of the device you're using Ram Cpu Gpu Ram Model Company

Okay!

Device1

Moto G5S (low-end) (MORE FPS drop) Snapdragon 430
3GB
Motorola
Adreno 505(GPU)

Device2

Redmi note7 (Mid-Range)(less FPS drop) Snapdragon 660 4GB Xiaomi Adreno 512

HeaTTheatR commented 3 years ago

This issue has already been discussed - https://github.com/kivy/python-for-android/issues/200. I see no reason to repeat all this here.

AM-ash-OR-AM-I commented 3 years ago

This issue has already been discussed - kivy/python-for-android#200. I see no reason to repeat all this here.

I have used that same Kivy version created by @quitegreensky but still the bug persists. The version that I had used was 2.0.0rc1 and I linked exact same version in buildozer as mentioned by him.

HeaTTheatR commented 3 years ago

@AM-ash-OR-AM-I Where in the Kivy issues there is another big discussion on this topic in which a person attached two packages built with different versions of dependencies. In one package the FPS falls steadily, in the other it does not. Only I don't remember the links to this discussion.

podraco commented 3 years ago

Also, if you use if inside properties instead of events, the comparison will be executed every frame instead of every time the event is launched.

HeaTTheatR commented 3 years ago

@podraco In the KivyMD library, checks occur in the properties of the widget. Especially in the updated MDDatePicker class: https://github.com/kivymd/KivyMD/blob/master/kivymd/uix/picker.py#L398 https://github.com/kivymd/KivyMD/blob/master/kivymd/uix/picker.py#L666

...

HeaTTheatR commented 3 years ago

@podraco But it seems to me that you are wrong. Checks don't happen every frame.

AM-ash-OR-AM-I commented 3 years ago

Also, if you use if inside properties instead of events, the comparison will be executed every frame instead of every time the event is launched.

MDNavigationDrawer:
    elevation: 0
    swipe_edge_width: 200
    opening_time: 0.4
    closing_time: 0.4
    id: nav_drawer 
    BoxLayout:
        orientation: 'vertical'
        padding: "8dp"
        spacing: "4dp"

        TwoLineAvatarListItem:
            id: email
            markup: True
            text: '[b]'+app.emailname
            secondary_text: '[b]'+app.emailaddress if app.emailname!='No account' else ' '

        OneLineIconListItem:
            text: "[b]COLORS"
            on_release: app.theme_dialog()
            theme_text_color: "Custom"
            text_color: app.theme_cls.primary_color

            IconLeftWidget:
                id: color
                icon: "checkbox-blank-circle"
                on_release: app.theme_dialog()
                theme_text_color: "Custom"
                text_color: app.theme_cls.primary_color

        OneLineIconListItem:

            text: "[b]DARK/LIGHT Mode"
            on_release: app.mode('press')

            IconLeftWidget:
                id: mode
                icon: "weather-night"
                on_release: app.mode('press')

        OneLineIconListItem:
            text: "[b]CHANGE PASSWORD"
            disabled: app.welcome_disable
            on_release:app.change_pass('create')
            theme_text_color: "Custom"
            text_color: 1,0,0,1

            IconLeftWidget:
                id: password
                icon: "lock"
                on_release:app.change_pass('create')
                theme_text_color: "Custom"
                disabled: app.welcome_disable
                text_color: 1,0,0,1
        OneLineIconListItem:
            id: security_list
            markup : True
            text: "[b]ADVANCED SECURITY"
            on_release: app.check_resume()
            theme_text_color: "Custom"
            text_color: 0,0.6,1,1
            IconLeftWidget:
                id: security
                icon: "shield"
                on_release: app.check_resume()
                theme_text_color: "Custom"
                text_color: 0,0.6,1,1
        OneLineIconListItem:
            text: '[b]BACKUP & RESTORE'
            disabled: app.welcome_disable
            on_release: app.choose('')
            theme_text_color: "Custom"
            text_color: 0,0.8,0.3,1
            IconLeftWidget:
                id: sync
                icon: 'backup-restore'
                on_release: app.choose('')
                theme_text_color: "Custom"
                text_color: 0,0.8,0.3,1

        MDSeparator:     

        MDRectangleFlatButton:
            id: demo
            text: 'START DEMO'
            theme_text_color: "Custom"
            text_color: app.theme_cls.primary_color if self.text!='STOP DEMO' else [1,0,0,0.7]
            on_release: app.tap_target_cust()if self.text!='STOP DEMO' else app.canceldemo()
            pos_hint: {'center_x':0.5}

        ScrollView:

Here's the Kv file for the Navigation drawer

podraco commented 3 years ago

@HeaTTheatR well, i seen how if you get for example:

widget:
    id:test_widget
    property; something if condition else value

will execute every frame and when you do

on_condition_related_property:
    test_widget.property= something if condition else value

Will only execute when the on_condition_related_property changes, instead of every other frame. The kivy clock even tells you when you have too many instructions at the same time.

HeaTTheatR commented 3 years ago

@podraco Seems to me that you are wrong:


from kivy.lang import Builder

from kivymd.app import MDApp

KV = '''
MDScreen:
    on_touch_down:
        app.theme_cls.theme_style = "Dark" \
         if app.theme_cls.theme_style == "Light" else "Light"

    MDLabel:
        halign: "center"
        text:
            app.get_dark() \
            if app.theme_cls.theme_style == "Dark" else app.get_light()
'''

class Example(MDApp):
    def build(self):
        return Builder.load_string(KV)

    def get_light(self):
        print("Method `get_light` is called")
        return "Light"

    def get_dark(self):
        print("Method `get_dark` is called")
        return "Dark"

Example().run()
podraco commented 3 years ago

well, it seems i was wrong, thanks.

Blaygor commented 3 years ago

I've just encountered this myself, however the problem is only present on 64 Bit builds (arm64-v8a). The exact same code, running on armabi-v7a, runs flawlessly. 64 bit build just tanks the framerate to unacceptable levels on both of my devices (Galaxy S7 and Galaxy S9) EDIT: update with video https://user-images.githubusercontent.com/74840429/107521629-e4d99380-6c06-11eb-9b42-7b5402f022db.mp4

HeaTTheatR commented 3 years ago

@Blaygor Thanks for the tests you did!

AM-ash-OR-AM-I commented 3 years ago

I've just encountered this myself, however the problem is only present on 64 Bit builds (arm64-v8a). The exact same code, running on armabi-v7a, runs flawlessly. 64 bit build just tanks the framerate to unacceptable levels on both of my devices (Galaxy S7 and Galaxy S9) EDIT: update with video https://user-images.githubusercontent.com/74840429/107521629-e4d99380-6c06-11eb-9b42-7b5402f022db.mp4

@Blaygor Does the arm-v7a has any other problems? Does it run on 32-bit? Can you tell me how do I make a build of arm-v7a in buildozer?

AM-ash-OR-AM-I commented 3 years ago

@Blaygor Thanks for the tests you did!

@HeaTTheatR Can you please Help me out on how can I build an apk in arm-v7a? I'm new to buildozer so I don't quite know how to do it...

Blaygor commented 3 years ago

Here's the issue right now. Google's play store will only accept 64 bit builds (you can include a 32bit build but a 64 bit build is necessary at first). With the processors you mentioned, they're both 64 bit. I would verify that your devices are running at 64 bit with something like 64 Bit Checker. In the buildozer.spec, there is a line which allows you to change architectures.

android.arch = arm64-v8a

If your spec file says this, then you're building a 64 bit application. You need to change arm64-v8a to armeabi-v7a to build the 32 bit application.

In my 32 bit application, the navigation drawer does not cause any significant FPS drop. The same code, compiled in 64 bit, tanks the FPS to single digits.

AM-ash-OR-AM-I commented 3 years ago

Here's the issue right now. Google's play store will only accept 64 bit builds (you can include a 32bit build but a 64 bit build is necessary at first). With the processors you mentioned, they're both 64 bit. I would verify that your devices are running at 64 bit with something like 64 Bit Checker. In the buildozer.spec, there is a line which allows you to change architectures.

android.arch = arm64-v8a

If your spec file says this, then you're building a 64 bit application. You need to change arm64-v8a to armeabi-v7a to build the 32 bit application.

In my 32 bit application, the navigation drawer does not cause any significant FPS drop. The same code, compiled in 64 bit, tanks the FPS to single digits.

I actually didn't pay a lot attention to the version and as it turns out the version in which I'm building it is indeed arm v7a by default I just didn't pay attention to that and even then Fps drop is visible (in low end processor). Key thing to note is fps is around 20fps while using Snapdragon 430 and 45fps while using Snapdragon 660 though 2nd one is acceptable but still it should be locked at 60fps all the time.

AM-ash-OR-AM-I commented 3 years ago

Here's the issue right now. Google's play store will only accept 64 bit builds (you can include a 32bit build but a 64 bit build is necessary at first). With the processors you mentioned, they're both 64 bit. I would verify that your devices are running at 64 bit with something like 64 Bit Checker. In the buildozer.spec, there is a line which allows you to change architectures. android.arch = arm64-v8a If your spec file says this, then you're building a 64 bit application. You need to change arm64-v8a to armeabi-v7a to build the 32 bit application. In my 32 bit application, the navigation drawer does not cause any significant FPS drop. The same code, compiled in 64 bit, tanks the FPS to single digits.

I actually didn't pay a lot attention to the version and as it turns out the version in which I'm building it is indeed arm v7a by default I just didn't pay attention to that and even then Fps drop is visible (in low end processor)

Key thing to note here

Description of the Bug

I've built a kivymd App but problem is extreme Frame drop lot, specially on low end devices.. Even when other apps that aren't created using kivymd work absolutely normally. It might be caused by SDL2 but what I know for sure is the earlier version of KivyMD like the one Demo in playstore work fine in lowend devices. Also lag is in general for all things I recorded only nav drawer as its 60fps video and max size is 10 MB to upload.

Here are 2 videos showing problem.

VIDEOS

Low-end processor(SD 430)

https://user-images.githubusercontent.com/59698257/107117182-6f846080-689e-11eb-8abf-ce3f61f7ba4b.mp4

Mid-range processor(Snapdragon 660)

https://user-images.githubusercontent.com/59698257/107116913-875ae500-689c-11eb-9986-1a4e715267bd.mp4

Versions

  • OS: Android
  • Python: 3.7
  • Kivy: 2.0.0rc1
  • KivyMD: Custom version forked from master.

P.S. Any solution other than downgrading to previous version is much appreciated.

Also as I mentioned here the old kivymd version that had the demo app in playstore was working almost more than 40fps(approximately to my eyes) all the time. There was no major frame drop in low end device that means something in all of the updates to kivymd or kivy itself might have caused it. Just a speculation...

podraco commented 3 years ago

There are many variables for us to be able to analyze that environment, the old version was made with different kivy, kivymd and android API also, there might be the possibility that the memory itself is the cause of the frame drop.

podraco commented 3 years ago

also, anyone knows if async works with android?

podraco commented 3 years ago

So, after some research, i believe this issue is more of a processor sided issue than form kivyMD, since the instruction set used are way too different for us to include into kivyMD. Pillow relies on basic instructions that can be compiled between architectures because they use the common instructions. But, devices in the side of ARM doesn't share the same basic instruction set.

The needed functions are SSE4+ based to improve the app UI but, such devices don't have those instructions. You can check this by reading android ABI help page.

Each architecture has its own instruction set implementation and a list with do and don't.

Even so, some devices adds some interesting architectures to improve data management and process time. But are too specific to be included in a common repo like KivyMD.

If someone is interested, they could add those improvements to pillow directly, I'm pretty sure they will appreciate the help. By the mean time, I'll be looking for some trick from the old school to improve the processing time required.

So, in resume. to solve this, the ideal approach would be that pillow added some SIMD (Single Instruction, Multiple Data) able instructions for ARMv7 and v8 (based on NEON for aarch64 = arm64v8, SSE,SSSE for x86 and x86_64; and VFPv3-D32 for armeabi-v7a) and for us to add som tricks and ilussions to improve the UX.

AM-ash-OR-AM-I commented 3 years ago

So, after some research, i believe this issue is more of a processor sided issue than form kivyMD, since the instruction set used are way too different for us to include into kivyMD. Pillow relies on basic instructions that can be compiled between architectures because they use the common instructions. But, devices in the side of ARM doesn't share the same basic instruction set.

The needed functions are SSE4+ based to improve the app UI but, such devices don't have those instructions. You can check this by reading android ABI help page.

Each architecture has its own instruction set implementation and a list with do and don't.

Even so, some devices adds some interesting architectures to improve data management and process time. But are too specific to be included in a common repo like KivyMD.

If someone is interested, they could add those improvements to pillow directly, I'm pretty sure they will appreciate the help. By the mean time, I'll be looking for some trick from the old school to improve the processing time required.

So, in resume. to solve this, the ideal approach would be that pillow added some SIMD (Single Instruction, Multiple Data) able instructions for ARMv7 and v8 (based on NEON for aarch64 = arm64v8, SSE,SSSE for x86 and x86_64; and VFPv3-D32 for armeabi-v7a) and for us to add som tricks and ilussions to improve the UX.

Okay, so inshort it means apps in KivyMD aren't directly optimised due to different architecture used in processor? And Just to emphasize this we can see apps build by Google ( and those in playstore) run absolutely fluid on the low-end phones. So it must be a optimisation issue. .

Hope, you could add some changes to atleast minimize frame drop.. And Looking forward to see changes in Pillow to add some SIMD that you need.

podraco commented 3 years ago

kivyMD doesn't optimize at all because kivyMd is a top-level framework, it doesn't compile any code, if you see, most of our code is purely python.

You could try and use pypy directly, but I'm not sure how well does that work.

Pillow is the base class for kivy, it manages arrays and textures used to be displayed on screen. I'm not sure if pillow have any optimization options for ARM, but as a quick tip, you can edit the python for android recipe directly stored in .buildozer/recipes/pillow and play with the compiler flags.

What kivyMD could do is fake some textures or a hard-coded compression of them. But this leads to some strange lines and behaviors displayed, due to mipmapping issues, and, any device not able of mipmapping, won't be compatible with kivyMD at first hand. but that configuration is on the kivy project side.