Skip to content
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

Implement WGL #64

Merged
merged 7 commits into from Oct 3, 2016
Merged

Implement WGL #64

merged 7 commits into from Oct 3, 2016

Conversation

@MortimerGoro
Copy link
Collaborator

MortimerGoro commented Sep 19, 2016

WGL implementation, now the servo webgl triangle demo runs on windows ;)

Copy link
Member

emilio left a comment

Super exciting to see this!

I need to run and I still haven't made it to the end. A lot of formatting nits and a few questions, but I still need to reach to the core of this PR, I'll try to do it over the rest of this week.

Thanks!

static ref GL_LIB: Option<HMODULEWrapper> = {
let p = unsafe{kernel32::LoadLibraryA(b"opengl32.dll\0".as_ptr() as *const _)};
if p.is_null() {
debug!("opengl32.dll not found!");

This comment has been minimized.

@emilio

emilio Sep 19, 2016

Member

nit: error! here will make it appear on the console, and seems more likely what we want.


lazy_static! {
static ref GL_LIB: Option<HMODULEWrapper> = {
let p = unsafe{kernel32::LoadLibraryA(b"opengl32.dll\0".as_ptr() as *const _)};

This comment has been minimized.

@emilio

emilio Sep 19, 2016

Member

nit: unsafe {, and as *const _) };.


pub struct NativeGLContext {
pub render_ctx: winapi::HGLRC,
pub device_ctx:winapi::HDC, //

This comment has been minimized.

@emilio

emilio Sep 19, 2016

Member

nit: space after the colon. Also, either do comment, or remove the two slashes.

Please make the members private, since the intention is making NativeGLContext cross-platform. Feel free to add accessor methods if needed.

}
}

pub struct NativeGLContextHandle(pub winapi::HGLRC, pub winapi::HDC);

This comment has been minimized.

@emilio

emilio Sep 19, 2016

Member

Same here regarding pub.

let p = wgl::GetProcAddress(addr) as *const _;
if !p.is_null() { return p; }
match *GL_LIB {
Some(ref lib) => kernel32::GetProcAddress(lib.0, addr) as *const _,

This comment has been minimized.

@emilio

emilio Sep 19, 2016

Member

hmm... I'm worried we can end up mixing symbols from taken from GL_LIB and from wgl. May it be a problem?

If it is, please only call wgl::GetProcAddress when it's None, if it's not, please write a comment saying why :)

This comment has been minimized.

@MortimerGoro

MortimerGoro Sep 20, 2016

Author Collaborator

It seems strange but we have to load and mix symbols from both because wglGetProcAddress​ doesn't return function pointers for some legacy functions that are exported by the opengl32.dll itself (old methods coming from OpenGL 1.1). I'll add some comments to the code to explain this.

}

fn create_shared(with: Option<&Self::Handle>) -> Result<NativeGLContext, &'static str> {
match unsafe{super::utils::create_offscreen(with, &WGLAttributes::default())}{

This comment has been minimized.

@emilio

emilio Sep 19, 2016

Member

nit: spaces between braces, just as before.

None => ptr::null_mut()
}
}

This comment has been minimized.

@emilio

emilio Sep 19, 2016

Member

nit: extra newline

}

fn current_handle() -> Option<Self::Handle> {
let handle = unsafe{ wgl::GetCurrentContext()};

This comment has been minimized.

@emilio

emilio Sep 19, 2016

Member

nit: spacing in braces, here and in the rest of the file.

device_ctx: handle.1,
weak: true
})
}

This comment has been minimized.

@emilio

emilio Sep 19, 2016

Member

nit: rust style is } else {.

Ok(())
}
else {
Err("gwl::MakeCurrent (on unbind)")

This comment has been minimized.

@emilio

emilio Sep 19, 2016

Member

We definitely shouldn't return an error if the current context was already unbound, the error condition should be wgl::MakeCurrent failing.

@emilio emilio closed this Sep 19, 2016
@emilio emilio reopened this Sep 19, 2016
@emilio
Copy link
Member

emilio commented Sep 19, 2016

(Sorry, misclick)

Copy link
Member

emilio left a comment

I need a bit more study still, but this looks great! Let me know if I can help somehow :)

fn current_handle() -> Option<Self::Handle> {
let handle = unsafe { wgl::GetCurrentContext() };
if !handle.is_null() {
let hdc = unsafe { wgl::GetCurrentDC() };

This comment has been minimized.

@emilio

emilio Sep 20, 2016

Member

Should we assert! here that hdc is not null (or return an error)?

if !share.is_null() {
if wgl::ShareLists(share as *const c_void, ctx) == 0 {
return Err(format!("wglShareLists failed: {}",
format!("{}", io::Error::last_os_error())));

This comment has been minimized.

@emilio

emilio Sep 20, 2016

Member

nit: this second format! (here and above) shouldn't be needed.

}
};

return Ok((ctx as winapi::HGLRC, hdc));

This comment has been minimized.

@emilio

emilio Sep 20, 2016

Member

nit: no need the return keyword at the end of the function, you can avoid the semicolon at the end of the line.

}

// creates a full context: attempts to use optional ext WGL functions
unsafe fn create_full_context(settings: &WGLAttributes,

This comment has been minimized.

@emilio

emilio Sep 20, 2016

Member

This seems sensible enough, though, I'll need to study a bit more since I'm not confident enough with the windows API. Thanks for pointing to glutin.

Also, can you add proper attribution to the glutin code?

This comment has been minimized.

@MortimerGoro

MortimerGoro Sep 21, 2016

Author Collaborator

I have added more attribution to glutin code and link to their repo in the last commit. Maybe you could create a licence/author files in this repo and we can add more attribution there

@MortimerGoro MortimerGoro force-pushed the MortimerGoro:wgl branch from 3a6ef18 to f80277a Sep 20, 2016
@emilio
emilio approved these changes Sep 26, 2016
Copy link
Member

emilio left a comment

The code looks reasonable, I can't test it, but I'm happy with it. Please rebase, do a squash and then I'll merge it.

If you find a way to run the tests this using AppVeyor or similar, that'd be awesome :-)

fn unbind(&self) -> Result<(), &'static str> {
unsafe {
if self.is_current() && wgl::MakeCurrent(ptr::null_mut(), ptr::null_mut()) == 0 {
Err("gwl::MakeCurrent (on unbind)")

This comment has been minimized.

@emilio

emilio Sep 26, 2016

Member

nit: wgl instead of gwl.


// Disable or enable vsync
if extensions.split(' ').find(|&i| i == "WGL_EXT_swap_control").is_some() {
let _guard = try!(CurrentContextGuard::make_current(hdc, ctx as winapi::HGLRC));

This comment has been minimized.

@emilio

emilio Sep 26, 2016

Member

Are you sure you need the CurrentContextGuard here? It seems to me we're going to bind the context right away after this, so we can rather bind it directly.

}

unsafe fn create_hidden_window() -> Result<winapi::HWND, &'static str> {

This comment has been minimized.

@emilio

emilio Sep 26, 2016

Member

nit: Remove this extra line.

…ing gl symbols after a context creation: wglGetProcAddress only works in the presence of a valid GL context, so we use a dummy ctx when the caller calls wglGetProcAddress without a valid GL context bound
@MortimerGoro MortimerGoro force-pushed the MortimerGoro:wgl branch from fac156e to 46fda29 Sep 27, 2016
Copy link
Member

emilio left a comment

Sorry I hadn't look more carefully the error paths, I've left a few comments on that to prevent leaks.

let addr = CString::new(addr.as_bytes()).unwrap();
let addr = addr.as_ptr();
unsafe {

This comment has been minimized.

@emilio

emilio Sep 27, 2016

Member

nit: extra line.

None => ptr::null_mut(),
}
}

This comment has been minimized.

@emilio

emilio Sep 27, 2016

Member

nit: Here too

let mut placement: winapi::WINDOWPLACEMENT = mem::zeroed();
placement.length = mem::size_of::<winapi::WINDOWPLACEMENT>() as winapi::UINT;
if user32::GetWindowPlacement(window, &mut placement) == 0 {
panic!();

This comment has been minimized.

@emilio

emilio Sep 27, 2016

Member

please panic with a descriptive message, or return an error.


let hdc = user32::GetDC(win);
if hdc.is_null() {
let err = Err(format!("GetDC function failed: {}", io::Error::last_os_error()));

This comment has been minimized.

@emilio

emilio Sep 27, 2016

Member

nit: return Err(..). Also, it seems you need to clean up the window you just created.

io::Error::last_os_error()));
}

let hdc = user32::GetDC(win);

This comment has been minimized.

@emilio

emilio Sep 27, 2016

Member

I assume hdc doesn't need any cleanup, am I right?

.map_err(|_| "Pixel format not available".to_owned()))
} else {
try!(choose_native_pixel_format(hdc, &settings.pixel_format)
.map_err(|_| "Pixel format not available".to_owned()))

This comment has been minimized.

@emilio

emilio Sep 27, 2016

Member

Would be nice using two different errors here.

}

match reqs.multisampling {
Some(0) => (),

This comment has been minimized.

@emilio

emilio Sep 27, 2016

Member

nit: Some(0) | None => (), instead of two braces.


// querying back the capabilities of what windows told us
let mut output: winapi::PIXELFORMATDESCRIPTOR = mem::zeroed();
if gdi32::DescribePixelFormat(hdc,

This comment has been minimized.

@emilio

emilio Sep 27, 2016

Member

does pf_id need cleanup?

This comment has been minimized.

@MortimerGoro

MortimerGoro Sep 28, 2016

Author Collaborator

No, its just a pixel format index and doesn't require a release call

// Attributes to use when creating an OpenGL context.
#[derive(Clone, Debug)]
pub struct WGLAttributes {
//

This comment has been minimized.

@emilio

emilio Sep 27, 2016

Member

nit: Empty comment, please remove.

}

if !share.is_null() {
if wgl::ShareLists(share as *const c_void, ctx) == 0 {

This comment has been minimized.

@emilio

emilio Sep 27, 2016

Member

You need to clean up the context if this fails.

@MortimerGoro
Copy link
Collaborator Author

MortimerGoro commented Sep 28, 2016

I have improved WGL & winapi disposal in error paths using a scoped struct. Also got rid of CurrentContextGuard code.

@MortimerGoro MortimerGoro force-pushed the MortimerGoro:wgl branch from dc5868f to 35e3534 Sep 28, 2016
});

// Unbind the current context so WGLScopedContext can release resources properly
// wgl::DeleteContex must be called with unbound contexts

This comment has been minimized.

@emilio

emilio Oct 2, 2016

Member

nit: DeleteContext


let result = create_full_context(settings, &extra, &extensions, ctx.device_ctx, shared_with);
if result.is_ok() {
ctx.dispose = false; // Everything is ok, don't dispose the scoped ctx

This comment has been minimized.

@emilio

emilio Oct 2, 2016

Member

probably something like removing the dispose flag, and use mem::forget is better here? It's probably fine anyway.

This comment has been minimized.

@MortimerGoro

MortimerGoro Oct 3, 2016

Author Collaborator

I like the mem::forget approach, it seems more rusty

@@ -54,10 +54,13 @@ impl Drop for NativeGLContext {
fn drop(&mut self) {
unsafe {
if !self.weak {
self.unbind().unwrap(); //wglDeleteContext requires unbind

This comment has been minimized.

@emilio

emilio Oct 2, 2016

Member

Does this mean that the context to be deleted needs to be unbound? Or that there must be no current context.

I guess this is the first one, but please be clearer in this regard in the comment. Also, space after //.

This comment has been minimized.

@MortimerGoro

MortimerGoro Oct 3, 2016

Author Collaborator

Improved comments

wgl::DeleteContext(self.render_ctx as *const _);
let window = user32::WindowFromDC(self.device_ctx);
user32::ReleaseDC(window, self.device_ctx);
user32::DestroyWindow(window);
if !window.is_null() {

This comment has been minimized.

@emilio

emilio Oct 2, 2016

Member

what has suddenly making window nullable? If it happened before and is something you've fixed, I guess that's fine.

But if it's because we can create multiple contexts associated with the same device context, and then have the window deleted, that can mean multiple things if I'm correct:

  • The context doesn't require the window to stay alive, in which case we can delete it earlier.
  • The context does require the window to stay alive, in which case this is wrong.
  • The context does require the window to stay alive at least until we do sharing? That doesn't make sense to me but could be it.

Can you tell me which one is the relevant one?

This comment has been minimized.

@MortimerGoro

MortimerGoro Oct 3, 2016

Author Collaborator

We are not creating multiple contexts associated with the same HDC. It was just a extra safety check because null is a possible return value of WindowFromDC. It shouldn't happen in our code, but it seems safer to check for null.

This comment has been minimized.

@emilio

emilio Oct 3, 2016

Member

Can we instead assert that it's not null, and handle it only if under some circumstances the assertion fails?

This comment has been minimized.

@MortimerGoro

MortimerGoro Oct 3, 2016

Author Collaborator

Done

@MortimerGoro MortimerGoro force-pushed the MortimerGoro:wgl branch from 35e3534 to 044a2a0 Oct 3, 2016
@MortimerGoro MortimerGoro force-pushed the MortimerGoro:wgl branch from 044a2a0 to 0876fc3 Oct 3, 2016
@emilio
emilio approved these changes Oct 3, 2016
Copy link
Member

emilio left a comment

Ok, let's do it. I don't think I can say too much right now with my limited wgl/winapi experience, and this has already stayed here for really long.

Sorry it took so long @MortimerGoro! Hopefully I wasn't too nitpicky :)

Thanks for this work!

If you look into how to test this (with AppVeyor, for example), so it doesn't regress, it'd be really nice :)

@emilio emilio merged commit 0a4c86a into servo:master Oct 3, 2016
1 check failed
1 check failed
continuous-integration/travis-ci/pr The Travis CI build failed
Details
@MortimerGoro MortimerGoro mentioned this pull request Oct 19, 2016
3 of 5 tasks complete
bors-servo added a commit to servo/servo that referenced this pull request Oct 21, 2016
WebGL support on Windows

<!-- Please describe your changes on the following line: -->
This is the final step to provide WebGL support on Windows ;)

Some Related PRs already merged in webrender and offscreen-gl-context:

servo/surfman#64
servo/webrender#432

---
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [ ] These changes fix #__ (github issue number if applicable).

- [X] There are tests for these changes OR
- [ ] These changes do not require tests because _____

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/13840)
<!-- Reviewable:end -->
moz-v2v-gh pushed a commit to mozilla/gecko-dev that referenced this pull request Feb 4, 2017
…render_dispatcher); r=emilio

<!-- Please describe your changes on the following line: -->
This is the final step to provide WebGL support on Windows ;)

Some Related PRs already merged in webrender and offscreen-gl-context:

servo/surfman#64
servo/webrender#432

---
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [ ] These changes fix #__ (github issue number if applicable).

- [X] There are tests for these changes OR
- [ ] These changes do not require tests because _____

Source-Repo: https://github.com/servo/servo
Source-Revision: 4216224f9cc7f3430db2b59f4d77061824ba7a1e
gecko-dev-updater pushed a commit to marco-c/gecko-dev-comments-removed that referenced this pull request Oct 1, 2019
…render_dispatcher); r=emilio

<!-- Please describe your changes on the following line: -->
This is the final step to provide WebGL support on Windows ;)

Some Related PRs already merged in webrender and offscreen-gl-context:

servo/surfman#64
servo/webrender#432

---
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [ ] These changes fix #__ (github issue number if applicable).

- [X] There are tests for these changes OR
- [ ] These changes do not require tests because _____

Source-Repo: https://github.com/servo/servo
Source-Revision: 4216224f9cc7f3430db2b59f4d77061824ba7a1e

UltraBlame original commit: c57538159933d9eb1840437dfa9c9860220dd805
gecko-dev-updater pushed a commit to marco-c/gecko-dev-wordified-and-comments-removed that referenced this pull request Oct 1, 2019
…render_dispatcher); r=emilio

<!-- Please describe your changes on the following line: -->
This is the final step to provide WebGL support on Windows ;)

Some Related PRs already merged in webrender and offscreen-gl-context:

servo/surfman#64
servo/webrender#432

---
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [ ] These changes fix #__ (github issue number if applicable).

- [X] There are tests for these changes OR
- [ ] These changes do not require tests because _____

Source-Repo: https://github.com/servo/servo
Source-Revision: 4216224f9cc7f3430db2b59f4d77061824ba7a1e

UltraBlame original commit: c57538159933d9eb1840437dfa9c9860220dd805
gecko-dev-updater pushed a commit to marco-c/gecko-dev-wordified that referenced this pull request Oct 1, 2019
…render_dispatcher); r=emilio

<!-- Please describe your changes on the following line: -->
This is the final step to provide WebGL support on Windows ;)

Some Related PRs already merged in webrender and offscreen-gl-context:

servo/surfman#64
servo/webrender#432

---
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [ ] These changes fix #__ (github issue number if applicable).

- [X] There are tests for these changes OR
- [ ] These changes do not require tests because _____

Source-Repo: https://github.com/servo/servo
Source-Revision: 4216224f9cc7f3430db2b59f4d77061824ba7a1e

UltraBlame original commit: c57538159933d9eb1840437dfa9c9860220dd805
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

None yet

2 participants
You can’t perform that action at this time.