Use the device OpenGL context for WGL surfaces (#4271)

This commit is contained in:
Zoxc 2023-10-20 21:45:43 +02:00 committed by GitHub
parent d876e0d844
commit e918031201
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -26,9 +26,9 @@ use winapi::{
libloaderapi::{GetModuleHandleA, GetProcAddress, LoadLibraryA},
wingdi::{
wglCreateContext, wglDeleteContext, wglGetCurrentContext, wglGetProcAddress,
wglMakeCurrent, wglShareLists, ChoosePixelFormat, DescribePixelFormat, GetPixelFormat,
SetPixelFormat, SwapBuffers, PFD_DOUBLEBUFFER, PFD_DRAW_TO_WINDOW, PFD_SUPPORT_OPENGL,
PFD_TYPE_RGBA, PIXELFORMATDESCRIPTOR,
wglMakeCurrent, ChoosePixelFormat, DescribePixelFormat, GetPixelFormat, SetPixelFormat,
SwapBuffers, PFD_DOUBLEBUFFER, PFD_DRAW_TO_WINDOW, PFD_SUPPORT_OPENGL, PFD_TYPE_RGBA,
PIXELFORMATDESCRIPTOR,
},
winuser::{
CreateWindowExA, DefWindowProcA, GetDC, RegisterClassExA, ReleaseDC, CS_OWNDC,
@ -133,7 +133,6 @@ unsafe impl Send for WglContext {}
unsafe impl Sync for WglContext {}
struct Inner {
opengl_module: HMODULE,
gl: glow::Context,
device: HDC,
context: WglContext,
@ -421,7 +420,6 @@ impl crate::Instance<super::Api> for Instance {
Ok(Instance {
inner: Arc::new(Mutex::new(Inner {
device: dc,
opengl_module,
gl,
context,
})),
@ -476,12 +474,12 @@ impl Drop for DeviceContextHandle {
}
pub struct Swapchain {
surface_context: WglContext,
surface_gl: glow::Context,
framebuffer: glow::Framebuffer,
renderbuffer: glow::Renderbuffer,
/// Extent because the window lies
extent: wgt::Extent3d,
format: wgt::TextureFormat,
format_desc: super::TextureFormatDesc,
#[allow(unused)]
@ -520,17 +518,19 @@ impl Surface {
window: self.window,
};
// Hold the lock for the shared context as we're using resources from there.
let _inner = context.inner.lock();
let inner = context.inner.lock();
if let Err(e) = sc.surface_context.make_current(dc.device) {
log::error!("unable to make the surface OpenGL context current: {e}",);
if let Err(e) = inner.context.make_current(dc.device) {
log::error!("unable to make the OpenGL context current for surface: {e}",);
return Err(crate::SurfaceError::Other(
"unable to make the surface OpenGL context current",
"unable to make the OpenGL context current for surface",
));
}
let gl = &sc.surface_gl;
let gl = &inner.gl;
unsafe { gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, None) };
unsafe { gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(sc.framebuffer)) };
// Note the Y-flipping here. GL's presentation is not flipped,
// but main rendering is. Therefore, we Y-flip the output positions
@ -550,6 +550,9 @@ impl Surface {
)
};
unsafe { gl.bind_renderbuffer(glow::RENDERBUFFER, None) };
unsafe { gl.bind_framebuffer(glow::READ_FRAMEBUFFER, None) };
if unsafe { SwapBuffers(dc.device) } == FALSE {
log::error!("unable to swap buffers: {}", Error::last_os_error());
return Err(crate::SurfaceError::Other("unable to swap buffers"));
@ -572,33 +575,6 @@ impl crate::Surface<super::Api> for Surface {
// Remove the old configuration.
unsafe { self.unconfigure(device) };
let format_desc = device.shared.describe_texture_format(config.format);
let inner = &device.shared.context.inner.lock();
if let Err(e) = inner.context.make_current(inner.device) {
log::error!("unable to make the shared OpenGL context current: {e}",);
return Err(crate::SurfaceError::Other(
"unable to make the shared OpenGL context current",
));
}
let gl = &inner.gl;
let renderbuffer = unsafe { gl.create_renderbuffer() }.map_err(|error| {
log::error!("Internal swapchain renderbuffer creation failed: {error}");
crate::DeviceError::OutOfMemory
})?;
unsafe { gl.bind_renderbuffer(glow::RENDERBUFFER, Some(renderbuffer)) };
unsafe {
gl.renderbuffer_storage(
glow::RENDERBUFFER,
format_desc.internal,
config.extent.width as _,
config.extent.height as _,
)
};
// Create the swap chain OpenGL context
let dc = unsafe { GetDC(self.window) };
if dc.is_null() {
log::error!(
@ -621,35 +597,48 @@ impl crate::Surface<super::Api> for Surface {
));
}
let context = unsafe { wglCreateContext(dc.device) };
if context.is_null() {
log::error!(
"unable to create surface OpenGL context: {}",
Error::last_os_error()
);
return Err(crate::SurfaceError::Other(
"unable to create surface OpenGL context",
));
}
let surface_context = WglContext { context };
let format_desc = device.shared.describe_texture_format(config.format);
let inner = &device.shared.context.inner.lock();
if unsafe { wglShareLists(inner.context.context, surface_context.context) } == FALSE {
log::error!(
"unable to share objects between OpenGL contexts: {}",
Error::last_os_error()
);
if let Err(e) = inner.context.make_current(dc.device) {
log::error!("unable to make the OpenGL context current for surface: {e}",);
return Err(crate::SurfaceError::Other(
"unable to share objects between OpenGL contexts",
"unable to make the OpenGL context current for surface",
));
}
if let Err(e) = surface_context.make_current(dc.device) {
log::error!("unable to make the surface OpengL context current: {e}",);
return Err(crate::SurfaceError::Other(
"unable to make the surface OpengL context current",
));
}
let gl = &inner.gl;
let renderbuffer = unsafe { gl.create_renderbuffer() }.map_err(|error| {
log::error!("Internal swapchain renderbuffer creation failed: {error}");
crate::DeviceError::OutOfMemory
})?;
unsafe { gl.bind_renderbuffer(glow::RENDERBUFFER, Some(renderbuffer)) };
unsafe {
gl.renderbuffer_storage(
glow::RENDERBUFFER,
format_desc.internal,
config.extent.width as _,
config.extent.height as _,
)
};
let framebuffer = unsafe { gl.create_framebuffer() }.map_err(|error| {
log::error!("Internal swapchain framebuffer creation failed: {error}");
crate::DeviceError::OutOfMemory
})?;
unsafe { gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(framebuffer)) };
unsafe {
gl.framebuffer_renderbuffer(
glow::READ_FRAMEBUFFER,
glow::COLOR_ATTACHMENT0,
glow::RENDERBUFFER,
Some(renderbuffer),
)
};
unsafe { gl.bind_renderbuffer(glow::RENDERBUFFER, None) };
unsafe { gl.bind_framebuffer(glow::READ_FRAMEBUFFER, None) };
// Setup presentation mode
let extra = Wgl::load_with(|name| load_gl_func(name, None));
let extentions = extensions(&extra, dc.device);
if !(extentions.contains("WGL_EXT_swap_control") && extra.SwapIntervalEXT.is_loaded()) {
@ -673,58 +662,7 @@ impl crate::Surface<super::Api> for Surface {
return Err(crate::SurfaceError::Other("unable to set swap interval"));
}
let surface_gl = unsafe {
glow::Context::from_loader_function(|name| {
load_gl_func(name, Some(inner.opengl_module))
})
};
// Check that the surface context OpenGL is new enough to support framebuffers.
let version = unsafe { gl.get_parameter_string(glow::VERSION) };
let version = super::Adapter::parse_full_version(&version);
match version {
Ok(version) => {
if version < (3, 0) {
log::error!(
"surface context OpenGL version ({}.{}) too old",
version.0,
version.1
);
return Err(crate::SurfaceError::Other(
"surface context OpenGL version too old",
));
}
}
Err(e) => {
log::error!("unable to parse surface context OpenGL version: {e}",);
return Err(crate::SurfaceError::Other(
"unable to parse surface context OpenGL version",
));
}
}
let framebuffer = unsafe { surface_gl.create_framebuffer() }.map_err(|error| {
log::error!("Internal swapchain framebuffer creation failed: {error}");
crate::DeviceError::OutOfMemory
})?;
unsafe { surface_gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(framebuffer)) };
unsafe {
surface_gl.framebuffer_renderbuffer(
glow::READ_FRAMEBUFFER,
glow::COLOR_ATTACHMENT0,
glow::RENDERBUFFER,
Some(renderbuffer),
)
};
unsafe { surface_gl.bind_renderbuffer(glow::RENDERBUFFER, None) };
unsafe { surface_gl.bind_framebuffer(glow::READ_FRAMEBUFFER, None) };
unsafe { surface_gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, None) };
unsafe { surface_gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(framebuffer)) };
self.swapchain = Some(Swapchain {
surface_context,
surface_gl,
renderbuffer,
framebuffer,
extent: config.extent,