alex/beta-minecraft-rust
Minecraft Beta 1.7.3 Rewrite
BRANCH main
SNAPSHOT Draw terrain GPU-driven from packed per-section buffers with GPU occlusion culling, add a render distance slider (2-128) with a quad/disk shape, cut chunk bookkeeping at high render distances, and fix a light underflow at y=0
DOWNLOAD
root crates client src gpu instance.rs
use std::ffi::{CStr, c_char};
use std::ptr::{self, null, null_mut};
use std::sync::Arc;
use raw_window_handle::{RawDisplayHandle, RawWindowHandle};
use volcanic::loader::{InstanceCommands, Loader};
use volcanic::*;
use super::validation::{LAYER, VAR, Validation};
use super::{Error, Result, check, create, zeroed};
pub struct Instance {
pub(crate) handle: VkInstance,
pub(crate) commands: InstanceCommands,
/// Whether `VK_KHR_get_surface_capabilities2` is enabled, which present timing needs.
pub(crate) surface_capabilities2: bool,
messenger: VkDebugUtilsMessengerEXT,
_loader: Loader,
}
// SAFETY: Vulkan instance handles and their loaded commands may be used from any thread.
unsafe impl Send for Instance {}
unsafe impl Sync for Instance {}
impl Instance {
pub fn new(display: RawDisplayHandle, validation: Option<Validation>) -> Result<Arc<Self>> {
let loader = unsafe { Loader::new()? };
let platform_extension = match display {
RawDisplayHandle::Wayland(_) => VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME,
RawDisplayHandle::Xlib(_) => VK_KHR_XLIB_SURFACE_EXTENSION_NAME,
RawDisplayHandle::Xcb(_) => VK_KHR_XCB_SURFACE_EXTENSION_NAME,
_ => return Err(Error::UnsupportedWindowSystem),
};
let validation = match validation {
Some(_) if !layer_available(&loader)? => {
tracing::warn!("{VAR} is set but {LAYER:?} is not installed");
None
}
validation => validation,
};
if let Some(validation) = validation {
tracing::info!("Vulkan validation enabled: {VAR}={validation}");
}
let mut extensions: Vec<*const c_char> = vec![
VK_KHR_SURFACE_EXTENSION_NAME.as_ptr(),
platform_extension.as_ptr(),
];
let surface_capabilities2 =
extension_available(&loader, VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME)?;
if surface_capabilities2 {
extensions.push(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME.as_ptr());
}
let layers: Vec<*const c_char> = if validation.is_some() {
extensions.push(VK_EXT_DEBUG_UTILS_EXTENSION_NAME.as_ptr());
extensions.push(VK_EXT_LAYER_SETTINGS_EXTENSION_NAME.as_ptr());
vec![LAYER.as_ptr()]
} else {
Vec::new()
};
let application = VkApplicationInfo {
sType: VkStructureType::ApplicationInfo,
pApplicationName: c"Minecraft".as_ptr(),
apiVersion: VK_API_VERSION_1_4,
..zeroed()
};
let report_flags = validation.map(Validation::report_flags).unwrap_or_default();
let layer_settings = validation.map(|v| v.layer_settings(&report_flags));
let messenger_info = validation.map(Validation::messenger_info);
let settings_info = layer_settings
.as_ref()
.map(|settings| VkLayerSettingsCreateInfoEXT {
sType: VkStructureType::LayerSettingsCreateInfoExt,
pNext: messenger_info
.as_ref()
.map_or(null(), |info| ptr::from_ref(info).cast()),
settingCount: settings.len() as u32,
pSettings: settings.as_ptr(),
});
let info = VkInstanceCreateInfo {
sType: VkStructureType::InstanceCreateInfo,
pNext: settings_info
.as_ref()
.map_or(null(), |info| ptr::from_ref(info).cast()),
pApplicationInfo: &application,
enabledLayerCount: layers.len() as u32,
ppEnabledLayerNames: layers.as_ptr(),
enabledExtensionCount: extensions.len() as u32,
ppEnabledExtensionNames: extensions.as_ptr(),
..zeroed()
};
let handle = create(|handle| unsafe { loader.vkCreateInstance(&info, null(), handle) })?;
let commands = unsafe { loader.load_instance(handle)? };
let messenger = match &messenger_info {
Some(messenger_info) => create(|messenger| unsafe {
commands.vkCreateDebugUtilsMessengerEXT(handle, messenger_info, null(), messenger)
})?,
None => VK_NULL_HANDLE,
};
Ok(Arc::new(Self {
handle,
commands,
surface_capabilities2,
messenger,
_loader: loader,
}))
}
}
impl Drop for Instance {
fn drop(&mut self) {
let commands = &self.commands;
unsafe {
if self.messenger != VK_NULL_HANDLE {
commands.vkDestroyDebugUtilsMessengerEXT(self.handle, self.messenger, null());
}
commands.vkDestroyInstance(self.handle, null());
}
}
}
fn layer_available(loader: &Loader) -> Result<bool> {
let layers = super::enumerate(|count, items| unsafe {
loader.vkEnumerateInstanceLayerProperties(count, items)
})?;
Ok(layers
.iter()
.any(|layer| unsafe { CStr::from_ptr(layer.layerName.as_ptr()) } == LAYER))
}
fn extension_available(loader: &Loader, name: &CStr) -> Result<bool> {
let extensions = super::enumerate(|count, items| unsafe {
loader.vkEnumerateInstanceExtensionProperties(null(), count, items)
})?;
Ok(extensions
.iter()
.any(|extension| unsafe { CStr::from_ptr(extension.extensionName.as_ptr()) } == name))
}
pub struct Surface {
pub(crate) handle: VkSurfaceKHR,
pub(crate) instance: Arc<Instance>,
}
impl Surface {
/// # Safety
/// The window and display handles must stay valid for the surface's lifetime.
pub unsafe fn new(
instance: &Arc<Instance>,
display: RawDisplayHandle,
window: RawWindowHandle,
) -> Result<Self> {
let (commands, mut handle) = (&instance.commands, VK_NULL_HANDLE);
let result = match (display, window) {
(RawDisplayHandle::Wayland(display), RawWindowHandle::Wayland(window)) => {
let info = VkWaylandSurfaceCreateInfoKHR {
sType: VkStructureType::WaylandSurfaceCreateInfoKhr,
display: display.display.as_ptr(),
surface: window.surface.as_ptr(),
..zeroed()
};
unsafe {
commands.vkCreateWaylandSurfaceKHR(instance.handle, &info, null(), &mut handle)
}
}
(RawDisplayHandle::Xlib(display), RawWindowHandle::Xlib(window)) => {
let info = VkXlibSurfaceCreateInfoKHR {
sType: VkStructureType::XlibSurfaceCreateInfoKhr,
dpy: display.display.map_or(null_mut(), |d| d.as_ptr()),
window: window.window,
..zeroed()
};
unsafe {
commands.vkCreateXlibSurfaceKHR(instance.handle, &info, null(), &mut handle)
}
}
(RawDisplayHandle::Xcb(display), RawWindowHandle::Xcb(window)) => {
let info = VkXcbSurfaceCreateInfoKHR {
sType: VkStructureType::XcbSurfaceCreateInfoKhr,
connection: display.connection.map_or(null_mut(), |c| c.as_ptr()),
window: window.window.get(),
..zeroed()
};
unsafe {
commands.vkCreateXcbSurfaceKHR(instance.handle, &info, null(), &mut handle)
}
}
_ => return Err(Error::UnsupportedWindowSystem),
};
check(result)?;
Ok(Self {
handle,
instance: instance.clone(),
})
}
}
impl Drop for Surface {
fn drop(&mut self) {
let commands = &self.instance.commands;
unsafe { commands.vkDestroySurfaceKHR(self.instance.handle, self.handle, null()) };
}
}