Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(51)

Side by Side Diff: chrome/gpu/gpu_info_collector_linux.cc

Issue 5861007: Collect GPU information (vendor id and device id) in Linux.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 10 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2006-2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/gpu/gpu_info_collector.h" 5 #include "chrome/gpu/gpu_info_collector.h"
6 6
7 #include <dlfcn.h>
8 #include <vector>
9
10 #include "app/gfx/gl/gl_bindings.h"
11 #include "app/gfx/gl/gl_context.h"
12 #include "app/gfx/gl/gl_implementation.h"
13 #include "base/logging.h"
14 #include "base/scoped_ptr.h"
15 #include "base/string_util.h"
16
17 namespace {
18
19 // PciDevice and PciAccess are defined to access libpci functions. Their
20 // members match the corresponding structures defined by libpci in size up to
21 // fields we may access. For those members we don't use, their names are
22 // defined as "fieldX", etc., or, left out if they are declared after the
23 // members we care about in libpci.
24
25 struct PciDevice {
26 PciDevice* next;
27
28 uint16 field0;
29 uint8 field1;
30 uint8 field2;
31 uint8 field3;
32 int field4;
33
34 uint16 vendor_id;
35 uint16 device_id;
36 uint16 device_class;
37 };
38
39 struct PciAccess {
40 unsigned int field0;
41 int field1;
42 int field2;
43 char* field3;
44 int field4;
45 int field5;
46 unsigned int field6;
47 int field7;
48
49 void (*function0)();
50 void (*function1)();
51 void (*function2)();
52
53 PciDevice* device_list;
54 };
55
56 // Define function types.
57 typedef PciAccess* (*FT_pci_alloc)();
58 typedef void (*FT_pci_init)(PciAccess*);
59 typedef void (*FT_pci_cleanup)(PciAccess*);
60 typedef void (*FT_pci_scan_bus)(PciAccess*);
61 typedef void (*FT_pci_scan_bus)(PciAccess*);
62 typedef int (*FT_pci_fill_info)(PciDevice*, int);
63 typedef char* (*FT_pci_lookup_name)(PciAccess*, char*, int, int, ...);
64
65 // This includes dynamically linked library handle and functions pointers from
66 // libpci.
67 struct PciInterface {
68 void* lib_handle;
69
70 FT_pci_alloc pci_alloc;
71 FT_pci_init pci_init;
72 FT_pci_cleanup pci_cleanup;
73 FT_pci_scan_bus pci_scan_bus;
74 FT_pci_fill_info pci_fill_info;
75 FT_pci_lookup_name pci_lookup_name;
76 };
77
78 // This dynamically opens libpci and get function pointers we need. Return
79 // NULL if library fails to open or any functions can not be located.
80 // Returned interface (if not NULL) should be deleted in FinalizeLibPci.
81 PciInterface* InitializeLibPci(const char* lib_name) {
82 void* handle = dlopen(lib_name, RTLD_LAZY);
83 if (handle == NULL) {
84 LOG(ERROR) << "Fail to dlopen libpci";
85 return NULL;
86 }
87 PciInterface* interface = new struct PciInterface;
88 interface->lib_handle = handle;
89 interface->pci_alloc = reinterpret_cast<FT_pci_alloc>(
90 dlsym(handle, "pci_alloc"));
91 interface->pci_init = reinterpret_cast<FT_pci_init>(
92 dlsym(handle, "pci_init"));
93 interface->pci_cleanup = reinterpret_cast<FT_pci_cleanup>(
94 dlsym(handle, "pci_cleanup"));
95 interface->pci_scan_bus = reinterpret_cast<FT_pci_scan_bus>(
96 dlsym(handle, "pci_scan_bus"));
97 interface->pci_fill_info = reinterpret_cast<FT_pci_fill_info>(
98 dlsym(handle, "pci_fill_info"));
99 interface->pci_lookup_name = reinterpret_cast<FT_pci_lookup_name>(
100 dlsym(handle, "pci_lookup_name"));
101 if (interface->pci_alloc == NULL ||
102 interface->pci_init == NULL ||
103 interface->pci_cleanup == NULL ||
104 interface->pci_scan_bus == NULL ||
105 interface->pci_fill_info == NULL ||
106 interface->pci_lookup_name == NULL) {
107 LOG(ERROR) << "Missing required function(s) from libpci";
108 dlclose(handle);
109 delete interface;
110 return NULL;
111 }
112 return interface;
113 }
114
115 // This close the dynamically opened libpci and delete the interface.
116 void FinalizeLibPci(PciInterface*& interface) {
117 DCHECK(interface != NULL && interface->lib_handle != NULL);
118 dlclose(interface->lib_handle);
119 delete interface;
120 interface = NULL;
121 }
122
123 // This creates an offscreen GL context fir gl queries. Returned GLContext
Ken Russell (switch to Gerrit) 2010/12/18 03:03:27 fir -> for
Zhenyao Mo 2010/12/20 17:36:47 Done.
124 // should be deleted in FinalizeGLContext.
125 gfx::GLContext* InitializeGLContext() {
126 if (!gfx::GLContext::InitializeOneOff()) {
127 LOG(ERROR) << "gfx::GLContext::InitializeOneOff() failed";
128 return NULL;
129 }
130 gfx::GLContext* context = gfx::GLContext::CreateOffscreenGLContext(NULL);
131 if (context == NULL) {
132 LOG(ERROR) << "gfx::GLContext::CreateOffscreenGLContext(NULL) failed";
133 return NULL;
134 }
135 if (!context->MakeCurrent()) {
136 LOG(ERROR) << "gfx::GLContext::MakeCurrent() failed";
137 context->Destroy();
138 delete context;
139 return NULL;
140 }
141 return context;
142 }
143
144 // This destroy and delete the GL context.
145 void FinalizeGLContext(gfx::GLContext*& context) {
146 DCHECK(context != NULL);
147 context->Destroy();
148 delete context;
149 context = NULL;
150 }
151
152 } // namespace anonymous
153
7 namespace gpu_info_collector { 154 namespace gpu_info_collector {
8 155
9 bool CollectGraphicsInfo(GPUInfo* gpu_info) { 156 bool CollectGraphicsInfo(GPUInfo* gpu_info) {
10 // TODO(rlp): complete this function 157 gfx::GLContext* context = InitializeGLContext();
11 // TODO(apatrick): this illustrates how can_lose_context will be implemented 158 if (context == NULL)
12 // on this platform in the future. 159 return false;
13 // bool can_lose_context = 160
14 // gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2; 161 // TODO(zmo): collect driver version, pixel shader version, vertex shader
15 162 // version, and gl version.
16 gpu_info->SetProgress(GPUInfo::kComplete); 163 std::wstring driver_version = L"";
17 164 uint32 pixel_shader_version = 0;
18 return true; 165 uint32 vertex_shader_version = 0;
166 uint32 gl_version = 0;
167 bool can_lose_context =
168 (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2);
169
170 // TODO(zmo): be more flexible about library name.
171 PciInterface* interface = InitializeLibPci("libpci.so.3");
172 if (interface == NULL) {
173 FinalizeGLContext(context);
174 return false;
175 }
176
177 PciAccess* access = (interface->pci_alloc)();
178 DCHECK(access != NULL);
179 (interface->pci_init)(access);
180 (interface->pci_scan_bus)(access);
181 std::vector<PciDevice*> gpu_list;
182 PciDevice* gpu_active = NULL;
183 for (PciDevice* device = access->device_list;
184 device != NULL; device = device->next) {
185 (interface->pci_fill_info)(device, 33); // Fill the IDs and class fields.
186 if (device->device_class == 0x0300) { // Device class is DISPLAY_VGA.
187 gpu_list.push_back(device);
188 }
189 }
190 if (gpu_list.size() == 1) {
191 gpu_active = gpu_list[0];
192 } else {
193 // If more than one graphics card are identified, find the one that matches
194 // gl VENDOR and RENDERER info.
Ken Russell (switch to Gerrit) 2010/12/18 03:03:27 Out of curiosity did you test this code path on a
Zhenyao Mo 2010/12/20 17:36:47 I've tested this path by commenting out the condit
195 std::string gl_vendor_string =
196 reinterpret_cast<const char*>(glGetString(GL_VENDOR));
197 std::string gl_renderer_string =
198 reinterpret_cast<const char*>(glGetString(GL_RENDERER));
199 const int buffer_size = 255;
200 scoped_array<char> buffer(new char[buffer_size]);
Ken Russell (switch to Gerrit) 2010/12/18 03:03:27 The contents of this array are uninitialized at th
Zhenyao Mo 2010/12/20 17:36:47 I looked into pci_lookup_name source code. It ret
201 std::vector<PciDevice*> candidates;
202 for (size_t i = 0; i < gpu_list.size(); ++i) {
203 PciDevice* gpu = gpu_list[i];
204 (interface->pci_lookup_name)(
205 access, buffer.get(), buffer_size, 1, gpu->vendor_id);
Ken Russell (switch to Gerrit) 2010/12/18 03:03:27 Is this guaranteed to succeed? If not, how does it
Zhenyao Mo 2010/12/20 17:36:47 See comment above. On 2010/12/18 03:03:27, kbr wr
206 std::string vendor_string = buffer.get();
Ken Russell (switch to Gerrit) 2010/12/18 03:03:27 Must ensure that we don't try to construct a std::
Zhenyao Mo 2010/12/20 17:36:47 See comment above. On 2010/12/18 03:03:27, kbr wr
207 if (!StartsWithASCII(gl_vendor_string, vendor_string, false))
Ken Russell (switch to Gerrit) 2010/12/18 03:03:27 I think it's good you're using a case-insensitive
Zhenyao Mo 2010/12/20 17:36:47 Done.
208 continue;
209 (interface->pci_lookup_name)(
210 access, buffer.get(), buffer_size, 2, gpu->vendor_id, gpu->device_id);
211 std::string device_string = buffer.get();
Ken Russell (switch to Gerrit) 2010/12/18 03:03:27 Same caveat about constructing a string out of pot
Zhenyao Mo 2010/12/20 17:36:47 See comment above. On 2010/12/18 03:03:27, kbr wr
212 size_t begin = device_string.find_first_of('[');
213 size_t end = device_string.find_last_of(']');
214 if (begin != std::string::npos && end != std::string::npos &&
215 begin < end) {
216 device_string = device_string.substr(begin + 1, end - begin - 1);
217 }
218 if (StartsWithASCII(gl_renderer_string, device_string, false)) {
Ken Russell (switch to Gerrit) 2010/12/18 03:03:27 Use case_sensitive here too.
Zhenyao Mo 2010/12/20 17:36:47 Done.
219 gpu_active = gpu;
220 break;
221 }
222 // If a device's vendor matches gl VENDOR string, we want to consider the
223 // possibility that libpci may not return the exact same name as gl
224 // RENDERER string.
225 candidates.push_back(gpu);
226 }
227 if (gpu_active == NULL && candidates.size() == 1)
228 gpu_active = candidates[0];
229 }
230 if (gpu_active != NULL) {
231 gpu_info->SetGraphicsInfo(gpu_active->vendor_id,
232 gpu_active->device_id,
233 driver_version,
234 pixel_shader_version,
235 vertex_shader_version,
236 gl_version,
237 can_lose_context);
238 gpu_info->SetProgress(GPUInfo::kComplete);
239 }
240 (interface->pci_cleanup)(access);
241 FinalizeLibPci(interface);
242 FinalizeGLContext(context);
243 return (gpu_active != NULL);
19 } 244 }
20 245
21 } // namespace gpu_info_collector 246 } // namespace gpu_info_collector
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698