AndroidTextureView/绘图/绘画性能

2023-11-27

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

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

我尝试过使用常规视图(不是TextureView)使用 OnDraw 时性能绝对糟糕 - 每秒不到 1 帧。即使我打电话也发生这种情况Invalidate(rect)仅改变了矩形。我尝试关闭视图的硬件加速,但没有渲染任何内容,我认为是因为 4096x4096 对于软件来说太大了。

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

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 更改为传递空值而不是矩形,则在 60 fps 时性能会很好,但TextureView闪烁并被损坏,这令人失望。我本以为它只是在下面使用 OpenGL 帧缓冲区/渲染纹理,或者至少有一个保留内容的选项。

除了在 Android 中的原始 OpenGL 中完成所有操作之外,是否还有其他选项可以在绘制调用之间保留的表面上进行高性能绘图和绘制?


首先,如果您想了解幕后发生的事情,您需要阅读Android图形架构文档。虽然很长,但如果您真诚地想了解“为什么”,那么就从这里开始吧。

关于纹理视图

TextureView的工作原理是这样的:它有一个Surface,它是一个具有生产者-消费者关系的缓冲区队列。如果您使用软件(Canvas)渲染,则锁定 Surface,这会为您提供缓冲区;你在它上面画画;然后解锁 Surface,它将缓冲区发送给消费者。在这种情况下,消费者位于同一进程中,称为 SurfaceTexture 或(在内部,更恰当)GLConsumer。它将缓冲区转换为 OpenGL ES 纹理,然后渲染到视图。

如果关闭硬件加速,GLES 将被禁用,TextureView 将无法执行任何操作。这就是为什么当你关闭硬件加速时你什么也得不到的原因。文档非常具体:“TextureView只能在硬件加速窗口中使用。当在软件中渲染时,TextureView将不绘制任何内容。”

如果指定脏矩形,软件渲染器会将以前的内容memcpy到帧中after渲染完成。我不相信它设置了剪辑矩形,因此如果您调用drawColor(),您将填充整个屏幕,然后覆盖这些像素。如果您当前没有设置剪辑矩形,您可能会发现这样做会带来一些性能优势。 (不过我没有检查代码。)

脏矩形是一个输入输出参数。当你打电话时你传递了你想要的矩形lockCanvas(),并且允许系统在调用返回之前对其进行修改。 (实际上,这样做的唯一原因是如果没有先前的框架或调整了 Surface 的大小,在这种情况下它会将其扩展以覆盖整个屏幕。我认为使用更直接的方法可以更好地处理这个问题“我拒绝你的矩形”信号。)你需要更新你返回的矩形内的每个像素。你是not允许改变矩形,您似乎试图在示例中执行此操作 - 无论之后的脏矩形中是什么lockCanvas()成功是你需要借鉴的。

我怀疑肮脏的矩形处理不当是你闪烁的根源。可悲的是,这是一个很容易犯的错误,因为lockCanvas() dirtyRectarg 仅记录在表面类 itself.

表面和缓冲

所有表面都是双缓冲或三缓冲的。没有办法解决这个问题——你不能同时读写而不被撕裂。如果您想要一个可以在需要时修改和推送的缓冲区,则需要锁定、复制和解锁该缓冲区,这会在组合管道中造成停顿。为了获得最佳吞吐量和延迟,翻转缓冲区更好。

如果您想要锁定-复制-解锁行为,您可以自己编写(或找到一个可以执行此操作的库),并且它将与系统为您执行此操作一样高效(假设您擅长使用blit 循环)。绘制到离屏 Canvas 并位图位图,或者绘制到 OpenGL ES FBO 并位图位图。您可以在 Grafika 的“中找到后者的示例”记录总帐应用程序“ Activity,其模式是在屏幕外渲染一次,然后进行两次位图传输(一次用于显示,一次用于录制视频)。

更快的速度等等

在 Android 上绘制像素有两种基本方法:使用 Canvas 或使用 OpenGL。 Canvas 渲染到 Surface 或位图始终在软件中完成,而 OpenGL 渲染则通过 GPU 完成。唯一的例外是,当渲染到自定义视图,您可以选择使用硬件加速,但这不适用于渲染到SurfaceView或TextureView的Surface。

绘图或绘画应用程序可以记住绘图命令,或者只是将像素放入缓冲区并将其用作内存。前者允许更深入的“撤消”,后者更简单,并且随着要渲染的内容量的增加而具有越来越好的性能。听起来你想做后者,所以从屏幕外传输是有道理的。

大多数移动设备对 GLES 纹理的硬件限制为 4096x4096 或更小,因此您无法将单个纹理用于​​更大的纹理。您可以查询大小限制值(GL_MAX_TEXTURE_SIZE),但是您最好使用一个与您想要的一样大的内部缓冲区,并且只渲染适合屏幕的部分。我不知道 Skia(画布)的限制是什么,但我相信您可以创建更大的位图。

根据您的需求,SurfaceView 可能比 TextureView 更好,因为它避免了中间的 GLES 纹理步骤。您在 Surface 上绘制的任何内容都会直接进入系统合成器 (SurfaceFlinger)。这种方法的缺点是,由于 Surface 的使用者不是进程内的,因此 View 系统没有机会处理输出,因此 Surface 是一个独立的层。 (对于绘图程序来说,这可能是有益的——正在绘制的图像位于一层上,而您的 UI 位于顶部的单独层上。)

FWIW,我没有看过代码,但是 Dan Sandler 的Markers应用程序可能值得一看(源代码here).

Update:腐败是被识别为错误 and 固定为“L”.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

AndroidTextureView/绘图/绘画性能 的相关文章

  • 如何更改我的应用程序的语言[重复]

    这个问题在这里已经有答案了 可能的重复 在 Android 中以编程方式更改语言 https stackoverflow com questions 2900023 change language programatically in an
  • 如何在 Java 中与 HttpGet 一起发送 cookie

    我试图将 cookie 与 HttpGet 请求一起发送 但每次尝试都无法成功发送 我也尝试直接修改标题 这是我的代码 DefaultHttpClient httpClient new DefaultHttpClient CookieSto
  • 在 Qt 中用像素图画笔画一条线?

    一段时间以来 我正在使用 Qt C 开发一个简单的绘图和绘画应用程序 目前我正在使用 QPainter drawLine 进行绘制 并且工作正常 我想做的是用像素图画笔绘图 这是我可以做到的 我可以使用 QPainterPath 和 QPa
  • Paypal 支付页面布局在 webview android 中损坏

    我在某些 Android 设备上遇到一个奇怪的问题 我正在 webview 上打开 PayPal 支付页面 但它的布局在某些设备上被破坏 请任何人有任何想法 请提出建议 我被困住了 该截图设备的浏览器为chrome版本34 0 1847 1
  • 如何在android中以编程方式读取我的应用程序中电子邮件附加的文件?

    我知道一种获取此处显示的电子邮件中附件名称的方法 Android 在我的应用程序中获取电子邮件附件名称 https stackoverflow com questions 6035535 android get email attachme
  • 如何使用baseadapter自定义listview

    我想创建一个定制的ListView像这样 我想我必须使用BaseAdapter但我对此一无所知 主要 xml
  • 在发布我的应用程序之前在 play.google 上获取我的应用程序的链接

    我想使用 facebook api 分享我的应用程序的链接 play google 上的链接 但在将应用程序发布到市场之前我必须拥有它才能将其放入我的代码中 除了发布后立即更新我的应用程序之外 还有其他解决方案吗 用这个 https pla
  • 内存分配/释放瓶颈?

    在典型的实际程序中 内存分配 释放的瓶颈有多大 欢迎来自性能通常很重要的任何类型的程序的答案 malloc free 垃圾收集的正确实现是否足够快 以至于它只是少数极端情况下的瓶颈 或者大多数性能关键型软件会从尝试减少内存分配量或拥有更快的
  • ScrollView 中的 ViewPager 不会垂直滚动

    我有一个layout有一个ViewPager自定义内部ScrollView并且 ViewPager 不会垂直滚动 自定义 ScrollView 用于修复使用 ScrollView 进行可怕的选项卡滑动的问题 是的 有足够的内容可以滚动 我已
  • 在 Android 媒体播放器上播放 MediaStore 中的音频

    有没有办法通过使用 MediaPLayer 播放从 MediaStore 获得的音频 或者我走的方向完全错误 到目前为止 我已经查看了 MediaStore Audio 但没有什么能真正帮助我 我只需要知道我是否走在正确的轨道上 首先 我假
  • Android 应用程序阿拉伯语支持

    我已经按照developer android官方网站上的教程Hello L10进行操作 但没有任何关于阿拉伯语的内容 Android 应用程序要使用阿拉伯语需要执行哪些步骤 例如 用户可以使用组合框或单选按钮来选择英语或阿拉伯语 我已经这样
  • Apache POI 的 ProGuard 设置

    我正在构建一个使用 Apache POI 库的应用程序 当我调试应用程序 在不运行 Proguard 的情况下编译它 时 一切都运行良好 但是在导出 APK 后 当我运行应用程序并打开 Excel 文件时 出现以下异常 RuntimeExc
  • Maven:如何获取捆绑在包中的 .so 库

    我有一个带有 jar 和 so 文件的第三方库 我配置了 pom xml 如下
  • 用dagger 2查看依赖注入

    我有一个自定义视图扩展TextView 我应该在哪里调用我的组件来注入视图 component inject customTextView 因此 我发现我需要在自定义视图的构造函数中添加注入 在所有视图中 或者使一个调用另一个 Exampl
  • 如何在Android Studio中关联.mp3文件

    我想根据列表视图项单击播放 mp3 文件 但是根据我的代码 我运行我的应用程序 出现此窗口 因此由于缺少音频选项 我真的不知道需要选择其中哪一个为了关联我的 mp3 文件 mainList setOnItemClickListener ne
  • 如何将 Facebook App 的 accessToken 添加到 GraphRequest.newGraphPathRequest 方法? [复制]

    这个问题在这里已经有答案了 我复制了下面的代码Facebook Graph Api console 但是 Android Studio 无法识别accessToken 我已经创建了一个Facebook App我得到了它acesstoken
  • numpy 数组最快的保存和加载选项

    我有一个生成二维的脚本numpy数组与dtype float和形状的顺序 1e3 1e6 现在我正在使用np save and np load对数组执行 IO 操作 然而 这些函数对于每个数组都需要几秒钟的时间 是否有更快的方法来保存和加载
  • Handler、MessageQueue、Looper,它们都是运行在UI线程上的吗?

    我正在尝试解决线程问题 并且我知道我可能会使用Handler将消息 可运行对象发布到MessageQueue 这又被Looper并发送回Handler进行加工 如果我发帖到Handler在我的活动中 是Activity Handler Me
  • recyclerview 未连接适配器;跳过布局

    刚刚实施RecyclerView在我的代码中 替换ListView 一切正常 显示数据 但正在记录错误消息 15 25 53 476 E RecyclerView No adapter attached skipping layout 15
  • 了解 FTS3/FTS4:什么是虚拟表并从中搜索具有可搜索的非虚拟表?

    阅读 SQLite3 的 FTS3 FTS4 文档的第一部分后 我现在感到非常困惑 我感到困惑的原因是散布在网络上的示例 我相信它没有涵盖所有可能的用例 另一个原因是我目前所处的情况 话虽如此 我有一个名为 Note 的表 其中包含两个类型

随机推荐