私のライトシェイダーでは、一部の携帯電話でパフォーマンスの問題が発生しています。 シェーダは、ノーマルマップに基づいて、ラインライトとポイントライトを計算します。 ターゲット上のヒットを示しています(これは2Dトップダウンシューティングゲームです)。古い携帯電話でのOpenGL ESシェーダの巨大なパフォーマンスの問題
私はSony Xperia Z5 Compactで開発していますが、すべてが動作するのは です。それから私は非常に古いサムスンのギャラクシーS2でそれを試しました、 それは本当に遅いです。私は電話の時代のために気にしなかった。
今私はGalaxy S4とGalaxy S5で試しましたが、それは よりも速くGalaxy S2上で実行されているようです。私もhuuuugeのコンパイル時間(約90秒)を持っていましたが、コードを最適化することによって数秒のようにそれを持ってきました(私はそれがまだ厄介だと思う、私は実際にシェイダーにはありません)。
私は本当にここでボトルネックとは何か、なぜそれらのS4とS5の上で実行されていないか分からない。
これは私のシェーダです:
#ifdef GL_ES
#define LOWP lowp
precision highp float;
#else
#define LOWP
#endif
#define MAX_NUM_POINTLIGHTS 16
uniform vec3 lpos[MAX_NUM_POINTLIGHTS]; // Light position
uniform vec3 foff[MAX_NUM_POINTLIGHTS]; // Light falloff
uniform vec4 acol[MAX_NUM_POINTLIGHTS]; // Ambient color
uniform vec4 lcol[MAX_NUM_POINTLIGHTS]; // Light color
//textures
uniform sampler2D u_texture1; // diffuse texture
uniform sampler2D u_texture2; // normalmap
varying vec4 vColor;
varying vec2 vTexCoord;
varying float vFlags;
uniform vec2 Resolution; //resolution of screen
const float WORLD_WIDTH = 1440.0;
const float WORLD_HEIGHT = 2560.0;
vec3 getPointLightColor(const vec4);
vec3 rotateVector(const vec3 vector, const float angle);
vec2 screenCoordToWorldCoord(const vec2 screencoord);
vec3 calculatePointLight(const vec4 DiffuseColor, vec3 LightPos, const vec3 Falloff, const vec4 LightColor, const vec4 AmbientColor);
const float stdratio = WORLD_HEIGHT/WORLD_WIDTH;
vec2 worldFragCoord;
const float worldRatio_W_DIV_H = WORLD_WIDTH/WORLD_HEIGHT;
const vec2 worldSize = vec2(WORLD_WIDTH, WORLD_HEIGHT);
// Light variables
vec3 NormalMap;
vec2 worldFragCoordNormalized;
vec3 N;
void main() {
worldFragCoord = screenCoordToWorldCoord(gl_FragCoord.xy);
// Common light calculations
NormalMap = texture2D(u_texture2, vTexCoord).rgb;
worldFragCoordNormalized = worldFragCoord/vec2(1440.0, 2560.0);
N = normalize(NormalMap * 2.0 - 1.0);
vec4 DiffuseColor = texture2D(u_texture1, vTexCoord);
vec2 fragcoord = gl_FragCoord.xy;
vec3 pointcolor = getPointLightColor(DiffuseColor);
vec4 finalColor;
// green channel of vColor indicates hit
if (vColor.g > 0.0 && vColor.a == 0.0) {
vec4 fragcol = vec4(pointcolor, DiffuseColor.a);
vec4 addColor;
if (vColor.g > 0.67)
addColor = vec4(1.0,1.0,1.0, DiffuseColor.a*vColor.g);
else if (vColor.g > 0.52)
addColor = vec4(1.0,0.0,0.0, DiffuseColor.a*vColor.g);
else if (vColor.g > 0.37)
addColor = vec4(0.0,0.0,1.0, DiffuseColor.a*vColor.g);
else if (vColor.g > 0.22)
addColor = vec4(1.0,1.0,0.0, DiffuseColor.a*vColor.g);
else
addColor = vec4(0.0,1.0,1.0, DiffuseColor.a*vColor.g);
finalColor = addColor*addColor.a + fragcol*(1.0-addColor.a);
}
else
finalColor = vec4(pointcolor, DiffuseColor.a);
gl_FragColor = finalColor;
}
vec3 rotateVector(const vec3 vector, const float angle){
float degree = radians(360.0*angle); // Angle is normalized to 0 - 1
float cos_ = cos(degree);
float sin_ = sin(degree);
return vec3(vector.x*cos_ - vector.y*sin_, vector.x*sin_ + vector.y*cos_, vector.z);
}
vec3 calculatePointLight(const vec4 DiffuseColor, vec3 LightPos, const vec3 Falloff, const vec4 LightColor, const vec4 AmbientColor){
if (LightPos.x == 0.0 && LightPos.y == 0.0)
return vec3(0.0);
LightPos.xy = LightPos.xy/worldSize;
//The delta position of light
vec3 LightDir = vec3(LightPos.xy - worldFragCoordNormalized, LightPos.z);
//Correct for aspect ratio
LightDir.x *= worldRatio_W_DIV_H;
//Determine distance (used for attenuation) BEFORE we normalize our LightDir
float D = length(LightDir);
//normalize our vectors
vec3 L = normalize(LightDir);
vec3 NN = N;
if (vColor.a == 0.0)
NN = normalize(rotateVector(NN, vColor.r));
//Pre-multiply light color with intensity
//Then perform "NN dot L" to determine our diffuse term
vec3 Diffuse = (LightColor.rgb * LightColor.a) * max(dot(NN, L), 0.0);
//pre-multiply ambient color with intensity
vec3 Ambient = AmbientColor.rgb * AmbientColor.a;
//calculate attenuation
float Attenuation = 1.0/(Falloff.x + (Falloff.y*D) + (Falloff.z*D*D));
//the calculation which brings it all together
vec3 Intensity = Ambient + Diffuse * Attenuation;
vec3 FinalColor = DiffuseColor.rgb * Intensity;
return FinalColor;
}
vec3 getPointLightColor(const vec4 DiffuseColor){
vec3 sum = vec3(0.0);
for (int i = 0; i < MAX_NUM_POINTLIGHTS; i++)
{
sum += calculatePointLight(DiffuseColor, lpos[i], foff[i], lcol[i], acol[i]);
}
return sum;
}
vec2 screenCoordToWorldCoord(const vec2 screencoord){
float ratio = Resolution.y/Resolution.x;
vec2 resCoord;
if (ratio == stdratio){
// Ratio is standard
resCoord = screencoord * (WORLD_HEIGHT/Resolution.y);
} else if (ratio > stdratio) {
// Screen gets extended vertically (black bars top/bottom)
float screenheight = Resolution.x * stdratio;
float bottom = (Resolution.y - screenheight)/2.0;
resCoord = vec2(screencoord.x, screencoord.y - bottom);
resCoord *= (WORLD_WIDTH/Resolution.x);
} else {
// Screen gets extended horizontally (black bars left/right)
float screenwidth = Resolution.y/stdratio;
float left = (Resolution.x - screenwidth)/2.0;
resCoord = vec2(screencoord.x - left, screencoord.y);
resCoord *= (WORLD_HEIGHT/Resolution.y);
}
return resCoord;
}
私の電話よりも消化する時間を見つけようとしますが、一般的なルールとして、ループや条件は問題です。不必要な作業をしたり、クランプやステップなどを組み合わせて効果的に廃棄します。 – Tommy
それらのループは前に展開されていましたが、定数を使ってループを読むのはうまくいきました。あなたはそれらの条件がこれを引き起こすと思いますか? – Draz
ええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええ、 'if(i)に追加すると、その実装の戦略に応じて、条件付き分岐が再導入される可能性があります。いくつかは選択的に再コンパイルします。条件付きでは、SIMDy並列化GPUの適用を妨げることが多いので、これを引き起こす可能性があります。ピクセルAとピクセルA + 1が同じ命令ストリームに従うことがもはや真でない場合、両方を同時に実行することは困難です。 –
Tommy