使用OpenGL ES 2.0和Galaxy S4手机,我有一个渲染目标1024x1024 RGBA8888,每帧渲染一些纹理。我需要计算渲染目标上渲染了多少红色RGBA(1,0,0,1)像素(每秒两次)。
主要问题是从GPU获取纹理非常昂贵(约300-400毫秒),并且冻结不适用于我的应用程序。
我知道原子计数器的OES_shader_image_atomic扩展(只是在frag着色器工作时增加一些值),但它只在OpenGL ES 3.1(及更高版本)中可用,我必须坚持使用ES 2.0。
我错过了什么常见的解决方案吗?
你可以尝试的是将所讨论的纹理“减少”到一个非常小的纹理,然后读回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完成所有先前发布的纹理绘制。因此,有两个纹理可能是有益的,在每个帧上渲染一个,另一个正在读取。交换它们的下一帧。这将有点延迟获得所需的数据,但应该消除一些冻结。