小编tan*_*avo的帖子

最小化Android GLSurfaceView滞后

关于Stack Overflow的其他一些问题,我已经从这里阅读了Android Surfaces,SurfaceViews等内部指南:

https://source.android.com/devices/graphics/architecture.html

该指南让我对Android上所有不同部分的组合方式有了更好的理解.它介绍了eglSwapBuffers如何将渲染帧推送到队列中,当它准备下一帧显示时,SurfaceFlinger将使用该队列.如果队列已满,那么它将等到缓冲区在返回之前可用于下一帧.上面的文档将其描述为"填充队列"并依赖交换缓冲区的"反压"来限制渲染到显示的vsync.这是使用GLSurfaceView的默认连续渲染模式发生的情况.

如果你的渲染是简单的并且在比帧周期少得多的情况下完成,那么这是由BufferQueue引起的额外延迟,因为SwapBuffers上的等待直到队列满了才发生,因此我们'重新渲染始终位于队列的后面,因此不会立即显示在下一个vsync上,因为队列中可能存在缓冲区.

相比之下,按需渲染的发生频率通常比显示更新速率低得多,因此通常这些视图的BufferQueues为空,因此推送到这些队列的任何更新都将被SurfaceFlinger在下一个vsync上抓取.

所以问题在于:如何设置连续渲染器,但延迟最小?目标是每个vsync开始时缓冲区队列为空,我在16ms内渲染我的内容,将其推送到队列(缓冲区计数= 1),然后由SurfaceFlinger在下一个vsync(缓冲区计数)上使用它= 0),重复一遍.队列中的缓冲区数量可以在systrace中看到,因此目标是在0和1之间交替使用.

我上面提到的文档介绍了Choreographer作为在每个vsync上获得回调的方法.但是我不相信这足以让我能够实现我追求的最小滞后行为.我已经测试了在vsync回调上使用非常小的onDrawFrame()执行requestRender(),它确实展示了0/1缓冲区计数行为.但是,如果SurfaceFlinger无法在一个帧周期内完成所有工作(可能是通知弹出或其他),该怎么办?在这种情况下,我希望我的渲染器很乐意为每个vsync生成1帧,但该BufferQueue的消费者端已经丢弃了一帧.结果:我们现在在队列中交替使用1到2个缓冲区,并且我们在渲染和查看帧之间获得了一段滞后.

该文档似乎建议查看报告的vsync时间与回调运行时间之间的时间偏差.我可以看到,如果你的回调由于你的主线程由于布局传递或其他东西而延迟传递,那会有什么帮助.但是我认为这不会允许检测到SurfaceFlinger跳过节拍并且不能消耗帧.应用程序是否有任何方法可以解决SurfaceFlinger丢帧的问题?似乎无法告诉队列的长度打破了使用vsync时间进行游戏状态更新的想法,因为在您实际渲染的渲染之前,队列中存在未知数量的帧.

减少队列的最大长度并依赖背压将是实现此目的的一种方法,但我认为没有API来设置GLSurfaceView BufferQueue中的最大缓冲区数量?

android lag surfaceview

25
推荐指数
1
解决办法
5155
查看次数

Android上的零拷贝摄像头处理和渲染管道

我需要对实时摄像机数据(仅来自Y平面)执行CPU端只读过程,然后在GPU上进行渲染.在处理完成之前不应渲染帧(因此我并不总是希望从摄像机渲染最新帧,只是CPU端已完成处理的最新帧).渲染与相机处理分离,即使相机帧以低于此速率的速度到达,目标也是60 FPS.

在Android上有一个相关但更高级别的问题:最低开销的相机到CPU到GPU的方法

更详细地描述当前设置:我们有一个用于摄像机数据的应用程序端缓冲池,其中缓冲区是"空闲","显示"或"待处理显示".当来自摄像机的新帧到达时,我们获取一个空闲缓冲区,在那里存储帧(或者如果实际数据在某个系统提供的缓冲池中,则对它进行引用),进行处理并将结果存储在缓冲区中,然后设置缓冲区"待处理显示".在渲染器线程中,如果在渲染循环开始处有任何缓冲区"待处理显示",我们将其锁定为"显示"中的一个,渲染相机,并使用从其计算的处理信息渲染其他内容相机框架.

感谢@ fadden对上面链接的问题的回复,我现在明白了android camera2 API的"并行输出"功能在各种输出队列之间共享缓冲区,因此不应该涉及数据上的任何副本,至少在现代android上.

在评论中有一个建议,我可以同时锁定SurfaceTexture和ImageReader输出,只是"坐在缓冲区",直到处理完成.不幸的是,我不认为这适用于我的情况,因为我们仍然希望以60 FPS驱动的解耦渲染,并且仍然需要访问前一帧,同时处理新帧以确保无法获得不同步.

我想到的一个解决方案是拥有多个SurfaceTextures - 我们每个应用程序端缓冲区中都有一个(我们目前使用3个).使用该方案,当我们获得一个新的相机帧时,我们将从我们的应用程序池中获得一个空闲缓冲区.然后我们调用acquireLatestImage()ImageReader获取要处理的数据,并updateTexImage()在空闲缓冲区中调用SurfaceTexture.在渲染时我们只需要确保来自"in display"缓冲区的SufaceTexture是绑定到GL的那个,并且所有内容都应该在大多数时间同步(因为@fadden评论说在调用updateTexImage()和之间存在争用acquireLatestImage()但是时间窗口应该足够小以使其变得罕见,并且无论如何使用缓冲区中的时间戳可能是可行的和可修复的).

我注意到文档updateTexImage()只能在SurfaceTexture绑定到GL上下文时调用,这表明我在相机处理线程中也需要GL上下文,因此相机线程可以updateTexImage()在"免费"缓冲区中的SurfaceTexture上执行而渲染线程仍然能够从"显示"缓冲区中的SurfaceTexture渲染.

所以,对于问题:

  1. 这看起来是一种明智的做法吗?
  2. SurfaceTextures基本上是共享缓冲池周围的轻量包装器,还是它们消耗了一些有限的硬件资源,应该谨慎使用?
  3. SurfaceTexture调用是否足够便宜,使用多个调用仍然只是复制数据的一大胜利?
  4. 计划是否有两个线程具有不同的GL上下文,每个可能有不同的SurfaceTexture绑定,或者我要求一个痛苦的世界和错误的驱动程序?

这听起来很有希望,我会试一试; 但是,如果有人(基本上是@fadden!)知道任何我忽略的内部细节会让这个想法变得糟糕,那么我觉得值得一试.

c++ android opengl-es android-camera2

10
推荐指数
1
解决办法
1375
查看次数

使用包含shared_ptr的对象的const正确性

考虑对象:

class Obj
{
    public:
        Obj() : val(new int(1)) {}
        int& get() {return *val;}
        const int& get() const {return *val;}

    private:
        std::shared_ptr<int> val;
};
Run Code Online (Sandbox Code Playgroud)

正如所料,当构造对象并进行复制时,它们都可以通过Obj公开的shared_ptr修改相同的值.

    Obj nonconst1;
    Obj nonconst2(nonconst1);
    nonconst2.get() = 2;
    cout << nonconst1.get() << ", " << nonconst2.get() << endl;
Run Code Online (Sandbox Code Playgroud)

也可以const Obj从非const中复制构造一个对象,这似乎做了正确的事情,因为它允许读取而不是写入值 - 正如预期的那样,下面的代码会导致编译错误:

    const Obj const1(nonconst1);
    const1.get() = 3;
Run Code Online (Sandbox Code Playgroud)

但是,可以从const one复制构造非const Obj,然后允许修改该值.

    Obj nonconst3(const1);
    nonconst3.get() = 3;
Run Code Online (Sandbox Code Playgroud)

对我来说,这并不觉得是正确的.

有没有办法防止这种行为,同时仍然允许复制构造函数工作?在我的实际用例中,我仍然希望Obd的std容器成为可能.

c++ const shared-ptr

7
推荐指数
1
解决办法
936
查看次数

Android上最低的摄像头到CPU到GPU的方法

我的应用程序需要在CPU上对实时相机帧进行一些处理,然后再在GPU上进行渲染.还有一些其他的东西在GPU上呈现,这取决于CPU处理的结果; 因此,保持所有内容同步非常重要,因此我们不会在GPU上渲染帧本身,直到该帧的CPU处理结果也可用.

问题是什么是Android上最低的开销方法?

在我的情况下CPU处理只需要一个灰度图像,因此Y平面打包的YUV格式是理想的(并且往往与相机设备的原生格式很好地匹配).NV12,NV21或全平面YUV都可以提供理想的低开销灰度访问,因此在CPU方面是首选.

在原始相机API中,setPreviewCallbackWithBuffer()是将数据输入CPU进行处理的唯一合理方法.这使Y平面分离,因此非常适合CPU处理.将此框架提供给OpenGL以便以低开销方式呈现是更具挑战性的方面.最后,我编写了一个NEON颜色转换例程来输出RGB565,并且只需使用glTexSubImage2d就可以在GPU上使用它.这首先是在Nexus 1时间帧中实现的,即使是320x240 glTexSubImage2d调用占用了50ms的CPU时间(我猜想,尝试进行纹理调配的不良驱动程序 - 后来在系统更新中显着改善).

回到那一天,我研究了像eglImage扩展这样的东西,但它们似乎没有足够的用户应用程序可用或有足够的文档记录.我对内部android GraphicsBuffer类进行了一些研究,但理想情况下希望保留在受支持的公共API的世界中.

android.hardware.camera2 API承诺能够将ImageReader和SurfaceTexture连接到捕获会话.不幸的是我无法看到任何方法来确保正确的顺序管道 - 阻止调用updateTexImage()直到CPU处理足够容易,但如果在该处理期间另一帧已到达,则updateTexImage()将直接跳到最新帧.在多个输出中似乎也会有每个队列中帧的独立副本,理想情况下我想避免这些副本.

理想情况下,这就是我想要的:

  1. 相机驱动程序用最新的帧填充一些内存
  2. CPU获取指向内存中数据的指针,可以在不进行复制的情况下读取Y数据
  3. 当帧准备就绪时,CPU处理数据并在我的代码中设置一个标志
  4. 开始渲染帧时,检查新帧是否准备就绪
  5. 调用一些API来绑定与GL纹理相同的内存
  6. 准备好较新的帧时,将保留前一帧的缓冲区释放回池中

我无法看到在Android上使用公共API完全实现零拷贝样式的方法,但是最接近它的是什么?

我试过的一个疯狂的事情似乎有效,但没有记录:ANativeWindow NDK API可以接受数据NV12格式,即使适当的格式常量不是公共标题中的一个.这允许通过memcpy()填充SurfaceTxture的NV12数据,以避免CPU端颜色转换以及glTexImage2d中驱动程序端发生的任何混乱.这仍然是数据的额外副本,虽然感觉它应该是不必要的,并且再次因为它没有文档可能不适用于所有设备.支持的顺序零拷贝摄像头 - > ImageReader - > SurfaceTexture或等效物将是完美的.

android opengl-es android-ndk android-camera

7
推荐指数
1
解决办法
1622
查看次数

全局std :: string导致iOS崩溃

我已将此作为错误提交给Apple,但只是为了确认,这里是测试代码:

#include <string>

std::string home_directory;

std::string BuildPath(const std::string directory, const std::string path)
{
  if(home_directory.compare(directory) == 0)
    printf("In home directory\n");

  return directory + "/" + path;
}

int main(int, char* [])
{
  home_directory = "home";
  printf("Home: '%s'\n", home_directory.c_str());
  printf("BuildPath: '%s'\n", BuildPath("base", "path").c_str());
}
Run Code Online (Sandbox Code Playgroud)

当使用最新的XCode 5.1,iOS SDK 7.1和LLVM 5.1构建时,使用libstdc ++作为C++标准库,当在iOS 5.1设备上运行时,这会在BuildPath函数的返回行上的std :: string实现中的某处崩溃.

输出是

Home: 'home'
CrashTest(1242) malloc: *** error for object 0x2fe2ac80: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
Run Code Online (Sandbox Code Playgroud)

堆栈爬行:

Exception Type:  EXC_CRASH (SIGABRT) …
Run Code Online (Sandbox Code Playgroud)

c++ std ios

6
推荐指数
1
解决办法
1648
查看次数

确保熊猫MultiIndex中的字典编排排序

我有一些带有MultiIndex的数据(一些时序统计信息,以及“设备”,“构建配置”,“测试功能”等的索引级别)。我想对其中一些索引列进行切片。

.loc函数的“切片器”似乎是可行的方法。但是文档包含以下警告:

警告:您需要确保选择轴已完全按照顺序排列!

后来在文档中有一个部分需要有序性与多指标其说

您有责任确保物品正确分类

但幸运的是,

MultiIndex对象具有用于显式检查排序深度的代码。因此,如果尝试在未对索引进行排序的深度进行索引,则会引发异常。

听起来不错。

但是,剩下的问题是如何使他们的数据正确排序以使索引正常工作?文档讨论了一种重要的新方法,sortlevel()但随后包含以下警告:

有一个重要的新方法sortlevel可以对MultiIndex中的轴进行排序,以便按该级别上关联因子的原始顺序对标签进行分组和排序。请注意,这并不一定意味着标签将按字典顺序排序!

在我的情况下,sortlevel()做对了,但是如果我的“相关因子的原始排序”没有排序怎么办?是否可以在任何MultiIndex-ed DataFrame上使用一个简单的单行代码,以确保它已准备好进行切片和完全按词法排序?


编辑:我的探索建议,大多数创建MultiIndex的方法都会在建立索引时自动对唯一标签进行lexsort。例:

In [1]: 
import pandas as pd
df = pd.DataFrame({'col1': ['b','d','b','a'], 'col2': [3,1,1,2],
                  'data':['one','two','three','four']})
df

Out[1]: 
  col1  col2   data
0    b     3    one
1    d     1    two
2    b     1  three
3    a     2   four

In [2]:
df2 = df.set_index(['col1','col2'])
df2

Out[2]: 
            data
col1 col2       
b    3       one
d    1       two
b    1     three
a    2      four

In [3]: df2.index
Out[3]: 
MultiIndex(levels=[[u'a', …
Run Code Online (Sandbox Code Playgroud)

pandas

5
推荐指数
1
解决办法
1397
查看次数