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
我的用户报告说在某些配备 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