Android TextureView/绘图/绘画性能 [英] Android TextureView / Drawing / Painting Performance

查看:23
本文介绍了Android TextureView/绘图/绘画性能的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在 Android 上使用 TextureView 制作绘图/绘画应用程序.我想支持高达 4096x4096 像素的绘图表面,这对于我的最小目标设备(我用于测试)来说似乎是合理的,它是具有出色四核 CPU 和 2GB 内存的 Google Nexus 7 2013.

I am attempting to make a drawing/painting app using TextureView on Android. I want to support a drawing surface of up to 4096x4096 pixels, which seems reasonable for my minimum target device (which I use for testing) which is a Google Nexus 7 2013 which has a nice quad core CPU and 2GB memory.

我的一个要求是我的视图必须位于允许放大、缩小和平移的视图内,这是我编写的所有自定义代码(想想 iOS 中的 UIScrollView).

One of my requirements is that my view must be inside of a view that allows it to be zoomed in and out and panned, which is all custom code I have written (think UIScrollView from iOS).

我尝试过使用带有 OnDraw 的常规视图(不是 TextureView),但性能非常糟糕 - 每秒不到 1 帧.即使我调用 Invalidate(rect) 时只更改了 rect,也会发生这种情况.我尝试关闭视图的硬件加速,但没有渲染,我认为是因为 4096x4096 对于软件来说太大了.

I've tried using a regular View (not TextureView) with OnDraw and performance was absolutely horrible - less than 1 frame a second. This happened even if I called Invalidate(rect) with only the rect that changed. I tried turning off hardware acceleration for the view, but nothing rendered, I assume because 4096x4096 is too big for software.

然后我尝试使用 TextureView 并且性能稍微好一点 - 大约每秒 5-10 帧(仍然很糟糕但更好).用户绘制位图,然后使用后台线程将其绘制到纹理中.我正在使用 Xamarin,但希望代码对 Java 人有意义.

I then tried using TextureView and performance is a little better - about 5-10 frames per second (still terrible but better). The user draws into a bitmap, which is then later drawn into the texture using a background thread. I'm using Xamarin but hopefully the code makes sense to Java people.

private void RunUpdateThread()
{
    try
    {
        TimeSpan sleep = TimeSpan.FromSeconds(1.0f / 60.0f);
        while (true)
        {
            lock (dirtyRect)
            {
                if (dirtyRect.Width() > 0 && dirtyRect.Height() > 0)
                {
                    Canvas c = LockCanvas(dirtyRect);
                    if (c != null)
                    {
                        c.DrawBitmap(bitmap, dirtyRect, dirtyRect, bufferPaint);
                        dirtyRect.Set(0, 0, 0, 0);
                        UnlockCanvasAndPost(c);
                    }
                }
            }
            Thread.Sleep(sleep);
        }
    }
    catch
    {
    }
}

如果我将 lockCanvas 更改为传递 null 而不是 rect,则性能在 60 fps 时非常出色,但 TextureView 的内容会闪烁并损坏,这令人失望.我原以为它只是在下面使用 OpenGL 帧缓冲区/渲染纹理,或者至少可以选择保留内容.

If I change lockCanvas to pass null instead of a rect, performance is great at 60 fps, but the contents of the TextureView flicker and get corrupted, which is disappointing. I would have thought it would simply be using an OpenGL frame buffer / render texture underneath or at least have an option to preserve contents.

除了在 Android 的原始 OpenGL 中执行所有操作以实现高性能绘图和在绘图调用之间保留的表面上绘图之外,还有其他选择吗?

Are there any other options short of doing everything in raw OpenGL in Android for high performance drawing and painting on a surface that is preserved in between draw calls?

推荐答案

更新 我放弃了 TextureView,现在使用 OpenGL 视图调用 glTexSubImage2D 来更新渲染纹理的更改部分.

UPDATE I ditched TextureView and now use an OpenGL view where I call glTexSubImage2D to update changed pieces of a render texture.

老答案我最终将 TextureView 平铺在 4x4 网格中.根据每个帧的脏矩形,我刷新相应的 TextureView 视图.在我调用 Invalidate 的框架上未更新的任何视图.

OLD ANSWER I ended up tiling TextureView in a 4x4 grid. Depending on the dirty rect each frame, I refresh the appropriate TextureView views. Any view that is not updated that frame I call Invalidate on.

某些设备(例如 Moto G 手机)存在双缓冲损坏一帧的问题.您可以通过在父视图调用 onLayout 时调用 lockCanvas 两次来解决此问题.

Some devices, such as the Moto G phone have an issue where the double buffering is corrupted for one frame. You can fix that by calling lockCanvas twice when the parent view has it's onLayout called.

private void InvalidateRect(int l, int t, int r, int b)
{
    dirtyRect.Set(l, t, r, b);

    foreach (DrawSubView v in drawViews)
    {
        if (Rect.Intersects(dirtyRect, v.Clip))
        {
            v.RedrawAsync();
        }
        else
        {
            v.Invalidate();
        }
    }

    Invalidate();
}

protected override void OnLayout(bool changed, int l, int t, int r, int b)
{
    for (int i = 0; i < ChildCount; i++)
    {
        View v = GetChildAt(i);
        v.Layout(v.Left, v.Top, v.Right, v.Bottom);
        DrawSubView sv = v as DrawSubView;
        if (sv != null)
        {
            sv.RedrawAsync();

            // why are we re-drawing you ask? because of double buffering bugs in Android :)
            PostDelayed(() => sv.RedrawAsync(), 50);
        }
    }
}

这篇关于Android TextureView/绘图/绘画性能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆