aboutsummaryrefslogtreecommitdiff
path: root/src/linux/gpu.c
blob: ae11c78a4aca97b8f4d618965851d813bf698a5f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>

#include <arm/linux/api.h>
#include <log.h>


/*
 * Map from Android GPU series ID to Android GPU vendor ID.
 * This map is used to avoid storing vendor IDs in tables.
 */
static enum cpuinfo_android_gpu_vendor gpu_series_vendor[cpuinfo_android_gpu_series_max] = {
	[cpuinfo_android_gpu_series_unknown]                 = cpuinfo_android_gpu_vendor_unknown,
	[cpuinfo_android_gpu_series_arm_mali]                = cpuinfo_android_gpu_vendor_arm,
	[cpuinfo_android_gpu_series_arm_mali_t]              = cpuinfo_android_gpu_vendor_arm,
	[cpuinfo_android_gpu_series_arm_mali_g]              = cpuinfo_android_gpu_vendor_arm,
	[cpuinfo_android_gpu_series_broadcom_videocore]      = cpuinfo_android_gpu_vendor_broadcom,
	[cpuinfo_android_gpu_series_intel_gen]               = cpuinfo_android_gpu_vendor_intel,
	[cpuinfo_android_gpu_series_intel_hd_graphics]       = cpuinfo_android_gpu_vendor_intel,
	[cpuinfo_android_gpu_series_nvidia_tegra]            = cpuinfo_android_gpu_vendor_nvidia,
	[cpuinfo_android_gpu_series_nvidia_tegra_k]          = cpuinfo_android_gpu_vendor_nvidia,
	[cpuinfo_android_gpu_series_nvidia_tegra_x]          = cpuinfo_android_gpu_vendor_nvidia,
	[cpuinfo_android_gpu_series_powervr_sgx]             = cpuinfo_android_gpu_vendor_powervr,
	[cpuinfo_android_gpu_series_powervr_rogue_g]         = cpuinfo_android_gpu_vendor_powervr,
	[cpuinfo_android_gpu_series_powervr_rogue_ge]        = cpuinfo_android_gpu_vendor_powervr,
	[cpuinfo_android_gpu_series_powervr_rogue_gm]        = cpuinfo_android_gpu_vendor_powervr,
	[cpuinfo_android_gpu_series_powervr_rogue_gt]        = cpuinfo_android_gpu_vendor_powervr,
	[cpuinfo_android_gpu_series_powervr_rogue_gx]        = cpuinfo_android_gpu_vendor_powervr,
	[cpuinfo_android_gpu_series_qualcomm_adreno]         = cpuinfo_android_gpu_vendor_qualcomm,
	[cpuinfo_android_gpu_series_vivante_gc]              = cpuinfo_android_gpu_vendor_vivante,
};

/* Map from Android GPU vendor ID to its string representation */
static const char* gpu_vendor_string[cpuinfo_arm_chipset_vendor_max] = {
	[cpuinfo_android_gpu_vendor_unknown]  = "Unknown",
	[cpuinfo_android_gpu_vendor_arm]      = "ARM",
	[cpuinfo_android_gpu_vendor_broadcom] = "Broadcom",
	[cpuinfo_android_gpu_vendor_intel]    = "Intel",
	[cpuinfo_android_gpu_vendor_nvidia]   = "Nvidia",
	[cpuinfo_android_gpu_vendor_powervr]  = "PowerVR",
	[cpuinfo_android_gpu_vendor_qualcomm] = "Qualcomm",
	[cpuinfo_android_gpu_vendor_vivante]  = "Vivante",
};

/* Map from ARM chipset series ID to its string representation */
static const char* gpu_series_string[cpuinfo_arm_chipset_series_max] = {
	[cpuinfo_android_gpu_series_arm_mali]                = "Mali-",
	[cpuinfo_android_gpu_series_arm_mali_t]              = "Mali-T",
	[cpuinfo_android_gpu_series_arm_mali_g]              = "Mali-G",
	[cpuinfo_android_gpu_series_broadcom_videocore]      = "VideoCore ",
	[cpuinfo_android_gpu_series_intel_gen]               = "Gen ",
	[cpuinfo_android_gpu_series_intel_hd_graphics]       = "HD Graphics ",
	[cpuinfo_android_gpu_series_nvidia_tegra]            = "Tegra ",
	[cpuinfo_android_gpu_series_nvidia_tegra_k]          = "Tegra K",
	[cpuinfo_android_gpu_series_nvidia_tegra_x]          = "Tegra X",
	[cpuinfo_android_gpu_series_powervr_sgx]             = "SGX",
	[cpuinfo_android_gpu_series_powervr_rogue_g]         = "Rogue G",
	[cpuinfo_android_gpu_series_powervr_rogue_ge]        = "Rogue GE",
	[cpuinfo_android_gpu_series_powervr_rogue_gm]        = "Rogue GM",
	[cpuinfo_android_gpu_series_powervr_rogue_gt]        = "Rogue GT",
	[cpuinfo_android_gpu_series_powervr_rogue_gx]        = "Rogue GX",
	[cpuinfo_android_gpu_series_qualcomm_adreno]         = "Adreno ",
	[cpuinfo_android_gpu_series_vivante_gc]              = "GC",
};

/* Convert GPU name represented by cpuinfo_android_gpu structure to a string representation */
void cpuinfo_android_gpu_to_string(
	const struct cpuinfo_android_gpu gpu[restrict static 1],
	char name[restrict static CPUINFO_GPU_NAME_MAX])
{
	enum cpuinfo_android_gpu_vendor vendor = gpu->vendor;
	if (vendor >= cpuinfo_android_gpu_vendor_max) {
		vendor = cpuinfo_android_gpu_vendor_unknown;
	}
	enum cpuinfo_android_gpu_series series = gpu->series;
	if (series >= cpuinfo_android_gpu_series_max) {
		series = cpuinfo_android_gpu_series_unknown;
	}
	const char* vendor_string = gpu_vendor_string[vendor];
	const char* series_string = gpu_series_string[series];
	const uint32_t model = gpu->model;
	if (model == 0) {
		if (series == cpuinfo_android_gpu_series_unknown) {
			strncpy(name, vendor_string, CPUINFO_GPU_NAME_MAX);
		} else {
			snprintf(name, CPUINFO_GPU_NAME_MAX,
				"%s %s", vendor_string, series_string);
		}
	} else {
		snprintf(name, CPUINFO_GPU_NAME_MAX,
			"%s %s%"PRIu32"%.*s",
			vendor_string, series_string, model,
			(int) strnlen(gpu->suffix, CPUINFO_ANDROID_GPU_SUFFIX_MAX), gpu->suffix);
	}
}

/*
 * Decodes GPU name from OpenGL (ES) GL_RENDERER string.
 *
 * @param[in] renderer - the GL_RENDERER string.
 *
 * @returns Decoded GPU name. If GPU could not be decoded, the resulting structure would use `unknown` vendor
 *          and series identifiers.
 */
struct cpuinfo_android_gpu cpuinfo_android_decode_gpu(const char* renderer) {
	struct cpuinfo_android_gpu gpu;
	memset(&gpu, 0, sizeof(gpu));

	if (renderer != NULL) {
		switch (renderer[0]) {
			case 'A':
				if (sscanf(renderer, "Adreno (TM) %"SCNu32, &gpu.model) == 1 && gpu.model != 0) {
					gpu.series = cpuinfo_android_gpu_series_qualcomm_adreno;
				}
				break;
			case 'G':
				if (sscanf(renderer, "GC%"SCNu32" core", &gpu.model) == 1 && gpu.model != 0) {
					gpu.series = cpuinfo_android_gpu_series_vivante_gc;
				}
				break;
			case 'I':
				if (strcmp(renderer, "Immersion.16") == 0) {
					/* Vivante GC4000 in early HiSilicon chipsets */
					gpu.series = cpuinfo_android_gpu_series_vivante_gc;
					gpu.model = 4000;
				} else if (strcmp(renderer, "Intel(R) HD Graphics for BayTrail") == 0) {
					gpu.series = cpuinfo_android_gpu_series_intel_gen;
					gpu.model = 7;
				} else if (strcmp(renderer, "Intel(R) HD Graphics for Atom(TM) x5/x7") == 0) {
					gpu.series = cpuinfo_android_gpu_series_intel_gen;
					gpu.model = 8;
				}
				break;
			case 'M':
				if (sscanf(renderer, "Mali-%"SCNu32, &gpu.model) == 1 && gpu.model != 0) {
					gpu.series = cpuinfo_android_gpu_series_arm_mali;
				} else if (sscanf(renderer, "Mali-T%"SCNu32, &gpu.model) == 1 && gpu.model != 0) {
					gpu.series = cpuinfo_android_gpu_series_arm_mali_t;
					/* Common bug: Mali-T760 reported as Mali-T764 */
					if (gpu.model == 764) {
						gpu.model = 760;
					}
				} else if (sscanf(renderer, "Mali-G%"SCNu32, &gpu.model) == 1 && gpu.model != 0) {
					gpu.series = cpuinfo_android_gpu_series_arm_mali_g;
				} else if (sscanf(renderer, "Mesa DRI Intel(R) HD Graphics %"SCNu32, &gpu.model) == 1 && gpu.model != 0) {
					gpu.series = cpuinfo_android_gpu_series_intel_hd_graphics;
				} else if (strcmp(renderer, "Mesa DRI Intel(R) Sandybridge Mobile x86/MMX/SSE2") == 0) {
					gpu.series = cpuinfo_android_gpu_series_intel_gen;
					gpu.model = 6;
				}
				break;
			case 'N':
				if (strcmp(renderer, "NVIDIA Tegra 3") == 0) {
					gpu.series = cpuinfo_android_gpu_series_nvidia_tegra;
					gpu.model = 3;
				} else if (strcmp(renderer, "NVIDIA Tegra") == 0) {
					gpu.series = cpuinfo_android_gpu_series_nvidia_tegra;
					gpu.model = 0;
				}
				break;
			case 'P':
				if (strcmp(renderer, "PXA1928 GPU") == 0) {
					/* Vivante GC5000 in PXA1928 chipset */
					gpu.series = cpuinfo_android_gpu_series_vivante_gc;
					gpu.model = 5000;
				} else if (sscanf(renderer, "PowerVR SGX %"SCNu32, &gpu.model) == 1 && gpu.model != 0) {
					gpu.series = cpuinfo_android_gpu_series_powervr_sgx;
				} else if (sscanf(renderer, "PowerVR Rogue G%"SCNu32, &gpu.model) == 1 && gpu.model != 0) {
					gpu.series = cpuinfo_android_gpu_series_powervr_rogue_g;
				} else if (sscanf(renderer, "PowerVR Rogue GE%"SCNu32, &gpu.model) == 1 && gpu.model != 0) {
					gpu.series = cpuinfo_android_gpu_series_powervr_rogue_ge;
				} else if (sscanf(renderer, "PowerVR Rogue GM%"SCNu32, &gpu.model) == 1 && gpu.model != 0) {
					gpu.series = cpuinfo_android_gpu_series_powervr_rogue_gm;
				} else if (sscanf(renderer, "PowerVR Rogue GT%"SCNu32, &gpu.model) == 1 && gpu.model != 0) {
					gpu.series = cpuinfo_android_gpu_series_powervr_rogue_gt;
				} else if (sscanf(renderer, "PowerVR Rogue GX%"SCNu32, &gpu.model) == 1 && gpu.model != 0) {
					gpu.series = cpuinfo_android_gpu_series_powervr_rogue_gx;
				} else if (strcmp(renderer, "PowerVR Rogue Han") == 0) {
					gpu.series = cpuinfo_android_gpu_series_powervr_rogue_g;
					gpu.model = 6200;
				} else if (strcmp(renderer, "PowerVR Rogue Hood") == 0) {
					gpu.series = cpuinfo_android_gpu_series_powervr_rogue_g;
					gpu.model = 6430;
				} else if (strcmp(renderer, "PowerVR Rogue Marlowe") == 0) {
					gpu.series = cpuinfo_android_gpu_series_powervr_rogue_gt;
					gpu.model = 7400;
					gpu.suffix[0] = '+';
				}
				break;
			case 'S':
				if (strcmp(renderer, "Sapphire 650") == 0) {
					/* ARM Mali-T720 in some MT8163 chipsets */
					gpu.series = cpuinfo_android_gpu_series_arm_mali_t;
					gpu.model = 720;
				}
				break;
			case 'V':
				if (strcmp(renderer, "VideoCore IV HW") == 0) {
					gpu.series = cpuinfo_android_gpu_series_broadcom_videocore;
					gpu.model = 4;
				} else if (sscanf(renderer, "Vivante GC%"SCNu32"%3s", &gpu.model, gpu.suffix) == 2 && gpu.model != 0) {
					gpu.series = cpuinfo_android_gpu_series_vivante_gc;
				}
				break;
		}
	}
	gpu.vendor = gpu_series_vendor[gpu.series];

	return gpu;
}