Android下OpenGL ES 3.1调用glReadPixels报1282错误求助
问题原因
你创建的纹理格式为GL_RGBA32F浮点型,绑定到帧缓冲区作为颜色附件后,OpenGL ES 3.1默认不支持直接通过glReadPixels将浮点颜色附件转换为GL_UNSIGNED_BYTE类型输出,这是触发GL_INVALID_OPERATION 1282错误的核心原因。
解决方案
方案1:保留浮点纹理,调整读取逻辑
如果业务需要保留浮点精度,可修改glReadPixels参数匹配纹理格式,读取后手动转换为Bitmap需要的无符号字节:
// 浮点纹理每个通道占4字节,总大小为 宽*高*4通道*4字节/通道 mainPixelBuf = ByteBuffer.allocateDirect(mWidth * mHeight * 4 * 4); mainPixelBuf.order(ByteOrder.LITTLE_ENDIAN); mainPixelBuf.rewind(); // 读取类型改为GL_FLOAT匹配RGBA32F纹理 GLES31.glReadPixels(0, 0, mWidth, mHeight, GLES31.GL_RGBA, GLES31.GL_FLOAT, mainPixelBuf); mTextureRender.checkGlError("glReadPixels mainPixelBuf"); // 转换浮点值到0~255范围的无符号字节 byte[] convertedData = new byte[mWidth * mHeight * 4]; mainPixelBuf.rewind(); for (int i = 0; i < convertedData.length; i++) { float floatVal = mainPixelBuf.getFloat(); // 钳位到0~1范围后映射到0~255 convertedData[i] = (byte) (Math.max(0f, Math.min(1f, floatVal)) * 255f); } ByteBuffer convertedBuffer = ByteBuffer.wrap(convertedData); convertedBuffer.rewind(); bmp.copyPixelsFromBuffer(convertedBuffer);
方案2:改用8位无符号纹理(性能更优)
如果不需要浮点精度,直接修改纹理格式为Bitmap原生匹配的GL_RGBA8,原有读取逻辑无需改动:
- 修改纹理创建代码:
// 将internalformat从GL_RGBA32F改为GL_RGBA8 GLES31.glTexStorage2D(GLES31.GL_TEXTURE_2D, 1, GLES31.GL_RGBA8, mWidth, mHeight);
- 修改计算着色器绑定纹理的代码:
// 对应格式改为GL_RGBA8 GLES31.glBindImageTexture(2, mainImageID, 0, false, 0, GLES31.GL_READ_WRITE, GLES31.GL_RGBA8);
- 同步修改Compute Shader中image2D的声明:
// 把原来的rgba32f改为rgba8 layout(rgba8, binding = 2) uniform image2D mainImage;
补充检查项
- 计算着色器执行完成后,建议添加内存屏障确保写入完成,相比glFinish性能更好:
GLES31.glDispatchCompute(WORK_GROUPS_X, WORK_GROUPS_Y, WORK_GROUPS_Z); GLES31.glMemoryBarrier(GLES31.GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
- 如果纹理宽度不是4的倍数,在
glReadPixels前添加如下代码关闭字节对齐限制:
GLES31.glPixelStorei(GLES31.GL_PACK_ALIGNMENT, 1);
内容的提问来源于stack exchange,提问作者Plasmabot
相关产品推荐
相关产品推荐

