Mali GPU 上 HALF_FLOAT 的问题

Issues with HALF_FLOAT on Mali GPUs

我的用户报告说在某些配备 Mali GPU 的设备(华为荣耀 9 和三星 Galaxy S10+ 分别配备 Mali G71 和 G76)上呈现半浮点数数据存在问题。

在 Adreno 和 PowerVR GPU 上正常工作时,它会导致在这些设备上呈现乱码。

我仔细检查了代码,它似乎是正确的:

...
     if (model.hasHalfFloats()) {
         GLES20.glVertexAttribPointer(shaderOutline.getRm_Vertex(), 3, GLES20.GL_FLOAT, false, 18, 0);
         GLES20.glVertexAttribPointer(shaderOutline.getRm_Normal(), 3, getGL_HALF_FLOAT(), false, 18, 12);
     } else {
         GLES20.glVertexAttribPointer(shaderOutline.getRm_Vertex(), 3, GLES20.GL_FLOAT, false, 24, 0);
         GLES20.glVertexAttribPointer(shaderOutline.getRm_Normal(), 3, GLES20.GL_FLOAT, false, 24, 12);
     }
...

/**
 * Returns either OES extension for GL 16-bit floats (if used in ES 2.0) or ES 3.0 constant.
 */
protected int getGL_HALF_FLOAT() {
    if(isES3()) {
        return GLES30.GL_HALF_FLOAT;
    } else {
        return GL_HALF_FLOAT_OES;
    }
}

代码似乎可以正确检测 OpenGL ES 3 并使用 getGL_HALF_FLOAT() 中的 GLES30.GL_HALF_FLOAT 值。

示例着色器代码:

    vertexShaderCode = "attribute vec4 rm_Vertex;\r\n" + 
            "attribute mediump vec3 rm_Normal;\r\n" +
            "uniform mat4 view_proj_matrix;\r\n" + 
            "uniform float uThickness1;\r\n" + 
            "void main( void )\r\n" + 
            "{\r\n" + 
            "   vec4 pos = vec4(rm_Vertex.xyz, 1.0);\r\n" + 
            "   float dist = (view_proj_matrix * pos).w;\r\n" + 
            "   vec4 normal = vec4(rm_Normal, 0.0);\r\n" + 
            "   pos += normal * uThickness1 * dist;\r\n" + 
            "   gl_Position = view_proj_matrix * pos;\r\n" + 
            "}";

    fragmentShaderCode = "precision mediump float;\r\n" + 
            "uniform vec4 uColor;\r\n" + 
            "void main( void )\r\n" + 
            "{\r\n" + 
            "    gl_FragColor = uColor;\r\n" + 
            "}";

我认为您遇到了对齐问题。从这个片段(和你的顶点着色器):

GLES20.glVertexAttribPointer(shaderOutline.getRm_Normal(), 3, getGL_HALF_FLOAT(), false, 18, 12);

我可以推断您正在尝试这样的顶点结构:

float fPos[3];
half fNormal[3];

您得出的顶点步长为 18,这大概是通过将元素的各个大小相加得到的 (3*sizeof(float))+(3*sizeof(half)) = 12 + 6 = 18

但是,步幅应为 20,否则您的顶点会错位。 4 字节浮点数必须从 4 字节边界开始,但事实并非如此。

来自 GLES3 规范:

Clients must align data elements consistently with the requirements of the client platform, with an additional base-level requirement that an offset within a buffer to a datum comprising N basic machine units be a multiple of N