Creating texture seems to leak ~250 bytes per texture, even when cleanup() is called appropriately. Following example code reproduces the behavior on Linux using Intel graphics, using the latest gfx-rs master with memory usage tracked via watch 'ps aux | grep leak'. Sorry the repro is ugly; it's just the triangle example with a texture-loading function crudely called each frame. See the "BUGGO" comment for what I've added.
#[macro_use]
extern crate gfx;
extern crate gfx_window_glutin;
extern crate glutin;
extern crate image;
use gfx::{Adapter, CommandQueue, Factory, FrameSync, GraphicsPoolExt,
Surface, SwapChain, SwapChainExt, WindowExt};
use gfx::format::Formatted;
use gfx::traits::FactoryExt;
use gfx::format::{Rgba8};
pub type ColorFormat = gfx::format::Rgba8;
pub type DepthFormat = gfx::format::DepthStencil;
gfx_defines!{
vertex Vertex {
pos: [f32; 2] = "a_Pos",
color: [f32; 3] = "a_Color",
}
pipeline pipe {
vbuf: gfx::VertexBuffer<Vertex> = (),
out: gfx::RenderTarget<ColorFormat> = "Target0",
}
}
const TRIANGLE: [Vertex; 3] = [
Vertex { pos: [ -0.5, -0.5 ], color: [1.0, 0.0, 0.0] },
Vertex { pos: [ 0.5, -0.5 ], color: [0.0, 1.0, 0.0] },
Vertex { pos: [ 0.0, 0.5 ], color: [0.0, 0.0, 1.0] }
];
const CLEAR_COLOR: [f32; 4] = [0.1, 0.2, 0.3, 1.0];
fn load_texture<R, F>(factory: &mut F, data: &[u8])
-> Result<gfx::handle::ShaderResourceView<R, [f32; 4]>, String> where
R: gfx::Resources, F: gfx::Factory<R> {
use std::io::Cursor;
use gfx::texture as t;
let img = image::load(Cursor::new(data), image::PNG).unwrap().to_rgba();
let (width, height) = img.dimensions();
let kind = t::Kind::D2(width as t::Size, height as t::Size, t::AaMode::Single);
let (_, view) = factory.create_texture_immutable_u8::<Rgba8>(kind, &[&img]).unwrap();
Ok(view)
}
pub fn main() {
// Create window
let mut events_loop = glutin::EventsLoop::new();
let wb = glutin::WindowBuilder::new()
.with_title("Triangle example".to_string())
.with_dimensions(1024, 768);
let gl_builder = glutin::ContextBuilder::new().with_vsync(true);
// let gl_builder = gfx_window_glutin::config_context(gl_builder, ColorFormat::get_format(), DepthFormat::get_format());
let window = glutin::GlWindow::new(wb, gl_builder, &events_loop).unwrap();
// Acquire surface and adapters
let (mut surface, adapters) = gfx_window_glutin::Window::new(window).get_surface_and_adapters();
// Open device (factory and queues)
let gfx::Device { mut factory, mut graphics_queues, .. } =
adapters[0].open_with(|family, ty| {
((ty.supports_graphics() && surface.supports_queue(&family)) as u32, gfx::QueueType::Graphics)
});
let mut graphics_queue = graphics_queues.pop().expect("Unable to find a graphics queue.");
// Create swapchain
let config = gfx::SwapchainConfig::new()
.with_color::<ColorFormat>();
let mut swap_chain = surface.build_swapchain(config, &graphics_queue);
let views = swap_chain.create_color_views(&mut factory);
let pso = factory.create_pipeline_simple(
include_bytes!("shader/triangle_150.glslv"),
include_bytes!("shader/triangle_150.glslf"),
pipe::new()
).unwrap();
let (vertex_buffer, slice) = factory.create_vertex_buffer_with_slice(&TRIANGLE, ());
let mut graphics_pool = graphics_queue.create_graphics_pool(1);
let frame_semaphore = factory.create_semaphore();
let draw_semaphore = factory.create_semaphore();
let frame_fence = factory.create_fence(false);
let mut data = pipe::Data {
vbuf: vertex_buffer,
out: views[0].clone(),
};
// main loop
let mut running = true;
while running {
// fetch events
events_loop.poll_events(|event| {
if let glutin::Event::WindowEvent { event, .. } = event {
match event {
glutin::WindowEvent::Closed => running = false,
glutin::WindowEvent::KeyboardInput {
input: glutin::KeyboardInput {
virtual_keycode: Some(glutin::VirtualKeyCode::Escape), ..
}, ..
} => return,
glutin::WindowEvent::Resized(_width, _height) => {
// TODO
},
_ => (),
}
}
});
// Get next frame
let frame = swap_chain.acquire_frame(FrameSync::Semaphore(&frame_semaphore));
data.out = views[frame.id()].clone();
// draw a frame
// wait for frame -> draw -> signal -> present
{
let mut encoder = graphics_pool.acquire_graphics_encoder();
encoder.clear(&data.out, CLEAR_COLOR);
encoder.draw(&slice, &pso, &data);
encoder.synced_flush(&mut graphics_queue, &[&frame_semaphore], &[&draw_semaphore], Some(&frame_fence));
}
// BUGGO: TEXTURE LOADED HERE EACH FRAME
let _ = load_texture(&mut factory, &include_bytes!("../blend/image/lena.png")[..]);
swap_chain.present(&mut graphics_queue, &[&draw_semaphore]);
factory.wait_for_fences(&[&frame_fence], gfx::WaitFor::All, 1_000_000);
graphics_queue.cleanup();
graphics_pool.reset();
}
}
Creating texture seems to leak ~250 bytes per texture, even when
cleanup()
is called appropriately. Following example code reproduces the behavior on Linux using Intel graphics, using the latest gfx-rs master with memory usage tracked viawatch 'ps aux | grep leak'
. Sorry the repro is ugly; it's just the triangle example with a texture-loading function crudely called each frame. See the "BUGGO" comment for what I've added.Original bug report here: https://github.com/ggez/ggez/issues/111 , there's a little bit of discussion there about potential causes.
Thanks in advance!