简体   繁体   English

使用位图高效onDraw,硬件加速复杂剪辑

[英]Efficient onDraw with bitmaps, and hardware accelerated complex clipping

I'm looking for advice about optimal rendering (and possibly caching) of animated content whose nature is determined at run-time and cannot be pre-computed. 我正在寻找有关动画内容的最佳渲染(以及可能的缓存)的建议,动画内容的性质是在运行时确定的,无法预先计算。

I am developing my first Android app, and have decided on a (currently) "toy" project that takes relatively short alphanumeric codes and converts them into images and animations. 我正在开发我的第一个Android应用程序,并决定采用相对较短的字母数字代码并将其转换为图像和动画的(当前)“玩具”项目。 (The SourceForge project is at http://sourceforge.net/projects/picturecode and a design document is at https://docs.google.com/file/d/0B-yO-2scTVuRSkk2NDdiZ3YzTDg/edit?usp=sharing ) (SourceForge项目位于http://sourceforge.net/projects/picturecode ,设计文档位于https://docs.google.com/file/d/0B-yO-2scTVuRSkk2NDdiZ3YzTDg/edit?usp=sharing

I'm at a point where I'm devising operations for nesting pre-defined and user-defined codes within other codes to allow even more complex images with even shorter codes. 我正在设计在其他代码中嵌套预定义和用户定义代码的操作,以允许甚至更短代码的更复杂图像。 I'm also trying to devise related operations that will assist in similarly complex, but interesting images with relatively simple code representation. 我还试图设计相关的操作,这些操作将协助具有相对简单的代码表示的类似复杂但有趣的图像。

As such, one of the operations I thought would be useful is the ability to use a pre-defined or user-defined code as a mask to clip other drawing operations. 因此,我认为有用的操作之一是能够使用预定义或用户定义的代码作为掩码来剪辑其他绘图操作。 I was able to get this working after I discovered that clipPath is not supported in hardware-accelerated views, and forced the view to be software-based. 在我发现硬件加速视图中不支持clipPath并强制视图基于软件后,我能够正常工作。 (My renderer checks whether we are in a mode that defines a "clipping path" and adds operations to a path instead of drawing them on the canvas, but that was kind of tedious and doesn't support all operations.) (我的渲染器会检查我们是否处于定义“剪切路径”的模式,并将操作添加到路径而不是在画布上绘制它们,但这样做很乏味,并且不支持所有操作。)

I'm considering alternatives for switching back to a hardware-accelerated mode. 我正在考虑切换回硬件加速模式的替代方案。 One that comes to mind is creating an ALPHA_888 bitmap and drawing to that instead of creating a clipping path when I'm in that clipping mode. 我想到的是创建一个ALPHA_888位图并绘制到它,而不是在我处于剪切模式时创建剪切路径。 One advantage this would likely have is that it would be more straightforward to support arbitrary operations; 这可能具有的一个优点是支持任意操作会更直接; I just draw them on that bitmap instead of on the main canvas when I'm in clipping mode. 当我处于剪辑模式时,我只是在那个位图而不是主画布上绘制它们。 Once I have the bitmap, I assume I can somehow use it with drawBitmap (into another intermediate bitmap) using a Paint with an appropriate PorterDuff mode. 一旦我有位图,我假设我可以使用具有适当的PorterDuff模式的Paint以某种方式将它与drawBitmap(进入另一个中间位图)一起使用。

I expect that someday I (or anyone for that matter, since the project is on SourceForge) might reuse this component in a larger project as a lightweight way of representing graphics that can be transferred in a plain text, but short/optimized format. 我希望有一天我(或任何人,因为项目在SourceForge上)可能会在一个更大的项目中重用这个组件,作为表示可以纯文本传输但短/优化格式的图形的轻量级方式。 I see it as an animated GIF, but simpler to create and smaller to transfer. 我认为它是一个动画GIF,但创建更简单,传输更小。

My questions are: 我的问题是:

  1. How important is hardware acceleration in general? 硬件加速一般有多重要? Is this an important feature to retain or should I give that up in favor of other features? 这是保留的重要特征还是我应该赞成其他功能? (If others were going to use this feature, I assume they'd often want a component to be hardware-acceleration-compatible.) (如果其他人打算使用此功能,我认为他们经常希望组件与硬件加速兼容。)
  2. Is masking a powerful/important operation, or is there something better I could be using instead (like pure porter-duff-filtered drawing directly to the canvas)? 掩盖一个强大/重要的操作,或者是否有更好的东西我可以使用(如纯粹的porter-duff-filtered绘图直接到画布)?
  3. Am I thinking along the right track for implementing complex masking? 我是否正在考虑实施复杂的掩蔽?

Finally and most importantly : 最后也是最重要的

  • How should I use and manage bitmaps if at all (for example, the mask bitmap)? 如果有的话,我应该如何使用和管理位图(例如,掩码位图)? When I started the project, I noticed that it's not advisable to allocate any new objects during OnDraw. 当我启动项目时,我注意到在OnDraw期间分配任何新对象是不可取的。 So I pre-allocated all that I could - a Paint, a PointF, a RectF, a Path, and a few others, so that I could use them during onDraw. 所以我预先分配了所有可能的东西 - 一个Paint,一个PointF,一个RectF,一个Path和一些其他的东西,以便我可以在onDraw期间使用它们。 At the moment, I'm still drawing directly to the canvas, but I'm wondering if I should be rendering to some sort of buffer, like a bitmap, on a separate thread and then just drawing the buffer to the screen during onDraw. 目前,我仍然直接绘制画布,但我想知道是否应该在单独的线程上渲染某种缓冲区(如位图),然后在onDraw期间将缓冲区绘制到屏幕上。 Would that defeat the purpose of hardware acceleration (and make it not necessary to turn off hardware acceleration on the view itself in the first place)? 这是否会破坏硬件加速的目的(并且首先不必关闭视图本身的硬件加速)? And more importantly how/when can I safely allocate these bitmaps without offending lint and well-seasoned android developers who know that allocating memory during onDraw is bad? 更重要的是,如何/何时可以安全地分配这些位图而不会冒犯lint和经验丰富的Android开发人员,他们知道在onDraw期间分配内存很糟糕? If I allocate the bitmap on a separate drawing thread, I may have to allocate it once for each frame of each included/embedded picture because these pictures can be animations. 如果我在单独的绘图线程上分配位图,我可能必须为每个包含/嵌入图片的每个帧分配一次,因为这些图片可以是动画。 Or I may just want to allocate a bitmap for the current frame to assist in clipping or composing multiple pieces of the image. 或者我可能只想为当前帧分配一个位图,以帮助剪切或合成多个图像片段。

It's hard to narrow this down to a very specific question. 很难将其缩小到一个非常具体的问题。 What I have is somewhere between a mess of questions and a request for general advice about features or ideas of which I might not even be aware. 我所拥有的是介于一堆问题和一些关于我可能甚至不知道的特征或想法的一般建议的请求之间。 I'm relatively new to Java and Android development, but thoroughly familiar with C#, 2D graphics and game development. 我对Java和Android开发相对较新,但对C#,2D图形和游戏开发非常熟悉。 Do my questions point out any glaring holes in my understanding of how 2D animation should work on Android? 我的问题是否指出了我对2D动画如何在Android上运行的理解中的任何明显漏洞?

In reading an article about Android hardware acceleration , I stumbled across a reference to the saveLayer functions of the Canvas, which I believe are the exact pieces I was missing here. 在阅读有关Android硬件加速文章时 ,我偶然发现了对Canvas的saveLayer函数的引用,我相信这是我在这里遗漏的确切部分。

Update: I have confirmed that saveLayer is what I'm after. 更新:我已经确认saveLayer是我所追求的。 Instead of applying a complex clipping region based on a path, and then drawing into that, I am calling saveLayer to create an off-screen buffer into which drawing operations will be applied, drawing one image, switching the Xfermode to SRC_IN, and then drawing the second image. 我没有应用基于路径的复杂剪切区域,而是绘制到那里,而是调用saveLayer创建一个将应用绘图操作的离屏缓冲区,绘制一个图像,将Xfermode切换为SRC_IN,然后绘制第二张图片。 This yields the intersection of the two images with the second image being the visible content. 这产生两个图像的交叉,第二个图像是可见内容。 When I call restore I essentially get the second image clipped by the content of the first image, which is better than what I was trying to accomplish in the first place. 当我调用恢复时,我基本上会得到第一个图像的内容剪切的第二个图像,这比我在第一时间尝试完成的要好。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM