8000 feat: Implementation of getGPUInfo API. by nitsakh · Pull Request #13486 · electron/electron · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

feat: Implementation of getGPUInfo API. #13486

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Sep 27, 2018
Merged

feat: Implementation of getGPUInfo API. #13486

merged 10 commits into from
Sep 27, 2018

Conversation

nitsakh
Copy link
Contributor
@nitsakh nitsakh commented Jun 28, 2018

This PR implements the app.getGPUInfo api to get the GPU details available on chrome://gpu.
This can be useful to clients for various purposes like working around bugs based on available details.

Chromium GPUInfo class provides an interface for an enumerator. Creating a custom enumerator and calling EnumerateFields on the GPUInfo class, will get us all the attributes in the class. Using this enumerator also saves us the maintenance burden when attributes are added/changed with newer versions of chromium.

I haven't updated the docs or added tests yet, will do that once I get some feedback on the API.

Checklist
  • PR description included and stakeholders cc'd
  • npm test passes
  • tests are changed or added
  • relevant documentation is changed or added
  • commit messages or PR title follow semantic commit guidelines

Notes: Implemented new getGPUInfo API to get details about the GPU.

@nitsakh nitsakh requested a review from a team June 28, 2018 19:31
@nitsakh
Copy link
Contributor Author
nitsakh commented Jun 28, 2018

This is the example response of the API.

{ auxAttributes:
   { amdSwitchable: true,
     canSupportThreadedTextureMailbox: false,
     directComposition: false,
     directRendering: true,
     driverDate: '',
     driverVendor: '',
     driverVersion: '',
     glExtensions: '',
     glRenderer: '',
     glResetNotificationStrategy: 0,
     glVendor: '',
     glVersion: '',
     glWsExtensions: '',
     glWsVendor: '',
     glWsVersion: '',
     inProcessGpu: false,
     initializationTime: 218,
     jpegDecodeAcceleratorSupported: false,
     maxMsaaSamples: '',
     optimus: false,
     passthroughCmdDecoder: false,
     pixelShaderVersion: '',
     sandboxed: false,
     softwareRendering: false,
     supportsOverlays: false,
     vertexShaderVersion: '',
     videoDecodeAcceleratorFlags: 0,
     videoDecodeAcceleratorSupportedProfile:
      { encrypted_only: false,
        maxResolutionHeight: 2160,
        maxResolutionWidth: 4096,
        minResolutionHeight: 16,
        minResolutionWidth: 16,
        profile: 3 },
     videoEncodeAcceleratorSupportedProfile:
      { maxFramerateDenominator: 1,
        maxFramerateNumerator: 30,
        maxResolutionHeight: 2160,
        maxResolutionWidth: 4096,
        profile: 3 } },
  gpuDevice:
   [ { active: true,
       deviceId: 26657,
       deviceString: '',
       vendorId: 4098,
       vendorString: '' },
     { active: false,
       deviceId: 3366,
       deviceString: '',
       vendorId: 32902,
       vendorString: '' } ],
  machineModelName: 'MacBookPro',
  machineModelVersion: '11.5' }

@nitsakh
Copy link
Contributor Author
nitsakh commented Jun 28, 2018

Also, I should change the code to omit attributes with empty strings. Done.

@felixrieseberg
Copy link
Member

You might want to take out the package_lock.json changes unless they were on purpose!

8000

@@ -1162,6 +1163,14 @@ v8::Local<v8::Value> App::GetGPUFeatureStatus(v8::Isolate* isolate) {
return mate::ConvertToV8(isolate, status ? *status : temp);
}

v8::Local<v8::Value> App::GetGPUInfo(v8::Isolate* isolate) {
const auto& gpu_info =
Copy link
Contributor
@miniak miniak Jun 29, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you may need to call content::GpuDataManagerImpl::GetInstance()->RequestCompleteGpuInfoIfNeeded() to make the information available

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Milan! I'll try that and will update the PR. 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That worked. Was able to fetch all the info with that.

@nitsakh nitsakh requested a review from a team July 3, 2018 18:37
@YurySolovyov
Copy link
Contributor

This API looks a bit awkward. How about making it

  1. Return Promise
  2. Parametrize the kind of info you want to get:
const info = await app.getGPUInfo('full');
// or
const info = await app.getGPUInfo('short');
// potentially use 'short' as default so above is the same as:
const info = await app.getGPUInfo();

zeke
zeke previously requested changes Jul 6, 2018
< 8000 span data-view-component="true"> Copy link
Contributor
@zeke zeke left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few typos, but otherwise the docs look good.

docs/api/app.md Outdated
@@ -904,6 +904,15 @@ Returns [`ProcessMetric[]`](structures/process-metric.md): Array of `ProcessMetr

Returns [`GPUFeatureStatus`](structures/gpu-feature-status.md) - The Graphics Feature Status from `chrome://gpu/`.

### `app.getGPUInfo([callback])`

Returns `Object` - GPU Information available in chromium's GPUInfo object. It's contains the version and driver information that's shown on `chrome://gpu` page.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo: It's contains

docs/api/app.md Outdated
* `callback` Function (optional)
* `gpuInfo` Object - List of all attributes and values available in [chromium's GPUInfo object](https://chromium.googlesource.com/chromium/src/gpu/+/master/config/gpu_info.cc).

Providing the optional callback will fetch the complete information available from the GPU process. In this case, the callback object will have all the available information, which can be more that what the returned object had.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Type: more that should be more than.

Can you also explain why the callback function will yield more results than the returned object?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @zeke! I'll update these with the other changes. 👍

@nitsakh
Copy link
Contributor Author
nitsakh commented Jul 9, 2018

Thanks @YurySolovyov . I like your idea. However, the main idea here was to get the short information synchronously, so that apps can immediately act upon it. It most likely would be used at startup, so getting the minimal information synchronously is better.

@YurySolovyov
Copy link
Contributor

I would argue that consistency is better. Besides, promises work well with async/await so that it can be used even at startup with almost the same ergonomics

8000

docs/api/app.md Outdated
@@ -904,6 +904,15 @@ Returns [`ProcessMetric[]`](structures/process-metric.md): Array of `ProcessMetr

Returns [`GPUFeatureStatus`](structures/gpu-feature-status.md) - The Graphics Feature Status from `chrome://gpu/`.

### `app.getGPUInfo([callback])`

Returns `Object` - GPU Information available in chromium's GPUInfo object. It's contains the version and driver information that's shown on `chrome://gpu` page.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Returning an object and accepting a callback 😕

Would it be better to callback with everything, it seems really weird for a single API to be both synchronous and asynchronous

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, it definitely is hacky. I'm leaning towards the promise way now. Will make changes and update the branch. Thanks @MarshallOfSound and @YurySolovyov !

docs/api/app.md Outdated
Returns `Object` - GPU Information available in chromium's GPUInfo object. It's contains the version and driver information that's shown on `chrome://gpu` page.

* `callback` Function (optional)
* `gpuInfo` Object - List of all attributes and values available in [chromium's GPUInfo object](https://chromium.googlesource.com/chromium/src/gpu/+/master/config/gpu_info.cc).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please use a link to a Chromium release tag, not to a master?
That file might get renamed or removed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I thought of doing that. We don't do that in other places in the docs though. Also, we should add another item on the release checklist to update the docs.

const activeDevice = gpuInfo.gpuDevice.find((device) => {
return device.active === true
})
expect(activeDevice).to.not.be.null()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Array#find() returns undefined if nothing is found.
Can you please check that activeDevice is an object instead of !== null?:

expect(activeDevice).to.be.an('object')

return device.active === true
})
expect(activeDevice).to.not.be.null()
expect(activeDevice.deviceId).to.be.a('number').not.lessThan(0)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it would be better to check for deviceId property existence first.
It will produce a failure message better than expected undefined to be a number.

expect(activeDevice).to.have.property('deviceId').that.is.a('number').not.lessThan(0)

docs/api/app.md Outdated
@@ -904,6 +904,14 @@ Returns [`ProcessMetric[]`](structures/process-metric.md): Array of `ProcessMetr

Returns [`GPUFeatureStatus`](structures/gpu-feature-status.md) - The Graphics Feature Status from `chrome://gpu/`.

### `app.getGPUInfo(info_type)`

* `info_type` String. Values can be either 'available' for currently available info or `complete` for complete info.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Docs are not consistent with tests: test use full/short and docs say complete/available
  2. Camel case info_type -> infoType or InfoType ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, still working on this PR. I have those changes made locally.

@nitsakh nitsakh changed the title feat: Implementation of getGPUInfo API. WIP:feat: Implementation of getGPUInfo API. Jul 12, 2018
@@ -1162,6 +1195,30 @@ v8::Local<v8::Value> App::GetGPUFeatureStatus(v8::Isolate* isolate) {
return mate::ConvertToV8(isolate, status ? *status : temp);
}

util::Promise* App::GetGPUInfo(const std::string& info_type) {
CHECK(!is_fetching_gpuinfo_);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is scary

Can't we just return gpinfo_promise_ instead here 😄

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good idea.

@@ -228,6 +232,10 @@ class App : public AtomBrowserClient::Delegate,

base::FilePath app_path_;

util::Promise* gpuinfo_promise_;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we explicitly initialize this to nullptr, if people do a truthy check on this in the future it wouldn't work without explicit initialization.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm doing that in the constructor.

@@ -228,6 +232,10 @@ class App : public AtomBrowserClient::Delegate,

base::FilePath app_path_;

util::Promise* gpuinfo_promise_;
bool has_complete_gpu_info_;
bool is_fetching_gpuinfo_;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A truthy check on gpuinfo_promise_ could replace this variable right?

Copy link
Contributor Author
@nitsakh nitsakh Jul 13, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not exactly. Also actually I'm still working on the changes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, if we return the same promise, then we don't need the variable.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please initialize the values here, we are using C++11 class member variable initialization:
#13030

miniak
miniak previously requested changes Jul 13, 2018
@@ -228,6 +232,10 @@ class App : public AtomBrowserClient::Delegate,

base::FilePath app_path_;

util::Promise* gpuinfo_promise_;
bool has_complete_gpu_info_;
bool is_fetching_gpuinfo_;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please initialize the values here, we are using C++11 class member variable initialization:
#13030

if (info_type == "complete") {
// In this case, we create an object on the heap and GPUInfoManager is
// responsible for deleting it
GPUInfoManager* info_mgr = new GPUInfoManager(isolate);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there something like enable_shared_from_this for chromium, so that I do not have to do this memory management dance?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The GPUInfoManager can be a base::Singleton<>, which takes ownership of the util::Promise. This also allows the class to be moved outside the api layer.

@nitsakh nitsakh changed the title WIP:feat: Implementation of getGPUInfo API. feat: Implementation of getGPUInfo API. Jul 13, 2018
return promise;
}
const auto gpu_data_manager = content::GpuDataManagerImpl::GetInstance();
if (!gpu_data_manager->GpuAccessAllowed(nullptr)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check can be merged with the previous one,

if (info_type != "..." || !gpu_data_manager->GpuAccessAllowed(nullptr))

@@ -1162,6 +1164,33 @@ v8::Local<v8::Value> App::GetGPUFeatureStatus(v8::Isolate* isolate) {
return mate::ConvertToV8(isolate, status ? *status : temp);
}

util::Promise* App::GetGPUInfo(v8::Isolate* isolate,
const std::string& info_type) {
if (info_type != "available" && info_type != "complete") {
Copy link
Member
@deepak1556 deepak1556 Jul 13, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you rename available to basic , the former seems too generic. Also the result from CollectBasicGraphicsInfo seems fixed, it would be best to list the data from it in the docs explicitly, that way users would have better idea to choose among the options.

if (NeedsCompleteGpuInfoCollection()) {
gpu_data_manager_->RequestCompleteGpuInfoIfNeeded();
} else {
content::BrowserThread::PostTask(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was the idea here to delay the call till next tick ? If so, use the thread task runner and post tasks with it.

if (info_type == "complete") {
// In this case, we create an object on the heap and GPUInfoManager is
// responsible for deleting it
GPUInfoManager* info_mgr = new GPUInfoManager(isolate);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The GPUInfoManager can be a base::Singleton<>, which takes ownership of the util::Promise. This also allows the class to be moved outside the api layer.

@nitsakh
Copy link
Contributor Author
nitsakh commented Jul 17, 2018

@zeke @miniak @deepak1556 @YurySolovyov Please let me know how you feel about this change now?

Copy link
Contributor
@YurySolovyov YurySolovyov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

API shape looks good to me. Haven't studied the implementation.

const auto& promise = new util::Promise(isolate);
if ((info_type != "basic" && info_type != "complete") ||
!gpu_data_manager->GpuAccessAllowed(nullptr)) {
promise->Reject();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we reject with a helpful error message here?

docs/api/app.md Outdated

For `infoType` equal to `basic`:
Promise is fulfilled with `Object` containing fewer attributes than when requested with `complete`. Here's an example of basic response:
```json
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change this to js to make it highlighted correctly

@codebytere
Copy link
Member

What's the current status of this PR?

Copy link
Member
@deepak1556 deepak1556 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, Thanks!

@MarshallOfSound MarshallOfSound dismissed stale reviews from zeke and miniak September 27, 2018 14:58

docs are looking good now

@MarshallOfSound MarshallOfSound merged commit 5c10872 into master Sep 27, 2018
@release-clerk
Copy link
release-clerk bot commented Sep 27, 2018

Release Notes Persisted

Implemented new getGPUInfo API to get details about the GPU.

@MarshallOfSound MarshallOfSound deleted the api-gpuinfo branch September 27, 2018 14:59
@MarshallOfSound MarshallOfSound added the semver/minor backwards-compatible functionality label Sep 27, 2018
codebytere pushed a commit that referenced this pull request Sep 27, 2018
* Implementation of getGPUInfo API.

* Clear promise set

* Changes to promise usage

* Minor fixes

* Fix linux build

* Update spec

* Fix lint (linter didn't run on windows locally)

* Test running single test for CI

* Update spec
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
semver/minor backwards-compatible functionality
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants
0