草庐IT

Android TextureView/绘图/绘画性能

coder 2023-11-28 原文

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

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

我试过在 OnDraw 中使用常规 View (不是 TextureView ),性能绝对糟糕 - 每秒不到 1 帧。即使我拨打 Invalidate(rect) 也会发生这种情况只有 rect 发生了变化。我尝试关闭 View 的硬件加速,但没有渲染,我认为是因为 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 更改为传递 null 而不是 rect,则性能在 60 fps 时非常出色,但是 TextureView 的内容闪烁并损坏,这是令人失望的。我原以为它只是在下面使用 OpenGL 帧缓冲区/渲染纹理,或者至少可以选择保留内容。

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

最佳答案

首先,如果您想了解幕后发生的事情,您需要阅读 Android Graphics Architecture document .它很长,但如果你真诚地想了解“为什么”,它就是开始的地方。

关于TextureView

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

如果关闭硬件加速,GLES 将被禁用,TextureView 将无法执行任何操作。这就是为什么当您关闭硬件加速时您一无所获。 The documentation非常具体:“TextureView 只能在硬件加速窗口中使用。在软件中渲染时,TextureView 不会绘制任何内容。”

如果指定dirty rect,软件渲染器会在渲染完成后将之前的内容memcpy到帧中。我不相信它会设置剪辑矩形,因此如果您调用 drawColor(),您将填满整个屏幕,然后覆盖这些像素。如果您当前没有设置剪辑矩形,您可能会从中看到一些性能优势。 (虽然我没有检查代码。)

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

我怀疑肮脏的 rect 处理不当是您闪烁的根源。可悲的是,这是一个很容易犯的错误,因为 lockCanvas() 的行为dirtyRect arg 仅记录在 the Surface class 中本身。

表面和缓冲

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

如果您想要锁定-复制-解锁行为,您可以自己编写(或找到一个执行此操作的库),并且它的效率将与系统为您完成时一样有效(假设您擅长blit 循环)。绘制到屏幕外的 Canvas 并 blit 位图,或绘制到 OpenGL ES FBO 并 blit 缓冲区。您可以在 Grafika 的“record GL app” Activity 中找到后者的示例,该 Activity 具有在屏幕外渲染一次,然后 blit 两次(一次用于显示,一次用于录制视频)的模式。

更多速度等

在 Android 上绘制像素有两种基本方法:使用 Canvas 或使用 OpenGL。 Canvas 渲染到 Surface 或 Bitmap 总是在软件中完成,而 OpenGL 渲染是用 GPU 完成的。唯一的异常(exception)是,当渲染到 custom View 时,您可以选择使用硬件加速,但这在渲染到 SurfaceView 或 TextureView 的 Surface 时不适用。

绘图或绘画应用程序可以记住绘图命令,或者只是将像素扔到缓冲区并将其用作其内存。前者允许更深层次的“撤消”,后者更简单,并且随着要渲染的内容数量的增加,性能也越来越好。听起来您想做后者,因此从屏幕外进行 blitting 是有道理的。

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

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

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

更新:腐败是identified as a bugfixed in 'L' .

关于Android TextureView/绘图/绘画性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31057293/

有关Android TextureView/绘图/绘画性能的更多相关文章

  1. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

  2. Ruby 的数字方法性能 - 2

    我正在使用Ruby解决一些ProjectEuler问题,特别是这里我要讨论的问题25(Fibonacci数列中包含1000位数字的第一项的索引是多少?)。起初,我使用的是Ruby2.2.3,我将问题编码为:number=3a=1b=2whileb.to_s.length但后来我发现2.4.2版本有一个名为digits的方法,这正是我需要的。我转换为代码:whileb.digits.length当我比较这两种方法时,digits慢得多。时间./025/problem025.rb0.13s用户0.02s系统80%cpu0.190总计./025/problem025.rb2.19s用户0.0

  3. ruby - Ruby 性能中的计时器 - 2

    我正在寻找一个用ruby​​演示计时器的在线示例,并发现了下面的代码。它按预期工作,但这个简单的程序使用30Mo内存(如Windows任务管理器中所示)和太多CPU有意义吗?非常感谢deftime_blockstart_time=Time.nowThread.new{yield}Time.now-start_timeenddefrepeat_every(seconds)whiletruedotime_spent=time_block{yield}#Tohandle-vesleepinteravalsleep(seconds-time_spent)iftime_spent

  4. ruby-on-rails - 如果条件与 &&,是否有任何性能提升 - 2

    如果用户是所有者,我有一个条件来检查说删除和文章。delete_articleifuser.owner?另一种方式是user.owner?&&delete_article选择它有什么好处还是它只是一种写作风格 最佳答案 性能不太可能成为该声明的问题。第一个要好得多-它更容易阅读。您future的自己和其他将开始编写代码的人会为此感谢您。 关于ruby-on-rails-如果条件与&&,是否有任何性能提升,我们在StackOverflow上找到一个类似的问题:

  5. ruby - 如何找到我的 Ruby 应用程序中的性能瓶颈? - 2

    我编写了一个Ruby应用程序,它可以解析来自不同格式html、xml和csv文件的源中的大量数据。我如何找出代码的哪些区域花费的时间最长?有没有关于如何提高Ruby应用程序性能的好资源?或者您是否有任何始终遵循的性能编码标准?例如,你总是用加入你的字符串吗?output=String.newoutput或者你会使用output="#{part_one}#{part_two}\n" 最佳答案 好吧,有一些众所周知的做法,例如字符串连接比“#{value}”慢得多,但是为了找出您的脚本在哪里消耗了大部分时间或比所需时间更多,您需要进行分

  6. STM32的HAL和LL库区别和性能对比 - 2

    LL库和HAL库简介LL:Low-Layer,底层库HAL:HardwareAbstractionLayer,硬件抽象层库LL库和hal库对比,很精简,这实际上是一个精简的库。LL库的配置选择如下:在STM32CUBEMX中,点击菜单的“ProjectManager”–>“AdvancedSettings”,在下面的界面中选择“AdvancedSettings”,然后在每个模块后面选择使用的库总结:1、如果使用的MCU是小容量的,那么STM32CubeLL将是最佳选择;2、如果结合可移植性和优化,使用STM32CubeHAL并使用特定的优化实现替换一些调用,可保持最大的可移植性。另外HAL和L

  7. ruby - GC.disable 的任何性能缺点? - 2

    是否存在GC.disable会降低性能的情况?只要我使用的是真正的RAM而不是交换内存,就可以这样做吗?我正在使用MRIRuby2.0,据我所知,它是64位的,并且使用的是64位的Ubuntu:ruby2.0.0p0(2013-02-24revision39474)[x86_64-linux]Linux[redacted]3.2.0-43-generic#68-UbuntuSMPWedMay1503:33:33UTC2013x86_64x86_64x86_64GNU/Linux 最佳答案 GC.disable将禁用垃圾回收。像rub

  8. ruby-on-rails - Rails with angular 与 Rails pure(查看性能) - 2

    我尝试在Internet上搜索有关使用angularJS进入RubyonRails项目与RubyonRailspure的View性能的信息。我的问题是因为2个月前我开始使用纯AngularJS,现在我需要将AngularJS集成到一个新项目中,但需要展示使用带有RubyonRails的AngularJS呈现View的性能如何,并消除对RubyonRails的负担.例如:带Rails的Angular:使用RubyonRails获取数据(从数据库或GET请求),将信息发送到file.js.erb并使用AngularJS操作数据并显示带有解析数据的View。纯粹的Rails:(自然流程)使用

  9. ruby-on-rails - 在 Rails 3 应用程序中使用 require_dependency 对性能有何影响? - 2

    我觉得我理解require和require_dependency之间的区别(来自Howarerequire,require_dependencyandconstantsreloadingrelatedinRails?)。但是,我想知道如果我使用一些不同的方法(参见http://hemju.com/2010/09/22/rails-3-quicktip-autoload-lib-directory-including-all-subdirectories/和Bestwaytoloadmodule/classfromlibfolderinRails3?)来加载所有文件会发生什么,所以我们:

  10. arrays - Ruby 中的并行分配性能 - 2

    设置一个临时变量来交换数组中的两个元素似乎比使用并行赋值更有效。谁能帮忙解释下?require"benchmark"Benchmark.bmdo|b|b.reportdo40000000.times{array[1],array[2]=array[2],array[1]}endendBenchmark.bmdo|b|b.reportdo40000000.timesdot=array[1]array[1]=array[2]array[2]=tendendend结果:usersystemtotalreal4.4700000.0200004.490000(4.510368)usersyste

随机推荐