计算渲染目标上的像素

时间:2019-03-28 16:05:34

标签: android shader opengl-es-2.0

使用OpenGL ES 2.0和Galaxy S4手机,我有一个渲染目标1024x1024 RGBA8888,其中每帧渲染一些纹理。我需要计算在渲染目标上渲染了多少红色RGBA(1、0、0、1)像素(每秒两次)。

主要问题是从GPU获取纹理非常昂贵(〜300-400毫秒),并且冻结不适用于我的应用程序。

我知道原子计数器的OES_shader_image_atomic扩展(只是在碎片着色器工作时增加一些值),但是仅在OpenGL ES 3.1(及更高版本)中可用,我必须坚持使用ES 2.0。

我错过了任何常见的解决方案吗?

1 个答案:

答案 0 :(得分:3)

您可以尝试的是将有问题的纹理“减少”到一个明显较小的纹理,然后再将其读回CPU(这应该在性能上便宜一些)。例如,您可以将纹理分割成N×N的正方形(其中N最好是2的幂),然后使用片段求和器将数字加起来,将“整个屏幕”四边形渲染为1024 / N×1024 / N的纹理相应正方形中的红色像素数:

sampler2D texture;

void main(void) {
    vec2 offset = N * gl_FragCoord.xy;
    int cnt = 0;
    for (float x = 0.; x < float(N); x += 1) {
        for(float y = 0.; y < float(N); y += 1) {
            if (texture2D(texture, (offset + vec2(x, y)) / 1024.) == vec4(1, 0, 0, 1)) {
                cnt += 1;
            }
        }
    }
    gl_FragColor = vec4((cnt % 256) / 255., ((cnt / 256) % 256) / 255., /* ... */);
}

还请记住,readPixels同步等待,直到GPU完成所有先前发布的纹理绘制为止。因此,具有两个纹理可能是有益的, 在每个帧上,一个正在渲染,而另一个正在从中读取。下一帧交换它们。这将在一定程度上延迟获取所需数据的时间,但应消除某些冻结现象。