Nexus Sの緑がかったディスプレイを何とかする(Video Driver編)

Nexus S のディスプレイ輝度を低くしたときに何となく緑がかっているのを直す話の続きです。

前回、SurfaceFlinger に手を入れる方法を試しましたが、輝度による特性の変化を考慮していなかったのと、ディスプレイ表示の直前にフィルタをかけるのでスクリーンショット画像の色合いまで変わってしまう問題があって別の方法を模索していました。

Video Driverまわりはプロプライエタリだと勝手に思っていたのですが、ソースが非公開なのはアクセラレータ周りで、ディスプレイパネルドライバは Samsung によって公開されていました。ソースは以下にあったので、すぐにgit clone して読み進めました。

http://android.git.kernel.org/?p=kernel/samsung.git

通常、パネルによって発色の特性は様々なので、ガンマを補正するための値が設定されています。Nexus Sでもこれは同様で、s3cfb_tl2796.c に gamma_lookup 関数が用意されていて、引数として brightness, RGB種別とその値を渡すことで、補正された値が返ってきます。で、どうやら この commit から gamma_table が予め計算された輝度ごとの値から、計算して求める方式に変更になっていました。

drivers/video/samsung/s3cfb_tl2796.c
static u32 gamma_lookup(struct s5p_lcd *lcd, u8 brightness, u32 val, int c)
{
	int i;
	u32 bl = 0;
	u32 bh = 0;
	u32 vl = 0;
	u32 vh;
	u32 b;
	u32 ret;
	u64 tmp;
	struct s5p_panel_data *pdata = lcd->data;
	const struct tl2796_gamma_adj_points *bv = lcd->gamma_adj_points;

	if (!val) {
		b = 0;
	} else {
		tmp = bv->v255 - bv->v0;
		tmp *= brightness;
		do_div(tmp, 255);

		tmp *= (val - bv->v0);
		do_div(tmp, bv->v255 - bv->v0);
		b = tmp + bv->v0;
	}

	for (i = 0; i < pdata->gamma_table_size; i++) {
		bl = bh;
		bh = pdata->gamma_table[i].brightness;
		if (bh >= b)
			break;
	}
	vh = pdata->gamma_table[i].v[c];
	if (i == 0 || (b - bl) == 0) {
		ret = vl = vh;
	} else {
		vl = pdata->gamma_table[i - 1].v[c];
		tmp = (u64)vh * (b - bl) + (u64)vl * (bh - b);
		do_div(tmp, bh - bl);
		ret = tmp;
	}

	pr_debug("%s: looking for %3d %08x c %d, %08x, "
		"found %08x:%08x, v %7d:%7d, ret %7d\n",
		__func__, brightness, val, c, b, bl, bh, vl, vh, ret);

	return ret;
}

この式を変更すればいいことは分かるのですが、調整するにはそれなりの時間と根気が必要です。そこで、herring-panel.c に設定されている gamma_table をいじって、お茶を濁すことにしました。以下が差分です。

diff --git a/arch/arm/mach-s5pv210/herring-panel.c b/arch/arm/mach-s5pv210/herring-panel.c
index c5f9775..0e44072 100755
--- a/arch/arm/mach-s5pv210/herring-panel.c
+++ b/arch/arm/mach-s5pv210/herring-panel.c
@@ -164,8 +164,8 @@ static const struct tl2796_gamma_adj_points gamma_adj_points = {
 };
 
 static const struct gamma_entry gamma_table[] = {
-       {       BV_0, { 4200000, 4200000, 4200000, }, },
-       {          1, { 3994200, 4107600, 3910200, }, },
+       {       BV_0, { 4200000, 4050000, 4130000, }, },
+       {          1, { 3994200, 4000000, 3910200, }, },
        {          2, { 3467167, 3789169, 3488171, }, },
        {    7000000, { 3310578, 3407998, 3280696, }, },
        {   14000000, { 3234532, 3291183, 3181487, }, },

というわけで修正済みの kernel をここに置いておきます。

まだ完璧ではないものの、とりあえず気にならないレベルにはなりました。グラフィック周りに詳しい方がちゃんと調整してくれるといいんですが…



このエントリーのはてなブックマーク (-)