Join GitHub today
GitHub is home to over 50 million developers working together to host and review code, manage projects, and build software together.
Sign upImplement WGL #64
Implement WGL #64
Conversation
|
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.
This comment has been minimized.
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.
This comment has been minimized.
|
|
||
| pub struct NativeGLContext { | ||
| pub render_ctx: winapi::HGLRC, | ||
| pub device_ctx:winapi::HDC, // |
This comment has been minimized.
This comment has been minimized.
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.
This comment has been minimized.
| 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.
This comment has been minimized.
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.
This comment has been minimized.
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.
This comment has been minimized.
| None => ptr::null_mut() | ||
| } | ||
| } | ||
|
|
This comment has been minimized.
This comment has been minimized.
| } | ||
|
|
||
| fn current_handle() -> Option<Self::Handle> { | ||
| let handle = unsafe{ wgl::GetCurrentContext()}; |
This comment has been minimized.
This comment has been minimized.
| device_ctx: handle.1, | ||
| weak: true | ||
| }) | ||
| } |
This comment has been minimized.
This comment has been minimized.
| Ok(()) | ||
| } | ||
| else { | ||
| Err("gwl::MakeCurrent (on unbind)") |
This comment has been minimized.
This comment has been minimized.
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.
|
(Sorry, misclick) |
|
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.
This comment has been minimized.
| 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.
This comment has been minimized.
| } | ||
| }; | ||
|
|
||
| return Ok((ctx as winapi::HGLRC, hdc)); |
This comment has been minimized.
This comment has been minimized.
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.
This comment has been minimized.
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.
This comment has been minimized.
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
|
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.
This comment has been minimized.
|
|
||
| // 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.
This comment has been minimized.
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.
This comment has been minimized.
|
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.
This comment has been minimized.
| None => ptr::null_mut(), | ||
| } | ||
| } | ||
|
|
This comment has been minimized.
This comment has been minimized.
| 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.
This comment has been minimized.
|
|
||
| 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.
This comment has been minimized.
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.
This comment has been minimized.
| .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.
This comment has been minimized.
| } | ||
|
|
||
| match reqs.multisampling { | ||
| Some(0) => (), |
This comment has been minimized.
This comment has been minimized.
|
|
||
| // 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.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
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.
This comment has been minimized.
| } | ||
|
|
||
| if !share.is_null() { | ||
| if wgl::ShareLists(share as *const c_void, ctx) == 0 { |
This comment has been minimized.
This comment has been minimized.
|
I have improved WGL & winapi disposal in error paths using a scoped struct. Also got rid of CurrentContextGuard code. |
| }); | ||
|
|
||
| // Unbind the current context so WGLScopedContext can release resources properly | ||
| // wgl::DeleteContex must be called with unbound contexts |
This comment has been minimized.
This comment has been minimized.
|
|
||
| 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.
This comment has been minimized.
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.
This comment has been minimized.
| @@ -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.
This comment has been minimized.
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.
This comment has been minimized.
| 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.
This comment has been minimized.
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.
This comment has been minimized.
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.
This comment has been minimized.
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.
This comment has been minimized.
|
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 :) |
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 -->
…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
…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
…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
…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
MortimerGoro commentedSep 19, 2016
WGL implementation, now the servo webgl triangle demo runs on windows ;)