First of all, Thank you very much for maintaining these rust bindings to bgfx - It's a great addition to the evolving rust ecosystem.
However, I'm facing one problem whenever I call bgfx:shutdown()
from my application there is an Segmentation fault happening. I was able to debug the root-cause up as following:
BX_ALIGNED_DELETE(g_allocator, ctx, Context::kAlignment);
in bgfx.cpp::shutdown()
is invoking the destructor of the Context class (bgfx_p.h). The Context class contains a list of TextureRefs m_textureHandle
in which the destructor for each element is invoked explicitly. Each TextureRef has an bx::String
m_name
for which the destructor is invoked explicitly. This destructor will call the clear()
method in bx::StringT
, which will call to BX_FREE(*AllocatorT, const_cast<char*>(m_ptr) );
.
This will call to bx::free
and from there to bgfx::AllocatorStub::realloc
. From there free
is called from the clib (bgfx.cpp, Line 192, ::free(_ptr);
).
Now here I do encounter the segmentation fault; even at this time my only texture is already released (automatically once its owner left the scope). There is still an fair chance, that the issue is due to an mistake in my application code - I double-checked multiple times and was not able to spot what could be the reason.
Below is a Minimal, Reproducible Example (the shaders are embedded, but there needs to be an file "test.png" in the working directory):
use bgfx::*;
use bgfx_rs::bgfx;
use glfw::{Action, Key, Window, WindowMode};
use raw_window_handle::{HasRawWindowHandle, RawWindowHandle};
const WIDTH: usize = 1280;
const HEIGHT: usize = 720;
fn load_image (filepath : &str) -> bgfx::Texture {
let mut file = std::fs::File::open(filepath).unwrap();
let img = stb::image::stbi_load_from_reader(&mut file, stb::image::Channels::RgbAlpha).unwrap();
return bgfx::create_texture_2d(img.0.width as u16, img.0.height as u16, false, 1, bgfx::TextureFormat::RGBA8, 0, &Memory::copy(&img.1.as_slice()));
}
fn load_shader() -> bgfx::Program {
let vsh_bytes: [u8;341] = [
0x56, 0x53, 0x48, 0x06, 0x00, 0x00, 0x00, 0x00, 0x6f, 0x1e, 0x3e, 0x3c, 0x01, 0x00, 0x0f, 0x75, // VSH.....o.><...u
0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x56, 0x69, 0x65, 0x77, 0x50, 0x72, 0x6f, 0x6a, 0x04, 0x01, // _modelViewProj..
0x00, 0x00, 0x01, 0x00, 0x2c, 0x01, 0x00, 0x00, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, // ....,...attribut
0x65, 0x20, 0x68, 0x69, 0x67, 0x68, 0x70, 0x20, 0x76, 0x65, 0x63, 0x33, 0x20, 0x61, 0x5f, 0x70, // e highp vec3 a_p
0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3b, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, // osition;.attribu
0x74, 0x65, 0x20, 0x68, 0x69, 0x67, 0x68, 0x70, 0x20, 0x76, 0x65, 0x63, 0x32, 0x20, 0x61, 0x5f, // te highp vec2 a_
0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x30, 0x3b, 0x0a, 0x76, 0x61, 0x72, 0x79, 0x69, // texcoord0;.varyi
0x6e, 0x67, 0x20, 0x68, 0x69, 0x67, 0x68, 0x70, 0x20, 0x76, 0x65, 0x63, 0x32, 0x20, 0x76, 0x5f, // ng highp vec2 v_
0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x30, 0x3b, 0x0a, 0x75, 0x6e, 0x69, 0x66, 0x6f, // texcoord0;.unifo
0x72, 0x6d, 0x20, 0x68, 0x69, 0x67, 0x68, 0x70, 0x20, 0x6d, 0x61, 0x74, 0x34, 0x20, 0x75, 0x5f, // rm highp mat4 u_
0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x56, 0x69, 0x65, 0x77, 0x50, 0x72, 0x6f, 0x6a, 0x3b, 0x0a, 0x76, // modelViewProj;.v
0x6f, 0x69, 0x64, 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x20, 0x28, 0x29, 0x0a, 0x7b, 0x0a, 0x20, 0x20, // oid main ().{.
0x68, 0x69, 0x67, 0x68, 0x70, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, // highp vec4 tmpva
0x72, 0x5f, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x31, 0x2e, // r_1;. tmpvar_1.
0x77, 0x20, 0x3d, 0x20, 0x31, 0x2e, 0x30, 0x3b, 0x0a, 0x20, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, // w = 1.0;. tmpva
0x72, 0x5f, 0x31, 0x2e, 0x78, 0x79, 0x7a, 0x20, 0x3d, 0x20, 0x61, 0x5f, 0x70, 0x6f, 0x73, 0x69, // r_1.xyz = a_posi
0x74, 0x69, 0x6f, 0x6e, 0x3b, 0x0a, 0x20, 0x20, 0x67, 0x6c, 0x5f, 0x50, 0x6f, 0x73, 0x69, 0x74, // tion;. gl_Posit
0x69, 0x6f, 0x6e, 0x20, 0x3d, 0x20, 0x28, 0x75, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x56, 0x69, // ion = (u_modelVi
0x65, 0x77, 0x50, 0x72, 0x6f, 0x6a, 0x20, 0x2a, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, // ewProj * tmpvar_
0x31, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x76, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, // 1);. v_texcoord
0x30, 0x20, 0x3d, 0x20, 0x61, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x30, 0x3b, // 0 = a_texcoord0;
0x0a, 0x7d, 0x0a, 0x0a, 0x00, // .}...
];
let fsh_bytes: [u8;215] = [
0x46, 0x53, 0x48, 0x06, 0x6f, 0x1e, 0x3e, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0a, 0x73, // FSH.o.><.......s
0x5f, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0xb3, // _texColor.......
0x00, 0x00, 0x00, 0x76, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x68, 0x69, 0x67, 0x68, 0x70, // ...varying highp
0x20, 0x76, 0x65, 0x63, 0x32, 0x20, 0x76, 0x5f, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, // vec2 v_texcoord
0x30, 0x3b, 0x0a, 0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x73, 0x61, 0x6d, 0x70, 0x6c, // 0;.uniform sampl
0x65, 0x72, 0x32, 0x44, 0x20, 0x73, 0x5f, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x3b, // er2D s_texColor;
0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x20, 0x28, 0x29, 0x0a, 0x7b, 0x0a, // .void main ().{.
0x20, 0x20, 0x6c, 0x6f, 0x77, 0x70, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x74, 0x6d, 0x70, 0x76, // lowp vec4 tmpv
0x61, 0x72, 0x5f, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, 0x31, // ar_1;. tmpvar_1
0x20, 0x3d, 0x20, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x32, 0x44, 0x20, 0x28, 0x73, 0x5f, // = texture2D (s_
0x74, 0x65, 0x78, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x2c, 0x20, 0x76, 0x5f, 0x74, 0x65, 0x78, 0x63, // texColor, v_texc
0x6f, 0x6f, 0x72, 0x64, 0x30, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, // oord0);. gl_Fra
0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x74, 0x6d, 0x70, 0x76, 0x61, 0x72, 0x5f, // gColor = tmpvar_
0x31, 0x3b, 0x0a, 0x7d, 0x0a, 0x0a, 0x00, // 1;.}...
];
let vsh = bgfx::create_shader(&Memory::copy(&vsh_bytes));
let fsh = bgfx::create_shader(&Memory::copy(&fsh_bytes));
bgfx::create_program(&vsh, &fsh, true)
}
fn draw_image(shader : &bgfx::Program, texture: &bgfx::Texture){
let id : bgfx::ViewId = 0x00;
let builder = bgfx::VertexLayoutBuilder::new();
builder.begin(get_render_type());
builder.add(bgfx::Attrib::Position, 2, bgfx::AttribType::Float, AddArgs::default());
builder.add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float, AddArgs::default());
builder.end();
let mut tvb = bgfx::TransientVertexBuffer::new();
if bgfx::get_avail_transient_vertex_buffer(4, &builder) == 4 {
bgfx::alloc_transient_vertex_buffer(&mut tvb, 4, &builder);
let vertices : [f32; 16] = [
0.0f32, 0.0f32, 0.0f32, 0.0f32,
1024.0f32, 0.0f32, 1024.0f32, 0.0f32,
0.0f32, 1024.0f32, 0.0f32, 1024.0f32,
1024.0f32, 1024.0f32, 1024.0f32, 1024.0f32,
];
unsafe {
std::ptr::copy_nonoverlapping(vertices.as_ptr() as *const u8, tvb.data as *mut u8, std::mem::size_of::<[f32; 16]>()); //this line causes SIGSEGV
}
bgfx::set_transient_vertex_buffer(0, &tvb, 0, 4);
bgfx::set_state(StatePtFlags::TRISTRIP.bits() | StateWriteFlags::RGB.bits() | StateDepthTestFlags::LESS.bits() | StateBlendFlags::SRC_ALPHA.bits() | StateFlags::MSAA.bits(), 0);
let mvp = [
0.0f32, 0.0f32, 0.0f32, 0.0f32,
0.0f32, 0.0f32, 0.0f32, 0.0f32,
0.0f32, 0.0f32, 0.0f32, 0.0f32,
0.0f32, 0.0f32, 0.0f32, 0.0f32,
];
bgfx::set_uniform(&bgfx::Uniform::create("modelViewProj", bgfx::UniformType::Mat4, 1), &mvp.as_slice(), 1);
bgfx::set_texture(0, &bgfx::Uniform::create("texColor", bgfx::UniformType::Sampler, 1), &texture, u32::MAX);
bgfx::submit(id, &shader, bgfx_rs::static_lib::SubmitArgs{ depth: 1, flags: DiscardFlags::NONE.bits() });
}
}
#[cfg(target_os = "linux")]
fn update_platform_handle(pd: &mut PlatformData, window: &Window) {
match window.raw_window_handle() {
RawWindowHandle::Xlib(x_data) => {
pd.ndt = x_data.display;
pd.nwh = x_data.window as *mut core::ffi::c_void;
}
_ => panic!("Unsupported window type"),
}
}
#[cfg(target_os = "windows")]
fn update_platform_handle(pd: &mut PlatformData, window: &Window) {
match window.raw_window_handle() {
RawWindowHandle::Windows(data) => {
pd.nwh = data.hwnd as *mut core::ffi::c_void;
}
_ => panic!("Unsupported window type"),
}
}
#[cfg(target_os = "linux")]
fn get_render_type() -> RendererType {
RendererType::OpenGL
}
#[cfg(not(target_os = "linux"))]
fn get_render_type() -> RendererType {
RendererType::Count
}
fn main() {
let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();
glfw.window_hint(glfw::WindowHint::ClientApi(glfw::ClientApiHint::NoApi));
let (mut window, events) = glfw
.create_window(
WIDTH as _,
HEIGHT as _,
"App - ESC to close",
glfw::WindowMode::Windowed,
)
.expect("Failed to create GLFW window.");
window.set_key_polling(true);
let mut pd = bgfx::PlatformData::new();
update_platform_handle(&mut pd, &window);
bgfx::set_platform_data(&pd);
let mut init = Init::new();
init.type_r = get_render_type();
init.resolution.width = WIDTH as u32;
init.resolution.height = HEIGHT as u32;
init.resolution.reset = ResetFlags::VSYNC.bits();
init.platform_data = pd;
if !bgfx::init(&init) {
panic!("failed to init bgfx");
}
bgfx::set_debug(DebugFlags::TEXT.bits());
let mut old_size = (0, 0);
{
let shader = load_shader();
let texture = load_image("test.png");
while !window.should_close() {
glfw.poll_events();
for (_, event) in glfw::flush_messages(&events) {
if let glfw::WindowEvent::Key(Key::Escape, _, Action::Press, _) = event {
window.set_should_close(true)
}
}
let size = window.get_framebuffer_size();
if old_size != size {
bgfx::reset(size.0 as _, size.1 as _, ResetArgs::default());
old_size = size;
}
bgfx::set_view_rect(0, 0, 0, size.0 as _, size.1 as _);
bgfx::set_view_clear(
0,
ClearFlags::COLOR.bits() | ClearFlags::DEPTH.bits(),
SetViewClearArgs {
rgba: 0x103030ff,
..Default::default()
},
);
bgfx::touch(0);
draw_image(&shader, &texture);
bgfx::frame(false);
}
}
bgfx::shutdown();
}
The dependencies are:
[dependencies]
bgfx-rs = "0.8"
glfw = "0.41"
raw-window-handle = "0.3"
stb = "0.3.2"
Either closing the window by clicking the X or pressing ESC will result in the Segmentation Fault.
Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)
Is there any problem in my code or could there be an problem with the bgfx rust bindings itself?