Use a better protocol between renderer and osmain

This commit is contained in:
Brian Anderson 2012-05-03 22:09:47 -07:00
parent 04575529ad
commit 09694fe58f
3 changed files with 103 additions and 42 deletions

View file

@ -4,26 +4,25 @@ import comm::*;
import layout::display_list::*; import layout::display_list::*;
enum msg { enum msg {
draw(display_list), render(display_list),
exit(comm::chan<()>) exit(comm::chan<()>)
} }
fn renderer(osmain: chan<osmain::msg>) -> chan<msg> { fn renderer(osmain: chan<osmain::msg>) -> chan<msg> {
task::spawn_listener::<msg> {|po| task::spawn_listener::<msg> {|po|
listen {|draw_target_ch| listen {|draw_target_ch|
osmain.send(osmain::get_draw_target(draw_target_ch)); #debug("renderer: beginning rendering loop");
let draw_target = draw_target_ch.recv(); osmain.send(osmain::begin_drawing(draw_target_ch));
loop { loop {
alt po.recv() { alt po.recv() {
draw(display_list) { render(display_list) {
#debug("renderer: got render request");
let draw_target = draw_target_ch.recv();
#debug("renderer: rendering");
draw_display_list(draw_target, display_list); draw_display_list(draw_target, display_list);
#debug("renderer: returning surface");
listen {|draw_ch| osmain.send(osmain::draw(draw_target_ch, draw_target));
osmain.send(osmain::draw(draw_ch));
draw_ch.recv();
}
} }
exit(response_ch) { exit(response_ch) {
response_ch.send(()); response_ch.send(());

View file

@ -33,7 +33,7 @@ fn layout(renderer: chan<renderer::msg>) -> chan<msg> {
let box = layout_dom(dom); let box = layout_dom(dom);
let dlist = build_display_list(box); let dlist = build_display_list(box);
send(renderer, gfx::renderer::draw(dlist)); send(renderer, gfx::renderer::render(dlist));
} }
exit { exit {
break; break;
@ -54,18 +54,18 @@ fn build_display_list(_box: @base::box) -> display_list::display_list {
display_item({ display_item({
item_type: solid_color, item_type: solid_color,
bounds: geom::box( bounds: geom::box(
int_to_au(r.next() as int % 800), int_to_au(r.next() as int % 800 - 100),
int_to_au(r.next() as int % 600), int_to_au(r.next() as int % 600 - 100),
int_to_au(100), int_to_au(200),
int_to_au(100)) int_to_au(200))
}), }),
display_item({ display_item({
item_type: solid_color, item_type: solid_color,
bounds: geom::box( bounds: geom::box(
int_to_au(100), int_to_au(r.next() as int % 800 - 100),
int_to_au(100), int_to_au(r.next() as int % 600 - 100),
int_to_au(100), int_to_au(200),
int_to_au(100)) int_to_au(200))
}) })
] ]
} }

View file

@ -2,9 +2,9 @@ import comm::*;
import azure::cairo::cairo_surface_t; import azure::cairo::cairo_surface_t;
enum msg { enum msg {
get_draw_target(chan<AzDrawTargetRef>), begin_drawing(chan<AzDrawTargetRef>),
draw(chan<AzDrawTargetRef>, AzDrawTargetRef),
add_key_handler(chan<()>), add_key_handler(chan<()>),
draw(chan<()>),
exit exit
} }
@ -31,7 +31,7 @@ fn mainloop(po: port<msg>) {
[sdl::video::doublebuf]); [sdl::video::doublebuf]);
assert !ptr::is_null(screen); assert !ptr::is_null(screen);
let surface = mk_surface(); let surfaces = surface_set();
loop { loop {
sdl::event::poll_event {|event| sdl::event::poll_event {|event|
@ -51,37 +51,85 @@ fn mainloop(po: port<msg>) {
add_key_handler(key_ch) { add_key_handler(key_ch) {
key_handlers += [key_ch]; key_handlers += [key_ch];
} }
get_draw_target(response_ch) { begin_drawing(sender) {
response_ch.send(copy(surface.az_target)); lend_surface(surfaces, sender);
} }
draw(response_ch) { draw(sender, dt) {
sdl::video::unlock_surface(surface.sdl_surf); return_surface(surfaces, dt);
sdl::video::blit_surface(surface.sdl_surf, ptr::null(), lend_surface(surfaces, sender);
#debug("osmain: drawing to screen");
assert surfaces.s1.surf.az_target == dt;
let sdl_surf = surfaces.s1.surf.sdl_surf;
sdl::video::unlock_surface(sdl_surf);
sdl::video::blit_surface(sdl_surf, ptr::null(),
screen, ptr::null()); screen, ptr::null());
sdl::video::lock_surface(surface.sdl_surf); sdl::video::lock_surface(sdl_surf);
sdl::video::flip(screen); sdl::video::flip(screen);
response_ch.send(());
} }
exit { break; } exit { break; }
} }
} }
} }
destroy_surface(surface); destroy_surface(surfaces.s1.surf);
destroy_surface(surfaces.s2.surf);
sdl::quit(); sdl::quit();
} }
#[doc = "A function for spawning into the platform's main thread"] type surface_set = {
fn on_osmain<T: send>(f: fn~(comm::port<T>)) -> comm::chan<T> { mut s1: {
let builder = task::builder(); surf: surface,
let opts = { have: bool
sched: some({ },
mode: task::osmain, mut s2: {
native_stack_size: none surf: surface,
}) have: bool
with task::get_opts(builder) }
};
fn lend_surface(surfaces: surface_set, recvr: chan<AzDrawTargetRef>) {
// We are in a position to lend out the surface?
assert surfaces.s1.have;
// Ok then take it
let dt1 = surfaces.s1.surf.az_target;
#debug("osmain: lending surface %?", dt1);
recvr.send(dt1);
// Now we don't have it
surfaces.s1 = {
have: false
with surfaces.s1
}; };
task::set_opts(builder, opts); // But we (hopefully) have another!
ret task::run_listener(builder, f); surfaces.s1 <-> surfaces.s2;
// Let's look
assert surfaces.s1.have;
}
fn return_surface(surfaces: surface_set, dt: AzDrawTargetRef) {
#debug("osmain: returning surface %?", dt);
// We have room for a return
assert surfaces.s1.have;
assert !surfaces.s2.have;
assert surfaces.s2.surf.az_target == dt;
// Now we have it again
surfaces.s2 = {
have: true
with surfaces.s2
};
}
fn surface_set() -> surface_set {
{
mut s1: {
surf: mk_surface(),
have: true
},
mut s2: {
surf: mk_surface(),
have: true
}
}
} }
type surface = { type surface = {
@ -129,6 +177,20 @@ fn destroy_surface(surface: surface) {
sdl::video::free_surface(surface.sdl_surf); sdl::video::free_surface(surface.sdl_surf);
} }
#[doc = "A function for spawning into the platform's main thread"]
fn on_osmain<T: send>(f: fn~(comm::port<T>)) -> comm::chan<T> {
let builder = task::builder();
let opts = {
sched: some({
mode: task::osmain,
native_stack_size: none
})
with task::get_opts(builder)
};
task::set_opts(builder, opts);
ret task::run_listener(builder, f);
}
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
mod platform { mod platform {
fn runmain(f: fn()) { fn runmain(f: fn()) {