本文档只是因为维护的Android项目使用了SDK封装的OpenGL接口,想知道底层到底作了哪些操作,纯粹是记录。
Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
// 内部调用native_texImage2D
// native_texImage2D(target, level/*0*/, /*internalformat*/-1, bitmap, /*type*/-1, border/*0*/);
根据AndroidXRef源码参考网站,在/frameworks/base/core/jni/android/opengl/util.cpp的文件将native_texImage2D映射为util_texImage2D。
static JNINativeMethod gUtilsMethods[] = {
{ "native_getInternalFormat", "(Landroid/graphics/Bitmap;)I", (void*) util_getInternalFormat },
{ "native_getType", "(Landroid/graphics/Bitmap;)I", (void*) util_getType },
{ "native_texImage2D", "(IIILandroid/graphics/Bitmap;II)I", (void*)util_texImage2D },
{ "native_texSubImage2D", "(IIIILandroid/graphics/Bitmap;II)I", (void*)util_texSubImage2D },
{ "setTracingLevel", "(I)V", (void*)setTracingLevel },
};
util_texImage2D函数根据bitmap信息决定通过glCompressedTexImage2D或glTexImage2D上传图像数据到OpenGL服务器端。
static jint util_texImage2D(JNIEnv *env, jclass clazz,
jint target, jint level, jint internalformat,
jobject jbitmap, jint type, jint border)
{
SkBitmap bitmap;
GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
SkColorType colorType = bitmap.colorType();
if (internalformat < 0) {
internalformat = getInternalFormat(colorType);
}
if (type < 0) {
type = getType(colorType);
}
int err = checkFormat(colorType, internalformat, type);
if (err)
return err;
bitmap.lockPixels();
const int w = bitmap.width();
const int h = bitmap.height();
const void* p = bitmap.getPixels();
if (internalformat == GL_PALETTE8_RGBA8_OES) {
if (sizeof(SkPMColor) != sizeof(uint32_t)) {
err = -1;
goto error;
}
const size_t size = bitmap.getSize();
const size_t palette_size = 256*sizeof(SkPMColor);
const size_t imageSize = size + palette_size;
void* const data = malloc(imageSize);
if (data) {
void* const pixels = (char*)data + palette_size;
SkColorTable* ctable = bitmap.getColorTable();
memcpy(data, ctable->readColors(), ctable->count() * sizeof(SkPMColor));
memcpy(pixels, p, size);
glCompressedTexImage2D(target, level, internalformat, w, h, border, imageSize, data);
free(data);
} else {
err = -1;
}
} else {
glTexImage2D(target, level, internalformat, w, h, border, internalformat, type, p);
}
error:
bitmap.unlockPixels();
return err;
}
static int getInternalFormat(SkColorType colorType)
{
switch(colorType) {
case kAlpha_8_SkColorType:
return GL_ALPHA;
case kARGB_4444_SkColorType:
return GL_RGBA;
case kN32_SkColorType:
return GL_RGBA;
case kIndex_8_SkColorType:
return GL_PALETTE8_RGBA8_OES;
case kRGB_565_SkColorType:
return GL_RGB;
default:
return -1;
}
}
static int checkFormat(SkColorType colorType, int format, int type)
{
switch(colorType) {
case kIndex_8_SkColorType:
if (format == GL_PALETTE8_RGBA8_OES)
return 0;
case kN32_SkColorType:
case kAlpha_8_SkColorType:
if (type == GL_UNSIGNED_BYTE)
return 0;
case kARGB_4444_SkColorType:
case kRGB_565_SkColorType:
switch (type) {
case GL_UNSIGNED_SHORT_4_4_4_4:
case GL_UNSIGNED_SHORT_5_6_5:
case GL_UNSIGNED_SHORT_5_5_5_1:
return 0;
case GL_UNSIGNED_BYTE:
if (format == GL_LUMINANCE_ALPHA)
return 0;
}
break;
default:
break;
}
return -1;
}
static int getType(SkColorType colorType)
{
switch(colorType) {
case kAlpha_8_SkColorType:
return GL_UNSIGNED_BYTE;
case kARGB_4444_SkColorType:
return GL_UNSIGNED_SHORT_4_4_4_4;
case kN32_SkColorType:
return GL_UNSIGNED_BYTE;
case kIndex_8_SkColorType:
return -1; // No type for compressed data.
case kRGB_565_SkColorType:
return GL_UNSIGNED_SHORT_5_6_5;
default:
return -1;
}
}