One of my game engine demo (Android) app runs well on devices with Adreno and PowerVR Gpus. However, when I test it on devices with Mali Gpus, I can not get any lighting effect on 3D objects, See the attached device screenshot (left) and RenderDoc snapshot (right):
I narrowed down the problem and found that it cause by accessing array elements by an variable index inside an Uniform buffer.
My shading model is a simple Blinn-Phong shading model. All light sources are passed in by a per-scene uniform buffer. There is 1 ambient light and 5 (up to) direction lights defined in this uniform buffer:
struct DirectionalLight{ vec4 color; vec3 direction; bool isActive; //Is this light in use?};
struct DirectionalLight
{
vec4 color;
vec3 direction;
bool isActive; //Is this light in use?
};
#define NUM_DIR_LIGHT 5layout (std140, set = 1, binding = 0) uniform ProjMatrixBuffer{ mat4 projMat; // Scene projection matrix
#define NUM_DIR_LIGHT 5
layout (std140, set = 1, binding = 0) uniform ProjMatrixBuffer
mat4 projMat; // Scene projection matrix
vec4 ambientColor; // Ambient color DirectionalLight lights[NUM_DIR_LIGHT]; // 5 directional light uint activeLightNum; // Num of active light};
vec4 ambientColor; // Ambient color
DirectionalLight lights[NUM_DIR_LIGHT]; // 5 directional light
uint activeLightNum; // Num of active light
The light effect is calculated by the following function:
LightingColorOutput blinnPhongShading(vec3 normal){
LightingColorOutput blinnPhongShading(vec3 normal)
... for(int i=0; i<activeLightNum; i++) // Loop through all directional lightings { DirectionalLight dirLight = lights[i]; <<<<======== Problem! using [i] makes dirLight has value of all-zero! vec3 lightVec = dirLight.direction; vec4 lightCol = dirLight.color;
for(int i=0; i<activeLightNum; i++) // Loop through all directional lightings
DirectionalLight dirLight = lights[i]; <<<<======== Problem! using [i] makes dirLight has value of all-zero!
vec3 lightVec = dirLight.direction;
vec4 lightCol = dirLight.color;
calculate the light effect generate by this direction light ...
...
}
The line "DirectionalLight dirLight = lights[ i ];" cause the problem. When I use variable "i" to access array element, the structure has all 0 values, and therefore 3D objects appear to be black or very dark.
When I hard code the array index by 0, 1, 2, ..., then I got the correct values that I passed in by Vulkan code.
So the workaround is that I can do the loop unrolling like:
if(lights[0].isActive) calculateLightEffect( lights[0]);if(lights[1].isActive) calculateLightEffect( lights[1]);if(lights[2].isActive) calculateLightEffect( lights[2]);if(lights[3].isActive) calculateLightEffect( lights[3]); ...
if(lights[0].isActive)
calculateLightEffect( lights[0]);
if(lights[1].isActive)
calculateLightEffect( lights[1]);
if(lights[2].isActive)
calculateLightEffect( lights[2]);
if(lights[3].isActive)
calculateLightEffect( lights[3]);
Certainly this is not a nice solution.
Note that my Vulkan shader works well on nVidia, AMD, Intel, PowerVR and Adreno Gpus and I think it complies with Spir-V specs. Is there any thing wrong when I use variable "i" as array index to access array elements? Or is there a special requirement for Mali Gpu? Thanks for any suggestions.
GameEngineDemo.zip
The attached ZIP file is the APK file "GameEngineDemo.apk". The binary is built with Debug info and Vulkan validation.