Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce frame output support. #1687

Merged
merged 1 commit into from Sep 13, 2017
Merged
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

@@ -66,6 +66,11 @@ pub trait Example {
fn get_external_image_handler(&self) -> Option<Box<webrender::ExternalImageHandler>> {
None
}
fn get_output_image_handler(&mut self, _gl: &gl::Gl) -> Option<Box<webrender::OutputImageHandler>> {
None
}
fn draw_custom(&self, _gl: &gl::Gl) {
}
}

pub fn main_wrapper(example: &mut Example,
@@ -111,7 +116,7 @@ pub fn main_wrapper(example: &mut Example,
};

let size = DeviceUintSize::new(width, height);
let (mut renderer, sender) = webrender::Renderer::new(gl, opts).unwrap();
let (mut renderer, sender) = webrender::Renderer::new(gl.clone(), opts).unwrap();
let api = sender.create_api();
let document_id = api.add_document(size);

@@ -121,6 +126,9 @@ pub fn main_wrapper(example: &mut Example,
if let Some(external_image_handler) = example.get_external_image_handler() {
renderer.set_external_image_handler(external_image_handler);
}
if let Some(output_image_handler) = example.get_output_image_handler(&*gl) {
renderer.set_output_image_handler(output_image_handler);
}

let epoch = Epoch(0);
let root_background_color = ColorF::new(0.3, 0.0, 0.0, 1.0);
@@ -202,6 +210,7 @@ pub fn main_wrapper(example: &mut Example,

renderer.update();
renderer.render(DeviceUintSize::new(width, height)).unwrap();
example.draw_custom(&*gl);
window.swap_buffers().ok();
}

@@ -0,0 +1,228 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate gleam;
extern crate glutin;
extern crate webrender;

#[path="common/boilerplate.rs"]
mod boilerplate;

use boilerplate::{Example, HandyDandyRectBuilder};
use gleam::gl;
use webrender::api::*;

// This example demonstrates using the frame output feature to copy
// the output of a WR framebuffer to a custom texture.

const VS: &str = "#version 130\nin vec2 aPos;out vec2 vUv;\nvoid main() { vUv = aPos; gl_Position = vec4(aPos, 0.0, 1.0); }\n";
const FS: &str = "#version 130\nout vec4 oFragColor;\nin vec2 vUv;\nuniform sampler2D s;\nvoid main() { oFragColor = texture(s, vUv); }\n";

struct App {
iframe_pipeline_id: Option<PipelineId>,
texture_id: gl::GLuint,
}

struct OutputHandler {
texture_id: gl::GLuint,
}

impl OutputHandler {
fn new(texture_id: gl::GLuint) -> OutputHandler {
OutputHandler {
texture_id
}
}
}

impl webrender::OutputImageHandler for OutputHandler {
fn lock(&mut self, _id: PipelineId) -> Option<(u32, DeviceIntSize)> {
Some((self.texture_id, DeviceIntSize::new(100, 100)))
}

fn unlock(&mut self, _id: PipelineId) {
}
}

impl Example for App {
fn render(&mut self,
api: &RenderApi,
builder: &mut DisplayListBuilder,
_resources: &mut ResourceUpdates,
_layout_size: LayoutSize,
_pipeline_id: PipelineId,
document_id: DocumentId) {
// Build the iframe display list on first render.
if self.iframe_pipeline_id.is_none() {
let epoch = Epoch(0);
let root_background_color = ColorF::new(0.0, 1.0, 0.0, 1.0);

let iframe_pipeline_id = PipelineId(0, 1);
let layout_size = LayoutSize::new(100.0, 100.0);
let mut builder = DisplayListBuilder::new(iframe_pipeline_id, layout_size);
let resources = ResourceUpdates::new();

let bounds = (0,0).to(50, 50);
let info = LayoutPrimitiveInfo {
rect: bounds,
local_clip: None,
is_backface_visible: true,
};
builder.push_stacking_context(&info,
ScrollPolicy::Scrollable,
None,
TransformStyle::Flat,
None,
MixBlendMode::Normal,
Vec::new());

builder.push_rect(&info, ColorF::new(1.0, 1.0, 0.0, 1.0));
builder.pop_stacking_context();

api.set_display_list(
document_id,
epoch,
Some(root_background_color),
layout_size,
builder.finalize(),
true,
resources
);

self.iframe_pipeline_id = Some(iframe_pipeline_id);
api.enable_frame_output(document_id, iframe_pipeline_id, true);
}

let bounds = (100,100).to(200, 200);
let info = LayoutPrimitiveInfo {
rect: bounds,
local_clip: None,
is_backface_visible: true,
};
builder.push_stacking_context(&info,
ScrollPolicy::Scrollable,
None,
TransformStyle::Flat,
None,
MixBlendMode::Normal,
Vec::new());

builder.push_iframe(&info, self.iframe_pipeline_id.unwrap());

builder.pop_stacking_context();
}

fn draw_custom(&self, gl: &gl::Gl) {
let vbo = gl.gen_buffers(1)[0];
let vao = gl.gen_vertex_arrays(1)[0];

let pid = create_program(gl);

let vertices: [f32; 12] = [
0.0, 1.0,
1.0, 0.0,
0.0, 0.0,
0.0, 1.0,
1.0, 1.0,
1.0, 0.0
];

gl.active_texture(gl::TEXTURE0);
gl.bind_texture(gl::TEXTURE_2D, self.texture_id);

gl.use_program(pid);
let sampler = gl.get_uniform_location(pid, "s");
debug_assert!(sampler != -1);
gl.uniform_1i(sampler, 0);

gl.bind_buffer(gl::ARRAY_BUFFER, vbo);
gl::buffer_data(gl, gl::ARRAY_BUFFER, &vertices, gl::STATIC_DRAW);

gl.bind_vertex_array(vao);
gl.enable_vertex_attrib_array(0);
gl.vertex_attrib_pointer(0, 2, gl::FLOAT, false, 8, 0);

gl.draw_arrays(gl::TRIANGLES, 0, 6);

gl.delete_vertex_arrays(&[vao]);
gl.delete_buffers(&[vbo]);
gl.delete_program(pid);
}

fn on_event(&mut self,
_event: glutin::Event,
_api: &RenderApi,
_document_id: DocumentId) -> bool {
false
}

fn get_output_image_handler(&mut self, gl: &gl::Gl) -> Option<Box<webrender::OutputImageHandler>> {
let texture_id = gl.gen_textures(1)[0];

gl.bind_texture(gl::TEXTURE_2D, texture_id);
gl.tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as gl::GLint);
gl.tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as gl::GLint);
gl.tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as gl::GLint);
gl.tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as gl::GLint);
gl.tex_image_2d(gl::TEXTURE_2D,
0,
gl::RGBA as gl::GLint,
100,
100,
0,
gl::BGRA,
gl::UNSIGNED_BYTE,
None);
gl.bind_texture(gl::TEXTURE_2D, 0);

self.texture_id = texture_id;
Some(Box::new(OutputHandler::new(texture_id)))
}
}

fn main() {
let mut app = App {
iframe_pipeline_id: None,
texture_id: 0,
};
boilerplate::main_wrapper(&mut app, None);
}

pub fn compile_shader(gl: &gl::Gl,
shader_type: gl::GLenum,
source: &str)
-> gl::GLuint {
let id = gl.create_shader(shader_type);
gl.shader_source(id, &[source.as_bytes()]);
gl.compile_shader(id);
let log = gl.get_shader_info_log(id);
if gl.get_shader_iv(id, gl::COMPILE_STATUS) == (0 as gl::GLint) {
panic!("{:?} {}", source, log);
}
id
}

pub fn create_program(gl: &gl::Gl) -> gl::GLuint {
let vs_id = compile_shader(gl, gl::VERTEX_SHADER, VS);
let fs_id = compile_shader(gl, gl::FRAGMENT_SHADER, FS);

let pid = gl.create_program();
gl.attach_shader(pid, vs_id);
gl.attach_shader(pid, fs_id);

gl.bind_attrib_location(pid, 0, "aPos");
gl.link_program(pid);

gl.detach_shader(pid, vs_id);
gl.detach_shader(pid, fs_id);
gl.delete_shader(vs_id);
gl.delete_shader(fs_id);

if gl.get_program_iv(pid, gl::LINK_STATUS) == (0 as gl::GLint) {
let error_log = gl.get_program_info_log(pid);
panic!("{}", error_log);
}

pid
}
@@ -16,7 +16,7 @@ use std::ptr;
use std::rc::Rc;
use std::thread;
use api::{ColorF, ImageFormat};
use api::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, DeviceUintSize};
use api::{DeviceIntRect, DeviceUintSize};

#[derive(Debug, Copy, Clone, PartialEq, Ord, Eq, PartialOrd)]
pub struct FrameId(usize);
@@ -978,6 +978,31 @@ impl Device {
}
}

pub fn create_fbo_for_external_texture(&mut self, texture_id: u32) -> FBOId {
let fbo = FBOId(self.gl.gen_framebuffers(1)[0]);
self.bind_external_draw_target(fbo);
self.gl.bind_framebuffer(gl::FRAMEBUFFER, fbo.0);
self.gl.framebuffer_texture_2d(gl::FRAMEBUFFER,
gl::COLOR_ATTACHMENT0,
gl::TEXTURE_2D,
texture_id,
0);
fbo
}

pub fn delete_fbo(&mut self, fbo: FBOId) {
self.gl.delete_framebuffers(&[fbo.0]);
}

pub fn bind_external_draw_target(&mut self, fbo_id: FBOId) {
debug_assert!(self.inside_frame);

if self.bound_draw_fbo != fbo_id {
self.bound_draw_fbo = fbo_id;
fbo_id.bind(self.gl(), FBOTarget::Draw);
}
}

pub fn bind_program(&mut self, program: &Program) {
debug_assert!(self.inside_frame);

@@ -1166,20 +1191,10 @@ impl Device {
}

pub fn blit_render_target(&mut self,
src_texture: Option<(&Texture, i32)>,
src_rect: Option<DeviceIntRect>,
src_rect: DeviceIntRect,
dest_rect: DeviceIntRect) {
debug_assert!(self.inside_frame);

let src_rect = src_rect.unwrap_or_else(|| {
let texture = src_texture.unwrap().0;
DeviceIntRect::new(DeviceIntPoint::zero(),
DeviceIntSize::new(texture.width as gl::GLint,
texture.height as gl::GLint))
});

self.bind_read_target(src_texture);

self.gl.blit_framebuffer(src_rect.origin.x,
src_rect.origin.y,
src_rect.origin.x + src_rect.size.width,
@@ -13,7 +13,7 @@ use clip::ClipRegion;
use clip_scroll_tree::{ClipScrollTree, ScrollStates};
use euclid::rect;
use gpu_cache::GpuCache;
use internal_types::{FastHashMap, RendererFrame};
use internal_types::{FastHashMap, FastHashSet, RendererFrame};
use frame_builder::{FrameBuilder, FrameBuilderConfig};
use profiler::{GpuCacheProfileCounters, TextureCacheProfileCounters};
use resource_cache::{ResourceCache, TiledImageMap};
@@ -478,7 +478,8 @@ impl Frame {
pipeline_id,
composition_operations,
stacking_context.transform_style,
is_backface_visible);
is_backface_visible,
false);

self.flatten_items(traversal,
pipeline_id,
@@ -848,6 +849,7 @@ impl Frame {
pipeline_id,
CompositeOps::default(),
TransformStyle::Flat,
true,
true);

// We do this here, rather than above because we want any of the top-level
@@ -1202,6 +1204,7 @@ impl Frame {
display_lists: &DisplayListMap,
device_pixel_ratio: f32,
pan: LayerPoint,
output_pipelines: &FastHashSet<PipelineId>,
texture_cache_profile: &mut TextureCacheProfileCounters,
gpu_cache_profile: &mut GpuCacheProfileCounters)
-> RendererFrame {
@@ -1210,6 +1213,7 @@ impl Frame {
gpu_cache,
display_lists,
device_pixel_ratio,
output_pipelines,
texture_cache_profile,
gpu_cache_profile);
frame
@@ -1220,6 +1224,7 @@ impl Frame {
gpu_cache: &mut GpuCache,
display_lists: &DisplayListMap,
device_pixel_ratio: f32,
output_pipelines: &FastHashSet<PipelineId>,
texture_cache_profile: &mut TextureCacheProfileCounters,
gpu_cache_profile: &mut GpuCacheProfileCounters)
-> RendererFrame {
@@ -1231,6 +1236,7 @@ impl Frame {
&mut self.clip_scroll_tree,
display_lists,
device_pixel_ratio,
output_pipelines,
texture_cache_profile,
gpu_cache_profile)
);
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.